Magic Logo

Magic Picker

Pick a file, an image or a video and get a MagicFile back.
The Pick facade for Magic apps opens the gallery, camera, file dialog and save dialog on every platform, and PickerServiceProvider lets Storage.download open the share sheet on mobile and desktop.

pub package CI codecov License: MIT pub points

Documentation · pub.dev · Issues

At a glance

Fact Value
Package magic_picker
Install flutter pub add magic_picker, then dart run magic:dowel plugin:install magic_picker
Import package:magic_picker/magic_picker.dart
Entry points Pick (facade), PickerServiceProvider (wiring, download handler), XFile.toMagicFile() and MagicFile.toXFile() (extensions); re-exports XFile and CameraDevice
Platforms Android, iOS, web, macOS, Windows and Linux. The camera on desktop needs a custom image_picker delegate; Pick.directory is not available on the web.
Requires Dart >=3.13, Flutter >=3.47, magic ^1.0.0
Dependencies magic, file_picker, image_picker, share_plus; dowel runs the installer
License MIT

Install

flutter pub add magic_picker
dart run magic:dowel plugin:install magic_picker

The installer registers PickerServiceProvider in the providers list of lib/config/app.dart. It publishes no config: Pick needs no settings.

Pick

Open a picker and store the result.

import 'package:magic_picker/magic_picker.dart';

Future<void> main() async {
  final image = await Pick.image(maxWidth: 1024, imageQuality: 85);
  if (image == null) return; // The user cancelled.

  await image.store('avatars/profile.jpg');
}
Member Returns Meaning
Pick.image, Pick.media, Pick.video Future<MagicFile?> One image, one image or video, one video from the gallery.
Pick.images Future<List<MagicFile>> Several images; empty on cancel.
Pick.camera, Pick.recordVideo Future<MagicFile?> A photo or a recording; fallbackToGallery and onError handle a refused permission.
Pick.file, Pick.files Future<MagicFile?>, Future<List<MagicFile>> One or several files, optionally filtered by extensions.
Pick.directory Future<String?> A directory path; not on the web.
Pick.saveFile Future<Uri?> Writes bytes through the save dialog; the Uri scheme is file, content or blob by platform.

A cancelled pick answers null (a list: empty), never an error. File contents are read on demand, not at pick time.

Download

Storage.download needs a handler on mobile and desktop, and PickerServiceProvider installs it.

import 'package:magic/magic.dart';

Future<void> main() async {
  await Storage.download('reports/2024.pdf', name: 'Annual Report.pdf');
}
Platform What happens
Mobile and desktop PickerServiceProvider.boot() sets LocalAdapterContract.downloadHandler; the file opens in the share sheet.
Web A browser download. The handler is ignored.
Mobile or desktop without the plugin download throws UnsupportedError, naming magic_picker.

XFile

toMagicFile() is a Future everywhere. toXFile() is synchronous on mobile and desktop, where it wraps the path, and a Future on the web, where it reads the bytes first. It throws UnsupportedError for a file with no path (IO) or no bytes (web).

For AI coding agents

Rules for an agent writing code against this package. Each one is a mistake that costs a user a crash or a silent no-op.

Do Because
Import only package:magic_picker/magic_picker.dart Everything under src/ is private; the barrel also exports XFile and CameraDevice.
Register PickerServiceProvider in lib/config/app.dart It is not auto-registered, and without it Storage.download throws on mobile and desktop.
Treat a null or empty result as a cancelled pick Cancelling is not an error.
Pass onError or fallbackToGallery to Pick.camera and Pick.recordVideo Otherwise a refused camera permission rethrows.
Read savedTo.scheme before toFilePath() on a Pick.saveFile result Only file uris convert; Android answers content and the web blob.
await toXFile() in code that also builds for the web It is a Future there and synchronous elsewhere.
Do not pass withData to Pick.file or Pick.files The parameter no longer exists; call readAsBytes on the result.
In a test, reset LocalAdapterContract.downloadHandler to null in tearDown It is a static that Magic.flush() does not clear.

Dependencies

magic for the container, MagicFile, Storage and the service provider base class; image_picker for the gallery and camera; file_picker for files, directories and the save dialog; share_plus for the share sheet; dowel to run the installer through dart run magic:dowel.

License

MIT, see LICENSE. Built by Anılcan Çakır.

Libraries

cli
The CLI surface of magic_picker, kept apart from the runtime barrel.
magic_picker
File and image picking for Magic apps.