diff --git a/file_picker/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerDelegate.java b/file_picker/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerDelegate.java
index b89cdb8..27b70fa 100644
--- a/file_picker/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerDelegate.java
+++ b/file_picker/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerDelegate.java
@@ -18,6 +18,7 @@ import androidx.core.app.ActivityCompat;
import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel;
@@ -100,11 +101,9 @@ public class FilePickerDelegate implements PluginRegistry.ActivityResultListener
Log.i(FilePickerDelegate.TAG, "[MultiFilePick] File #" + currentItem + " - URI: " + currentUri.getPath());
currentItem++;
}
- if (paths.size() > 1) {
- finishWithSuccess(paths);
- } else {
- finishWithSuccess(paths.get(0));
- }
+
+ finishWithSuccess(paths);
+
} else if (data.getData() != null) {
Uri uri = data.getData();
String fullPath;
@@ -125,7 +124,7 @@ public class FilePickerDelegate implements PluginRegistry.ActivityResultListener
if (fullPath != null) {
Log.i(FilePickerDelegate.TAG, "Absolute file path:" + fullPath);
- finishWithSuccess(fullPath);
+ finishWithSuccess(Arrays.asList(fullPath));
} else {
finishWithError("unknown_path", "Failed to retrieve path.");
}
diff --git a/file_picker/example/README.md b/file_picker/example/README.md
new file mode 100644
index 0000000..a135626
--- /dev/null
+++ b/file_picker/example/README.md
@@ -0,0 +1,16 @@
+# example
+
+A new Flutter project.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
+
+For help getting started with Flutter, view our
+[online documentation](https://flutter.dev/docs), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
diff --git a/file_picker/example/android/app/build.gradle b/file_picker/example/android/app/build.gradle
index ae8e6ae..97913c1 100644
--- a/file_picker/example/android/app/build.gradle
+++ b/file_picker/example/android/app/build.gradle
@@ -22,7 +22,7 @@ android {
}
defaultConfig {
- applicationId "com.mr.flutter.plugin.filepickerexample"
+ applicationId "com.mr.flutter.plugin.filepicker.example"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
diff --git a/file_picker/example/android/app/src/debug/AndroidManifest.xml b/file_picker/example/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..66063d7
--- /dev/null
+++ b/file_picker/example/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/file_picker/example/android/app/src/main/AndroidManifest.xml b/file_picker/example/android/app/src/main/AndroidManifest.xml
index 91966c1..6365b83 100644
--- a/file_picker/example/android/app/src/main/AndroidManifest.xml
+++ b/file_picker/example/android/app/src/main/AndroidManifest.xml
@@ -1,5 +1,5 @@
+
+
diff --git a/file_picker/example/ios/Flutter/.last_build_id b/file_picker/example/ios/Flutter/.last_build_id
new file mode 100644
index 0000000..0b85c88
--- /dev/null
+++ b/file_picker/example/ios/Flutter/.last_build_id
@@ -0,0 +1 @@
+0915ff87e81a3bfb122df4ced418a2b0
\ No newline at end of file
diff --git a/file_picker/example/ios/Runner.xcodeproj/project.pbxproj b/file_picker/example/ios/Runner.xcodeproj/project.pbxproj
index 97a44e0..039ac22 100644
--- a/file_picker/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/file_picker/example/ios/Runner.xcodeproj/project.pbxproj
@@ -310,7 +310,6 @@
/* Begin XCBuildConfiguration section */
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -366,7 +365,6 @@
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
diff --git a/file_picker/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/file_picker/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/file_picker/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/file_picker/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/file_picker/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/file_picker/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/file_picker/example/ios/Runner/AppDelegate.swift b/file_picker/example/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000..70693e4
--- /dev/null
+++ b/file_picker/example/ios/Runner/AppDelegate.swift
@@ -0,0 +1,13 @@
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+}
diff --git a/file_picker/example/ios/Runner/Runner-Bridging-Header.h b/file_picker/example/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000..308a2a5
--- /dev/null
+++ b/file_picker/example/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/file_picker/example/lib/generated_plugin_registrant.dart b/file_picker/example/lib/generated_plugin_registrant.dart
new file mode 100644
index 0000000..daa72e8
--- /dev/null
+++ b/file_picker/example/lib/generated_plugin_registrant.dart
@@ -0,0 +1,16 @@
+//
+// Generated file. Do not edit.
+//
+
+// ignore: unused_import
+import 'dart:ui';
+
+import 'package:file_picker/src/file_picker_web.dart';
+
+import 'package:flutter_web_plugins/flutter_web_plugins.dart';
+
+// ignore: public_member_api_docs
+void registerPlugins(PluginRegistry registry) {
+ FilePickerWeb.registerWith(registry.registrarFor(FilePickerWeb));
+ registry.registerMessageHandler();
+}
diff --git a/file_picker/example/lib/src/file_picker_demo.dart b/file_picker/example/lib/src/file_picker_demo.dart
index 47ac026..99f61ee 100644
--- a/file_picker/example/lib/src/file_picker_demo.dart
+++ b/file_picker/example/lib/src/file_picker_demo.dart
@@ -5,19 +5,18 @@ import 'package:file_picker/file_picker.dart';
class FilePickerDemo extends StatefulWidget {
@override
- _FilePickerDemoState createState() => new _FilePickerDemoState();
+ _FilePickerDemoState createState() => _FilePickerDemoState();
}
class _FilePickerDemoState extends State {
final GlobalKey _scaffoldKey = GlobalKey();
String _fileName;
- String _path;
- Map _paths;
+ List _paths;
String _extension;
bool _loadingPath = false;
bool _multiPick = false;
FileType _pickingType = FileType.any;
- TextEditingController _controller = new TextEditingController();
+ TextEditingController _controller = TextEditingController();
@override
void initState() {
@@ -28,97 +27,84 @@ class _FilePickerDemoState extends State {
void _openFileExplorer() async {
setState(() => _loadingPath = true);
try {
- if (_multiPick) {
- _path = null;
- _paths = await FilePicker.getMultiFilePath(
- type: _pickingType,
- allowedExtensions: (_extension?.isNotEmpty ?? false)
- ? _extension?.replaceAll(' ', '')?.split(',')
- : null,
- );
- } else {
- _paths = null;
- _path = await FilePicker.getFilePath(
- type: _pickingType,
- allowedExtensions: (_extension?.isNotEmpty ?? false)
- ? _extension?.replaceAll(' ', '')?.split(',')
- : null,
- );
- }
+ _paths = (await FilePicker.instance.pickFiles(
+ type: _pickingType,
+ allowMultiple: _multiPick,
+ allowedExtensions: (_extension?.isNotEmpty ?? false) ? _extension?.replaceAll(' ', '')?.split(',') : null,
+ ))
+ ?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
+ } catch (ex) {
+ print(ex);
}
if (!mounted) return;
setState(() {
_loadingPath = false;
- _fileName = _path != null
- ? _path.split('/').last
- : _paths != null ? _paths.keys.toString() : '...';
+ _fileName = _paths != null ? _paths.map((e) => e.name).toString() : '...';
});
}
void _clearCachedFiles() {
- FilePicker.clearTemporaryFiles().then((result) {
+ FilePicker.instance.clearTemporaryFiles().then((result) {
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: result ? Colors.green : Colors.red,
- content: Text((result
- ? 'Temporary files removed with success.'
- : 'Failed to clean temporary files')),
+ content: Text((result ? 'Temporary files removed with success.' : 'Failed to clean temporary files')),
),
);
});
}
void _selectFolder() {
- FilePicker.getDirectoryPath().then((value) {
- setState(() => _path = value);
+ FilePicker.instance.getDirectoryPath().then((value) {
+ setState(() => _paths = [value]);
});
}
@override
Widget build(BuildContext context) {
- return new MaterialApp(
- home: new Scaffold(
+ return MaterialApp(
+ home: Scaffold(
key: _scaffoldKey,
- appBar: new AppBar(
+ appBar: AppBar(
title: const Text('File Picker example app'),
),
- body: new Center(
- child: new Padding(
+ body: Center(
+ child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
- child: new SingleChildScrollView(
- child: new Column(
+ child: SingleChildScrollView(
+ child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
- new Padding(
+ Padding(
padding: const EdgeInsets.only(top: 20.0),
- child: new DropdownButton(
- hint: new Text('LOAD PATH FROM'),
+ child: DropdownButton(
+ hint: Text('LOAD PATH FROM'),
value: _pickingType,
items: [
- new DropdownMenuItem(
- child: new Text('FROM AUDIO'),
+ DropdownMenuItem(
+ child: Text('FROM AUDIO'),
value: FileType.audio,
),
- new DropdownMenuItem(
- child: new Text('FROM IMAGE'),
+ DropdownMenuItem(
+ child: Text('FROM IMAGE'),
value: FileType.image,
),
- new DropdownMenuItem(
- child: new Text('FROM VIDEO'),
+ DropdownMenuItem(
+ child: Text('FROM VIDEO'),
value: FileType.video,
),
- new DropdownMenuItem(
- child: new Text('FROM MEDIA'),
+ DropdownMenuItem(
+ child: Text('FROM MEDIA'),
value: FileType.media,
),
- new DropdownMenuItem(
- child: new Text('FROM ANY'),
+ DropdownMenuItem(
+ child: Text('FROM ANY'),
value: FileType.any,
),
- new DropdownMenuItem(
- child: new Text('CUSTOM FORMAT'),
+ DropdownMenuItem(
+ child: Text('CUSTOM FORMAT'),
value: FileType.custom,
),
],
@@ -129,87 +115,76 @@ class _FilePickerDemoState extends State {
}
})),
),
- new ConstrainedBox(
- constraints: BoxConstraints.tightFor(width: 100.0),
+ ConstrainedBox(
+ constraints: const BoxConstraints.tightFor(width: 100.0),
child: _pickingType == FileType.custom
- ? new TextFormField(
+ ? TextFormField(
maxLength: 15,
autovalidate: true,
controller: _controller,
- decoration:
- InputDecoration(labelText: 'File extension'),
+ decoration: InputDecoration(labelText: 'File extension'),
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.none,
)
- : new Container(),
+ : const SizedBox(),
),
- new ConstrainedBox(
- constraints: BoxConstraints.tightFor(width: 200.0),
- child: new SwitchListTile.adaptive(
- title: new Text('Pick multiple files',
- textAlign: TextAlign.right),
- onChanged: (bool value) =>
- setState(() => _multiPick = value),
+ ConstrainedBox(
+ constraints: const BoxConstraints.tightFor(width: 200.0),
+ child: SwitchListTile.adaptive(
+ title: Text('Pick multiple files', textAlign: TextAlign.right),
+ onChanged: (bool value) => setState(() => _multiPick = value),
value: _multiPick,
),
),
- new Padding(
+ Padding(
padding: const EdgeInsets.only(top: 50.0, bottom: 20.0),
child: Column(
children: [
- new RaisedButton(
+ RaisedButton(
onPressed: () => _openFileExplorer(),
- child: new Text("Open file picker"),
+ child: Text("Open file picker"),
),
- new RaisedButton(
+ RaisedButton(
onPressed: () => _selectFolder(),
- child: new Text("Pick folder"),
+ child: Text("Pick folder"),
),
- new RaisedButton(
+ RaisedButton(
onPressed: () => _clearCachedFiles(),
- child: new Text("Clear temporary files"),
+ child: Text("Clear temporary files"),
),
],
),
),
- new Builder(
+ Builder(
builder: (BuildContext context) => _loadingPath
? Padding(
padding: const EdgeInsets.only(bottom: 10.0),
- child: const CircularProgressIndicator())
- : _path != null || _paths != null
- ? new Container(
+ child: const CircularProgressIndicator(),
+ )
+ : _paths != null
+ ? Container(
padding: const EdgeInsets.only(bottom: 30.0),
height: MediaQuery.of(context).size.height * 0.50,
- child: new Scrollbar(
- child: new ListView.separated(
- itemCount: _paths != null && _paths.isNotEmpty
- ? _paths.length
- : 1,
+ child: Scrollbar(
+ child: ListView.separated(
+ itemCount: _paths != null && _paths.isNotEmpty ? _paths.length : 1,
itemBuilder: (BuildContext context, int index) {
- final bool isMultiPath =
- _paths != null && _paths.isNotEmpty;
- final String name = 'File $index: ' +
- (isMultiPath
- ? _paths.keys.toList()[index]
- : _fileName ?? '...');
- final path = isMultiPath
- ? _paths.values.toList()[index].toString()
- : _path;
+ final bool isMultiPath = _paths != null && _paths.isNotEmpty;
+ final String name =
+ 'File $index: ' + (isMultiPath ? _paths.map((e) => e.name).toList()[index] : _fileName ?? '...');
+ final path = _paths.map((e) => e.path).toList()[index].toString();
- return new ListTile(
- title: new Text(
+ return ListTile(
+ title: Text(
name,
),
- subtitle: new Text(path),
+ subtitle: Text(path),
);
},
- separatorBuilder:
- (BuildContext context, int index) =>
- new Divider(),
+ separatorBuilder: (BuildContext context, int index) => const Divider(),
)),
)
- : new Container(),
+ : const SizedBox(),
),
],
),
diff --git a/file_picker/example/test/widget_test.dart b/file_picker/example/test/widget_test.dart
new file mode 100644
index 0000000..747db1d
--- /dev/null
+++ b/file_picker/example/test/widget_test.dart
@@ -0,0 +1,30 @@
+// This is a basic Flutter widget test.
+//
+// To perform an interaction with a widget in your test, use the WidgetTester
+// utility that Flutter provides. For example, you can send tap and scroll
+// gestures. You can also use WidgetTester to find child widgets in the widget
+// tree, read text, and verify that the values of widget properties are correct.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:example/main.dart';
+
+void main() {
+ testWidgets('Counter increments smoke test', (WidgetTester tester) async {
+ // Build our app and trigger a frame.
+ await tester.pumpWidget(MyApp());
+
+ // Verify that our counter starts at 0.
+ expect(find.text('0'), findsOneWidget);
+ expect(find.text('1'), findsNothing);
+
+ // Tap the '+' icon and trigger a frame.
+ await tester.tap(find.byIcon(Icons.add));
+ await tester.pump();
+
+ // Verify that our counter has incremented.
+ expect(find.text('0'), findsNothing);
+ expect(find.text('1'), findsOneWidget);
+ });
+}
diff --git a/file_picker/example/web/favicon.png b/file_picker/example/web/favicon.png
new file mode 100644
index 0000000..8aaa46a
Binary files /dev/null and b/file_picker/example/web/favicon.png differ
diff --git a/file_picker/example/web/icons/Icon-192.png b/file_picker/example/web/icons/Icon-192.png
new file mode 100644
index 0000000..b749bfe
Binary files /dev/null and b/file_picker/example/web/icons/Icon-192.png differ
diff --git a/file_picker/example/web/icons/Icon-512.png b/file_picker/example/web/icons/Icon-512.png
new file mode 100644
index 0000000..88cfd48
Binary files /dev/null and b/file_picker/example/web/icons/Icon-512.png differ
diff --git a/file_picker/example/web/index.html b/file_picker/example/web/index.html
new file mode 100644
index 0000000..9b7a438
--- /dev/null
+++ b/file_picker/example/web/index.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ example
+
+
+
+
+
+
+
+
diff --git a/file_picker/example/web/manifest.json b/file_picker/example/web/manifest.json
new file mode 100644
index 0000000..c638001
--- /dev/null
+++ b/file_picker/example/web/manifest.json
@@ -0,0 +1,23 @@
+{
+ "name": "example",
+ "short_name": "example",
+ "start_url": ".",
+ "display": "minimal-ui",
+ "background_color": "#0175C2",
+ "theme_color": "#0175C2",
+ "description": "A new Flutter project.",
+ "orientation": "portrait-primary",
+ "prefer_related_applications": false,
+ "icons": [
+ {
+ "src": "icons/Icon-192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "icons/Icon-512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ]
+}
diff --git a/file_picker/ios/Classes/FilePickerPlugin.m b/file_picker/ios/Classes/FilePickerPlugin.m
index ab65a33..72738aa 100644
--- a/file_picker/ios/Classes/FilePickerPlugin.m
+++ b/file_picker/ios/Classes/FilePickerPlugin.m
@@ -253,7 +253,7 @@
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url{
[self.documentPickerController dismissViewControllerAnimated:YES completion:nil];
NSString * path = (NSString *)[url path];
- _result(path);
+ _result(@[path]);
_result = nil;
}
@@ -267,12 +267,7 @@ didPickDocumentsAtURLs:(NSArray *)urls{
[self.documentPickerController dismissViewControllerAnimated:YES completion:nil];
NSArray * result = [FileUtils resolvePath:urls];
-
- if([result count] > 1) {
- _result(result);
- } else {
- _result([result objectAtIndex:0]);
- }
+ _result(result);
_result = nil;
}
@@ -323,7 +318,7 @@ didPickDocumentsAtURLs:(NSArray *)urls{
return;
}
- _result([pickedVideoUrl != nil ? pickedVideoUrl : pickedImageUrl path]);
+ _result(@[[pickedVideoUrl != nil ? pickedVideoUrl : pickedImageUrl path]]);
_result = nil;
}
diff --git a/file_picker/lib/file_picker.dart b/file_picker/lib/file_picker.dart
index 96c63de..7a75eb1 100644
--- a/file_picker/lib/file_picker.dart
+++ b/file_picker/lib/file_picker.dart
@@ -1,131 +1,5 @@
-import 'dart:async';
-import 'dart:io';
+library file_picker;
-import 'package:file_picker_platform_interface/file_picker_platform_interface.dart';
-import 'package:file_picker_platform_interface/method_channel_file_picker.dart';
-
-export 'package:file_picker_platform_interface/file_picker_platform_interface.dart'
- show FileType;
-
-final MethodChannelFilePicker _filePickerPlatform = FilePickerPlatform.instance;
-
-class FilePicker {
- FilePicker._();
-
- /// Returns an absolute file path from the calling platform.
- ///
- /// Extension filters are allowed with [FileType.custom], when used, make sure to provide a [List]
- /// of `allowedExtensions` (e.g. [`pdf`, `svg`, `jpg`].).
- ///
- /// If you want to track picking status, for example, because some files may take some time to be
- /// cached (particularly those picked from cloud providers), you may want to set [onFileLoading] handler
- /// that will give you the current status of picking.
- ///
- /// If you plan on picking images/videos and don't want them to be compressed automatically by OS,
- /// you should set `allowCompression` to [false]. Calling this on Android won't have any effect, as
- /// it already provides you the original file (or integral copy).
- ///
- /// Defaults to [FileType.any] which will display all file types.
- static Future getFilePath({
- FileType type = FileType.any,
- List allowedExtensions,
- Function(FilePickerStatus) onFileLoading,
- bool allowCompression,
- }) async =>
- await _filePickerPlatform.getFiles(
- type: type,
- allowedExtensions: allowedExtensions,
- onFileLoading: onFileLoading,
- allowCompression: allowCompression,
- );
-
- /// Returns an iterable [Map] where the `key` is the name of the file
- /// and the `value` the path.
- ///
- /// A [List] with `allowedExtensions` can be provided to filter the allowed files to picked.
- /// If provided, make sure you select [FileType.custom] as type.
- ///
- /// If you want to track picking status, for example, because some files may take some time to be
- /// cached (particularly those picked from cloud providers), you may want to set `onFileLoading` handler
- /// that will give you the current status of picking.
- ///
- /// If you plan on picking images/videos and don't want them to be compressed automatically by OS,
- /// you should set `allowCompression` to [false]. Calling this on Android won't have any effect, as
- /// it already provides you the original file (or integral copy).
- ///
- /// Defaults to `FileType.any`, which allows any combination of files to be multi selected at once.
- static Future