From 4b3c599ca0ee2a53ca8ab92c2c0a68b724ef9468 Mon Sep 17 00:00:00 2001 From: BeMacized Date: Mon, 21 Jun 2021 14:51:50 +0200 Subject: [PATCH 01/16] Migrate image picker platform interface to cross_file --- .../CHANGELOG.md | 8 +++ .../lib/image_picker_platform_interface.dart | 1 + .../method_channel_image_picker.dart | 17 ++--- .../image_picker_platform.dart | 16 ++--- .../types/{picked_file => }/lost_data.dart | 3 +- .../lib/src/types/picked_file/base.dart | 62 ------------------- .../lib/src/types/picked_file/html.dart | 49 --------------- .../lib/src/types/picked_file/io.dart | 41 ------------ .../src/types/picked_file/picked_file.dart | 8 --- .../src/types/picked_file/unsupported.dart | 18 ------ .../lib/src/types/types.dart | 2 +- .../pubspec.yaml | 3 +- .../test/picked_file_html_test.dart | 38 ------------ .../test/picked_file_io_test.dart | 42 ------------- 14 files changed, 32 insertions(+), 276 deletions(-) rename packages/image_picker/image_picker_platform_interface/lib/src/types/{picked_file => }/lost_data.dart (96%) delete mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart delete mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart delete mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart delete mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart delete mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart delete mode 100644 packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart delete mode 100644 packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index e2def7243592..36188838cc2d 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,3 +1,11 @@ +## 3.0.0 + +* Breaking changes: + * pickImage now returns XFile instead of PickedFile + * pickVideo now returns XFile instead of PickedFile + * changed LostData file parameter type to XFile + * removed PickedFile class and its tests + ## 2.1.0 * Add `pickMultiImage` method. diff --git a/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart b/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart index b384e3845c4b..133c05ecfebf 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart @@ -4,3 +4,4 @@ export 'package:image_picker_platform_interface/src/platform_interface/image_picker_platform.dart'; export 'package:image_picker_platform_interface/src/types/types.dart'; +export 'package:cross_file/cross_file.dart'; diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart index e0f46457a8b8..9f36d5b07d03 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:image_picker_platform_interface/src/types/lost_data.dart'; import 'package:meta/meta.dart' show visibleForTesting; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; @@ -19,7 +20,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { MethodChannel get channel => _channel; @override - Future pickImage({ + Future pickImage({ required ImageSource source, double? maxWidth, double? maxHeight, @@ -33,11 +34,11 @@ class MethodChannelImagePicker extends ImagePickerPlatform { imageQuality: imageQuality, preferredCameraDevice: preferredCameraDevice, ); - return path != null ? PickedFile(path) : null; + return path != null ? XFile(path) : null; } @override - Future?> pickMultiImage({ + Future?> pickMultiImage({ double? maxWidth, double? maxHeight, int? imageQuality, @@ -49,9 +50,9 @@ class MethodChannelImagePicker extends ImagePickerPlatform { ); if (paths == null) return null; - final List files = []; + final List files = []; for (final path in paths) { - files.add(PickedFile(path)); + files.add(XFile(path)); } return files; } @@ -117,7 +118,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override - Future pickVideo({ + Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, Duration? maxDuration, @@ -127,7 +128,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { maxDuration: maxDuration, preferredCameraDevice: preferredCameraDevice, ); - return path != null ? PickedFile(path) : null; + return path != null ? XFile(path) : null; } Future _pickVideoPath({ @@ -175,7 +176,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { final String? path = result['path']; return LostData( - file: path != null ? PickedFile(path) : null, + file: path != null ? XFile(path) : null, exception: exception, type: retrieveType, ); diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart index 32af7747185a..5f35c5300c94 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart @@ -3,6 +3,8 @@ // found in the LICENSE file. import 'dart:async'; +import 'package:cross_file/cross_file.dart'; +import 'package:image_picker_platform_interface/src/types/lost_data.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -40,7 +42,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { // Next version of the API. - /// Returns a [PickedFile] with the image that was picked. + /// Returns a [XFile] with the image that was picked. /// /// The `source` argument controls where the image comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. @@ -68,7 +70,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. /// /// If no images were picked, the return value is null. - Future pickImage({ + Future pickImage({ required ImageSource source, double? maxWidth, double? maxHeight, @@ -78,7 +80,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { throw UnimplementedError('pickImage() has not been implemented.'); } - /// Returns a [List] with the images that were picked. + /// Returns a [List] with the images that were picked. /// /// The images come from the [ImageSource.gallery]. /// @@ -96,7 +98,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// a warning message will be logged. /// /// If no images were picked, the return value is null. - Future?> pickMultiImage({ + Future?> pickMultiImage({ double? maxWidth, double? maxHeight, int? imageQuality, @@ -104,7 +106,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { throw UnimplementedError('pickMultiImage() has not been implemented.'); } - /// Returns a [PickedFile] containing the video that was picked. + /// Returns a [XFile] containing the video that was picked. /// /// The [source] argument controls where the video comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. @@ -120,7 +122,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. /// /// If no images were picked, the return value is null. - Future pickVideo({ + Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, Duration? maxDuration, @@ -128,7 +130,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { throw UnimplementedError('pickVideo() has not been implemented.'); } - /// Retrieve the lost [PickedFile] file when [pickImage] or [pickVideo] failed because the MainActivity is destroyed. (Android only) + /// Retrieve the lost [XFile] file when [pickImage] or [pickVideo] failed because the MainActivity is destroyed. (Android only) /// /// Image or video can be lost if the MainActivity is destroyed. And there is no guarantee that the MainActivity is always alive. /// Call this method to retrieve the lost data and process the data according to your APP's business logic. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data.dart similarity index 96% rename from packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart rename to packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data.dart index 64f6a1f27538..a270eece235e 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:cross_file/cross_file.dart'; import 'package:flutter/services.dart'; import 'package:image_picker_platform_interface/src/types/types.dart'; @@ -31,7 +32,7 @@ class LostData { /// The file that was lost in a previous [pickImage] or [pickVideo] call due to MainActivity being destroyed. /// /// Can be null if [exception] exists. - final PickedFile? file; + final XFile? file; /// The exception of the last [pickImage] or [pickVideo]. /// diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart deleted file mode 100644 index de259e0611dd..000000000000 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:meta/meta.dart'; - -/// The interface for a PickedFile. -/// -/// A PickedFile is a container that wraps the path of a selected -/// file by the user and (in some platforms, like web) the bytes -/// with the contents of the file. -/// -/// This class is a very limited subset of dart:io [File], so all -/// the methods should seem familiar. -@immutable -abstract class PickedFileBase { - /// Construct a PickedFile - PickedFileBase(String path); - - /// Get the path of the picked file. - /// - /// This should only be used as a backwards-compatibility clutch - /// for mobile apps, or cosmetic reasons only (to show the user - /// the path they've picked). - /// - /// Accessing the data contained in the picked file by its path - /// is platform-dependant (and won't work on web), so use the - /// byte getters in the PickedFile instance instead. - String get path { - throw UnimplementedError('.path has not been implemented.'); - } - - /// Synchronously read the entire file contents as a string using the given [Encoding]. - /// - /// By default, `encoding` is [utf8]. - /// - /// Throws Exception if the operation fails. - Future readAsString({Encoding encoding = utf8}) { - throw UnimplementedError('readAsString() has not been implemented.'); - } - - /// Synchronously read the entire file contents as a list of bytes. - /// - /// Throws Exception if the operation fails. - Future readAsBytes() { - throw UnimplementedError('readAsBytes() has not been implemented.'); - } - - /// Create a new independent [Stream] for the contents of this file. - /// - /// If `start` is present, the file will be read from byte-offset `start`. Otherwise from the beginning (index 0). - /// - /// If `end` is present, only up to byte-index `end` will be read. Otherwise, until end of file. - /// - /// In order to make sure that system resources are freed, the stream must be read to completion or the subscription on the stream must be cancelled. - Stream openRead([int? start, int? end]) { - throw UnimplementedError('openRead() has not been implemented.'); - } -} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart deleted file mode 100644 index 24e1931008b6..000000000000 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:http/http.dart' as http show readBytes; - -import './base.dart'; - -/// A PickedFile that works on web. -/// -/// It wraps the bytes of a selected file. -class PickedFile extends PickedFileBase { - final String path; - final Uint8List? _initBytes; - - /// Construct a PickedFile object from its ObjectUrl. - /// - /// Optionally, this can be initialized with `bytes` - /// so no http requests are performed to retrieve files later. - PickedFile(this.path, {Uint8List? bytes}) - : _initBytes = bytes, - super(path); - - Future get _bytes async { - if (_initBytes != null) { - return Future.value(UnmodifiableUint8ListView(_initBytes!)); - } - return http.readBytes(Uri.parse(path)); - } - - @override - Future readAsString({Encoding encoding = utf8}) async { - return encoding.decode(await _bytes); - } - - @override - Future readAsBytes() async { - return Future.value(await _bytes); - } - - @override - Stream openRead([int? start, int? end]) async* { - final bytes = await _bytes; - yield bytes.sublist(start ?? 0, end ?? bytes.length); - } -} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart deleted file mode 100644 index 7037b6b7121a..000000000000 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import './base.dart'; - -/// A PickedFile backed by a dart:io File. -class PickedFile extends PickedFileBase { - final File _file; - - /// Construct a PickedFile object backed by a dart:io File. - PickedFile(String path) - : _file = File(path), - super(path); - - @override - String get path { - return _file.path; - } - - @override - Future readAsString({Encoding encoding = utf8}) { - return _file.readAsString(encoding: encoding); - } - - @override - Future readAsBytes() { - return _file.readAsBytes(); - } - - @override - Stream openRead([int? start, int? end]) { - return _file - .openRead(start ?? 0, end) - .map((chunk) => Uint8List.fromList(chunk)); - } -} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart deleted file mode 100644 index c8c9e5a0ac79..000000000000 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -export 'lost_data.dart'; -export 'unsupported.dart' - if (dart.library.html) 'html.dart' - if (dart.library.io) 'io.dart'; diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart deleted file mode 100644 index ad3ed6a4f86a..000000000000 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import './base.dart'; - -/// A PickedFile is a cross-platform, simplified File abstraction. -/// -/// It wraps the bytes of a selected file, and its (platform-dependant) path. -class PickedFile extends PickedFileBase { - /// Construct a PickedFile object, from its `bytes`. - /// - /// Optionally, you may pass a `path`. See caveats in [PickedFileBase.path]. - PickedFile(String path) : super(path) { - throw UnimplementedError( - 'PickedFile is not available in your current platform.'); - } -} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart index 10e7745f2741..18d0ff81b76a 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart @@ -5,7 +5,7 @@ export 'camera_device.dart'; export 'image_source.dart'; export 'retrieve_type.dart'; -export 'picked_file/picked_file.dart'; +export 'lost_data.dart'; /// Denotes that an image is being picked. const String kTypeImage = 'image'; diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 8e176a09a626..8243bb2112c5 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/plugins/tree/master/packages/image_picker issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.1.0 +version: 3.0.0 environment: sdk: ">=2.12.0 <3.0.0" @@ -16,6 +16,7 @@ dependencies: http: ^0.13.0 meta: ^1.3.0 plugin_platform_interface: ^2.0.0 + cross_file: ^0.3.1+1 dev_dependencies: flutter_test: diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart deleted file mode 100644 index 7721f66148e0..000000000000 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@TestOn('chrome') // Uses web-only Flutter SDK - -import 'dart:convert'; -import 'dart:html' as html; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; - -final String expectedStringContents = 'Hello, world!'; -final List bytes = utf8.encode(expectedStringContents); -final html.File textFile = html.File([bytes], 'hello.txt'); -final String textFileUrl = html.Url.createObjectUrl(textFile); - -void main() { - group('Create with an objectUrl', () { - final pickedFile = PickedFile(textFileUrl); - - test('Can be read as a string', () async { - expect(await pickedFile.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await pickedFile.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await pickedFile.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect( - await pickedFile.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - }); -} diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart deleted file mode 100644 index d366204c36bf..000000000000 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@TestOn('vm') // Uses dart:io - -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; - -final pathPrefix = - Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; -final path = pathPrefix + 'hello.txt'; -final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); -final File textFile = File(path); -final String textFilePath = textFile.path; - -void main() { - group('Create with an objectUrl', () { - final PickedFile pickedFile = PickedFile(textFilePath); - - test('Can be read as a string', () async { - expect(await pickedFile.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await pickedFile.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await pickedFile.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect( - await pickedFile.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - }); -} From f4fbd0cf463564db9e97ec15f9c8510adc10855b Mon Sep 17 00:00:00 2001 From: BeMacized Date: Wed, 23 Jun 2021 10:51:36 +0200 Subject: [PATCH 02/16] [image_picker_for_web] Migration to cross_file --- .../image_picker_for_web/CHANGELOG.md | 5 +++++ .../lib/image_picker_for_web.dart | 18 +++++++++--------- .../image_picker_for_web/pubspec.yaml | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index 7b2c4077e28d..2ebe3350460b 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,3 +1,8 @@ +# 3.0.0 + +* Breaking change: + * Changed all usages of PickedFile to XFile + # 2.0.0 * Migrate to null safety. diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index 2fb66380e1d8..88114e0ba261 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -34,7 +34,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { ImagePickerPlatform.instance = ImagePickerPlugin(); } - /// Returns a [PickedFile] with the image that was picked. + /// Returns a [XFile] with the image that was picked. /// /// The `source` argument controls where the image comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. @@ -47,7 +47,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// /// If no images were picked, the return value is null. @override - Future pickImage({ + Future pickImage({ required ImageSource source, double? maxWidth, double? maxHeight, @@ -58,7 +58,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { return pickFile(accept: _kAcceptImageMimeType, capture: capture); } - /// Returns a [PickedFile] containing the video that was picked. + /// Returns a [XFile] containing the video that was picked. /// /// The [source] argument controls where the video comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. @@ -71,7 +71,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// /// If no images were picked, the return value is null. @override - Future pickVideo({ + Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, Duration? maxDuration, @@ -81,12 +81,12 @@ class ImagePickerPlugin extends ImagePickerPlatform { } /// Injects a file input with the specified accept+capture attributes, and - /// returns the PickedFile that the user selected locally. + /// returns the XFile that the user selected locally. /// /// `capture` is only supported in mobile browsers. /// See https://caniuse.com/#feat=html-media-capture @visibleForTesting - Future pickFile({ + Future pickFile({ String? accept, String? capture, }) { @@ -130,13 +130,13 @@ class ImagePickerPlugin extends ImagePickerPlatform { } /// Monitors an and returns the selected file. - Future _getSelectedFile(html.FileUploadInputElement input) { - final Completer _completer = Completer(); + Future _getSelectedFile(html.FileUploadInputElement input) { + final Completer _completer = Completer(); // Observe the input until we can return something input.onChange.first.then((event) { final objectUrl = _handleOnChangeEvent(event); if (!_completer.isCompleted && objectUrl != null) { - _completer.complete(PickedFile(objectUrl)); + _completer.complete(XFile(objectUrl)); } }); input.onError.first.then((event) { diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index 768f7e27ce77..c9940d773dcd 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_for_web description: Web platform implementation of image_picker repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 2.0.0 +version: 3.0.0 environment: sdk: ">=2.12.0 <3.0.0" From 68e2ef837b458f01fb1cfbf48783404b3a4d2214 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 18:47:40 +0200 Subject: [PATCH 03/16] Re-added old methods and marked them as deprecated. --- .../method_channel_image_picker.dart | 115 ++++- .../image_picker_platform.dart | 128 ++++- .../lib/src/types/lost_data_response.dart | 53 ++ .../lib/src/types/picked_file/base.dart | 62 +++ .../lib/src/types/picked_file/html.dart | 49 ++ .../lib/src/types/picked_file/io.dart | 41 ++ .../types/{ => picked_file}/lost_data.dart | 3 +- .../src/types/picked_file/picked_file.dart | 8 + .../src/types/picked_file/unsupported.dart | 18 + .../lib/src/types/types.dart | 3 +- .../new_method_channel_image_picker_test.dart | 473 +++++++++++++++++- .../test/picked_file_html_test.dart | 38 ++ .../test/picked_file_io_test.dart | 42 ++ 13 files changed, 1005 insertions(+), 28 deletions(-) create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data_response.dart create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart rename packages/image_picker/image_picker_platform_interface/lib/src/types/{ => picked_file}/lost_data.dart (96%) create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart create mode 100644 packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart create mode 100644 packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart index 9f36d5b07d03..e0c3f0d5cf52 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart @@ -6,7 +6,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:image_picker_platform_interface/src/types/lost_data.dart'; import 'package:meta/meta.dart' show visibleForTesting; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; @@ -20,44 +19,44 @@ class MethodChannelImagePicker extends ImagePickerPlatform { MethodChannel get channel => _channel; @override - Future pickImage({ + Future pickImage({ required ImageSource source, double? maxWidth, double? maxHeight, int? imageQuality, CameraDevice preferredCameraDevice = CameraDevice.rear, }) async { - String? path = await _pickImagePath( + String? path = await _getImagePath( source: source, maxWidth: maxWidth, maxHeight: maxHeight, imageQuality: imageQuality, preferredCameraDevice: preferredCameraDevice, ); - return path != null ? XFile(path) : null; + return path != null ? PickedFile(path) : null; } @override - Future?> pickMultiImage({ + Future?> pickMultiImage({ double? maxWidth, double? maxHeight, int? imageQuality, }) async { - final List? paths = await _pickMultiImagePath( + final List? paths = await _getMultiImagePath( maxWidth: maxWidth, maxHeight: maxHeight, imageQuality: imageQuality, ); if (paths == null) return null; - final List files = []; + final List files = []; for (final path in paths) { - files.add(XFile(path)); + files.add(PickedFile(path)); } return files; } - Future?> _pickMultiImagePath({ + Future?> _getMultiImagePath({ double? maxWidth, double? maxHeight, int? imageQuality, @@ -85,7 +84,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { ); } - Future _pickImagePath({ + Future _getImagePath({ required ImageSource source, double? maxWidth, double? maxHeight, @@ -118,20 +117,20 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override - Future pickVideo({ + Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, Duration? maxDuration, }) async { - final String? path = await _pickVideoPath( + final String? path = await _getVideoPath( source: source, maxDuration: maxDuration, preferredCameraDevice: preferredCameraDevice, ); - return path != null ? XFile(path) : null; + return path != null ? PickedFile(path) : null; } - Future _pickVideoPath({ + Future _getVideoPath({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, Duration? maxDuration, @@ -176,6 +175,94 @@ class MethodChannelImagePicker extends ImagePickerPlatform { final String? path = result['path']; return LostData( + file: path != null ? PickedFile(path) : null, + exception: exception, + type: retrieveType, + ); + } + + @override + Future getImage({ + required ImageSource source, + double? maxWidth, + double? maxHeight, + int? imageQuality, + CameraDevice preferredCameraDevice = CameraDevice.rear, + }) async { + String? path = await _getImagePath( + source: source, + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: imageQuality, + preferredCameraDevice: preferredCameraDevice, + ); + return path != null ? XFile(path) : null; + } + + @override + Future?> getMultiImage({ + double? maxWidth, + double? maxHeight, + int? imageQuality, + }) async { + final List? paths = await _getMultiImagePath( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: imageQuality, + ); + if (paths == null) return null; + + final List files = []; + for (final path in paths) { + files.add(XFile(path)); + } + return files; + } + + @override + Future getVideo({ + required ImageSource source, + CameraDevice preferredCameraDevice = CameraDevice.rear, + Duration? maxDuration, + }) async { + final String? path = await _getVideoPath( + source: source, + maxDuration: maxDuration, + preferredCameraDevice: preferredCameraDevice, + ); + return path != null ? XFile(path) : null; + } + + @override + Future getLostData() async { + final Map? result = + await _channel.invokeMapMethod('retrieve'); + + if (result == null) { + return LostDataResponse.empty(); + } + + assert(result.containsKey('path') ^ result.containsKey('errorCode')); + + final String? type = result['type']; + assert(type == kTypeImage || type == kTypeVideo); + + RetrieveType? retrieveType; + if (type == kTypeImage) { + retrieveType = RetrieveType.image; + } else if (type == kTypeVideo) { + retrieveType = RetrieveType.video; + } + + PlatformException? exception; + if (result.containsKey('errorCode')) { + exception = PlatformException( + code: result['errorCode'], message: result['errorMessage']); + } + + final String? path = result['path']; + + return LostDataResponse( file: path != null ? XFile(path) : null, exception: exception, type: retrieveType, diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart index 5f35c5300c94..b89e8c221abe 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart @@ -3,11 +3,9 @@ // found in the LICENSE file. import 'dart:async'; -import 'package:cross_file/cross_file.dart'; -import 'package:image_picker_platform_interface/src/types/lost_data.dart'; +import 'package:cross_file/cross_file.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - import 'package:image_picker_platform_interface/src/method_channel/method_channel_image_picker.dart'; import 'package:image_picker_platform_interface/src/types/types.dart'; @@ -42,7 +40,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { // Next version of the API. - /// Returns a [XFile] with the image that was picked. + /// Returns a [PickedFile] with the image that was picked. /// /// The `source` argument controls where the image comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. @@ -70,7 +68,8 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. /// /// If no images were picked, the return value is null. - Future pickImage({ + @Deprecated('Switch to using getImage instead') + Future pickImage({ required ImageSource source, double? maxWidth, double? maxHeight, @@ -80,7 +79,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { throw UnimplementedError('pickImage() has not been implemented.'); } - /// Returns a [List] with the images that were picked. + /// Returns a [List] with the images that were picked. /// /// The images come from the [ImageSource.gallery]. /// @@ -98,7 +97,8 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// a warning message will be logged. /// /// If no images were picked, the return value is null. - Future?> pickMultiImage({ + @Deprecated('Switch to using getMultiImage instead') + Future?> pickMultiImage({ double? maxWidth, double? maxHeight, int? imageQuality, @@ -106,7 +106,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { throw UnimplementedError('pickMultiImage() has not been implemented.'); } - /// Returns a [XFile] containing the video that was picked. + /// Returns a [PickedFile] containing the video that was picked. /// /// The [source] argument controls where the video comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. @@ -122,7 +122,8 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. /// /// If no images were picked, the return value is null. - Future pickVideo({ + @Deprecated('Switch to using getVideo instead') + Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, Duration? maxDuration, @@ -130,7 +131,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { throw UnimplementedError('pickVideo() has not been implemented.'); } - /// Retrieve the lost [XFile] file when [pickImage] or [pickVideo] failed because the MainActivity is destroyed. (Android only) + /// Retrieve the lost [PickedFile] file when [pickImage] or [pickVideo] failed because the MainActivity is destroyed. (Android only) /// /// Image or video can be lost if the MainActivity is destroyed. And there is no guarantee that the MainActivity is always alive. /// Call this method to retrieve the lost data and process the data according to your APP's business logic. @@ -146,4 +147,111 @@ abstract class ImagePickerPlatform extends PlatformInterface { Future retrieveLostData() { throw UnimplementedError('retrieveLostData() has not been implemented.'); } + + /// Returns an [XFile] with the image that was picked. + /// + /// The `source` argument controls where the image comes from. This can + /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// + /// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used + /// in addition to a size modification, of which the usage is explained below. + /// + /// If specified, the image will be at most `maxWidth` wide and + /// `maxHeight` tall. Otherwise the image will be returned at it's + /// original width and height. + /// + /// The `imageQuality` argument modifies the quality of the image, ranging from 0-100 + /// where 100 is the original/max quality. If `imageQuality` is null, the image with + /// the original quality will be returned. Compression is only supported for certain + /// image types such as JPEG. If compression is not supported for the image that is picked, + /// a warning message will be logged. + /// + /// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera]. + /// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device. + /// Defaults to [CameraDevice.rear]. Note that Android has no documented parameter for an intent to specify if + /// the front or rear camera should be opened, this function is not guaranteed + /// to work on an Android device. + /// + /// In Android, the MainActivity can be destroyed for various reasons. If that happens, the result will be lost + /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. + /// + /// If no images were picked, the return value is null. + Future getImage({ + required ImageSource source, + double? maxWidth, + double? maxHeight, + int? imageQuality, + CameraDevice preferredCameraDevice = CameraDevice.rear, + }) { + throw UnimplementedError('getImage() has not been implemented.'); + } + + /// Returns a [List] with the images that were picked. + /// + /// The images come from the [ImageSource.gallery]. + /// + /// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used + /// in addition to a size modification, of which the usage is explained below. + /// + /// If specified, the image will be at most `maxWidth` wide and + /// `maxHeight` tall. Otherwise the image will be returned at it's + /// original width and height. + /// + /// The `imageQuality` argument modifies the quality of the images, ranging from 0-100 + /// where 100 is the original/max quality. If `imageQuality` is null, the images with + /// the original quality will be returned. Compression is only supported for certain + /// image types such as JPEG. If compression is not supported for the image that is picked, + /// a warning message will be logged. + /// + /// If no images were picked, the return value is null. + Future?> getMultiImage({ + double? maxWidth, + double? maxHeight, + int? imageQuality, + }) { + throw UnimplementedError('getMultiImage() has not been implemented.'); + } + + /// Returns a [XFile] containing the video that was picked. + /// + /// The [source] argument controls where the video comes from. This can + /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// + /// The [maxDuration] argument specifies the maximum duration of the captured video. If no [maxDuration] is specified, + /// the maximum duration will be infinite. + /// + /// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera]. + /// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device. + /// Defaults to [CameraDevice.rear]. + /// + /// In Android, the MainActivity can be destroyed for various fo reasons. If that happens, the result will be lost + /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. + /// + /// If no images were picked, the return value is null. + Future getVideo({ + required ImageSource source, + CameraDevice preferredCameraDevice = CameraDevice.rear, + Duration? maxDuration, + }) { + throw UnimplementedError('getVideo() has not been implemented.'); + } + + /// Retrieve the lost [XFile] file when [getImage], [getMultiImage] or [getVideo] failed because the MainActivity is + /// destroyed. (Android only) + /// + /// Image or video can be lost if the MainActivity is destroyed. And there is no guarantee that the MainActivity is + /// always alive. Call this method to retrieve the lost data and process the data according to your APP's business logic. + /// + /// Returns a [LostDataResponse] object if successfully retrieved the lost data. The [LostDataResponse] object can + /// represent either a successful image/video selection, or a failure. + /// + /// Calling this on a non-Android platform will throw [UnimplementedError] exception. + /// + /// See also: + /// * [LostDataResponse], for what's included in the response. + /// * [Android Activity Lifecycle](https://developer.android.com/reference/android/app/Activity.html), for more + /// information on MainActivity destruction. + Future getLostData() { + throw UnimplementedError('getLostData() has not been implemented.'); + } } diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data_response.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data_response.dart new file mode 100644 index 000000000000..576ad334bd35 --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data_response.dart @@ -0,0 +1,53 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:cross_file/cross_file.dart'; +import 'package:flutter/services.dart'; +import 'package:image_picker_platform_interface/src/types/types.dart'; + +/// The response object of [ImagePicker.getLostData]. +/// +/// Only applies to Android. +/// See also: +/// * [ImagePicker.getLostData] for more details on retrieving lost data. +class LostDataResponse { + /// Creates an instance with the given [file], [exception], and [type]. Any of + /// the params may be null, but this is never considered to be empty. + LostDataResponse({this.file, this.exception, this.type}); + + /// Initializes an instance with all member params set to null and considered + /// to be empty. + LostDataResponse.empty() + : file = null, + exception = null, + type = null, + _empty = true; + + /// Whether it is an empty response. + /// + /// An empty response should have [file], [exception] and [type] to be null. + bool get isEmpty => _empty; + + /// The file that was lost in a previous [getImage], [getMultiImage] or [getVideo] call due to MainActivity being destroyed. + /// + /// Can be null if [exception] exists. + final XFile? file; + + /// The exception of the last [getImage], [getMultiImage] or [getVideo]. + /// + /// If the last [getImage], [getMultiImage] or [getVideo] threw some exception before the MainActivity destruction, + /// this variable keeps that exception. + /// You should handle this exception as if the [getImage], [getMultiImage] or [getVideo] got an exception when + /// the MainActivity was not destroyed. + /// + /// Note that it is not the exception that caused the destruction of the MainActivity. + final PlatformException? exception; + + /// Can either be [RetrieveType.image] or [RetrieveType.video]; + /// + /// If the lost data is empty, this will be null. + final RetrieveType? type; + + bool _empty = false; +} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart new file mode 100644 index 000000000000..de259e0611dd --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart @@ -0,0 +1,62 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:meta/meta.dart'; + +/// The interface for a PickedFile. +/// +/// A PickedFile is a container that wraps the path of a selected +/// file by the user and (in some platforms, like web) the bytes +/// with the contents of the file. +/// +/// This class is a very limited subset of dart:io [File], so all +/// the methods should seem familiar. +@immutable +abstract class PickedFileBase { + /// Construct a PickedFile + PickedFileBase(String path); + + /// Get the path of the picked file. + /// + /// This should only be used as a backwards-compatibility clutch + /// for mobile apps, or cosmetic reasons only (to show the user + /// the path they've picked). + /// + /// Accessing the data contained in the picked file by its path + /// is platform-dependant (and won't work on web), so use the + /// byte getters in the PickedFile instance instead. + String get path { + throw UnimplementedError('.path has not been implemented.'); + } + + /// Synchronously read the entire file contents as a string using the given [Encoding]. + /// + /// By default, `encoding` is [utf8]. + /// + /// Throws Exception if the operation fails. + Future readAsString({Encoding encoding = utf8}) { + throw UnimplementedError('readAsString() has not been implemented.'); + } + + /// Synchronously read the entire file contents as a list of bytes. + /// + /// Throws Exception if the operation fails. + Future readAsBytes() { + throw UnimplementedError('readAsBytes() has not been implemented.'); + } + + /// Create a new independent [Stream] for the contents of this file. + /// + /// If `start` is present, the file will be read from byte-offset `start`. Otherwise from the beginning (index 0). + /// + /// If `end` is present, only up to byte-index `end` will be read. Otherwise, until end of file. + /// + /// In order to make sure that system resources are freed, the stream must be read to completion or the subscription on the stream must be cancelled. + Stream openRead([int? start, int? end]) { + throw UnimplementedError('openRead() has not been implemented.'); + } +} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart new file mode 100644 index 000000000000..24e1931008b6 --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:http/http.dart' as http show readBytes; + +import './base.dart'; + +/// A PickedFile that works on web. +/// +/// It wraps the bytes of a selected file. +class PickedFile extends PickedFileBase { + final String path; + final Uint8List? _initBytes; + + /// Construct a PickedFile object from its ObjectUrl. + /// + /// Optionally, this can be initialized with `bytes` + /// so no http requests are performed to retrieve files later. + PickedFile(this.path, {Uint8List? bytes}) + : _initBytes = bytes, + super(path); + + Future get _bytes async { + if (_initBytes != null) { + return Future.value(UnmodifiableUint8ListView(_initBytes!)); + } + return http.readBytes(Uri.parse(path)); + } + + @override + Future readAsString({Encoding encoding = utf8}) async { + return encoding.decode(await _bytes); + } + + @override + Future readAsBytes() async { + return Future.value(await _bytes); + } + + @override + Stream openRead([int? start, int? end]) async* { + final bytes = await _bytes; + yield bytes.sublist(start ?? 0, end ?? bytes.length); + } +} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart new file mode 100644 index 000000000000..7037b6b7121a --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart @@ -0,0 +1,41 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import './base.dart'; + +/// A PickedFile backed by a dart:io File. +class PickedFile extends PickedFileBase { + final File _file; + + /// Construct a PickedFile object backed by a dart:io File. + PickedFile(String path) + : _file = File(path), + super(path); + + @override + String get path { + return _file.path; + } + + @override + Future readAsString({Encoding encoding = utf8}) { + return _file.readAsString(encoding: encoding); + } + + @override + Future readAsBytes() { + return _file.readAsBytes(); + } + + @override + Stream openRead([int? start, int? end]) { + return _file + .openRead(start ?? 0, end) + .map((chunk) => Uint8List.fromList(chunk)); + } +} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart similarity index 96% rename from packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data.dart rename to packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart index a270eece235e..64f6a1f27538 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:cross_file/cross_file.dart'; import 'package:flutter/services.dart'; import 'package:image_picker_platform_interface/src/types/types.dart'; @@ -32,7 +31,7 @@ class LostData { /// The file that was lost in a previous [pickImage] or [pickVideo] call due to MainActivity being destroyed. /// /// Can be null if [exception] exists. - final XFile? file; + final PickedFile? file; /// The exception of the last [pickImage] or [pickVideo]. /// diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart new file mode 100644 index 000000000000..c8c9e5a0ac79 --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart @@ -0,0 +1,8 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +export 'lost_data.dart'; +export 'unsupported.dart' + if (dart.library.html) 'html.dart' + if (dart.library.io) 'io.dart'; diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart new file mode 100644 index 000000000000..ad3ed6a4f86a --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart @@ -0,0 +1,18 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import './base.dart'; + +/// A PickedFile is a cross-platform, simplified File abstraction. +/// +/// It wraps the bytes of a selected file, and its (platform-dependant) path. +class PickedFile extends PickedFileBase { + /// Construct a PickedFile object, from its `bytes`. + /// + /// Optionally, you may pass a `path`. See caveats in [PickedFileBase.path]. + PickedFile(String path) : super(path) { + throw UnimplementedError( + 'PickedFile is not available in your current platform.'); + } +} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart index 18d0ff81b76a..ad7cd3fbcaab 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart @@ -5,7 +5,8 @@ export 'camera_device.dart'; export 'image_source.dart'; export 'retrieve_type.dart'; -export 'lost_data.dart'; +export 'picked_file/picked_file.dart'; +export 'lost_data_response.dart'; /// Denotes that an image is being picked. const String kTypeImage = 'image'; diff --git a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart index 83ae6fac9071..070ffb22ff8d 100644 --- a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart @@ -342,7 +342,7 @@ void main() { }); }); - group('#pickVideoPath', () { + group('#pickVideo', () { test('passes the image source argument correctly', () async { await picker.pickVideo(source: ImageSource.camera); await picker.pickVideo(source: ImageSource.gallery); @@ -497,5 +497,476 @@ void main() { expect(picker.retrieveLostData(), throwsAssertionError); }); }); + + group('#getImage', () { + test('passes the image source argument correctly', () async { + await picker.getImage(source: ImageSource.camera); + await picker.getImage(source: ImageSource.gallery); + + expect( + log, + [ + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'cameraDevice': 0 + }), + isMethodCall('pickImage', arguments: { + 'source': 1, + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'cameraDevice': 0 + }), + ], + ); + }); + + test('passes the width and height arguments correctly', () async { + await picker.getImage(source: ImageSource.camera); + await picker.getImage( + source: ImageSource.camera, + maxWidth: 10.0, + ); + await picker.getImage( + source: ImageSource.camera, + maxHeight: 10.0, + ); + await picker.getImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: 20.0, + ); + await picker.getImage( + source: ImageSource.camera, + maxWidth: 10.0, + imageQuality: 70, + ); + await picker.getImage( + source: ImageSource.camera, + maxHeight: 10.0, + imageQuality: 70, + ); + await picker.getImage( + source: ImageSource.camera, + maxWidth: 10.0, + maxHeight: 20.0, + imageQuality: 70, + ); + + expect( + log, + [ + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'cameraDevice': 0 + }), + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': 10.0, + 'maxHeight': null, + 'imageQuality': null, + 'cameraDevice': 0 + }), + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': null, + 'maxHeight': 10.0, + 'imageQuality': null, + 'cameraDevice': 0 + }), + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': 10.0, + 'maxHeight': 20.0, + 'imageQuality': null, + 'cameraDevice': 0 + }), + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': 10.0, + 'maxHeight': null, + 'imageQuality': 70, + 'cameraDevice': 0 + }), + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': null, + 'maxHeight': 10.0, + 'imageQuality': 70, + 'cameraDevice': 0 + }), + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': 10.0, + 'maxHeight': 20.0, + 'imageQuality': 70, + 'cameraDevice': 0 + }), + ], + ); + }); + + test('does not accept a invalid imageQuality argument', () { + expect( + () => picker.getImage(imageQuality: -1, source: ImageSource.gallery), + throwsArgumentError, + ); + + expect( + () => + picker.getImage(imageQuality: 101, source: ImageSource.gallery), + throwsArgumentError, + ); + + expect( + () => picker.getImage(imageQuality: -1, source: ImageSource.camera), + throwsArgumentError, + ); + + expect( + () => picker.getImage(imageQuality: 101, source: ImageSource.camera), + throwsArgumentError, + ); + }); + + test('does not accept a negative width or height argument', () { + expect( + () => picker.getImage(source: ImageSource.camera, maxWidth: -1.0), + throwsArgumentError, + ); + + expect( + () => picker.getImage(source: ImageSource.camera, maxHeight: -1.0), + throwsArgumentError, + ); + }); + + test('handles a null image path response gracefully', () async { + picker.channel + .setMockMethodCallHandler((MethodCall methodCall) => null); + + expect(await picker.getImage(source: ImageSource.gallery), isNull); + expect(await picker.getImage(source: ImageSource.camera), isNull); + }); + + test('camera position defaults to back', () async { + await picker.getImage(source: ImageSource.camera); + + expect( + log, + [ + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'cameraDevice': 0, + }), + ], + ); + }); + + test('camera position can set to front', () async { + await picker.getImage( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.front); + + expect( + log, + [ + isMethodCall('pickImage', arguments: { + 'source': 0, + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'cameraDevice': 1, + }), + ], + ); + }); + }); + + group('#getMultiImage', () { + test('calls the method correctly', () async { + returnValue = ['0', '1']; + await picker.getMultiImage(); + + expect( + log, + [ + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + }), + ], + ); + }); + + test('passes the width and height arguments correctly', () async { + returnValue = ['0', '1']; + await picker.getMultiImage(); + await picker.getMultiImage( + maxWidth: 10.0, + ); + await picker.getMultiImage( + maxHeight: 10.0, + ); + await picker.getMultiImage( + maxWidth: 10.0, + maxHeight: 20.0, + ); + await picker.getMultiImage( + maxWidth: 10.0, + imageQuality: 70, + ); + await picker.getMultiImage( + maxHeight: 10.0, + imageQuality: 70, + ); + await picker.getMultiImage( + maxWidth: 10.0, + maxHeight: 20.0, + imageQuality: 70, + ); + + expect( + log, + [ + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': 10.0, + 'maxHeight': null, + 'imageQuality': null, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': 10.0, + 'imageQuality': null, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': 10.0, + 'maxHeight': 20.0, + 'imageQuality': null, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': 10.0, + 'maxHeight': null, + 'imageQuality': 70, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': 10.0, + 'imageQuality': 70, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': 10.0, + 'maxHeight': 20.0, + 'imageQuality': 70, + }), + ], + ); + }); + + test('does not accept a negative width or height argument', () { + returnValue = ['0', '1']; + expect( + () => picker.getMultiImage(maxWidth: -1.0), + throwsArgumentError, + ); + + expect( + () => picker.getMultiImage(maxHeight: -1.0), + throwsArgumentError, + ); + }); + + test('does not accept a invalid imageQuality argument', () { + returnValue = ['0', '1']; + expect( + () => picker.getMultiImage(imageQuality: -1), + throwsArgumentError, + ); + + expect( + () => picker.getMultiImage(imageQuality: 101), + throwsArgumentError, + ); + }); + + test('handles a null image path response gracefully', () async { + picker.channel + .setMockMethodCallHandler((MethodCall methodCall) => null); + + expect(await picker.getMultiImage(), isNull); + expect(await picker.getMultiImage(), isNull); + }); + }); + + group('#getVideo', () { + test('passes the image source argument correctly', () async { + await picker.getVideo(source: ImageSource.camera); + await picker.getVideo(source: ImageSource.gallery); + + expect( + log, + [ + isMethodCall('pickVideo', arguments: { + 'source': 0, + 'cameraDevice': 0, + 'maxDuration': null, + }), + isMethodCall('pickVideo', arguments: { + 'source': 1, + 'cameraDevice': 0, + 'maxDuration': null, + }), + ], + ); + }); + + test('passes the duration argument correctly', () async { + await picker.getVideo(source: ImageSource.camera); + await picker.getVideo( + source: ImageSource.camera, + maxDuration: const Duration(seconds: 10), + ); + await picker.getVideo( + source: ImageSource.camera, + maxDuration: const Duration(minutes: 1), + ); + await picker.getVideo( + source: ImageSource.camera, + maxDuration: const Duration(hours: 1), + ); + expect( + log, + [ + isMethodCall('pickVideo', arguments: { + 'source': 0, + 'maxDuration': null, + 'cameraDevice': 0, + }), + isMethodCall('pickVideo', arguments: { + 'source': 0, + 'maxDuration': 10, + 'cameraDevice': 0, + }), + isMethodCall('pickVideo', arguments: { + 'source': 0, + 'maxDuration': 60, + 'cameraDevice': 0, + }), + isMethodCall('pickVideo', arguments: { + 'source': 0, + 'maxDuration': 3600, + 'cameraDevice': 0, + }), + ], + ); + }); + + test('handles a null video path response gracefully', () async { + picker.channel + .setMockMethodCallHandler((MethodCall methodCall) => null); + + expect(await picker.getVideo(source: ImageSource.gallery), isNull); + expect(await picker.getVideo(source: ImageSource.camera), isNull); + }); + + test('camera position defaults to back', () async { + await picker.getVideo(source: ImageSource.camera); + + expect( + log, + [ + isMethodCall('pickVideo', arguments: { + 'source': 0, + 'cameraDevice': 0, + 'maxDuration': null, + }), + ], + ); + }); + + test('camera position can set to front', () async { + await picker.getVideo( + source: ImageSource.camera, + preferredCameraDevice: CameraDevice.front, + ); + + expect( + log, + [ + isMethodCall('pickVideo', arguments: { + 'source': 0, + 'maxDuration': null, + 'cameraDevice': 1, + }), + ], + ); + }); + }); + + group('#getLostData', () { + test('getLostData get success response', () async { + picker.channel.setMockMethodCallHandler((MethodCall methodCall) async { + return { + 'type': 'image', + 'path': '/example/path', + }; + }); + // ignore: deprecated_member_use_from_same_package + final LostDataResponse response = await picker.getLostData(); + expect(response.type, RetrieveType.image); + expect(response.file, isNotNull); + expect(response.file!.path, '/example/path'); + }); + + test('getLostData get error response', () async { + picker.channel.setMockMethodCallHandler((MethodCall methodCall) async { + return { + 'type': 'video', + 'errorCode': 'test_error_code', + 'errorMessage': 'test_error_message', + }; + }); + // ignore: deprecated_member_use_from_same_package + final LostDataResponse response = await picker.getLostData(); + expect(response.type, RetrieveType.video); + expect(response.exception, isNotNull); + expect(response.exception!.code, 'test_error_code'); + expect(response.exception!.message, 'test_error_message'); + }); + + test('getLostData get null response', () async { + picker.channel.setMockMethodCallHandler((MethodCall methodCall) async { + return null; + }); + expect((await picker.getLostData()).isEmpty, true); + }); + + test('getLostData get both path and error should throw', () async { + picker.channel.setMockMethodCallHandler((MethodCall methodCall) async { + return { + 'type': 'video', + 'errorCode': 'test_error_code', + 'errorMessage': 'test_error_message', + 'path': '/example/path', + }; + }); + expect(picker.getLostData(), throwsAssertionError); + }); + }); }); } diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart new file mode 100644 index 000000000000..0fa296ad4f2e --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart @@ -0,0 +1,38 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@TestOn('chrome') // Uses web-only Flutter SDK + +import 'dart:convert'; +import 'dart:html' as html; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; + +final String expectedStringContents = 'Hello, world!'; +final List bytes = utf8.encode(expectedStringContents); +final html.File textFile = html.File([bytes], 'hello.txt'); +final String textFileUrl = html.Url.createObjectUrl(textFile); + +void main() { + group('Create with an objectUrl', () { + final pickedFile = PickedFile(textFileUrl); + + test('Can be read as a string', () async { + expect(await pickedFile.readAsString(), equals(expectedStringContents)); + }); + test('Can be read as bytes', () async { + expect(await pickedFile.readAsBytes(), equals(bytes)); + }); + + test('Can be read as a stream', () async { + expect(await pickedFile.openRead().first, equals(bytes)); + }); + + test('Stream can be sliced', () async { + expect( + await pickedFile.openRead(2, 5).first, equals(bytes.sublist(2, 5))); + }); + }); +} \ No newline at end of file diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart new file mode 100644 index 000000000000..5e3edc454691 --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@TestOn('vm') // Uses dart:io + +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; + +final pathPrefix = +Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; +final path = pathPrefix + 'hello.txt'; +final String expectedStringContents = 'Hello, world!'; +final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); +final File textFile = File(path); +final String textFilePath = textFile.path; + +void main() { + group('Create with an objectUrl', () { + final PickedFile pickedFile = PickedFile(textFilePath); + + test('Can be read as a string', () async { + expect(await pickedFile.readAsString(), equals(expectedStringContents)); + }); + test('Can be read as bytes', () async { + expect(await pickedFile.readAsBytes(), equals(bytes)); + }); + + test('Can be read as a stream', () async { + expect(await pickedFile.openRead().first, equals(bytes)); + }); + + test('Stream can be sliced', () async { + expect( + await pickedFile.openRead(2, 5).first, equals(bytes.sublist(2, 5))); + }); + }); +} \ No newline at end of file From a0ab00eae365e359cb9334b4233b1fab35a9266e Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 19:00:49 +0200 Subject: [PATCH 04/16] Update to match platform interface changes --- .../lib/image_picker_for_web.dart | 98 +++++++++++++++++-- .../test/image_picker_for_web_test.dart | 23 ++++- 2 files changed, 113 insertions(+), 8 deletions(-) diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index 88114e0ba261..14d28ab70d07 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -34,7 +34,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { ImagePickerPlatform.instance = ImagePickerPlugin(); } - /// Returns a [XFile] with the image that was picked. + /// Returns a [PickedFile] with the image that was picked. /// /// The `source` argument controls where the image comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. @@ -47,7 +47,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// /// If no images were picked, the return value is null. @override - Future pickImage({ + Future pickImage({ required ImageSource source, double? maxWidth, double? maxHeight, @@ -58,7 +58,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { return pickFile(accept: _kAcceptImageMimeType, capture: capture); } - /// Returns a [XFile] containing the video that was picked. + /// Returns a [PickedFile] containing the video that was picked. /// /// The [source] argument controls where the video comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. @@ -71,7 +71,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// /// If no images were picked, the return value is null. @override - Future pickVideo({ + Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, Duration? maxDuration, @@ -81,12 +81,13 @@ class ImagePickerPlugin extends ImagePickerPlatform { } /// Injects a file input with the specified accept+capture attributes, and - /// returns the XFile that the user selected locally. + /// returns the PickedFile that the user selected locally. /// /// `capture` is only supported in mobile browsers. /// See https://caniuse.com/#feat=html-media-capture @visibleForTesting - Future pickFile({ + @Deprecated("Switch to using getFile instead") + Future pickFile({ String? accept, String? capture, }) { @@ -96,6 +97,68 @@ class ImagePickerPlugin extends ImagePickerPlatform { return _getSelectedFile(input); } + /// Returns an [XFile] with the image that was picked. + /// + /// The `source` argument controls where the image comes from. This can + /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// + /// Note that the `maxWidth`, `maxHeight` and `imageQuality` arguments are not supported on the web. If any of these arguments is supplied, it'll be silently ignored by the web version of the plugin. + /// + /// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera]. + /// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device. + /// Defaults to [CameraDevice.rear]. + /// + /// If no images were picked, the return value is null. + @override + Future getImage({ + required ImageSource source, + double? maxWidth, + double? maxHeight, + int? imageQuality, + CameraDevice preferredCameraDevice = CameraDevice.rear, + }) { + String? capture = computeCaptureAttribute(source, preferredCameraDevice); + return getFile(accept: _kAcceptImageMimeType, capture: capture); + } + + /// Returns an [XFile] containing the video that was picked. + /// + /// The [source] argument controls where the video comes from. This can + /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// + /// Note that the `maxDuration` argument is not supported on the web. If the argument is supplied, it'll be silently ignored by the web version of the plugin. + /// + /// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera]. + /// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device. + /// Defaults to [CameraDevice.rear]. + /// + /// If no images were picked, the return value is null. + @override + Future getVideo({ + required ImageSource source, + CameraDevice preferredCameraDevice = CameraDevice.rear, + Duration? maxDuration, + }) { + String? capture = computeCaptureAttribute(source, preferredCameraDevice); + return getFile(accept: _kAcceptVideoMimeType, capture: capture); + } + + /// Injects a file input with the specified accept+capture attributes, and + /// returns the PickedFile that the user selected locally. + /// + /// `capture` is only supported in mobile browsers. + /// See https://caniuse.com/#feat=html-media-capture + @visibleForTesting + Future getFile({ + String? accept, + String? capture, + }) { + html.FileUploadInputElement input = + createInputElement(accept, capture) as html.FileUploadInputElement; + _injectAndActivate(input); + return _getSelectedXFile(input); + } + // DOM methods /// Converts plugin configuration into a proper value for the `capture` attribute. @@ -130,7 +193,28 @@ class ImagePickerPlugin extends ImagePickerPlatform { } /// Monitors an and returns the selected file. - Future _getSelectedFile(html.FileUploadInputElement input) { + @Deprecated("Use _getSelectedXFile instead") + Future _getSelectedFile(html.FileUploadInputElement input) { + final Completer _completer = Completer(); + // Observe the input until we can return something + input.onChange.first.then((event) { + final objectUrl = _handleOnChangeEvent(event); + if (!_completer.isCompleted && objectUrl != null) { + _completer.complete(PickedFile(objectUrl)); + } + }); + input.onError.first.then((event) { + if (!_completer.isCompleted) { + _completer.completeError(event); + } + }); + // Note that we don't bother detaching from these streams, since the + // "input" gets re-created in the DOM every time the user needs to + // pick a file. + return _completer.future; + } + + Future _getSelectedXFile(html.FileUploadInputElement input) { final Completer _completer = Completer(); // Observe the input until we can return something input.onChange.first.then((event) { diff --git a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart index fbdd1d38bee6..f70c273d03bc 100644 --- a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart +++ b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart @@ -24,7 +24,7 @@ void main() { plugin = ImagePickerPlugin(); }); - test('Can select a file', () async { + test('Can select a file (Deprecated)', () async { final mockInput = html.FileUploadInputElement(); final overrides = ImagePickerPluginTestOverrides() @@ -45,6 +45,27 @@ void main() { expect((await file).readAsBytes(), completion(isNotEmpty)); }); + test('Can select a file', () async { + final mockInput = html.FileUploadInputElement(); + + final overrides = ImagePickerPluginTestOverrides() + ..createInputElement = ((_, __) => mockInput) + ..getFileFromInput = ((_) => textFile); + + final plugin = ImagePickerPlugin(overrides: overrides); + + // Init the pick file dialog... + final file = plugin.getFile(); + + // Mock the browser behavior of selecting a file... + mockInput.dispatchEvent(html.Event('change')); + + // Now the file should be available + expect(file, completes); + // And readable + expect((await file).readAsBytes(), completion(isNotEmpty)); + }); + // There's no good way of detecting when the user has "aborted" the selection. test('computeCaptureAttribute', () { From a9871706a8dcfcc2f3ce49a403146fe95e88bb66 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 19:26:40 +0200 Subject: [PATCH 05/16] Format & annotate deprecated classes. --- .../method_channel_image_picker.dart | 2 +- .../lib/src/types/picked_file/base.dart | 1 + .../lib/src/types/picked_file/html.dart | 1 + .../lib/src/types/picked_file/io.dart | 1 + .../lib/src/types/picked_file/lost_data.dart | 1 + .../src/types/picked_file/unsupported.dart | 1 + .../new_method_channel_image_picker_test.dart | 21 +++++++++---------- .../test/picked_file_html_test.dart | 2 +- .../test/picked_file_io_test.dart | 4 ++-- 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart index e0c3f0d5cf52..02ad17907cea 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart @@ -236,7 +236,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { @override Future getLostData() async { final Map? result = - await _channel.invokeMapMethod('retrieve'); + await _channel.invokeMapMethod('retrieve'); if (result == null) { return LostDataResponse.empty(); diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart index de259e0611dd..0adaee63ceaa 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart @@ -16,6 +16,7 @@ import 'package:meta/meta.dart'; /// This class is a very limited subset of dart:io [File], so all /// the methods should seem familiar. @immutable +@Deprecated("Switch to using XFile instead") abstract class PickedFileBase { /// Construct a PickedFile PickedFileBase(String path); diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart index 24e1931008b6..c8218605e1bd 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart @@ -12,6 +12,7 @@ import './base.dart'; /// A PickedFile that works on web. /// /// It wraps the bytes of a selected file. +@Deprecated("Switch to using XFile instead") class PickedFile extends PickedFileBase { final String path; final Uint8List? _initBytes; diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart index 7037b6b7121a..b2905803ad0c 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart @@ -9,6 +9,7 @@ import 'dart:typed_data'; import './base.dart'; /// A PickedFile backed by a dart:io File. +@Deprecated("Switch to using XFile instead") class PickedFile extends PickedFileBase { final File _file; diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart index 64f6a1f27538..e29ae409d6d5 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart @@ -10,6 +10,7 @@ import 'package:image_picker_platform_interface/src/types/types.dart'; /// Only applies to Android. /// See also: /// * [ImagePicker.retrieveLostData] for more details on retrieving lost data. +@Deprecated("Switch to using LostDataResponse instead") class LostData { /// Creates an instance with the given [file], [exception], and [type]. Any of /// the params may be null, but this is never considered to be empty. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart index ad3ed6a4f86a..b2fb6873de3b 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart @@ -7,6 +7,7 @@ import './base.dart'; /// A PickedFile is a cross-platform, simplified File abstraction. /// /// It wraps the bytes of a selected file, and its (platform-dependant) path. +@Deprecated("Switch to using XFile instead") class PickedFile extends PickedFileBase { /// Construct a PickedFile object, from its `bytes`. /// diff --git a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart index 070ffb22ff8d..800d4f7b12c5 100644 --- a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart @@ -614,35 +614,34 @@ void main() { test('does not accept a invalid imageQuality argument', () { expect( - () => picker.getImage(imageQuality: -1, source: ImageSource.gallery), + () => picker.getImage(imageQuality: -1, source: ImageSource.gallery), throwsArgumentError, ); expect( - () => - picker.getImage(imageQuality: 101, source: ImageSource.gallery), + () => picker.getImage(imageQuality: 101, source: ImageSource.gallery), throwsArgumentError, ); expect( - () => picker.getImage(imageQuality: -1, source: ImageSource.camera), + () => picker.getImage(imageQuality: -1, source: ImageSource.camera), throwsArgumentError, ); expect( - () => picker.getImage(imageQuality: 101, source: ImageSource.camera), + () => picker.getImage(imageQuality: 101, source: ImageSource.camera), throwsArgumentError, ); }); test('does not accept a negative width or height argument', () { expect( - () => picker.getImage(source: ImageSource.camera, maxWidth: -1.0), + () => picker.getImage(source: ImageSource.camera, maxWidth: -1.0), throwsArgumentError, ); expect( - () => picker.getImage(source: ImageSource.camera, maxHeight: -1.0), + () => picker.getImage(source: ImageSource.camera, maxHeight: -1.0), throwsArgumentError, ); }); @@ -781,12 +780,12 @@ void main() { test('does not accept a negative width or height argument', () { returnValue = ['0', '1']; expect( - () => picker.getMultiImage(maxWidth: -1.0), + () => picker.getMultiImage(maxWidth: -1.0), throwsArgumentError, ); expect( - () => picker.getMultiImage(maxHeight: -1.0), + () => picker.getMultiImage(maxHeight: -1.0), throwsArgumentError, ); }); @@ -794,12 +793,12 @@ void main() { test('does not accept a invalid imageQuality argument', () { returnValue = ['0', '1']; expect( - () => picker.getMultiImage(imageQuality: -1), + () => picker.getMultiImage(imageQuality: -1), throwsArgumentError, ); expect( - () => picker.getMultiImage(imageQuality: 101), + () => picker.getMultiImage(imageQuality: 101), throwsArgumentError, ); }); diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart index 0fa296ad4f2e..7721f66148e0 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart @@ -35,4 +35,4 @@ void main() { await pickedFile.openRead(2, 5).first, equals(bytes.sublist(2, 5))); }); }); -} \ No newline at end of file +} diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart index 5e3edc454691..d366204c36bf 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart @@ -12,7 +12,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; final pathPrefix = -Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; + Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; final path = pathPrefix + 'hello.txt'; final String expectedStringContents = 'Hello, world!'; final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); @@ -39,4 +39,4 @@ void main() { await pickedFile.openRead(2, 5).first, equals(bytes.sublist(2, 5))); }); }); -} \ No newline at end of file +} From 3fa10b9e56425e2db69864fce445f109b98f1d5d Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 19:32:44 +0200 Subject: [PATCH 06/16] Updated pubspec and changelog. --- .../image_picker_platform_interface/CHANGELOG.md | 16 ++++++++-------- .../image_picker_platform_interface/pubspec.yaml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 36188838cc2d..6abbd4771fc7 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,11 +1,11 @@ -## 3.0.0 - -* Breaking changes: - * pickImage now returns XFile instead of PickedFile - * pickVideo now returns XFile instead of PickedFile - * changed LostData file parameter type to XFile - * removed PickedFile class and its tests - +## 2.2.0 + +* pickImage has been deprecated in favor of getImage +* pickVideo has been deprecated in favor of getVideo +* pickMultiImage has been deprecated in favor of getMultiImage +* getImage, getVideo and getMultiImage functions have been added to return XFile instances instead of PickedFile instances. +* PickedFile and related classes have been marked deprecated. + ## 2.1.0 * Add `pickMultiImage` method. diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 8243bb2112c5..0953e76f03ee 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/plugins/tree/master/packages/image_picker issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 3.0.0 +version: 2.2.0 environment: sdk: ">=2.12.0 <3.0.0" From addfe99f0ae6eabc4e680a32d28128da80ae9322 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 19:33:30 +0200 Subject: [PATCH 07/16] Updated platform interface dependency version --- packages/image_picker/image_picker_for_web/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index c9940d773dcd..e6af2b3c4e60 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - image_picker_platform_interface: ^2.0.0 + image_picker_platform_interface: ^2.2.0 meta: ^1.3.0 dev_dependencies: From aefff739dad7130ff0130fd013f44bdd7d72190a Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 19:35:59 +0200 Subject: [PATCH 08/16] Updated changelog and pubspec version --- packages/image_picker/image_picker_for_web/CHANGELOG.md | 5 ++--- packages/image_picker/image_picker_for_web/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index 2ebe3350460b..d7d752276988 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,7 +1,6 @@ -# 3.0.0 +# 2.1.0 -* Breaking change: - * Changed all usages of PickedFile to XFile +* Added getImage, getVideo and getFile methods that return XFile instances rather than PickedFile instances. # 2.0.0 diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index e6af2b3c4e60..d9b9c5e5cb86 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_for_web description: Web platform implementation of image_picker repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 3.0.0 +version: 2.1.0 environment: sdk: ">=2.12.0 <3.0.0" From 2c4cd91c2f3f1923516ffe330e67817eaf02fac0 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Fri, 2 Jul 2021 10:36:10 +0200 Subject: [PATCH 09/16] Fix analysis issues for deprecations --- .../method_channel_image_picker.dart | 4 ++ .../image_picker_platform.dart | 5 ++- .../new_method_channel_image_picker_test.dart | 45 +++++++++++++++++++ .../test/picked_file_html_test.dart | 1 + .../test/picked_file_io_test.dart | 1 + 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart index 02ad17907cea..54197ccb732e 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart @@ -19,6 +19,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { MethodChannel get channel => _channel; @override + @Deprecated('Switch to using getImage instead') Future pickImage({ required ImageSource source, double? maxWidth, @@ -37,6 +38,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override + @Deprecated('Switch to using getMultiImage instead') Future?> pickMultiImage({ double? maxWidth, double? maxHeight, @@ -117,6 +119,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override + @Deprecated('Switch to using getVideo instead') Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, @@ -146,6 +149,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override + @Deprecated("Switch to using getLostData instead") Future retrieveLostData() async { final Map? result = await _channel.invokeMapMethod('retrieve'); diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart index b89e8c221abe..9b3b5d1cf180 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart @@ -144,6 +144,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// See also: /// * [LostData], for what's included in the response. /// * [Android Activity Lifecycle](https://developer.android.com/reference/android/app/Activity.html), for more information on MainActivity destruction. + @Deprecated("Switch to using getLostData instead") Future retrieveLostData() { throw UnimplementedError('retrieveLostData() has not been implemented.'); } @@ -173,7 +174,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// to work on an Android device. /// /// In Android, the MainActivity can be destroyed for various reasons. If that happens, the result will be lost - /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. + /// in this call. You can then call [getLostData] when your app relaunches to retrieve the lost data. /// /// If no images were picked, the return value is null. Future getImage({ @@ -225,7 +226,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// Defaults to [CameraDevice.rear]. /// /// In Android, the MainActivity can be destroyed for various fo reasons. If that happens, the result will be lost - /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. + /// in this call. You can then call [getLostData] when your app relaunches to retrieve the lost data. /// /// If no images were picked, the return value is null. Future getVideo({ diff --git a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart index 800d4f7b12c5..7850a3011f9c 100644 --- a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart @@ -29,7 +29,9 @@ void main() { group('#pickImage', () { test('passes the image source argument correctly', () async { + // ignore: deprecated_member_use_from_same_package await picker.pickImage(source: ImageSource.camera); + // ignore: deprecated_member_use_from_same_package await picker.pickImage(source: ImageSource.gallery); expect( @@ -54,30 +56,37 @@ void main() { }); test('passes the width and height arguments correctly', () async { + // ignore: deprecated_member_use_from_same_package await picker.pickImage(source: ImageSource.camera); + // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxWidth: 10.0, ); + // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxHeight: 10.0, ); + // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxWidth: 10.0, maxHeight: 20.0, ); + // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxWidth: 10.0, imageQuality: 70, ); + // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxHeight: 10.0, imageQuality: 70, ); + // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxWidth: 10.0, @@ -143,22 +152,26 @@ void main() { test('does not accept a invalid imageQuality argument', () { expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickImage(imageQuality: -1, source: ImageSource.gallery), throwsArgumentError, ); expect( () => + // ignore: deprecated_member_use_from_same_package picker.pickImage(imageQuality: 101, source: ImageSource.gallery), throwsArgumentError, ); expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickImage(imageQuality: -1, source: ImageSource.camera), throwsArgumentError, ); expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickImage(imageQuality: 101, source: ImageSource.camera), throwsArgumentError, ); @@ -166,11 +179,13 @@ void main() { test('does not accept a negative width or height argument', () { expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickImage(source: ImageSource.camera, maxWidth: -1.0), throwsArgumentError, ); expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickImage(source: ImageSource.camera, maxHeight: -1.0), throwsArgumentError, ); @@ -180,11 +195,14 @@ void main() { picker.channel .setMockMethodCallHandler((MethodCall methodCall) => null); + // ignore: deprecated_member_use_from_same_package expect(await picker.pickImage(source: ImageSource.gallery), isNull); + // ignore: deprecated_member_use_from_same_package expect(await picker.pickImage(source: ImageSource.camera), isNull); }); test('camera position defaults to back', () async { + // ignore: deprecated_member_use_from_same_package await picker.pickImage(source: ImageSource.camera); expect( @@ -202,6 +220,7 @@ void main() { }); test('camera position can set to front', () async { + // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, preferredCameraDevice: CameraDevice.front); @@ -224,6 +243,7 @@ void main() { group('#pickMultiImage', () { test('calls the method correctly', () async { returnValue = ['0', '1']; + // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage(); expect( @@ -240,25 +260,32 @@ void main() { test('passes the width and height arguments correctly', () async { returnValue = ['0', '1']; + // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage(); + // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxWidth: 10.0, ); + // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxHeight: 10.0, ); + // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxWidth: 10.0, maxHeight: 20.0, ); + // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxWidth: 10.0, imageQuality: 70, ); + // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxHeight: 10.0, imageQuality: 70, ); + // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxWidth: 10.0, maxHeight: 20.0, @@ -310,11 +337,13 @@ void main() { test('does not accept a negative width or height argument', () { returnValue = ['0', '1']; expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickMultiImage(maxWidth: -1.0), throwsArgumentError, ); expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickMultiImage(maxHeight: -1.0), throwsArgumentError, ); @@ -323,11 +352,13 @@ void main() { test('does not accept a invalid imageQuality argument', () { returnValue = ['0', '1']; expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickMultiImage(imageQuality: -1), throwsArgumentError, ); expect( + // ignore: deprecated_member_use_from_same_package () => picker.pickMultiImage(imageQuality: 101), throwsArgumentError, ); @@ -337,14 +368,18 @@ void main() { picker.channel .setMockMethodCallHandler((MethodCall methodCall) => null); + // ignore: deprecated_member_use_from_same_package expect(await picker.pickMultiImage(), isNull); + // ignore: deprecated_member_use_from_same_package expect(await picker.pickMultiImage(), isNull); }); }); group('#pickVideo', () { test('passes the image source argument correctly', () async { + // ignore: deprecated_member_use_from_same_package await picker.pickVideo(source: ImageSource.camera); + // ignore: deprecated_member_use_from_same_package await picker.pickVideo(source: ImageSource.gallery); expect( @@ -365,15 +400,19 @@ void main() { }); test('passes the duration argument correctly', () async { + // ignore: deprecated_member_use_from_same_package await picker.pickVideo(source: ImageSource.camera); + // ignore: deprecated_member_use_from_same_package await picker.pickVideo( source: ImageSource.camera, maxDuration: const Duration(seconds: 10), ); + // ignore: deprecated_member_use_from_same_package await picker.pickVideo( source: ImageSource.camera, maxDuration: const Duration(minutes: 1), ); + // ignore: deprecated_member_use_from_same_package await picker.pickVideo( source: ImageSource.camera, maxDuration: const Duration(hours: 1), @@ -409,11 +448,14 @@ void main() { picker.channel .setMockMethodCallHandler((MethodCall methodCall) => null); + // ignore: deprecated_member_use_from_same_package expect(await picker.pickVideo(source: ImageSource.gallery), isNull); + // ignore: deprecated_member_use_from_same_package expect(await picker.pickVideo(source: ImageSource.camera), isNull); }); test('camera position defaults to back', () async { + // ignore: deprecated_member_use_from_same_package await picker.pickVideo(source: ImageSource.camera); expect( @@ -429,6 +471,7 @@ void main() { }); test('camera position can set to front', () async { + // ignore: deprecated_member_use_from_same_package await picker.pickVideo( source: ImageSource.camera, preferredCameraDevice: CameraDevice.front, @@ -482,6 +525,7 @@ void main() { picker.channel.setMockMethodCallHandler((MethodCall methodCall) async { return null; }); + // ignore: deprecated_member_use_from_same_package expect((await picker.retrieveLostData()).isEmpty, true); }); @@ -494,6 +538,7 @@ void main() { 'path': '/example/path', }; }); + // ignore: deprecated_member_use_from_same_package expect(picker.retrieveLostData(), throwsAssertionError); }); }); diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart index 7721f66148e0..42fea59a6f81 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart @@ -17,6 +17,7 @@ final String textFileUrl = html.Url.createObjectUrl(textFile); void main() { group('Create with an objectUrl', () { + // ignore: deprecated_member_use_from_same_package final pickedFile = PickedFile(textFileUrl); test('Can be read as a string', () async { diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart index d366204c36bf..d4ccca84092e 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart @@ -21,6 +21,7 @@ final String textFilePath = textFile.path; void main() { group('Create with an objectUrl', () { + // ignore: deprecated_member_use_from_same_package final PickedFile pickedFile = PickedFile(textFilePath); test('Can be read as a string', () async { From 29e0c40c73a1b0388cfe00ee5c2716f927abb2c6 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 7 Jul 2021 18:53:02 -0700 Subject: [PATCH 10/16] Remove Deprecation tags so we don't break consumers of this package once it gets published. --- .../CHANGELOG.md | 11 +++-- .../method_channel_image_picker.dart | 4 -- .../image_picker_platform.dart | 4 -- .../lib/src/types/picked_file/base.dart | 1 - .../lib/src/types/picked_file/html.dart | 1 - .../lib/src/types/picked_file/io.dart | 1 - .../lib/src/types/picked_file/lost_data.dart | 1 - .../src/types/picked_file/unsupported.dart | 1 - .../new_method_channel_image_picker_test.dart | 49 ------------------- .../test/picked_file_html_test.dart | 1 - .../test/picked_file_io_test.dart | 1 - 11 files changed, 6 insertions(+), 69 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 6abbd4771fc7..bd56f0ca77a6 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,10 +1,11 @@ ## 2.2.0 -* pickImage has been deprecated in favor of getImage -* pickVideo has been deprecated in favor of getVideo -* pickMultiImage has been deprecated in favor of getMultiImage -* getImage, getVideo and getMultiImage functions have been added to return XFile instances instead of PickedFile instances. -* PickedFile and related classes have been marked deprecated. +* Added new methods that return `XFile` (from `package:cross_file`) + * `getImage` (will deprecate `pickImage`) + * `getVideo` (will deprecate `pickVideo`) + * `getMultiImage` (will deprecate `pickMultiImage`) + +_`PickedFile` will also be marked as deprecated in an upcoming release._ ## 2.1.0 diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart index 54197ccb732e..02ad17907cea 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart @@ -19,7 +19,6 @@ class MethodChannelImagePicker extends ImagePickerPlatform { MethodChannel get channel => _channel; @override - @Deprecated('Switch to using getImage instead') Future pickImage({ required ImageSource source, double? maxWidth, @@ -38,7 +37,6 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override - @Deprecated('Switch to using getMultiImage instead') Future?> pickMultiImage({ double? maxWidth, double? maxHeight, @@ -119,7 +117,6 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override - @Deprecated('Switch to using getVideo instead') Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, @@ -149,7 +146,6 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override - @Deprecated("Switch to using getLostData instead") Future retrieveLostData() async { final Map? result = await _channel.invokeMapMethod('retrieve'); diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart index 9b3b5d1cf180..8f9ab99eae06 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart @@ -68,7 +68,6 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. /// /// If no images were picked, the return value is null. - @Deprecated('Switch to using getImage instead') Future pickImage({ required ImageSource source, double? maxWidth, @@ -97,7 +96,6 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// a warning message will be logged. /// /// If no images were picked, the return value is null. - @Deprecated('Switch to using getMultiImage instead') Future?> pickMultiImage({ double? maxWidth, double? maxHeight, @@ -122,7 +120,6 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. /// /// If no images were picked, the return value is null. - @Deprecated('Switch to using getVideo instead') Future pickVideo({ required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, @@ -144,7 +141,6 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// See also: /// * [LostData], for what's included in the response. /// * [Android Activity Lifecycle](https://developer.android.com/reference/android/app/Activity.html), for more information on MainActivity destruction. - @Deprecated("Switch to using getLostData instead") Future retrieveLostData() { throw UnimplementedError('retrieveLostData() has not been implemented.'); } diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart index 0adaee63ceaa..de259e0611dd 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/base.dart @@ -16,7 +16,6 @@ import 'package:meta/meta.dart'; /// This class is a very limited subset of dart:io [File], so all /// the methods should seem familiar. @immutable -@Deprecated("Switch to using XFile instead") abstract class PickedFileBase { /// Construct a PickedFile PickedFileBase(String path); diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart index c8218605e1bd..24e1931008b6 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart @@ -12,7 +12,6 @@ import './base.dart'; /// A PickedFile that works on web. /// /// It wraps the bytes of a selected file. -@Deprecated("Switch to using XFile instead") class PickedFile extends PickedFileBase { final String path; final Uint8List? _initBytes; diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart index b2905803ad0c..7037b6b7121a 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/io.dart @@ -9,7 +9,6 @@ import 'dart:typed_data'; import './base.dart'; /// A PickedFile backed by a dart:io File. -@Deprecated("Switch to using XFile instead") class PickedFile extends PickedFileBase { final File _file; diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart index e29ae409d6d5..64f6a1f27538 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/lost_data.dart @@ -10,7 +10,6 @@ import 'package:image_picker_platform_interface/src/types/types.dart'; /// Only applies to Android. /// See also: /// * [ImagePicker.retrieveLostData] for more details on retrieving lost data. -@Deprecated("Switch to using LostDataResponse instead") class LostData { /// Creates an instance with the given [file], [exception], and [type]. Any of /// the params may be null, but this is never considered to be empty. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart index b2fb6873de3b..ad3ed6a4f86a 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart @@ -7,7 +7,6 @@ import './base.dart'; /// A PickedFile is a cross-platform, simplified File abstraction. /// /// It wraps the bytes of a selected file, and its (platform-dependant) path. -@Deprecated("Switch to using XFile instead") class PickedFile extends PickedFileBase { /// Construct a PickedFile object, from its `bytes`. /// diff --git a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart index 7850a3011f9c..e5321abc0121 100644 --- a/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart @@ -29,9 +29,7 @@ void main() { group('#pickImage', () { test('passes the image source argument correctly', () async { - // ignore: deprecated_member_use_from_same_package await picker.pickImage(source: ImageSource.camera); - // ignore: deprecated_member_use_from_same_package await picker.pickImage(source: ImageSource.gallery); expect( @@ -56,37 +54,30 @@ void main() { }); test('passes the width and height arguments correctly', () async { - // ignore: deprecated_member_use_from_same_package await picker.pickImage(source: ImageSource.camera); - // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxWidth: 10.0, ); - // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxHeight: 10.0, ); - // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxWidth: 10.0, maxHeight: 20.0, ); - // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxWidth: 10.0, imageQuality: 70, ); - // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxHeight: 10.0, imageQuality: 70, ); - // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, maxWidth: 10.0, @@ -152,26 +143,22 @@ void main() { test('does not accept a invalid imageQuality argument', () { expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickImage(imageQuality: -1, source: ImageSource.gallery), throwsArgumentError, ); expect( () => - // ignore: deprecated_member_use_from_same_package picker.pickImage(imageQuality: 101, source: ImageSource.gallery), throwsArgumentError, ); expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickImage(imageQuality: -1, source: ImageSource.camera), throwsArgumentError, ); expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickImage(imageQuality: 101, source: ImageSource.camera), throwsArgumentError, ); @@ -179,13 +166,11 @@ void main() { test('does not accept a negative width or height argument', () { expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickImage(source: ImageSource.camera, maxWidth: -1.0), throwsArgumentError, ); expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickImage(source: ImageSource.camera, maxHeight: -1.0), throwsArgumentError, ); @@ -195,14 +180,11 @@ void main() { picker.channel .setMockMethodCallHandler((MethodCall methodCall) => null); - // ignore: deprecated_member_use_from_same_package expect(await picker.pickImage(source: ImageSource.gallery), isNull); - // ignore: deprecated_member_use_from_same_package expect(await picker.pickImage(source: ImageSource.camera), isNull); }); test('camera position defaults to back', () async { - // ignore: deprecated_member_use_from_same_package await picker.pickImage(source: ImageSource.camera); expect( @@ -220,7 +202,6 @@ void main() { }); test('camera position can set to front', () async { - // ignore: deprecated_member_use_from_same_package await picker.pickImage( source: ImageSource.camera, preferredCameraDevice: CameraDevice.front); @@ -243,7 +224,6 @@ void main() { group('#pickMultiImage', () { test('calls the method correctly', () async { returnValue = ['0', '1']; - // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage(); expect( @@ -260,32 +240,25 @@ void main() { test('passes the width and height arguments correctly', () async { returnValue = ['0', '1']; - // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage(); - // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxWidth: 10.0, ); - // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxHeight: 10.0, ); - // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxWidth: 10.0, maxHeight: 20.0, ); - // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxWidth: 10.0, imageQuality: 70, ); - // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxHeight: 10.0, imageQuality: 70, ); - // ignore: deprecated_member_use_from_same_package await picker.pickMultiImage( maxWidth: 10.0, maxHeight: 20.0, @@ -337,13 +310,11 @@ void main() { test('does not accept a negative width or height argument', () { returnValue = ['0', '1']; expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickMultiImage(maxWidth: -1.0), throwsArgumentError, ); expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickMultiImage(maxHeight: -1.0), throwsArgumentError, ); @@ -352,13 +323,11 @@ void main() { test('does not accept a invalid imageQuality argument', () { returnValue = ['0', '1']; expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickMultiImage(imageQuality: -1), throwsArgumentError, ); expect( - // ignore: deprecated_member_use_from_same_package () => picker.pickMultiImage(imageQuality: 101), throwsArgumentError, ); @@ -368,18 +337,14 @@ void main() { picker.channel .setMockMethodCallHandler((MethodCall methodCall) => null); - // ignore: deprecated_member_use_from_same_package expect(await picker.pickMultiImage(), isNull); - // ignore: deprecated_member_use_from_same_package expect(await picker.pickMultiImage(), isNull); }); }); group('#pickVideo', () { test('passes the image source argument correctly', () async { - // ignore: deprecated_member_use_from_same_package await picker.pickVideo(source: ImageSource.camera); - // ignore: deprecated_member_use_from_same_package await picker.pickVideo(source: ImageSource.gallery); expect( @@ -400,19 +365,15 @@ void main() { }); test('passes the duration argument correctly', () async { - // ignore: deprecated_member_use_from_same_package await picker.pickVideo(source: ImageSource.camera); - // ignore: deprecated_member_use_from_same_package await picker.pickVideo( source: ImageSource.camera, maxDuration: const Duration(seconds: 10), ); - // ignore: deprecated_member_use_from_same_package await picker.pickVideo( source: ImageSource.camera, maxDuration: const Duration(minutes: 1), ); - // ignore: deprecated_member_use_from_same_package await picker.pickVideo( source: ImageSource.camera, maxDuration: const Duration(hours: 1), @@ -448,14 +409,11 @@ void main() { picker.channel .setMockMethodCallHandler((MethodCall methodCall) => null); - // ignore: deprecated_member_use_from_same_package expect(await picker.pickVideo(source: ImageSource.gallery), isNull); - // ignore: deprecated_member_use_from_same_package expect(await picker.pickVideo(source: ImageSource.camera), isNull); }); test('camera position defaults to back', () async { - // ignore: deprecated_member_use_from_same_package await picker.pickVideo(source: ImageSource.camera); expect( @@ -471,7 +429,6 @@ void main() { }); test('camera position can set to front', () async { - // ignore: deprecated_member_use_from_same_package await picker.pickVideo( source: ImageSource.camera, preferredCameraDevice: CameraDevice.front, @@ -498,7 +455,6 @@ void main() { 'path': '/example/path', }; }); - // ignore: deprecated_member_use_from_same_package final LostData response = await picker.retrieveLostData(); expect(response.type, RetrieveType.image); expect(response.file, isNotNull); @@ -513,7 +469,6 @@ void main() { 'errorMessage': 'test_error_message', }; }); - // ignore: deprecated_member_use_from_same_package final LostData response = await picker.retrieveLostData(); expect(response.type, RetrieveType.video); expect(response.exception, isNotNull); @@ -525,7 +480,6 @@ void main() { picker.channel.setMockMethodCallHandler((MethodCall methodCall) async { return null; }); - // ignore: deprecated_member_use_from_same_package expect((await picker.retrieveLostData()).isEmpty, true); }); @@ -538,7 +492,6 @@ void main() { 'path': '/example/path', }; }); - // ignore: deprecated_member_use_from_same_package expect(picker.retrieveLostData(), throwsAssertionError); }); }); @@ -970,7 +923,6 @@ void main() { 'path': '/example/path', }; }); - // ignore: deprecated_member_use_from_same_package final LostDataResponse response = await picker.getLostData(); expect(response.type, RetrieveType.image); expect(response.file, isNotNull); @@ -985,7 +937,6 @@ void main() { 'errorMessage': 'test_error_message', }; }); - // ignore: deprecated_member_use_from_same_package final LostDataResponse response = await picker.getLostData(); expect(response.type, RetrieveType.video); expect(response.exception, isNotNull); diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart index 42fea59a6f81..7721f66148e0 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart @@ -17,7 +17,6 @@ final String textFileUrl = html.Url.createObjectUrl(textFile); void main() { group('Create with an objectUrl', () { - // ignore: deprecated_member_use_from_same_package final pickedFile = PickedFile(textFileUrl); test('Can be read as a string', () async { diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart index d4ccca84092e..d366204c36bf 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart @@ -21,7 +21,6 @@ final String textFilePath = textFile.path; void main() { group('Create with an objectUrl', () { - // ignore: deprecated_member_use_from_same_package final PickedFile pickedFile = PickedFile(textFilePath); test('Can be read as a string', () async { From 4615db1f8d15e764932a1a6e2cb3b7103c1795a5 Mon Sep 17 00:00:00 2001 From: BeMacized Date: Thu, 8 Jul 2021 14:56:52 +0200 Subject: [PATCH 11/16] Temporary platform interface reference dependency --- packages/image_picker/image_picker_for_web/pubspec.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index d9b9c5e5cb86..9f4c68e02cef 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -20,8 +20,10 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - image_picker_platform_interface: ^2.2.0 meta: ^1.3.0 + # TODO: CHANGE TO VERSION REFERENCE WHEN NEW INTERFACE HAS BEEN PUBLISHED + image_picker_platform_interface: + path: ../image_picker_platform_interface dev_dependencies: flutter_test: From faa1a9941a74a2cb310870df12a66cc970d652f3 Mon Sep 17 00:00:00 2001 From: BeMacized Date: Thu, 8 Jul 2021 15:15:08 +0200 Subject: [PATCH 12/16] Implement PR feedback --- .../method_channel_image_picker.dart | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart index 02ad17907cea..bb9e18e78d83 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart @@ -49,11 +49,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { ); if (paths == null) return null; - final List files = []; - for (final path in paths) { - files.add(PickedFile(path)); - } - return files; + return paths.map((path) => PickedFile(path)).toList(); } Future?> _getMultiImagePath({ @@ -154,7 +150,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { return LostData.empty(); } - assert(result.containsKey('path') ^ result.containsKey('errorCode')); + assert(result.containsKey('path') != result.containsKey('errorCode')); final String? type = result['type']; assert(type == kTypeImage || type == kTypeVideo); @@ -212,11 +208,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { ); if (paths == null) return null; - final List files = []; - for (final path in paths) { - files.add(XFile(path)); - } - return files; + return paths.map((path) => XFile(path)).toList(); } @override @@ -242,7 +234,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { return LostDataResponse.empty(); } - assert(result.containsKey('path') ^ result.containsKey('errorCode')); + assert(result.containsKey('path') != result.containsKey('errorCode')); final String? type = result['type']; assert(type == kTypeImage || type == kTypeVideo); From 60c2ffd416777e5ccecf0c2fe0ee2a547a55852d Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 8 Jul 2021 17:16:02 -0700 Subject: [PATCH 13/16] Depend on the published version of the platform interface --- packages/image_picker/image_picker_for_web/pubspec.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index 9f4c68e02cef..d9b9c5e5cb86 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -20,10 +20,8 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter + image_picker_platform_interface: ^2.2.0 meta: ^1.3.0 - # TODO: CHANGE TO VERSION REFERENCE WHEN NEW INTERFACE HAS BEEN PUBLISHED - image_picker_platform_interface: - path: ../image_picker_platform_interface dev_dependencies: flutter_test: From 5e7abfde64277d411b4fd37ae56685869c266418 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 8 Jul 2021 17:16:27 -0700 Subject: [PATCH 14/16] Remove Deprecated methods, so consumers don't break immediately. --- .../image_picker_for_web/lib/image_picker_for_web.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index 14d28ab70d07..d7f0c7955b65 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -86,7 +86,6 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// `capture` is only supported in mobile browsers. /// See https://caniuse.com/#feat=html-media-capture @visibleForTesting - @Deprecated("Switch to using getFile instead") Future pickFile({ String? accept, String? capture, @@ -193,7 +192,6 @@ class ImagePickerPlugin extends ImagePickerPlatform { } /// Monitors an and returns the selected file. - @Deprecated("Use _getSelectedXFile instead") Future _getSelectedFile(html.FileUploadInputElement input) { final Completer _completer = Completer(); // Observe the input until we can return something From de50d56c955bdfbac81292297fa1cce3bc35b3db Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 8 Jul 2021 17:53:29 -0700 Subject: [PATCH 15/16] Port tests from --platform=chrome to integration_test --- .cirrus.yml | 2 +- .../image_picker_for_web/CHANGELOG.md | 3 ++- .../image_picker_for_web/example/README.md | 9 +++++++ .../image_picker_for_web_test.dart | 15 +++++------ .../example/lib/main.dart | 25 +++++++++++++++++++ .../image_picker_for_web/example/pubspec.yaml | 21 ++++++++++++++++ .../image_picker_for_web/example/run_test.sh | 22 ++++++++++++++++ .../example/test_driver/integration_test.dart | 7 ++++++ .../example/web/index.html | 13 ++++++++++ .../image_picker_for_web/test/README.md | 5 ++++ .../test/tests_exist_elsewhere_test.dart | 14 +++++++++++ 11 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 packages/image_picker/image_picker_for_web/example/README.md rename packages/image_picker/image_picker_for_web/{test => example/integration_test}/image_picker_for_web_test.dart (85%) create mode 100644 packages/image_picker/image_picker_for_web/example/lib/main.dart create mode 100644 packages/image_picker/image_picker_for_web/example/pubspec.yaml create mode 100755 packages/image_picker/image_picker_for_web/example/run_test.sh create mode 100644 packages/image_picker/image_picker_for_web/example/test_driver/integration_test.dart create mode 100644 packages/image_picker/image_picker_for_web/example/web/index.html create mode 100644 packages/image_picker/image_picker_for_web/test/README.md create mode 100644 packages/image_picker/image_picker_for_web/test/tests_exist_elsewhere_test.dart diff --git a/.cirrus.yml b/.cirrus.yml index 4ad5e8e03a25..8f69bd188c06 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -168,7 +168,7 @@ task: env: # Currently missing; see https://github.com/flutter/flutter/issues/81982 # and https://github.com/flutter/flutter/issues/82211 - PLUGINS_TO_EXCLUDE_INTEGRATION_TESTS: "file_selector,image_picker_for_web,shared_preferences_web" + PLUGINS_TO_EXCLUDE_INTEGRATION_TESTS: "file_selector,shared_preferences_web" matrix: CHANNEL: "master" CHANNEL: "stable" diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index d7d752276988..b0379ad2c07c 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,6 +1,7 @@ # 2.1.0 -* Added getImage, getVideo and getFile methods that return XFile instances rather than PickedFile instances. +* Implemented `getImage`, `getVideo` and `getFile` methods that return `XFile` instances. +* Move tests to `example` directory, so they run as integration_tests with `flutter drive`. # 2.0.0 diff --git a/packages/image_picker/image_picker_for_web/example/README.md b/packages/image_picker/image_picker_for_web/example/README.md new file mode 100644 index 000000000000..4348451b14e2 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/example/README.md @@ -0,0 +1,9 @@ +# Testing + +This package uses `package:integration_test` to run its tests in a web browser. + +See [Plugin Tests > Web Tests](https://github.com/flutter/flutter/wiki/Plugin-Tests#web-tests) +in the Flutter wiki for instructions to setup and run the tests in this package. + +Check [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) +for more info. diff --git a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart b/packages/image_picker/image_picker_for_web/example/integration_test/image_picker_for_web_test.dart similarity index 85% rename from packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart rename to packages/image_picker/image_picker_for_web/example/integration_test/image_picker_for_web_test.dart index f70c273d03bc..c6d0b3b532ca 100644 --- a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart +++ b/packages/image_picker/image_picker_for_web/example/integration_test/image_picker_for_web_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@TestOn('chrome') // Uses dart:html - import 'dart:convert'; import 'dart:html' as html; import 'dart:typed_data'; @@ -11,12 +9,15 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker_for_web/image_picker_for_web.dart'; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; +import 'package:integration_test/integration_test.dart'; final String expectedStringContents = "Hello, world!"; final Uint8List bytes = utf8.encode(expectedStringContents) as Uint8List; final html.File textFile = html.File([bytes], "hello.txt"); void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + // Under test... late ImagePickerPlugin plugin; @@ -24,7 +25,7 @@ void main() { plugin = ImagePickerPlugin(); }); - test('Can select a file (Deprecated)', () async { + testWidgets('Can select a file (Deprecated)', (WidgetTester tester) async { final mockInput = html.FileUploadInputElement(); final overrides = ImagePickerPluginTestOverrides() @@ -45,7 +46,7 @@ void main() { expect((await file).readAsBytes(), completion(isNotEmpty)); }); - test('Can select a file', () async { + testWidgets('Can select a file', (WidgetTester tester) async { final mockInput = html.FileUploadInputElement(); final overrides = ImagePickerPluginTestOverrides() @@ -68,7 +69,7 @@ void main() { // There's no good way of detecting when the user has "aborted" the selection. - test('computeCaptureAttribute', () { + testWidgets('computeCaptureAttribute', (WidgetTester tester) async { expect( plugin.computeCaptureAttribute(ImageSource.gallery, CameraDevice.front), isNull, @@ -88,14 +89,14 @@ void main() { }); group('createInputElement', () { - test('accept: any, capture: null', () { + testWidgets('accept: any, capture: null', (WidgetTester tester) async { html.Element input = plugin.createInputElement('any', null); expect(input.attributes, containsPair('accept', 'any')); expect(input.attributes, isNot(contains('capture'))); }); - test('accept: any, capture: something', () { + testWidgets('accept: any, capture: something', (WidgetTester tester) async { html.Element input = plugin.createInputElement('any', 'something'); expect(input.attributes, containsPair('accept', 'any')); diff --git a/packages/image_picker/image_picker_for_web/example/lib/main.dart b/packages/image_picker/image_picker_for_web/example/lib/main.dart new file mode 100644 index 000000000000..e1a38dcdcd46 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/example/lib/main.dart @@ -0,0 +1,25 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +void main() { + runApp(MyApp()); +} + +/// App for testing +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: Text('Testing... Look at the console output for results!'), + ); + } +} diff --git a/packages/image_picker/image_picker_for_web/example/pubspec.yaml b/packages/image_picker/image_picker_for_web/example/pubspec.yaml new file mode 100644 index 000000000000..8dadde267e8a --- /dev/null +++ b/packages/image_picker/image_picker_for_web/example/pubspec.yaml @@ -0,0 +1,21 @@ +name: connectivity_for_web_integration_tests +publish_to: none + +environment: + sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.2.0" + +dependencies: + image_picker_for_web: + path: ../ + flutter: + sdk: flutter + +dev_dependencies: + js: ^0.6.3 + flutter_test: + sdk: flutter + flutter_driver: + sdk: flutter + integration_test: + sdk: flutter diff --git a/packages/image_picker/image_picker_for_web/example/run_test.sh b/packages/image_picker/image_picker_for_web/example/run_test.sh new file mode 100755 index 000000000000..aa52974f310e --- /dev/null +++ b/packages/image_picker/image_picker_for_web/example/run_test.sh @@ -0,0 +1,22 @@ +#!/usr/bin/bash +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +if pgrep -lf chromedriver > /dev/null; then + echo "chromedriver is running." + + if [ $# -eq 0 ]; then + echo "No target specified, running all tests..." + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' + else + echo "Running test target: $1..." + set -x + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1 + fi + + else + echo "chromedriver is not running." + echo "Please, check the README.md for instructions on how to use run_test.sh" +fi + diff --git a/packages/image_picker/image_picker_for_web/example/test_driver/integration_test.dart b/packages/image_picker/image_picker_for_web/example/test_driver/integration_test.dart new file mode 100644 index 000000000000..4f10f2a522f3 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/example/test_driver/integration_test.dart @@ -0,0 +1,7 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/packages/image_picker/image_picker_for_web/example/web/index.html b/packages/image_picker/image_picker_for_web/example/web/index.html new file mode 100644 index 000000000000..7fb138cc90fa --- /dev/null +++ b/packages/image_picker/image_picker_for_web/example/web/index.html @@ -0,0 +1,13 @@ + + + + + + example + + + + + diff --git a/packages/image_picker/image_picker_for_web/test/README.md b/packages/image_picker/image_picker_for_web/test/README.md new file mode 100644 index 000000000000..7c5b4ad682ba --- /dev/null +++ b/packages/image_picker/image_picker_for_web/test/README.md @@ -0,0 +1,5 @@ +## test + +This package uses integration tests for testing. + +See `example/README.md` for more info. diff --git a/packages/image_picker/image_picker_for_web/test/tests_exist_elsewhere_test.dart b/packages/image_picker/image_picker_for_web/test/tests_exist_elsewhere_test.dart new file mode 100644 index 000000000000..442c50144727 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/test/tests_exist_elsewhere_test.dart @@ -0,0 +1,14 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Tell the user where to find the real tests', () { + print('---'); + print('This package uses integration_test for its tests.'); + print('See `example/README.md` for more info.'); + print('---'); + }); +} From b01daeb9b94231e10e0964e2f10ad491cb65146f Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 8 Jul 2021 18:03:00 -0700 Subject: [PATCH 16/16] dart format --- .../image_picker_for_web/lib/image_picker_for_web.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index d7f0c7955b65..08ce801cafbe 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -153,7 +153,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { String? capture, }) { html.FileUploadInputElement input = - createInputElement(accept, capture) as html.FileUploadInputElement; + createInputElement(accept, capture) as html.FileUploadInputElement; _injectAndActivate(input); return _getSelectedXFile(input); }