[image_picker_platform_interface] Added pickMultiImage (#3782)
* Added pickMultiImage to image_picker_platform_interface
* Added tests
* fixed platform_interface tests
* Added tests
* fixed platform_interface tests
* Fixed tests
* Fixed version in pubspec.yaml
* Added test for imageQuality value; Implemented feedback
* Format
diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md
index 598f83b..e2def72 100644
--- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md
+++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.1.0
+
+* Add `pickMultiImage` method.
+
## 2.0.1
* Update platform_plugin_interface version requirement.
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 429c51b..e0f4645 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
@@ -36,6 +36,54 @@
return path != null ? PickedFile(path) : null;
}
+ @override
+ Future<List<PickedFile>?> pickMultiImage({
+ double? maxWidth,
+ double? maxHeight,
+ int? imageQuality,
+ }) async {
+ final List<dynamic>? paths = await _pickMultiImagePath(
+ maxWidth: maxWidth,
+ maxHeight: maxHeight,
+ imageQuality: imageQuality,
+ );
+ if (paths == null) return null;
+
+ final List<PickedFile> files = [];
+ for (final path in paths) {
+ files.add(PickedFile(path));
+ }
+ return files;
+ }
+
+ Future<List<dynamic>?> _pickMultiImagePath({
+ double? maxWidth,
+ double? maxHeight,
+ int? imageQuality,
+ }) {
+ if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
+ throw ArgumentError.value(
+ imageQuality, 'imageQuality', 'must be between 0 and 100');
+ }
+
+ if (maxWidth != null && maxWidth < 0) {
+ throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative');
+ }
+
+ if (maxHeight != null && maxHeight < 0) {
+ throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative');
+ }
+
+ return _channel.invokeMethod<List<dynamic>?>(
+ 'pickMultiImage',
+ <String, dynamic>{
+ 'maxWidth': maxWidth,
+ 'maxHeight': maxHeight,
+ 'imageQuality': imageQuality,
+ },
+ );
+ }
+
Future<String?> _pickImagePath({
required ImageSource source,
double? maxWidth,
@@ -74,7 +122,7 @@
CameraDevice preferredCameraDevice = CameraDevice.rear,
Duration? maxDuration,
}) async {
- String? path = await _pickVideoPath(
+ final String? path = await _pickVideoPath(
source: source,
maxDuration: maxDuration,
preferredCameraDevice: preferredCameraDevice,
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 3bbf422..32af774 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
@@ -54,9 +54,9 @@
///
/// 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 supportted for certain
+ /// 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,
- /// an warning message will be logged.
+ /// 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.
@@ -78,6 +78,32 @@
throw UnimplementedError('pickImage() has not been implemented.');
}
+ /// Returns a [List<PickedFile>] 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<List<PickedFile>?> pickMultiImage({
+ double? maxWidth,
+ double? maxHeight,
+ int? imageQuality,
+ }) {
+ throw UnimplementedError('pickMultiImage() has not been implemented.');
+ }
+
/// Returns a [PickedFile] containing the video that was picked.
///
/// The [source] argument controls where the video comes from. This can
diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml
index 3443f15..bd197a6 100644
--- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml
+++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml
@@ -3,7 +3,7 @@
homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_platform_interface
# 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.0.1
+version: 2.1.0
dependencies:
flutter:
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 2621733..83ae6fa 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
@@ -15,11 +15,13 @@
MethodChannelImagePicker picker = MethodChannelImagePicker();
final List<MethodCall> log = <MethodCall>[];
+ dynamic returnValue = '';
setUp(() {
+ returnValue = '';
picker.channel.setMockMethodCallHandler((MethodCall methodCall) async {
log.add(methodCall);
- return '';
+ return returnValue;
});
log.clear();
@@ -139,6 +141,29 @@
);
});
+ test('does not accept a invalid imageQuality argument', () {
+ expect(
+ () => picker.pickImage(imageQuality: -1, source: ImageSource.gallery),
+ throwsArgumentError,
+ );
+
+ expect(
+ () =>
+ picker.pickImage(imageQuality: 101, source: ImageSource.gallery),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.pickImage(imageQuality: -1, source: ImageSource.camera),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.pickImage(imageQuality: 101, source: ImageSource.camera),
+ throwsArgumentError,
+ );
+ });
+
test('does not accept a negative width or height argument', () {
expect(
() => picker.pickImage(source: ImageSource.camera, maxWidth: -1.0),
@@ -196,6 +221,127 @@
});
});
+ group('#pickMultiImage', () {
+ test('calls the method correctly', () async {
+ returnValue = ['0', '1'];
+ await picker.pickMultiImage();
+
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('pickMultiImage', arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ }),
+ ],
+ );
+ });
+
+ test('passes the width and height arguments correctly', () async {
+ returnValue = ['0', '1'];
+ await picker.pickMultiImage();
+ await picker.pickMultiImage(
+ maxWidth: 10.0,
+ );
+ await picker.pickMultiImage(
+ maxHeight: 10.0,
+ );
+ await picker.pickMultiImage(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ );
+ await picker.pickMultiImage(
+ maxWidth: 10.0,
+ imageQuality: 70,
+ );
+ await picker.pickMultiImage(
+ maxHeight: 10.0,
+ imageQuality: 70,
+ );
+ await picker.pickMultiImage(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ );
+
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('pickMultiImage', arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ }),
+ isMethodCall('pickMultiImage', arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ }),
+ isMethodCall('pickMultiImage', arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': 10.0,
+ 'imageQuality': null,
+ }),
+ isMethodCall('pickMultiImage', arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': 20.0,
+ 'imageQuality': null,
+ }),
+ isMethodCall('pickMultiImage', arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': null,
+ 'imageQuality': 70,
+ }),
+ isMethodCall('pickMultiImage', arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': 10.0,
+ 'imageQuality': 70,
+ }),
+ isMethodCall('pickMultiImage', arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': 20.0,
+ 'imageQuality': 70,
+ }),
+ ],
+ );
+ });
+
+ test('does not accept a negative width or height argument', () {
+ returnValue = ['0', '1'];
+ expect(
+ () => picker.pickMultiImage(maxWidth: -1.0),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.pickMultiImage(maxHeight: -1.0),
+ throwsArgumentError,
+ );
+ });
+
+ test('does not accept a invalid imageQuality argument', () {
+ returnValue = ['0', '1'];
+ expect(
+ () => picker.pickMultiImage(imageQuality: -1),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.pickMultiImage(imageQuality: 101),
+ throwsArgumentError,
+ );
+ });
+
+ test('handles a null image path response gracefully', () async {
+ picker.channel
+ .setMockMethodCallHandler((MethodCall methodCall) => null);
+
+ expect(await picker.pickMultiImage(), isNull);
+ expect(await picker.pickMultiImage(), isNull);
+ });
+ });
+
group('#pickVideoPath', () {
test('passes the image source argument correctly', () async {
await picker.pickVideo(source: ImageSource.camera);