diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0e14d8e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "disabled" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 41cc7d8..9072f13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ -## 0.0.1 +## 0.1.4 +* Changed Meta minimum version due to versioning conflict with flutter_localization. -* TODO: Describe initial release. +## 0.1.3 + +* Updated readme. + +## 0.1.2 + +* Changed license from Apache 2.0 to MIT. +* Adds demo screenshot. + +## 0.1.1 + +* Adds license information (Apache 2.0). +* Adds CHANGELOG details. + +## 0.1.0 + +* Initial realise. +* Supports picking paths from files on local storage, cloud. +* Supports picking paths from both gallery & camera due to [image_picker](https://pub.dartlang.org/packages/image_picker) dependency. diff --git a/LICENSE b/LICENSE index ba75c69..e8b4b28 100644 --- a/LICENSE +++ b/LICENSE @@ -1 +1,21 @@ -TODO: Add your license here. +MIT License + +Copyright (c) 2018 Miguel Ruivo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 95161b6..14c9cbf 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,85 @@ # file_picker -A new flutter plugin project. +File picker plugin alows you to use a native file explorer to load absolute file path from different types of files. + +## Installation + +First, add *file_picker* as a dependency in [your pubspec.yaml file](https://flutter.io/platform-plugins/). + +``` +file_picker: ^0.1.3 +``` +## Android +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`: + +* `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. + +## To-do +[X] Load paths from local files & cloud (GDrive, Dropbox, iCloud)
+[X] Load PDF file path
+[X] Load path from gallery
+[X] Load path from camera shot
+[ ] Load a custom format
+ +## Demo App + +![Demo](https://github.com/miguelpruivo/plugins_flutter_file_picker/blob/master/example/demo.png) + +## Example +``` +import 'package:file_picker/file_picker.dart'; + +class MyHomePage extends StatefulWidget { + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +class _MyHomePageState extends State { + String _filePath; + + void getFilePath() async { + try { + String filePath = await FilePicker.getFilePath(type: FileType.PDF); + if (filePath == '') { + return; + } + print("File path: " + filePath); + setState((){this._filePath = filePath;}); + } on PlatformException catch (e) { + print("Error while picking the file: " + e.toString()); + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('File Picker Example'), + ), + body: new Center( + child: _filePath == null + ? new Text('No file selected.') + : new Text('Path' + _filePath), + ), + floatingActionButton: new FloatingActionButton( + onPressed: getFilePath, + tooltip: 'Select file', + child: new Icon(Icons.sd_storage), + ), + ); + } +} + +``` ## Getting Started For help getting started with Flutter, view our online [documentation](https://flutter.io/). -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). \ No newline at end of file +For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs index 6aa97a9..e889521 100644 --- a/android/.settings/org.eclipse.buildship.core.prefs +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -1,2 +1,2 @@ -connection.project.dir=../example/android +connection.project.dir= eclipse.preferences.version=1 diff --git a/example/demo.png b/example/demo.png new file mode 100644 index 0000000..b2bf21c Binary files /dev/null and b/example/demo.png differ diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..652a159 --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,28 @@ +PODS: + - file_picker (0.0.1): + - Flutter + - Flutter (1.0.0) + - image_picker (0.0.1): + - Flutter + +DEPENDENCIES: + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - Flutter (from `.symlinks/flutter/ios`) + - image_picker (from `.symlinks/plugins/image_picker/ios`) + +EXTERNAL SOURCES: + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + Flutter: + :path: ".symlinks/flutter/ios" + image_picker: + :path: ".symlinks/plugins/image_picker/ios" + +SPEC CHECKSUMS: + file_picker: 78c3344d9b2c343bb3090c2f032b796242ebaea7 + Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296 + image_picker: ee00aab0487cedc80a304085219503cc6d0f2e22 + +PODFILE CHECKSUM: 1e5af4103afd21ca5ead147d7b81d06f494f51a2 + +COCOAPODS: 1.5.3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 1d98193..b694a11 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 94EE95F5D222CC3C902F7AA8 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E29C2B321AA1B6738D05DCC /* libPods-Runner.a */; }; 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; @@ -56,6 +57,7 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9E29C2B321AA1B6738D05DCC /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -65,6 +67,7 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 94EE95F5D222CC3C902F7AA8 /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -91,7 +94,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, + EE3450EDCED914F636FA6BB9 /* Pods */, + BDC8FA085BD2993252DE5757 /* Frameworks */, ); sourceTree = ""; }; @@ -127,6 +131,21 @@ name = "Supporting Files"; sourceTree = ""; }; + BDC8FA085BD2993252DE5757 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9E29C2B321AA1B6738D05DCC /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + EE3450EDCED914F636FA6BB9 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -134,12 +153,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + A3515840785C8A9829855BB5 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + AB4C7D1508951531E70F0A36 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -228,6 +249,42 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + A3515840785C8A9829855BB5 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + AB4C7D1508951531E70F0A36 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 09849c0..15b1edd 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -4,8 +4,15 @@ CFBundleDevelopmentRegion en + CFBundleExecutable $(EXECUTABLE_NAME) + NSCameraUsageDescription + Used to demonstrate image picker plugin + NSMicrophoneUsageDescription + Used to capture audio for image picker plugin + NSPhotoLibraryUsageDescription + Used to demonstrate image picker plugin CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion diff --git a/example/lib/main.dart b/example/lib/main.dart index c1b824f..c65897b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -13,10 +13,11 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { String _path = '...'; String _fileName = '...'; + FileType _pickingType; void _openFileExplorer() async { try { - _path = await FilePicker.getFilePath; + _path = await FilePicker.getFilePath(type: _pickingType); } on PlatformException catch (e) { print(e.toString()); } @@ -24,7 +25,7 @@ class _MyAppState extends State { if (!mounted) return; setState(() { - _fileName = _path.split('/').last; + _fileName = _path != null ? _path.split('/').last : '...'; }); } @@ -45,6 +46,32 @@ class _MyAppState extends State { 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, + ), + new DropdownMenuItem( + child: new Text('FROM GALLERY'), + value: FileType.IMAGE, + ), + new DropdownMenuItem( + child: new Text('FROM PDF'), + value: FileType.PDF, + ) + ], + onChanged: (value) { + setState(() { + _pickingType = value; + }); + }, + ), + ), new Padding( padding: const EdgeInsets.all(20.0), child: new RaisedButton( diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart deleted file mode 100644 index 8b7e66d..0000000 --- a/example/test/widget_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -// 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:file_picker_example/main.dart'; - -void main() { - testWidgets('Verify Platform version', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(new MyApp()); - - // Verify that platform version is retrieved. - expect( - find.byWidgetPredicate( - (Widget widget) => - widget is Text && widget.data.startsWith('Running on:'), - ), - findsOneWidget); - }); -} diff --git a/lib/file_picker.dart b/lib/file_picker.dart index 4868fc1..8987b37 100644 --- a/lib/file_picker.dart +++ b/lib/file_picker.dart @@ -1,9 +1,35 @@ import 'dart:async'; import 'package:flutter/services.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:meta/meta.dart'; class FilePicker { static const MethodChannel _channel = const MethodChannel('file_picker'); - static Future get getFilePath async => await _channel.invokeMethod('pickPDF'); + static Future get _getPDF async => await _channel.invokeMethod('pickPDF'); + + static Future _getImage(ImageSource type) async { + var image = await ImagePicker.pickImage(source: type); + + return image?.path; + } + + static Future getFilePath({@required FileType type}) async { + switch (type) { + case FileType.PDF: + return _getPDF; + case FileType.IMAGE: + return _getImage(ImageSource.gallery); + case FileType.CAPTURE: + return _getImage(ImageSource.camera); + } + return ''; + } +} + +enum FileType { + PDF, + IMAGE, + CAPTURE, } diff --git a/pubspec.yaml b/pubspec.yaml index f3a0388..54e0f04 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,15 +1,17 @@ name: file_picker -description: A new flutter plugin project. -version: 0.0.1 -author: -homepage: +description: A plugin that allows you to pick absolute paths from diferent file types. +version: 0.1.4 +author: Miguel Ruivo +homepage: https://github.com/miguelpruivo/plugins_flutter_file_picker dependencies: flutter: sdk: flutter + image_picker: ^0.4.10 + meta: ^1.1.5 environment: - sdk: '<3.0.0' + sdk: ">=1.19.0 <3.0.0" # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec