Merge branch 'feature/null-safety'

This commit is contained in:
Miguel Ruivo 2021-03-04 18:02:21 +00:00
commit eb04cec551
10 changed files with 75 additions and 73 deletions

View File

@ -1,3 +1,5 @@
## 3.0.0
Adds null safety support ([#510](https://github.com/miguelpruivo/flutter_file_picker/issues/510)).
## 2.1.7 ## 2.1.7
### iOS ### iOS
- Fixes an issue where a crash could happen when picking a lot of media files in low memory devices ([#606](https://github.com/miguelpruivo/flutter_file_picker/issues/606)). - Fixes an issue where a crash could happen when picking a lot of media files in low memory devices ([#606](https://github.com/miguelpruivo/flutter_file_picker/issues/606)).
@ -17,13 +19,13 @@ iOS & Android: Updates `size` property from `PlatformFile` to be in bytes instea
iOS: Fixes iOS ViewController which is nil when UIWindow.rootViewController have changed. ([#525](https://github.com/miguelpruivo/flutter_file_picker/issues/525)). Thank you @devcxm. iOS: Fixes iOS ViewController which is nil when UIWindow.rootViewController have changed. ([#525](https://github.com/miguelpruivo/flutter_file_picker/issues/525)). Thank you @devcxm.
## 2.1.3 ## 2.1.3
Android: Updates file name handling method. ([#487](https://github.com/miguelpruivo/flutter_file_picker/issues/487)). Android: Updates file name handling method. ([#487](https://github.com/miguelpruivo/flutter_file_picker/issues/487))
## 2.1.2 ## 2.1.2
Desktop (Go): Fixed desktop plugin implementation. Thank you @DenchikBY. Desktop (Go): Fixed desktop plugin implementation. Thank you @DenchikBY. ([#382](https://github.com/miguelpruivo/flutter_file_picker/issues/382#issuecomment-744055654))
## 2.1.1 ## 2.1.1
iOS: Fixes an issue that could result in a crash when selecting a media item twice. ([#518](https://github.com/miguelpruivo/flutter_file_picker/issues/518)). iOS: Fixes an issue that could result in a crash when selecting a media item twice. ([#518](https://github.com/miguelpruivo/flutter_file_picker/issues/518))
## 2.1.0 ## 2.1.0
Adds `withReadStream` that allows bigger files to be streamed read into a `Stream<List<int>>`. Thanks @redsolver. Adds `withReadStream` that allows bigger files to be streamed read into a `Stream<List<int>>`. Thanks @redsolver.
@ -34,8 +36,8 @@ Updates `extension` helper getter to use the `name` property instead of `path`,
## 2.0.12 ## 2.0.12
Android: Android:
- Fixes an issue that could result in some files not being properly retrieved due to special characters on their names. ([#472](https://github.com/miguelpruivo/flutter_file_picker/issues/472)). - Fixes an issue that could result in some files not being properly retrieved due to special characters on their names. ([#472](https://github.com/miguelpruivo/flutter_file_picker/issues/472))
- Fixes a NPE that could happen with some devices. ([#482](https://github.com/miguelpruivo/flutter_file_picker/issues/482)). - Fixes a NPE that could happen with some devices. ([#482](https://github.com/miguelpruivo/flutter_file_picker/issues/482))
## 2.0.11 ## 2.0.11

View File

@ -2,15 +2,14 @@
// Generated file. Do not edit. // Generated file. Do not edit.
// //
// ignore: unused_import // ignore_for_file: lines_longer_than_80_chars
import 'dart:ui';
import 'package:file_picker/src/file_picker_web.dart'; import 'package:file_picker/src/file_picker_web.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// ignore: public_member_api_docs // ignore: public_member_api_docs
void registerPlugins(PluginRegistry registry) { void registerPlugins(Registrar registrar) {
FilePickerWeb.registerWith(registry.registrarFor(FilePickerWeb)); FilePickerWeb.registerWith(registrar);
registry.registerMessageHandler(); registrar.registerMessageHandler();
} }

View File

@ -50,7 +50,7 @@ class _FilePickerDemoState extends State<FilePickerDemo> {
void _clearCachedFiles() { void _clearCachedFiles() {
FilePicker.platform.clearTemporaryFiles().then((result) { FilePicker.platform.clearTemporaryFiles().then((result) {
_scaffoldKey.currentState.showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
backgroundColor: result ? Colors.green : Colors.red, backgroundColor: result ? Colors.green : Colors.red,
content: Text((result content: Text((result

View File

@ -2,6 +2,9 @@ name: file_picker_example
description: An example of how to use the file_picker plugin. description: An example of how to use the file_picker plugin.
version: 1.0.0+1 version: 1.0.0+1
environment:
sdk: '>=2.10.0 <3.0.0'
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter

View File

@ -60,14 +60,14 @@ abstract class FilePicker extends PlatformInterface {
/// with useful information regarding the picked [List<PlatformFile>]. /// with useful information regarding the picked [List<PlatformFile>].
/// ///
/// Returns [null] if aborted. /// Returns [null] if aborted.
Future<FilePickerResult> pickFiles({ Future<FilePickerResult?> pickFiles({
FileType type = FileType.any, FileType type = FileType.any,
List<String> allowedExtensions, List<String>? allowedExtensions,
Function(FilePickerStatus) onFileLoading, Function(FilePickerStatus)? onFileLoading,
bool allowCompression, bool? allowCompression,
bool allowMultiple = false, bool allowMultiple = false,
bool withData, bool? withData,
bool withReadStream, bool? withReadStream,
}) async => }) async =>
throw UnimplementedError('pickFiles() has not been implemented.'); throw UnimplementedError('pickFiles() has not been implemented.');
@ -78,13 +78,13 @@ abstract class FilePicker extends PlatformInterface {
/// of it whenever needed. However, this will force the cleanup if you want to manage those on your own. /// of it whenever needed. However, this will force the cleanup if you want to manage those on your own.
/// ///
/// Returns [true] if the files were removed with success, [false] otherwise. /// Returns [true] if the files were removed with success, [false] otherwise.
Future<bool> clearTemporaryFiles() async => throw UnimplementedError( Future<bool?> clearTemporaryFiles() async => throw UnimplementedError(
'clearTemporaryFiles() has not been implemented.'); 'clearTemporaryFiles() has not been implemented.');
/// Selects a directory and returns its absolute path. /// Selects a directory and returns its absolute path.
/// ///
/// On Android, this requires to be running on SDK 21 or above, else won't work. /// On Android, this requires to be running on SDK 21 or above, else won't work.
/// Returns [null] if folder path couldn't be resolved. /// Returns [null] if folder path couldn't be resolved.
Future<String> getDirectoryPath() async => Future<String?> getDirectoryPath() async =>
throw UnimplementedError('getDirectoryPath() has not been implemented.'); throw UnimplementedError('getDirectoryPath() has not been implemented.');
} }

View File

@ -21,17 +21,17 @@ const EventChannel _eventChannel =
/// An implementation of [FilePicker] that uses method channels. /// An implementation of [FilePicker] that uses method channels.
class FilePickerIO extends FilePicker { class FilePickerIO extends FilePicker {
static const String _tag = 'MethodChannelFilePicker'; static const String _tag = 'MethodChannelFilePicker';
static StreamSubscription _eventSubscription; static StreamSubscription? _eventSubscription;
@override @override
Future<FilePickerResult> pickFiles({ Future<FilePickerResult?> pickFiles({
FileType type = FileType.any, FileType type = FileType.any,
List<String> allowedExtensions, List<String>? allowedExtensions,
Function(FilePickerStatus) onFileLoading, Function(FilePickerStatus)? onFileLoading,
bool allowCompression = true, bool? allowCompression = true,
bool allowMultiple = false, bool allowMultiple = false,
bool withData = false, bool? withData = false,
bool withReadStream = false, bool? withReadStream = false,
}) => }) =>
_getPath( _getPath(
type, type,
@ -44,11 +44,11 @@ class FilePickerIO extends FilePicker {
); );
@override @override
Future<bool> clearTemporaryFiles() async => Future<bool?> clearTemporaryFiles() async =>
_channel.invokeMethod<bool>('clear'); _channel.invokeMethod<bool>('clear');
@override @override
Future<String> getDirectoryPath() async { Future<String?> getDirectoryPath() async {
try { try {
return await _channel.invokeMethod('dir', {}); return await _channel.invokeMethod('dir', {});
} on PlatformException catch (ex) { } on PlatformException catch (ex) {
@ -60,14 +60,14 @@ class FilePickerIO extends FilePicker {
return null; return null;
} }
Future<FilePickerResult> _getPath( Future<FilePickerResult?> _getPath(
FileType fileType, FileType fileType,
bool allowMultipleSelection, bool allowMultipleSelection,
bool allowCompression, bool? allowCompression,
List<String> allowedExtensions, List<String>? allowedExtensions,
Function(FilePickerStatus) onFileLoading, Function(FilePickerStatus)? onFileLoading,
bool withData, bool? withData,
bool withReadStream, bool? withReadStream,
) async { ) async {
final String type = describeEnum(fileType); final String type = describeEnum(fileType);
if (type != 'custom' && (allowedExtensions?.isNotEmpty ?? false)) { if (type != 'custom' && (allowedExtensions?.isNotEmpty ?? false)) {
@ -85,7 +85,7 @@ class FilePickerIO extends FilePicker {
); );
} }
final List<Map> result = await _channel.invokeListMethod(type, { final List<Map>? result = await _channel.invokeListMethod(type, {
'allowMultipleSelection': allowMultipleSelection, 'allowMultipleSelection': allowMultipleSelection,
'allowedExtensions': allowedExtensions, 'allowedExtensions': allowedExtensions,
'allowCompression': allowCompression, 'allowCompression': allowCompression,
@ -102,7 +102,7 @@ class FilePickerIO extends FilePicker {
platformFiles.add( platformFiles.add(
PlatformFile.fromMap( PlatformFile.fromMap(
platformFileMap, platformFileMap,
readStream: withReadStream readStream: withReadStream!
? File(platformFileMap['path']).openRead() ? File(platformFileMap['path']).openRead()
: null, : null,
), ),

View File

@ -19,7 +19,7 @@ class FilePickerResult {
/// original files (which can be accessed through its URI property). /// original files (which can be accessed through its URI property).
/// ///
/// Only available on IO. Throws `UnsupportedError` on Web. /// Only available on IO. Throws `UnsupportedError` on Web.
List<String> get paths => files List<String?> get paths => files
.map((file) => kIsWeb .map((file) => kIsWeb
? throw UnsupportedError( ? throw UnsupportedError(
'Picking paths is unsupported on Web. Please, use bytes property instead.') 'Picking paths is unsupported on Web. Please, use bytes property instead.')
@ -27,5 +27,5 @@ class FilePickerResult {
.toList(); .toList();
/// A `List<String>` containing all names from picked files with its extensions. /// A `List<String>` containing all names from picked files with its extensions.
List<String> get names => files.map((file) => file.name).toList(); List<String?> get names => files.map((file) => file.name).toList();
} }

View File

@ -9,7 +9,7 @@ import 'file_picker_result.dart';
import 'platform_file.dart'; import 'platform_file.dart';
class FilePickerWeb extends FilePicker { class FilePickerWeb extends FilePicker {
Element _target; late Element _target;
final String _kFilePickerInputsDomId = '__file_picker_web-file-input'; final String _kFilePickerInputsDomId = '__file_picker_web-file-input';
final int _readStreamChunkSize = 1000 * 1000; // 1 MB final int _readStreamChunkSize = 1000 * 1000; // 1 MB
@ -26,12 +26,12 @@ class FilePickerWeb extends FilePicker {
/// Initializes a DOM container where we can host input elements. /// Initializes a DOM container where we can host input elements.
Element _ensureInitialized(String id) { Element _ensureInitialized(String id) {
Element target = querySelector('#$id'); Element? target = querySelector('#$id');
if (target == null) { if (target == null) {
final Element targetElement = Element.tag('flt-file-picker-inputs') final Element targetElement = Element.tag('flt-file-picker-inputs')
..id = id; ..id = id;
querySelector('body').children.add(targetElement); querySelector('body')!.children.add(targetElement);
target = targetElement; target = targetElement;
} }
return target; return target;
@ -40,18 +40,18 @@ class FilePickerWeb extends FilePicker {
@override @override
Future<FilePickerResult> pickFiles({ Future<FilePickerResult> pickFiles({
FileType type = FileType.any, FileType type = FileType.any,
List<String> allowedExtensions, List<String>? allowedExtensions,
bool allowMultiple = false, bool allowMultiple = false,
Function(FilePickerStatus) onFileLoading, Function(FilePickerStatus)? onFileLoading,
bool allowCompression, bool? allowCompression,
bool withData = true, bool? withData = true,
bool withReadStream = false, bool? withReadStream = false,
}) async { }) async {
final Completer<List<PlatformFile>> filesCompleter = final Completer<List<PlatformFile>> filesCompleter =
Completer<List<PlatformFile>>(); Completer<List<PlatformFile>>();
String accept = _fileType(type, allowedExtensions); String accept = _fileType(type, allowedExtensions);
InputElement uploadInput = FileUploadInputElement(); InputElement uploadInput = FileUploadInputElement() as InputElement;
uploadInput.draggable = true; uploadInput.draggable = true;
uploadInput.multiple = allowMultiple; uploadInput.multiple = allowMultiple;
uploadInput.accept = accept; uploadInput.accept = accept;
@ -63,14 +63,14 @@ class FilePickerWeb extends FilePicker {
} }
changeEventTriggered = true; changeEventTriggered = true;
final List<File> files = uploadInput.files; final List<File> files = uploadInput.files!;
final List<PlatformFile> pickedFiles = []; final List<PlatformFile> pickedFiles = [];
void addPickedFile( void addPickedFile(
File file, File file,
Uint8List bytes, Uint8List? bytes,
String path, String? path,
Stream<List<int>> readStream, Stream<List<int>>? readStream,
) { ) {
pickedFiles.add(PlatformFile( pickedFiles.add(PlatformFile(
name: file.name, name: file.name,
@ -86,15 +86,15 @@ class FilePickerWeb extends FilePicker {
} }
files.forEach((File file) { files.forEach((File file) {
if (withReadStream) { if (withReadStream!) {
addPickedFile(file, null, null, _openFileReadStream(file)); addPickedFile(file, null, null, _openFileReadStream(file));
return; return;
} }
if (!withData) { if (!withData!) {
final FileReader reader = FileReader(); final FileReader reader = FileReader();
reader.onLoadEnd.listen((e) { reader.onLoadEnd.listen((e) {
addPickedFile(file, null, reader.result, null); addPickedFile(file, null, reader.result as String?, null);
}); });
reader.readAsDataUrl(file); reader.readAsDataUrl(file);
return; return;
@ -102,7 +102,7 @@ class FilePickerWeb extends FilePicker {
final FileReader reader = FileReader(); final FileReader reader = FileReader();
reader.onLoadEnd.listen((e) { reader.onLoadEnd.listen((e) {
addPickedFile(file, reader.result, null, null); addPickedFile(file, reader.result as Uint8List?, null, null);
}); });
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
}); });
@ -119,7 +119,7 @@ class FilePickerWeb extends FilePicker {
return FilePickerResult(await filesCompleter.future); return FilePickerResult(await filesCompleter.future);
} }
static String _fileType(FileType type, List<String> allowedExtensions) { static String _fileType(FileType type, List<String>? allowedExtensions) {
switch (type) { switch (type) {
case FileType.any: case FileType.any:
return ''; return '';
@ -137,11 +137,9 @@ class FilePickerWeb extends FilePicker {
return 'video/*|image/*'; return 'video/*|image/*';
case FileType.custom: case FileType.custom:
return allowedExtensions.fold( return allowedExtensions!
'', (prev, next) => '${prev.isEmpty ? '' : '$prev,'} .$next'); .fold('', (prev, next) => '${prev.isEmpty ? '' : '$prev,'} .$next');
break;
} }
return '';
} }
Stream<List<int>> _openFileReadStream(File file) async* { Stream<List<int>> _openFileReadStream(File file) async* {
@ -155,7 +153,7 @@ class FilePickerWeb extends FilePicker {
final blob = file.slice(start, end); final blob = file.slice(start, end);
reader.readAsArrayBuffer(blob); reader.readAsArrayBuffer(blob);
await reader.onLoad.first; await reader.onLoad.first;
yield reader.result; yield reader.result as List<int>;
start += _readStreamChunkSize; start += _readStreamChunkSize;
} }
} }

View File

@ -21,21 +21,21 @@ class PlatformFile {
/// ``` /// ```
/// final File myFile = File(platformFile.path); /// final File myFile = File(platformFile.path);
/// ``` /// ```
final String path; final String? path;
/// File name including its extension. /// File name including its extension.
final String name; final String? name;
/// Byte data for this file. Particurlarly useful if you want to manipulate its data /// Byte data for this file. Particurlarly useful if you want to manipulate its data
/// or easily upload to somewhere else. /// or easily upload to somewhere else.
final Uint8List bytes; final Uint8List? bytes;
/// File content as stream /// File content as stream
final Stream<List<int>> readStream; final Stream<List<int>>? readStream;
/// The file size in bytes. /// The file size in bytes.
final int size; final int? size;
/// File extension for this file. /// File extension for this file.
String get extension => name?.split('.')?.last; String? get extension => name?.split('.').last;
} }

View File

@ -1,7 +1,7 @@
name: file_picker name: file_picker
description: A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support. description: A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.
homepage: https://github.com/miguelpruivo/plugins_flutter_file_picker homepage: https://github.com/miguelpruivo/plugins_flutter_file_picker
version: 2.1.7 version: 3.0.0
dependencies: dependencies:
flutter: flutter:
@ -9,13 +9,13 @@ dependencies:
flutter_web_plugins: flutter_web_plugins:
sdk: flutter sdk: flutter
flutter_plugin_android_lifecycle: ^1.0.6 flutter_plugin_android_lifecycle: ^2.0.0
plugin_platform_interface: ^1.0.1 plugin_platform_interface: ^2.0.0
environment: environment:
sdk: ">=2.0.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
flutter: ">=1.10.0 <2.0.0" flutter: ">=1.10.0"
flutter: flutter:
plugin: plugin:
platforms: platforms: