diff --git a/.gitignore b/.gitignore
index b4779f1..73ee123 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,33 @@
.DS_Store
.atom/
-.idea
+.idea/
+.vscode/
+
.packages
-.dart_tool/
.pub/
-build/
-ios/.generated/
-packages
+.dart_tool/
pubspec.lock
-.iml
+
+Podfile
Podfile.lock
-file_picker.iml
\ No newline at end of file
+Pods/
+.symlinks/
+**/Flutter/App.framework/
+**/Flutter/Flutter.framework/
+**/Flutter/Generated.xcconfig
+**/Flutter/flutter_assets/
+ServiceDefinitions.json
+xcuserdata/
+
+local.properties
+.gradle/
+gradlew
+gradlew.bat
+gradle-wrapper.jar
+*.iml
+
+GeneratedPluginRegistrant.h
+GeneratedPluginRegistrant.m
+GeneratedPluginRegistrant.java
+build/
+.flutter-plugins
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dc5bfb4..8251cb0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,20 @@
+## 1.1.0
+
+**Breaking changes**
+ * `FileType.PDF` was removed since now it can be used along with custom file types by using the `FileType.CUSTOM` and providing the file extension (e.g. PDF, SVG, ZIP, etc.).
+ * `FileType.CAPTURE` is now `FileType.CAMERA`
+
+**New features**
+ * Now it is possible to provide a custom file extension to filter file picking options by using `FileType.CUSTOM`
+
+**Bug fixes and updates**
+ * Fixes file names from cloud on Android. Previously it would always display **Document**
+ * Fixes an issue on iOS where an exception was being thrown after canceling and re-opening the picker.
+ * Fixes an issue where collision could happen with request codes on Android.
+ * Adds public documentation to `file_picker`
+ * Example app updated.
+ * Updates .gitignore
+
## 1.0.3
* Fixes `build.gradle`.
diff --git a/README.md b/README.md
index bc05d74..be20362 100644
--- a/README.md
+++ b/README.md
@@ -4,17 +4,17 @@
# file_picker
-File picker plugin alows you to use a native file explorer to load absolute file path from different types of files.
+File picker plugin alows you to use a native file explorer to load absolute file path from different file types.
## Installation
First, add *file_picker* as a dependency in [your pubspec.yaml file](https://flutter.io/platform-plugins/).
```
-file_picker: ^1.0.2
+file_picker: ^1.1.0
```
## Android
-Add `` to your app `AndroidManifest.xml` file.
+Add `` to your app `AndroidManifest.xml` file.
## iOS
Since we are using *image_picker* as a dependency from this plugin to load paths from gallery and camera, we need the following keys to your _Info.plist_ file, located in `/ios/Runner/Info.plist`:
@@ -22,19 +22,19 @@ Since we are using *image_picker* as a dependency from this plugin to load paths
* `NSPhotoLibraryUsageDescription` - describe why your app needs permission for the photo library. This is called _Privacy - Photo Library Usage Description_ in the visual editor.
* `NSCameraUsageDescription` - describe why your app needs access to the camera. This is called _Privacy - Camera Usage Description_ in the visual editor.
* `NSMicrophoneUsageDescription` - describe why your app needs access to the microphone, if you intend to record videos. This is called _Privacy - Microphone Usage Description_ in the visual editor.
+* `UIBackgroundModes` with the `fetch` and `remote-notifications` keys - describe why your app needs to access background taks, such downloading files (from cloud services) when not cached to locate path. This is called _Required background modes_, with the keys _App download content from network_ and _App downloads content in response to push notifications_ respectively in the visual editor (since both methods aren't actually overriden, not adding this property/keys may only display a warning, but shouldn't prevent its correct usage).
-## To-do
+## Currently supported features
* [X] Load paths from **cloud files** (GDrive, Dropbox, iCloud)
-* [X] Load path from **PDF**
* [X] Load path from **gallery**
* [X] Load path from **camera**
* [X] Load path from **video**
* [X] Load path from **any** type of file (without filtering)
-* [ ] Load path from a **custom format**
+* [X] Load path from a **custom format** by providing a file extension (pdf, svg, zip, etc.)
## Demo App
-![Demo](https://github.com/miguelpruivo/plugins_flutter_file_picker/blob/master/example/demo.png)
+![Demo](https://github.com/miguelpruivo/plugins_flutter_file_picker/blob/master/example/example.gif)
## Example
```
diff --git a/android/.gitignore b/android/.gitignore
index adcdcf5..5aa89be 100644
--- a/android/.gitignore
+++ b/android/.gitignore
@@ -1,6 +1,7 @@
*.iml
*.class
.gradle
+.idea/
/local.properties
/.idea/workspace.xml
/.idea/libraries
diff --git a/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerPlugin.java b/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerPlugin.java
index b49139d..7fbcfa9 100644
--- a/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerPlugin.java
+++ b/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerPlugin.java
@@ -6,11 +6,14 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
+import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
+import android.webkit.MimeTypeMap;
import java.io.BufferedOutputStream;
+import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
@@ -25,10 +28,11 @@ import io.flutter.plugin.common.PluginRegistry.Registrar;
/** FilePickerPlugin */
public class FilePickerPlugin implements MethodCallHandler {
- private static final int REQUEST_CODE = 43;
+ private static final int REQUEST_CODE = FilePickerPlugin.class.hashCode() + 43;
+ private static final int PERM_CODE = FilePickerPlugin.class.hashCode() + 50;
private static final String TAG = "FilePicker";
-
private static final String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+
private static Result result;
private static Registrar instance;
private static String fileType;
@@ -54,7 +58,7 @@ public class FilePickerPlugin implements MethodCallHandler {
if(fullPath == null)
{
FileOutputStream fos = null;
- cloudFile = instance.activeContext().getCacheDir().getAbsolutePath() + "/Document";
+ cloudFile = instance.activeContext().getCacheDir().getAbsolutePath() + "/" + FileUtils.getFileName(uri, instance.activeContext());
try {
fos = new FileOutputStream(cloudFile);
@@ -78,7 +82,7 @@ public class FilePickerPlugin implements MethodCallHandler {
e.printStackTrace();
}
- Log.i(TAG, "Loaded file from cloud created on:" + cloudFile);
+ Log.i(TAG, "Cloud file loaded and cached on:" + cloudFile);
fullPath = cloudFile;
}
@@ -94,7 +98,7 @@ public class FilePickerPlugin implements MethodCallHandler {
instance.addRequestPermissionsResultListener(new PluginRegistry.RequestPermissionsResultListener() {
@Override
public boolean onRequestPermissionsResult(int requestCode, String[] strings, int[] grantResults) {
- if (requestCode == 0 && grantResults.length > 0
+ if (requestCode == PERM_CODE && grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startFileExplorer(fileType);
return true;
@@ -128,11 +132,20 @@ public class FilePickerPlugin implements MethodCallHandler {
Activity activity = instance.activity();
Log.i(TAG, "Requesting permission: " + permission);
String[] perm = { permission };
- ActivityCompat.requestPermissions(activity, perm, 0);
+ ActivityCompat.requestPermissions(activity, perm, PERM_CODE);
}
private String resolveType(String type) {
+ final boolean isCustom = type.contains("__CUSTOM_");
+
+ if(isCustom) {
+ final String extension = type.split("__CUSTOM_")[1].toLowerCase();
+ String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ Log.i(TAG, "Custom file type: " + mime);
+ return mime;
+ }
+
switch (type) {
case "PDF":
return "application/pdf";
@@ -152,14 +165,19 @@ public class FilePickerPlugin implements MethodCallHandler {
Intent intent;
if (checkPermission()) {
- if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
intent = new Intent(Intent.ACTION_PICK);
} else {
intent = new Intent(Intent.ACTION_GET_CONTENT);
}
+ Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath() + File.separator);
+ intent.setDataAndType(uri, type);
intent.setType(type);
intent.addCategory(Intent.CATEGORY_OPENABLE);
+
+ Log.d(TAG, "Intent: " + intent.toString());
+
instance.activity().startActivityForResult(intent, REQUEST_CODE);
} else {
requestPermission();
diff --git a/android/src/main/java/com/mr/flutter/plugin/filepicker/FileUtils.java b/android/src/main/java/com/mr/flutter/plugin/filepicker/FileUtils.java
index ca034c0..9a6bf56 100644
--- a/android/src/main/java/com/mr/flutter/plugin/filepicker/FileUtils.java
+++ b/android/src/main/java/com/mr/flutter/plugin/filepicker/FileUtils.java
@@ -1,4 +1,5 @@
package com.mr.flutter.plugin.filepicker;
+
import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.Context;
@@ -10,50 +11,42 @@ import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
+import android.webkit.MimeTypeMap;
/**
- * Credits to NiRRaNjAN from package in.gauriinfotech.commons;.
+ * Credits to NiRRaNjAN from utils extracted of in.gauriinfotech.commons;.
**/
-public class FileUtils
-{
+
+public class FileUtils {
private static final String tag = "FilePathPicker";
- public static String getPath(final Uri uri, Context context)
- {
+ public static String getPath(final Uri uri, Context context) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
- if (isKitKat)
- {
+ if (isKitKat) {
return getForApi19(context, uri);
- } else if ("content".equalsIgnoreCase(uri.getScheme()))
- {
- if (isGooglePhotosUri(uri))
- {
+ } else if ("content".equalsIgnoreCase(uri.getScheme())) {
+ if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
return getDataColumn(context, uri, null, null);
- } else if ("file".equalsIgnoreCase(uri.getScheme()))
- {
+ } else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
@TargetApi(19)
- private static String getForApi19(Context context, Uri uri)
- {
+ private static String getForApi19(Context context, Uri uri) {
Log.e(tag, "+++ API 19 URI :: " + uri);
- if (DocumentsContract.isDocumentUri(context, uri))
- {
+ if (DocumentsContract.isDocumentUri(context, uri)) {
Log.e(tag, "+++ Document URI");
- if (isExternalStorageDocument(uri))
- {
+ if (isExternalStorageDocument(uri)) {
Log.e(tag, "+++ External Document URI");
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
- if ("primary".equalsIgnoreCase(type))
- {
+ if ("primary".equalsIgnoreCase(type)) {
Log.e(tag, "+++ Primary External Document URI");
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
@@ -65,13 +58,25 @@ public class FileUtils
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
- try {
- final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
- return getDataColumn(context, contentUri, null, null);
- } catch (Exception e) {
- Log.e(tag, "+++ Something went wrong while retrieving document path: " + e.toString());
+
+ String[] contentUriPrefixesToTry = new String[]{
+ "content://downloads/public_downloads",
+ "content://downloads/my_downloads",
+ "content://downloads/all_downloads"
+ };
+ for (String contentUriPrefix : contentUriPrefixesToTry) {
+ Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
+ try {
+ String path = getDataColumn(context, contentUri, null, null);
+ if (path != null) {
+ return path;
+ }
+ } catch (Exception e) {
+ Log.e(tag, "+++ Something went wrong while retrieving document path: " + e.toString());
+ }
+ }
+
}
- }
} else if (isMediaDocument(uri)) {
Log.e(tag, "+++ Media Document URI");
final String docId = DocumentsContract.getDocumentId(uri);
@@ -79,16 +84,13 @@ public class FileUtils
final String type = split[0];
Uri contentUri = null;
- if ("image".equals(type))
- {
+ if ("image".equals(type)) {
Log.e(tag, "+++ Image Media Document URI");
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- } else if ("video".equals(type))
- {
+ } else if ("video".equals(type)) {
Log.e(tag, "+++ Video Media Document URI");
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- } else if ("audio".equals(type))
- {
+ } else if ("audio".equals(type)) {
Log.e(tag, "+++ Audio Media Document URI");
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
@@ -100,15 +102,13 @@ public class FileUtils
return getDataColumn(context, contentUri, selection, selectionArgs);
}
- } else if ("content".equalsIgnoreCase(uri.getScheme()))
- {
+ } else if ("content".equalsIgnoreCase(uri.getScheme())) {
Log.e(tag, "+++ No DOCUMENT URI :: CONTENT ");
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
- } else if ("file".equalsIgnoreCase(uri.getScheme()))
- {
+ } else if ("file".equalsIgnoreCase(uri.getScheme())) {
Log.e(tag, "+++ No DOCUMENT URI :: FILE ");
return uri.getPath();
}
@@ -116,47 +116,74 @@ public class FileUtils
}
private static String getDataColumn(Context context, Uri uri, String selection,
- String[] selectionArgs)
- {
+ String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
- try
- {
+ try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
- if (cursor != null && cursor.moveToFirst())
- {
+ if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
- } finally
- {
+ } finally {
if (cursor != null)
cursor.close();
}
return null;
}
- private static boolean isExternalStorageDocument(Uri uri)
- {
+ public static String getFileName(Uri uri, Context context) {
+ String result = null;
+
+ //if uri is content
+ if (uri.getScheme() != null && uri.getScheme().equals("content")) {
+ Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ //local filesystem
+ int index = cursor.getColumnIndex("_data");
+ if (index == -1)
+ //google drive
+ index = cursor.getColumnIndex("_display_name");
+ result = cursor.getString(index);
+ if (result != null)
+ uri = Uri.parse(result);
+ else
+ return null;
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ if(uri.getPath() != null) {
+ result = uri.getPath();
+ int cut = result.lastIndexOf('/');
+ if (cut != -1)
+ result = result.substring(cut + 1);
+ }
+
+ return result;
+ }
+
+
+ private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
- private static boolean isDownloadsDocument(Uri uri)
- {
+ private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
- private static boolean isMediaDocument(Uri uri)
- {
+ private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
- private static boolean isGooglePhotosUri(Uri uri)
- {
+ private static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
diff --git a/example/README.md b/example/README.md
deleted file mode 100644
index 012df4a..0000000
--- a/example/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# file_picker_example
-
-Demonstrates how to use the file_picker plugin.
-
-## Getting Started
-
-For help getting started with Flutter, view our online
-[documentation](https://flutter.io/).
diff --git a/example/demo.png b/example/demo.png
deleted file mode 100644
index 3811f04..0000000
Binary files a/example/demo.png and /dev/null differ
diff --git a/example/example.gif b/example/example.gif
new file mode 100644
index 0000000..77ffada
Binary files /dev/null and b/example/example.gif differ
diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist
index b841323..a25de3b 100644
--- a/example/ios/Runner/Info.plist
+++ b/example/ios/Runner/Info.plist
@@ -38,6 +38,11 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
+ UIBackgroundModes
+
+ fetch
+ remote-notification
+
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 39d5966..5e27ef0 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -13,20 +13,31 @@ class MyApp extends StatefulWidget {
class _MyAppState extends State {
String _fileName = '...';
String _path = '...';
- FileType _pickingType = FileType.ANY;
+ String _extension;
+ bool _hasValidMime = false;
+ FileType _pickingType;
+ TextEditingController _controller = new TextEditingController();
+
+ @override
+ void initState() {
+ super.initState();
+ _controller.addListener(() => _extension = _controller.text);
+ }
void _openFileExplorer() async {
- try {
- _path = await FilePicker.getFilePath(type: _pickingType);
- } on PlatformException catch (e) {
- print(e.toString());
+ if (_pickingType != FileType.CUSTOM || _hasValidMime) {
+ try {
+ _path = await FilePicker.getFilePath(type: _pickingType, fileExtension: _extension);
+ } on PlatformException catch (e) {
+ print("Unsupported operation" + e.toString());
+ }
+
+ if (!mounted) return;
+
+ setState(() {
+ _fileName = _path != null ? _path.split('/').last : '...';
+ });
}
-
- if (!mounted) return;
-
- setState(() {
- _fileName = _path != null ? _path.split('/').last : '...';
- });
}
@override
@@ -36,78 +47,97 @@ class _MyAppState extends State {
appBar: new AppBar(
title: const Text('Plugin example app'),
),
- body: new Center(
+ body: SingleChildScrollView(
+ child: new Center(
+ child: new Padding(
+ padding: const EdgeInsets.only(top: 50.0, left: 10.0, right: 10.0),
child: new Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- new Padding(
- padding: const EdgeInsets.all(20.0),
- child: new DropdownButton(
- hint: new Text('LOAD FILE PATH FROM...'),
- value: _pickingType,
- items: [
- new DropdownMenuItem(
- child: new Text('FROM CAMERA'),
- value: FileType.CAPTURE,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ new Padding(
+ padding: const EdgeInsets.only(top: 20.0),
+ child: new DropdownButton(
+ hint: new Text('LOAD PATH FROM'),
+ value: _pickingType,
+ items: [
+ new DropdownMenuItem(
+ child: new Text('FROM CAMERA'),
+ value: FileType.CAMERA,
+ ),
+ new DropdownMenuItem(
+ child: new Text('FROM GALLERY'),
+ value: FileType.IMAGE,
+ ),
+ new DropdownMenuItem(
+ child: new Text('FROM VIDEO'),
+ value: FileType.VIDEO,
+ ),
+ new DropdownMenuItem(
+ child: new Text('FROM ANY'),
+ value: FileType.ANY,
+ ),
+ new DropdownMenuItem(
+ child: new Text('CUSTOM FORMAT'),
+ value: FileType.CUSTOM,
+ ),
+ ],
+ onChanged: (value) => setState(() => _pickingType = value)),
+ ),
+ new ConstrainedBox(
+ constraints: new BoxConstraints(maxWidth: 150.0),
+ child: _pickingType == FileType.CUSTOM
+ ? new TextFormField(
+ maxLength: 20,
+ autovalidate: true,
+ controller: _controller,
+ decoration: InputDecoration(labelText: 'File type'),
+ keyboardType: TextInputType.text,
+ textCapitalization: TextCapitalization.none,
+ validator: (value) {
+ RegExp reg = new RegExp(r'[^a-zA-Z0-9]');
+ if (reg.hasMatch(value)) {
+ _hasValidMime = false;
+ return 'Invalid format';
+ }
+ _hasValidMime = true;
+ },
+ )
+ : new Container(),
+ ),
+ new Padding(
+ padding: const EdgeInsets.only(top: 50.0, bottom: 20.0),
+ child: new RaisedButton(
+ onPressed: () => _openFileExplorer(),
+ child: new Text("Open file picker"),
),
- new DropdownMenuItem(
- child: new Text('FROM GALLERY'),
- value: FileType.IMAGE,
+ ),
+ new Text(
+ 'URI PATH ',
+ textAlign: TextAlign.center,
+ style: new TextStyle(fontWeight: FontWeight.bold),
+ ),
+ new Text(
+ _path ?? '...',
+ textAlign: TextAlign.center,
+ softWrap: true,
+ textScaleFactor: 0.85,
+ ),
+ new Padding(
+ padding: const EdgeInsets.only(top: 10.0),
+ child: new Text(
+ 'FILE NAME ',
+ textAlign: TextAlign.center,
+ style: new TextStyle(fontWeight: FontWeight.bold),
),
- new DropdownMenuItem(
- child: new Text('FROM PDF'),
- value: FileType.PDF,
- ),
- new DropdownMenuItem(
- child: new Text('FROM VIDEO'),
- value: FileType.VIDEO,
- ),
- new DropdownMenuItem(
- child: new Text('FROM ANY'),
- value: FileType.ANY,
- )
- ],
- onChanged: (value) {
- setState(
- () {
- _pickingType = value;
- },
- );
- },
- ),
+ ),
+ new Text(
+ _fileName,
+ textAlign: TextAlign.center,
+ ),
+ ],
),
- new Padding(
- padding: const EdgeInsets.all(20.0),
- child: new RaisedButton(
- onPressed: () => _openFileExplorer(),
- child: new Text("Open file picker"),
- ),
- ),
- new Text(
- 'URI PATH ',
- textAlign: TextAlign.center,
- style: new TextStyle(fontWeight: FontWeight.bold),
- ),
- new Text(
- _path ?? '...',
- textAlign: TextAlign.center,
- softWrap: true,
- textScaleFactor: 0.85,
- ),
- new Padding(
- padding: const EdgeInsets.only(top: 10.0),
- child: new Text(
- 'FILE NAME ',
- textAlign: TextAlign.center,
- style: new TextStyle(fontWeight: FontWeight.bold),
- ),
- ),
- new Text(
- _fileName,
- textAlign: TextAlign.center,
- ),
- ],
- )),
+ )),
+ ),
),
);
}
diff --git a/ios/Classes/FilePickerPlugin.h b/ios/Classes/FilePickerPlugin.h
index d7d2a7d..145a322 100644
--- a/ios/Classes/FilePickerPlugin.h
+++ b/ios/Classes/FilePickerPlugin.h
@@ -2,5 +2,5 @@
#import
#import
-@interface FilePickerPlugin : NSObject
+@interface FilePickerPlugin : NSObject
@end
diff --git a/ios/Classes/FilePickerPlugin.m b/ios/Classes/FilePickerPlugin.m
index 4823c4c..f9bc5d3 100644
--- a/ios/Classes/FilePickerPlugin.m
+++ b/ios/Classes/FilePickerPlugin.m
@@ -83,7 +83,6 @@ didPickDocumentsAtURLs:(NSArray *)urls{
// VideoPicker delegate
-
- (void) resolvePickVideo{
UIImagePickerController *videoPicker = [[UIImagePickerController alloc] init];
@@ -102,7 +101,13 @@ didPickDocumentsAtURLs:(NSArray *)urls{
_result([videoURL path]);
}
+- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
+ _result = nil;
+ [controller dismissViewControllerAnimated:YES completion:NULL];
+}
+
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
+ _result = nil;
[picker dismissViewControllerAnimated:YES completion:NULL];
}
diff --git a/ios/Classes/FileUtils.h b/ios/Classes/FileUtils.h
index c5dbd83..a02ba06 100644
--- a/ios/Classes/FileUtils.h
+++ b/ios/Classes/FileUtils.h
@@ -4,6 +4,7 @@
//
// Created by Miguel Ruivo on 05/12/2018.
//
+#import
@interface FileUtils : NSObject
+ (NSString*) resolveType:(NSString*)type;
+ (NSString*) resolvePath:(NSArray *)urls;
diff --git a/ios/Classes/FileUtils.m b/ios/Classes/FileUtils.m
index 10576ab..ae24524 100644
--- a/ios/Classes/FileUtils.m
+++ b/ios/Classes/FileUtils.m
@@ -11,6 +11,18 @@
+ (NSString*) resolveType:(NSString*)type {
+ BOOL isCustom = [type containsString:@"__CUSTOM_"];
+
+ if(isCustom) {
+ type = [type stringByReplacingOccurrencesOfString:@"__CUSTOM_" withString:@""];
+ NSString * format = [NSString stringWithFormat:@"dummy.%@", type];
+ CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[format pathExtension], NULL);
+ NSString * UTIString = (__bridge NSString *)(UTI);
+ CFRelease(UTI);
+ NSLog(@"Custom file type: %@", UTIString);
+ return [UTIString containsString:@"dyn."] ? nil : UTIString;
+ }
+
if ([type isEqualToString:@"PDF"]) {
return @"com.adobe.pdf";
}
diff --git a/lib/file_picker.dart b/lib/file_picker.dart
index c722e9d..e1f60f2 100644
--- a/lib/file_picker.dart
+++ b/lib/file_picker.dart
@@ -6,36 +6,55 @@ import 'package:image_picker/image_picker.dart';
/// Supported file types, [ANY] should be used if the file you need isn't listed
enum FileType {
ANY,
- PDF,
IMAGE,
VIDEO,
- CAPTURE,
+ CAMERA,
+ CUSTOM,
}
class FilePicker {
static const MethodChannel _channel = const MethodChannel('file_picker');
+ static const String _tag = 'FilePicker';
- static Future _getPath(String type) async => await _channel.invokeMethod(type);
-
- static Future _getImage(ImageSource type) async {
- var image = await ImagePicker.pickImage(source: type);
-
- return image?.path;
+ static Future _getPath(String type) async {
+ try {
+ return await _channel.invokeMethod(type);
+ } on PlatformException catch (e) {
+ print("[$_tag] Platform exception: " + e.toString());
+ } catch (e) {
+ print(
+ "[$_tag] Unsupported operation. This probably have happened because [${type.split('_').last}] is an unsupported file type. You may want to try FileType.ALL instead.");
+ }
+ return null;
}
- /// Returns a [String] with the absolute path for the selected file
- static Future getFilePath({FileType type = FileType.ANY}) async {
+ static Future _getImage(ImageSource type) async {
+ try {
+ var image = await ImagePicker.pickImage(source: type);
+ return image?.path;
+ } on PlatformException catch (e) {
+ print("[$_tag] Platform exception: " + e.toString());
+ }
+ return null;
+ }
+
+ /// Returns an absolute file path from the calling platform
+ ///
+ /// A [type] must be provided to filter the picking results.
+ /// Can be used a custom file type with `FileType.CUSTOM`. A [fileExtension] must be provided (e.g. PDF, SVG, etc.)
+ /// Defaults to `FileType.ANY` which will display all file types.
+ static Future getFilePath({FileType type = FileType.ANY, String fileExtension}) async {
switch (type) {
case FileType.IMAGE:
return _getImage(ImageSource.gallery);
- case FileType.CAPTURE:
+ case FileType.CAMERA:
return _getImage(ImageSource.camera);
- case FileType.PDF:
- return _getPath('PDF');
case FileType.VIDEO:
return _getPath('VIDEO');
case FileType.ANY:
return _getPath('ANY');
+ case FileType.CUSTOM:
+ return _getPath('__CUSTOM_' + (fileExtension ?? ''));
default:
return _getPath('ANY');
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 71f999d..909ddab 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: file_picker
description: A plugin that allows you to pick absolute paths from diferent file types.
-version: 1.0.3
+version: 1.1.0
author: Miguel Ruivo
homepage: https://github.com/miguelpruivo/plugins_flutter_file_picker
@@ -23,33 +23,3 @@ flutter:
androidPackage: com.mr.flutter.plugin.filepicker
pluginClass: FilePickerPlugin
- # To add assets to your plugin package, add an assets section, like this:
- # assets:
- # - images/a_dot_burr.jpeg
- # - images/a_dot_ham.jpeg
- #
- # For details regarding assets in packages, see
- # https://flutter.io/assets-and-images/#from-packages
- #
- # An image asset can refer to one or more resolution-specific "variants", see
- # https://flutter.io/assets-and-images/#resolution-aware.
-
- # To add custom fonts to your plugin package, add a fonts section here,
- # in this "flutter" section. Each entry in this list should have a
- # "family" key with the font family name, and a "fonts" key with a
- # list giving the asset and other descriptors for the font. For
- # example:
- # fonts:
- # - family: Schyler
- # fonts:
- # - asset: fonts/Schyler-Regular.ttf
- # - asset: fonts/Schyler-Italic.ttf
- # style: italic
- # - family: Trajan Pro
- # fonts:
- # - asset: fonts/TrajanPro.ttf
- # - asset: fonts/TrajanPro_Bold.ttf
- # weight: 700
- #
- # For details regarding fonts in packages, see
- # https://flutter.io/custom-fonts/#from-packages