unified_file_picker 0.1.2
unified_file_picker: ^0.1.2 copied to clipboard
Cross-platform Flutter file and folder picker with a unified, fully customizable explorer-style UI — list, details, tiles, and icons views, search, thumbnails, theming, and RTL on Android, iOS, and desktop.
[unified_file_picker logo]
unified_file_picker
[unified_file_picker — cross-platform explorer-style file and folder picker for Flutter]
Cross-platform file and folder picker for Flutter with a unified, fully customizable explorer-style UI.
Published by quds.cc
Instead of relying on each platform's native dialog, unified_file_picker renders one consistent Flutter interface on Android, iOS, Windows, Linux, and macOS — with list/details/tiles/icons views, recursive search, keyboard shortcuts, thumbnails, and RTL support.
Table of contents #
- Features
- Platform support
- Installation
- Setup
- Quick start
- API overview
- Picker modes
- File type filters
- View modes
- Explorer UI
- Keyboard shortcuts
- Theming
- Localization
- Embedding the picker
- Saving files
- Return values
- Example app
- License
Features #
Core capabilities #
- Open files - single or multiple selection with preset or custom type filters
- Pick folders - navigate into subfolders on desktop; confirm current folder or selected folders
- Save files - choose destination folder, edit file name, optional overwrite confirmation
- Write bytes - persist data to a path returned by the save dialog
Explorer UI #
- Breadcrumb path bar - click segments to navigate; click the current segment or background to type/paste a full path (
Enternavigates,Escapecancels) - Navigation history - back, forward, and go-up controls
- Quick-access sidebar - Home, Desktop, Documents, Downloads, Pictures, Videos, Music, and drives/volumes (layout adapts to available width)
- Four view modes -list, details (sortable table), tiles, and icons with zoom controls
- Recursive search - search within the current folder tree with progress and cancel (desktop)
- Thumbnails - image and video previews where supported
- Context menu - sort by name/modified/type/size; switch view mode (desktop right-click)
- Marquee selection - drag to select multiple items (desktop, multi-select modes)
- Animated folder transitions - smooth content changes when navigating
Customization #
- Full theming - colors, typography, modal dimensions, sidebar width, per-kind icon overrides
- Presentation - modal dialog or fullscreen route with configurable enter/exit animations
- Localization - English and Arabic built-in; override any string per session
- RTL - layout direction support via
textDirectionor app locale - Adaptive chrome - Material on most platforms; Cupertino navigation on iOS/macOS
Platform support #
| Platform | Status | Notes |
|---|---|---|
| Windows | Full | dart:io backend; This PC root; drive list with volume labels and free/total space |
| Linux | Full | XDG user directories; root and mounted volumes |
| macOS | Full | Home shortcuts; ~/Movies for Videos |
| iOS | Full | Photos library via native plugin; phasset:// URIs; permission handling |
| Android | Partial | Native plugin is a stub — gallery/filesystem integration is not yet implemented |
Desktop platforms use a pure Dart dart:io backend and do not require native filesystem code. Mobile platforms use a platform channel (unified_file_picker) for gallery access and permissions.
Installation #
Add to your pubspec.yaml:
dependencies:
unified_file_picker: ^0.1.2
Then run:
flutter pub get
Requirements: Dart SDK ^3.12.2, Flutter >=3.3.0.
Setup #
Register the localization delegate in your app (required for built-in UI strings):
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:unified_file_picker/unified_file_picker.dart';
MaterialApp(
localizationsDelegates: const [
UnifiedFilePickerLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en'),
Locale('ar'),
],
// ...
);
Quick start #
Pick files #
final files = await UnifiedFilePicker.pickFiles(
context,
type: FilePickerType.images,
selection: SelectionMode.multiple,
);
if (files != null) {
for (final file in files) {
print('${file.name} → ${file.path}');
}
}
Pick a folder #
final folders = await UnifiedFilePicker.pickFolder(context);
if (folders != null && folders.isNotEmpty) {
print('Selected: ${folders.first.path}');
}
Save a file #
final location = await UnifiedFilePicker.saveFile(
context,
suggestedFileName: 'report.pdf',
type: FilePickerType.documents,
);
if (location != null) {
final success = await UnifiedFilePicker.writeBytes(location, pdfBytes);
}
Full control with options #
final result = await UnifiedFilePicker.pick(
context,
options: FilePickerOptions(
mode: FilePickerMode.open,
type: FilePickerType.images,
selection: SelectionMode.multiple,
initialViewMode: FilePickerViewMode.tiles,
showThumbnails: true,
presentation: FilePickerPresentation.modal,
theme: const FilePickerTheme(
title: 'Choose photos',
primaryColor: Color(0xFF5B4FCF),
borderRadius: 16,
),
),
);
API overview #
UnifiedFilePicker #
| Method | Returns | Description |
|---|---|---|
pick(context, options:) |
List<PickedFile>? |
Opens the picker with full FilePickerOptions configuration |
pickFiles(context, …) |
List<PickedFile>? |
Convenience wrapper for open-file mode |
pickFolder(context, …) |
List<PickedFile>? |
Convenience wrapper for folder mode |
saveFile(context, …) |
PickedFile? |
Save dialog; returns a single destination |
writeBytes(location, bytes) |
bool |
Writes bytes to a path from saveFile |
Presentation helpers #
| Function | Description |
|---|---|
showUnifiedFilePicker(context, options:) |
Dispatches modal or fullscreen based on options.presentation |
showUnifiedFilePickerModal(context, options:) |
Shows a centered dialog with theme constraints |
showUnifiedFilePickerRoute(context, options:) |
Pushes a fullscreen PageRoute |
Options factory #
Use FilePickerOptionsFactory for opinionated defaults, then copyWith for overrides:
final options = FilePickerOptionsFactory.openFiles(
type: FilePickerType.documents,
selection: SelectionMode.single,
).copyWith(
initialDirectory: '/home/user/Documents',
barrierDismissible: false,
);
Picker modes #
FilePickerMode.open #
Pick one or more files from the filesystem or mobile gallery.
- Filter by
FilePickerTypepreset or customFileTypeFilterlist - Optional thumbnails for images and videos
- Single-click to select, double-click to open on desktop
FilePickerMode.folder #
Pick one or more folders.
- On desktop: single-click selects, double-click enters a folder
- Use this folder action confirms the current directory without selecting a child
- Folder filter dropdown is hidden
FilePickerMode.save #
Choose a destination folder and file name.
- Pre-fills
suggestedFileName - File-type filter can append the correct extension
- Optional overwrite confirmation when
confirmExistingFileistrue(default)
Selection #
enum SelectionMode {
single, // one item at confirm
multiple, // Ctrl/Cmd+click, Shift+range, marquee, Select All
}
File type filters #
Preset types (FilePickerType) #
| Type | Description |
|---|---|
any |
All files |
documents |
PDF, Office, text, markdown, JSON, XML, HTML, CSV, … |
images |
JPG, PNG, GIF, WebP, HEIC, SVG, TIFF, … |
videos |
MP4, MOV, AVI, MKV, WebM, … |
Custom filters #
await UnifiedFilePicker.pickFiles(
context,
customFilters: const [
FileTypeFilter(
label: 'Markdown',
extensions: ['.md', '.markdown'],
mimeTypes: ['text/markdown'],
),
FileTypeFilter(
label: 'Archives',
extensions: ['.zip', '.tar', '.gz'],
),
],
initialFilter: /* optional FileTypeFilter */,
);
When customFilters is non-empty, it replaces the default filter derived from FilePickerType.
View modes #
Configure via initialViewMode and allowedViewModes:
| Mode | Description |
|---|---|
list |
Compact rows with icon and name |
details |
Sortable table — name, modified date, type, size |
tiles |
Medium square tiles in a zoomable grid |
icons |
Large square icons in a zoomable grid |
Tiles and icons modes include a zoom slider (0.7×–1.8×). Restrict available modes:
allowedViewModes: [
FilePickerViewMode.list,
FilePickerViewMode.details,
],
Explorer UI #
Breadcrumb path bar #
- Shows the current path as clickable segments
- Click any segment to jump to that folder
- Click the last segment or empty area to enter edit mode — type or paste a full path
- Enter navigates immediately; Escape cancels
- On Windows, paths display with backslashes (e.g.
C:\Users\…)
Quick-access sidebar #
When showShortcutsSidebar is true (default):
- Quick access — OS-specific shortcuts (Home, Desktop, Documents, Downloads, Pictures, Videos, Music)
- This PC — drives and mounted volumes
- Wide layouts show a vertical sidebar; compact layouts use a horizontal chip bar
On Windows, the empty path shows This PC with drive tiles including volume label, capacity bar, and free/total space.
Search #
Recursive folder search is available on desktop when browsing a real directory (not at the This PC root):
- Type in the search bar to scan subfolders
- Progress indicator and stop button during search
- Skips hidden and build directories (
.git,node_modules,build, …)
Sorting #
Sort folder contents by name, modified, type, or size (ascending/descending):
- Click column headers in details view
- Use the right-click context menu on desktop
Directories always sort before files.
Selection behavior #
| Platform | Behavior |
|---|---|
| Desktop | Single-click selects; double-click opens folder or confirms file |
| Mobile | Single tap activates |
| Multi-select | Ctrl/Cmd+click toggles; Shift+click range-selects; marquee drag on desktop |
The confirm button shows the selection count in multi-select mode.
Keyboard shortcuts #
| Shortcut | Action |
|---|---|
Escape |
Dismiss the picker |
Escape (path edit) |
Cancel path editing |
Enter (path edit) |
Navigate to typed path |
Ctrl/Cmd + A |
Select all (multi-select, non-save modes) |
Ctrl/Cmd + Click |
Toggle item in multi-select |
Shift + Click |
Range select (desktop) |
Theming #
Pass a FilePickerTheme to any pick method or embed it in FilePickerOptions:
const theme = FilePickerTheme(
primaryColor: Color(0xFF5B4FCF),
backgroundColor: Color(0xFF1E1E2E),
textColor: Colors.white,
borderRadius: 16,
modalMaxWidth: 1024,
modalMaxHeight: 720,
sidebarWidth: 240,
title: 'Choose files',
confirmLabel: 'Open',
cancelLabel: 'Cancel',
iconOverrides: {
FileEntryKind.folder: Icons.folder_special_rounded,
FileEntryKind.drive: Icons.storage_rounded,
},
);
Customizable properties #
| Category | Properties |
|---|---|
| Colors | primaryColor, backgroundColor, surfaceColor, textColor, subtitleColor, selectedColor, sidebar colors, per-kind icon colors, dividerColor, barrierColor |
| Modal | modalMaxWidth/Height, modalMinWidth/Height, modalElevation, modalInsetPadding, modalBorderSide, modalShadowColor |
| Layout | borderRadius, sidebarWidth, useGridWhenThumbnails |
| Typography | titleTextStyle, bodyTextStyle, subtitleTextStyle, sectionTitleStyle |
| Labels | title, confirmLabel, cancelLabel |
| Icons | iconOverrides — map of FileEntryKind → IconData |
Unset values inherit from the host app's ThemeData via mergeWithTheme. The picker also builds a harmonized ThemeData for internal Material widgets.
Presentation and transitions #
FilePickerOptions(
presentation: FilePickerPresentation.modal, // or .fullscreen
transition: FilePickerTransition(
kind: FilePickerTransitionKind.slideUp, // fade, slideFromStart, scale
duration: Duration(milliseconds: 280),
curve: Curves.easeOutCubic,
),
barrierDismissible: true,
)
Localization #
Built-in locales:
| Locale | Language |
|---|---|
en |
English |
ar |
Arabic (RTL) |
Override strings per session #
Extend UnifiedFilePickerStrings (or EnglishFilePickerStrings) and pass via FilePickerOptions.strings:
class BrandStrings extends EnglishFilePickerStrings {
const BrandStrings();
@override
String get selectFiles => 'Choose attachments';
@override
String get thisPc => 'My Computer';
}
await UnifiedFilePicker.pick(
context,
options: FilePickerOptions(
strings: const BrandStrings(),
textDirection: TextDirection.rtl, // optional explicit direction
),
);
The strings interface covers titles, action buttons, sidebar sections, sorting/view labels, search messages, path bar hints, save/overwrite dialogs, empty states, and permission prompts.
Embedding the picker #
Use FilePickerScreen to embed the explorer inside your own navigation instead of a modal:
FilePickerScreen(
options: myOptions,
// Optional: inject a custom FileSystemService for testing
)
Or call the lower-level helpers directly:
await showUnifiedFilePickerModal(context, options: myOptions);
await showUnifiedFilePickerRoute(context, options: myOptions);
Saving files #
Typical workflow #
// 1. Show save dialog
final location = await UnifiedFilePicker.saveFile(
context,
suggestedFileName: 'export.csv',
type: FilePickerType.documents,
confirmExistingFile: true,
);
if (location == null) return; // user cancelled
// 2. Write data
final ok = await UnifiedFilePicker.writeBytes(location, csvBytes);
Additional helpers #
// Copy an existing file to the save location
await SaveFileHelper.copyFrom(location, '/path/to/source.pdf');
// Check whether the target already exists
final exists = await SaveFileHelper.exists(location);
On save, the file-type filter can automatically append the correct extension via ensureExtension.
Return values #
| Method | Cancelled | Success |
|---|---|---|
pick / pickFiles / pickFolder |
null |
Non-empty List<PickedFile> |
saveFile |
null |
Single PickedFile |
PickedFile fields #
| Field | Description |
|---|---|
path |
Absolute filesystem path or platform URI (content://, phasset://) |
name |
Display file or folder name |
size |
Size in bytes when known |
mimeType |
MIME type hint |
isDirectory |
true for folder selections |
Example app #
The example/ app is a live customization demo. Run it from the plugin root:
cd example
flutter pub get
flutter run
Or use the example launch config in .vscode/launch.json.
The demo includes:
- Live embedded preview of
FilePickerScreen - Theme controls — accent color, dark mode, corner radius, modal size, sidebar width
- Presentation and transition pickers
- View mode and thumbnail toggles
- Custom strings and icon overrides
- English ↔ Arabic locale toggle with RTL
- Pick files, pick folder, and save file actions with result display
See example/README.md for additional run options and troubleshooting.
License #
MIT — see LICENSE.
Links #
- Repository: github.com/MohammedAsaadAsaad/unified_file_picker
- Issues: github.com/MohammedAsaadAsaad/unified_file_picker/issues
- Publisher: quds.cc
Publishing to pub.dev #
This package is ready for publication. Brand assets live in doc/ (logo.png, poster.png) and are referenced from this README for pub.dev and GitHub.
Before running flutter pub publish:
- Log in —
dart pub login(use the Google account that will own the package). - Verify the package — from the plugin root:
flutter pub get
flutter analyze
flutter test
flutter pub publish --dry-run
- Publish — when the dry run passes:
flutter pub publish - Tag the release on GitHub (required for pub.dev repository verification):
pub.dev checks thatgit tag v0.1.2 git push origin main --tagspubspec.yamlon GitHub matches the published package and that therepositoryURL is correct. - Optional verified publisher — to display
quds.ccas the verified publisher on pub.dev, complete domain verification and addpublisher: quds.ccback topubspec.yaml.
Note: The example app uses
publish_to: 'none'and is bundled for demonstration only — it is not published separately.