adaptive_media_picker 0.0.9
adaptive_media_picker: ^0.0.9 copied to clipboard
Adaptive Flutter media picker for images & videos with smart permissions, limited access UI, and cross-platform support (Android, iOS, Web, Desktop).
πΈ Adaptive Media Picker #
π Adaptive, permission-aware media picker for Flutter
Handles limited & full access gracefully β with native-like UX on Android, iOS, Web, and Desktop.
β¨ Why Adaptive Media Picker? #
Most media pickers only open the gallery or camera β but fail when permissions are limited or restricted.
adaptive_media_picker
is designed to handle every case automatically, making your UX seamless.
π‘ What makes it different? #
- β Auto permission handling
- β Built-in limited-access sheet (for iOS & Android)
- β Optional image cropping (Android / iOS / Web)
- β Works seamlessly on Web, Desktop, and Mobile
- β Single unified API for images & videos
β¨ Built-in limited access bottom sheet UI (native full-access flow on Android/iOS)
π Features at a Glance #
Feature | Description |
---|---|
π· Image & Video Picker | Pick single/multiple images or single videos |
βοΈ Cropping | Optional crop (Android, iOS, Web) |
π Permission-aware | Handles full, limited, denied states |
π§ Cross-platform | Works on mobile, web, and desktop |
πΌοΈ Built-in Limited Access UI | Native-like bottom sheet |
π§© Fallbacks | Smart fallbacks for unsupported platforms |
π― Web Safe | No dart:io β works on Flutter Web |
β οΈ Multiple video selection is not supported by native APIs.
ποΈ Platform Support Matrix #
Feature | Android | iOS | Web | macOS | Windows | Linux |
---|---|---|---|---|---|---|
Single image pick | β | β | β | β | β | β |
Multi-image pick | β | β | β | β | β | β |
Single video pick | β | β | β | β | β | β |
Multiple videos | β | β | β | β | β | β |
Camera capture | β | β | β | β | β | β |
Limited-access UX | β | β | β | β | β | β |
Cropping (single image) | β | β | β | β | β | β |
β‘ Quick Start #
final picker = AdaptiveMediaPicker();
// Pick a single image
final singleImage = await picker.pickImage(
context: context,
options: const PickOptions(source: ImageSource.gallery, imageQuality: 80),
);
// Pick and crop
final croppedImage = await picker.pickImage(
context: context,
options: const PickOptions(source: ImageSource.gallery, wantToCrop: true),
);
// Pick multiple images
final multiImages = await picker.pickMultiImage(
context: context,
options: const PickOptions(maxImages: 5, source: ImageSource.gallery),
);
// Pick a single video
final singleVideo = await picker.pickVideo(
context: context,
options: const PickOptions(source: ImageSource.gallery),
);
π¨ Theming #
Both the built-in limited-access bottom sheet and the optional cropper can follow your app theme or be overridden via PickOptions
:
- Automatic: By default, the package uses
Theme.of(context)
for surfaces and text. - Override: Set these optional fields on
PickOptions
:themeBrightness
:Brightness.light
orBrightness.dark
primaryColor
: the primary accent color (e.g.Colors.blue
)
Example:
final result = await picker.pickImage(
context: context,
options: const PickOptions(
wantToCrop: true,
themeBrightness: Brightness.dark,
primaryColor: Colors.blue,
),
);
Notes:
- Limited-access bottom sheet inherits your app theme when overrides are not provided.
- Android cropper toolbar, controls, and grid/frame colors derive from
themeBrightness
andprimaryColor
. - Web cropper uses the provided
context
(dialog/page) and will follow your theme colors; primary accent applies to available UI elements.
π Common Use Cases #
- πΌοΈ Select & crop a profile picture
- πΈ Capture or choose multiple images for a gallery/post
- π₯ Pick single video from camera or gallery
- π Handle limited access permissions gracefully
βοΈ Cropping Setup #
Cropping is supported on Android, iOS, and Web.
π± Android #
Add UCropActivity
to your AndroidManifest.xml
:
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
β Android embedding v2 required
βΉοΈ If you enable cropping and build a release APK/AAB (R8/minify), UCrop may reference OkHttp classes. Add these dependencies to your appβs
build.gradle(.kts)
to avoid missing-class errors (only needed when cropping on Android):
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okio:okio:3.6.0")
}
π iOS #
No additional setup required.
π Web #
Add cropperjs to web/index.html
:
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.js"></script>
π Limited Access UX #
When the user grants limited access, the picker automatically shows a native-like dialog with options:
- π Manage Selection (iOS only)
- βοΈ Open Settings (iOS/macOS/Android)
- π Auto-dismisses after interaction
βοΈ Permissions Setup #
π§± Android #
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
π iOS #
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to pick images.</string>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to take photos and videos.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access when recording videos.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app may save images/videos to your photo library.</string>
π» macOS #
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
π§© Desktop platforms use native file dialogs. Camera capture is not supported on desktop.
π§© API Overview #
Method | Description |
---|---|
pickImage() |
Pick single image (optionally cropped) |
pickMultiImage() |
Pick multiple images |
pickVideo() |
Pick single video |
π Data Models Overview #
π§© PickOptions #
Configuration options for image/video picking operations.
Field | Type | Description |
---|---|---|
maxImages |
int? |
Maximum number of images for multi-image pick. Ignored for single image/video. |
imageQuality |
int? |
JPEG compression quality (0β100). |
maxWidth |
int? |
Resize width for images when supported. |
maxHeight |
int? |
Resize height for images when supported. |
source |
ImageSource |
Source β gallery or camera . Falls back to gallery on web/desktop. |
showOpenSettingsDialog |
bool |
Show βOpen Settingsβ dialog when permission is permanently denied. |
settingsDialogTitle |
String? |
Custom title for the settings dialog. |
settingsDialogMessage |
String? |
Custom message for the settings dialog. |
settingsButtonLabel |
String? |
Label for the confirm button. |
cancelButtonLabel |
String? |
Label for the cancel button. |
wantToCrop |
bool |
Enable crop flow (Android/iOS/Web only, single image only). |
themeBrightness |
Brightness? |
Override theme for limited sheet & cropper (light /dark ). |
primaryColor |
Color? |
Primary accent color for limited sheet & cropper (e.g., blue). |
logTag |
String? |
Optional debug tag for internal logging. |
πΌοΈ PickedMedia #
Represents a single picked image or video.
Field | Type | Description |
---|---|---|
path |
String |
Local file path to the picked media. |
mimeType |
String? |
MIME type if available. |
width |
int? |
Image width (when known). |
height |
int? |
Image height (when known). |
π§Ύ PickResultSingle #
Returned from pickImage()
or pickVideo()
.
Field | Type | Description |
---|---|---|
item |
PickedMedia? |
Picked item, or null if none. |
permissionResolution |
PermissionResolution |
Final permission state after operation. |
metadata |
PickMetadata |
Metadata about crop and sizes. |
error |
PickError? |
Indicates if operation failed or canceled. |
π‘ Use
.isEmpty
to check if no item was selected.
π§Ύ PickResultMultiple #
Returned from pickMultiImage()
.
Field | Type | Description |
---|---|---|
items |
List<PickedMedia> |
All picked images. Empty if none. |
permissionResolution |
PermissionResolution |
Final permission state. |
π‘ Use
.isEmpty
to check if no images were selected.
π§ PickMetadata #
Extra info for debugging and analytics.
Field | Type | Description |
---|---|---|
cropApplied |
bool |
Whether cropping was applied. |
originalSize |
Size? |
Size before transformations. |
finalSize |
Size? |
Size after transformations. |
β οΈ PickError #
Typed error codes for single-pick operations.
Value | Description |
---|---|
canceled |
User canceled selection. |
cropCanceled |
User canceled cropping. |
io |
I/O or platform failure. |
unknown |
Unknown reason. |
π PermissionResolution #
Represents the final permission outcome.
Field | Type | Description |
---|---|---|
granted |
bool |
True if any form of access was granted. |
limited |
bool |
True if access is limited (iOS/Android 14+). |
permanentlyDenied |
bool |
True if user must change settings manually. |
Factories
Factory | Description |
---|---|
PermissionResolution.grantedFull() |
Full access granted. |
PermissionResolution.grantedLimited() |
Limited access granted. |
PermissionResolution.denied() |
Access denied (optionally permanent). |
π€ Author #
Created with β€οΈ by Jaimin Kavathia - πΌ LinkedIn
π License #
Licensed under the MIT License. Free for personal & commercial use.
β If you like this package, give it a star on GitHub & pub.dev!