# File Picker
- [Introduction](#introduction)
- [Picking Images](#picking-images)
- [Picking Videos](#picking-videos)
- [Picking Files](#picking-files)
- [MagicFile Reference](#magicfile-reference)
- [Properties](#properties)
- [Methods](#methods)
- [Complete Examples](#complete-examples)
## Introduction
The `Pick` facade provides a Laravel-style interface for accessing the device's camera and file system. It handles platform-specific implementations and permissions, returning a unified `MagicFile` object.
**Underlying packages:**
- `image_picker` for images and camera
- `file_picker` for documents and directories
## Picking Images
### From Gallery
```dart
// Single image
final MagicFile? image = await Pick.image(
maxWidth: 1024,
maxHeight: 1024,
imageQuality: 85, // 0-100
);
// Multiple images
final List images = await Pick.images();
```
### From Camera
```dart
final MagicFile? photo = await Pick.camera(
preferredCamera: CameraDevice.front, // or .rear
maxWidth: 800,
imageQuality: 90,
fallbackToGallery: true, // If camera permission denied
onError: (e) => print('Camera error: $e'),
);
```
## Picking Videos
### From Gallery
```dart
final MagicFile? video = await Pick.video(
maxDuration: Duration(minutes: 5),
);
```
### Record New Video
```dart
final MagicFile? video = await Pick.recordVideo(
maxDuration: Duration(seconds: 30),
preferredCamera: CameraDevice.rear,
);
```
## Picking Files
### Any File
```dart
final MagicFile? file = await Pick.file();
```
### Filtered by Extension
```dart
final MagicFile? pdf = await Pick.file(extensions: ['pdf']);
final MagicFile? doc = await Pick.file(extensions: ['doc', 'docx']);
```
### Multiple Files
```dart
final List files = await Pick.files(
extensions: ['jpg', 'png', 'pdf'],
);
```
### Directory (Mobile/Desktop)
```dart
final String? directoryPath = await Pick.directory();
```
## MagicFile Reference
All `Pick` methods return `MagicFile` (or `List`). This class provides unified access to file data and convenient methods for storage and upload.
### Properties
| Property | Type | Description |
|----------|------|-------------|
| `path` | `String?` | Original file path (null on Web) |
| `name` | `String` | File name with extension (e.g., 'photo.jpg') |
| `size` | `int?` | File size in bytes |
| `mimeType` | `String?` | MIME type (e.g., 'image/jpeg') |
| `extension` | `String` | Extension without dot (e.g., 'jpg') |
| `isImage` | `bool` | True for: jpg, jpeg, png, gif, webp, bmp, heic |
| `isVideo` | `bool` | True for: mp4, mov, avi, mkv, webm, m4v |
**Example:**
```dart
final file = await Pick.image();
if (file != null) {
print(file.name); // 'IMG_001.jpg'
print(file.extension); // 'jpg'
print(file.mimeType); // 'image/jpeg'
print(file.size); // 245760
print(file.isImage); // true
print(file.isVideo); // false
}
```
### Methods
#### readAsBytes()
Read file as byte array. Bytes are cached after first read.
```dart
final Uint8List? bytes = await file.readAsBytes();
```
#### store(path, {disk})
Save to [Magic Storage](/digging-deeper/file-storage):
```dart
final storedPath = await file.store('avatars/profile.jpg');
// Returns: 'avatars/profile.jpg'
// To specific disk
await file.store('avatars/profile.jpg', disk: 'public');
```
#### storeAs(directory, {disk})
Save with auto-generated unique filename:
```dart
final storedPath = await file.storeAs('uploads');
// Returns: 'uploads/1704067200000_IMG_001.jpg'
```
#### upload(url, {fieldName, data, headers})
Upload to server via multipart form:
```dart
final response = await file.upload(
'/api/upload',
fieldName: 'document', // Form field name (default: 'file')
data: {
'user_id': user.id,
'category': 'profile',
},
headers: {
'X-Custom-Header': 'value',
},
);
if (response.successful) {
final uploadedUrl = response['url'];
Magic.success('Uploaded!', uploadedUrl);
} else {
Magic.error('Upload failed', response['message']);
}
```
## Complete Examples
### Profile Picture Upload
```dart
Future updateAvatar() async {
final image = await Pick.image(maxWidth: 512, imageQuality: 80);
if (image == null) return;
Magic.loading(message: 'Uploading...');
final response = await image.upload('/api/user/avatar');
Magic.closeLoading();
if (response.successful) {
Magic.success('Success', 'Avatar updated!');
user.avatarUrl = response['url'];
} else {
Magic.error('Error', response['message'] ?? 'Upload failed');
}
}
```
### Document Picker with Local Storage
```dart
Future saveDocument() async {
final doc = await Pick.file(extensions: ['pdf', 'doc', 'docx']);
if (doc == null) return;
// Store locally
final path = await doc.storeAs('documents');
// Save reference
await Document.create({
'name': doc.name,
'path': path,
'size': doc.size,
'mime_type': doc.mimeType,
});
Magic.success('Saved', doc.name);
}
```
### Gallery with Multiple Selection
```dart
Future uploadGallery() async {
final images = await Pick.images();
if (images.isEmpty) return;
Magic.loading(message: 'Uploading ${images.length} images...');
for (final image in images) {
await image.upload('/api/gallery', data: {
'album_id': currentAlbum.id,
});
}
Magic.closeLoading();
Magic.success('Done', '${images.length} images uploaded');
}
```