From a4e46125c429b6219e95ebfada187349989a89ce Mon Sep 17 00:00:00 2001 From: Piotr Mitkowski Date: Mon, 6 Jun 2022 11:58:09 +0200 Subject: [PATCH 1/7] Added fullMetadata argument to multi image picking method --- .../method_channel_image_picker.dart | 20 +++++++++ .../image_picker_platform.dart | 21 ++++++++++ .../src/types/multi_image_picker_options.dart | 41 +++++++++++++++++++ .../pubspec.yaml | 2 +- 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.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 ba5d60d7a677..a3f2f5f0a8de 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 @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; +import 'package:image_picker_platform_interface/src/types/multi_image_picker_options.dart'; const MethodChannel _channel = MethodChannel('plugins.flutter.io/image_picker'); @@ -57,6 +58,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { double? maxWidth, double? maxHeight, int? imageQuality, + bool requestFullMetadata = true, }) { if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) { throw ArgumentError.value( @@ -77,6 +79,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { 'maxWidth': maxWidth, 'maxHeight': maxHeight, 'imageQuality': imageQuality, + 'requestFullMetadata': requestFullMetadata, }, ); } @@ -233,6 +236,23 @@ class MethodChannelImagePicker extends ImagePickerPlatform { return paths.map((dynamic path) => XFile(path as String)).toList(); } + @override + Future?> getMultiImageWithOptions({ + MultiImagePickerOptions options = const MultiImagePickerOptions(), + }) async { + final List? paths = await _getMultiImagePath( + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + imageQuality: options.imageQuality, + requestFullMetadata: options.requestFullMetadata, + ); + if (paths == null) { + return null; + } + + return paths.map((dynamic path) => XFile(path as String)).toList(); + } + @override Future getVideo({ required ImageSource source, 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 d1d06f904fe6..5d06c53cc7d8 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 @@ -6,6 +6,7 @@ import 'dart:async'; import 'package:cross_file/cross_file.dart'; import 'package:image_picker_platform_interface/src/method_channel/method_channel_image_picker.dart'; +import 'package:image_picker_platform_interface/src/types/multi_image_picker_options.dart'; import 'package:image_picker_platform_interface/src/types/types.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -186,6 +187,8 @@ abstract class ImagePickerPlatform extends PlatformInterface { throw UnimplementedError('getImage() has not been implemented.'); } + /// This method is deprecated in favor of [getMultiImageWithOptions] and will be removed in a future update. + /// /// Returns a [List] with the images that were picked. /// /// The images come from the [ImageSource.gallery]. @@ -283,4 +286,22 @@ abstract class ImagePickerPlatform extends PlatformInterface { preferredCameraDevice: options.preferredCameraDevice, ); } + + /// Returns a [List] with the images that were picked. + /// + /// The images come from the [ImageSource.gallery]. + /// + /// The `options` argument controls additional settings that can be used when + /// picking an image. See [MultiImagePickerOptions] for more details. + /// + /// If no images were picked, the return value is null. + Future?> getMultiImageWithOptions({ + MultiImagePickerOptions options = const MultiImagePickerOptions(), + }) { + return getMultiImage( + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + imageQuality: options.imageQuality, + ); + } } diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart new file mode 100644 index 000000000000..504199c45308 --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.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. + +/// Specifies options for picking multiple images from the device's gallery. +class MultiImagePickerOptions { + /// Creates an instance with the given [maxHeight], [maxWidth], [imageQuality] + /// and [requestFullMetadata]. + const MultiImagePickerOptions({ + this.maxHeight, + this.maxWidth, + this.imageQuality, + this.requestFullMetadata = true, + }); + + /// The maximum width of the image, in pixels. + /// + /// If null, the image will only be resized if [maxHeight] is specified. + final double? maxWidth; + + /// The maximum height of the image, in pixels. + /// + /// If null, the image will only be resized if [maxWidth] is specified. + final double? maxHeight; + + /// Modifies the quality of the image, ranging from 0-100 where 100 is the + /// original/max quality. + /// + /// 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 null, the image will be returned with the original quality. + final int? imageQuality; + + /// If true, requests full image metadata, which may require extra permissions + /// on some platforms, (e.g., NSPhotoLibraryUsageDescription on iOS). + // + // Defaults to true. + final bool requestFullMetadata; +} diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 4ce1d2fc52f1..50d84f81d888 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/main/packages/image_picker/i 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.5.0 +version: 2.6.0 environment: sdk: ">=2.12.0 <3.0.0" From b3a68bb0728a38c3e13cdf2f6d9ed931350b0502 Mon Sep 17 00:00:00 2001 From: Piotr Mitkowski Date: Mon, 6 Jun 2022 12:09:21 +0200 Subject: [PATCH 2/7] Added tests covering the new argument --- .../new_method_channel_image_picker_test.dart | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) 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 72ed363ef7ae..165352ab828d 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 @@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker_platform_interface/image_picker_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/multi_image_picker_options.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -244,6 +245,7 @@ void main() { 'maxWidth': null, 'maxHeight': null, 'imageQuality': null, + 'requestFullMetadata': true, }), ], ); @@ -283,36 +285,43 @@ void main() { 'maxWidth': null, 'maxHeight': null, 'imageQuality': null, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': null, 'imageQuality': null, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': 10.0, 'imageQuality': null, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': 20.0, 'imageQuality': null, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': null, 'imageQuality': 70, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': 10.0, 'imageQuality': 70, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': 20.0, 'imageQuality': 70, + 'requestFullMetadata': true, }), ], ); @@ -723,6 +732,7 @@ void main() { 'maxWidth': null, 'maxHeight': null, 'imageQuality': null, + 'requestFullMetadata': true, }), ], ); @@ -762,36 +772,43 @@ void main() { 'maxWidth': null, 'maxHeight': null, 'imageQuality': null, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': null, 'imageQuality': null, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': 10.0, 'imageQuality': null, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': 20.0, 'imageQuality': null, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': null, 'imageQuality': 70, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': 10.0, 'imageQuality': 70, + 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': 20.0, 'imageQuality': 70, + 'requestFullMetadata': true, }), ], ); @@ -1257,5 +1274,188 @@ void main() { ); }); }); + + group('#getMultiImageWithOptions', () { + test('calls the method correctly', () async { + returnValue = ['0', '1']; + await picker.getMultiImageWithOptions(); + + expect( + log, + [ + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'requestFullMetadata': true, + }), + ], + ); + }); + + test('passes the width and height arguments correctly', () async { + returnValue = ['0', '1']; + await picker.getMultiImageWithOptions(); + await picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions(maxWidth: 10.0), + ); + await picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions(maxHeight: 10.0), + ); + await picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions( + maxWidth: 10.0, + maxHeight: 20.0, + ), + ); + await picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions( + maxWidth: 10.0, + imageQuality: 70, + ), + ); + await picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions( + maxHeight: 10.0, + imageQuality: 70, + ), + ); + await picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions( + maxWidth: 10.0, + maxHeight: 20.0, + imageQuality: 70, + ), + ); + + expect( + log, + [ + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'requestFullMetadata': true, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': 10.0, + 'maxHeight': null, + 'imageQuality': null, + 'requestFullMetadata': true, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': 10.0, + 'imageQuality': null, + 'requestFullMetadata': true, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': 10.0, + 'maxHeight': 20.0, + 'imageQuality': null, + 'requestFullMetadata': true, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': 10.0, + 'maxHeight': null, + 'imageQuality': 70, + 'requestFullMetadata': true, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': 10.0, + 'imageQuality': 70, + 'requestFullMetadata': true, + }), + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': 10.0, + 'maxHeight': 20.0, + 'imageQuality': 70, + 'requestFullMetadata': true, + }), + ], + ); + }); + + test('does not accept a negative width or height argument', () { + returnValue = ['0', '1']; + expect( + () => picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions(maxWidth: -1.0), + ), + throwsArgumentError, + ); + + expect( + () => picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions(maxHeight: -1.0), + ), + throwsArgumentError, + ); + }); + + test('does not accept an invalid imageQuality argument', () { + returnValue = ['0', '1']; + expect( + () => picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions(imageQuality: -1), + ), + throwsArgumentError, + ); + + expect( + () => picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions(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); + }); + + test('Request full metadata argument defaults to true', () async { + returnValue = ['0', '1']; + await picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions(), + ); + + expect( + log, + [ + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'requestFullMetadata': true, + }), + ], + ); + }); + + test('passes the request full metadata argument correctly', () async { + returnValue = ['0', '1']; + await picker.getMultiImageWithOptions( + options: const MultiImagePickerOptions(requestFullMetadata: false), + ); + + expect( + log, + [ + isMethodCall('pickMultiImage', arguments: { + 'maxWidth': null, + 'maxHeight': null, + 'imageQuality': null, + 'requestFullMetadata': false, + }), + ], + ); + }); + }); }); } From 040609f935be470da638468400c242879a49bbdf Mon Sep 17 00:00:00 2001 From: Piotr Mitkowski Date: Mon, 6 Jun 2022 12:18:59 +0200 Subject: [PATCH 3/7] Updated changelog --- .../image_picker_platform_interface/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 0a4e98bf7dbe..163485c5993d 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.6.0 +* Deprecates `getMultiImage` in favor of a new method `getMultiImageWithOptions`. + * Adds `requestFullMetadata` option that allows disabling extra permission requests + on certain platforms. + * Moves optional image picking parameters to `MultiImagePickerOptions` class. + ## 2.5.0 * Deprecates `getImage` in favor of a new method `getImageFromSource`. From b4cb48d4bc51cd2f3027ede550ad5e914e869e40 Mon Sep 17 00:00:00 2001 From: Piotr Mitkowski Date: Fri, 1 Jul 2022 09:17:57 +0200 Subject: [PATCH 4/7] PR remarks --- .../image_picker/image_picker_platform_interface/CHANGELOG.md | 1 + .../lib/src/platform_interface/image_picker_platform.dart | 2 ++ .../lib/src/types/multi_image_picker_options.dart | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 163485c5993d..120b7b00ed15 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,4 +1,5 @@ ## 2.6.0 + * Deprecates `getMultiImage` in favor of a new method `getMultiImageWithOptions`. * Adds `requestFullMetadata` option that allows disabling extra permission requests on certain platforms. 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 5d06c53cc7d8..18a8f3fb5564 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 @@ -177,6 +177,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// 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. + @Deprecated('Use `getImageFromSource` instead.') Future getImage({ required ImageSource source, double? maxWidth, @@ -207,6 +208,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// a warning message will be logged. /// /// If no images were picked, the return value is null. + @Deprecated('Use `getMultiImageWithOptions` instead.') Future?> getMultiImage({ double? maxWidth, double? maxHeight, diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart index 504199c45308..ba3ebf0e1bb2 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart @@ -9,7 +9,7 @@ class MultiImagePickerOptions { const MultiImagePickerOptions({ this.maxHeight, this.maxWidth, - this.imageQuality, + this.imageQuality = 100, this.requestFullMetadata = true, }); @@ -31,7 +31,7 @@ class MultiImagePickerOptions { /// message will be logged. /// /// If null, the image will be returned with the original quality. - final int? imageQuality; + final int imageQuality; /// If true, requests full image metadata, which may require extra permissions /// on some platforms, (e.g., NSPhotoLibraryUsageDescription on iOS). From 527ec7c889b743a818d1f9f9bac70878aad7cb7d Mon Sep 17 00:00:00 2001 From: Piotr Mitkowski Date: Fri, 1 Jul 2022 11:42:53 +0200 Subject: [PATCH 5/7] Fixed failing tests --- .../new_method_channel_image_picker_test.dart | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) 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 165352ab828d..6c0019a08f68 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 @@ -1286,14 +1286,15 @@ void main() { isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': null, - 'imageQuality': null, + 'imageQuality': 100, 'requestFullMetadata': true, }), ], ); }); - test('passes the width and height arguments correctly', () async { + test('passes the width, height and imageQuality arguments correctly', + () async { returnValue = ['0', '1']; await picker.getMultiImageWithOptions(); await picker.getMultiImageWithOptions( @@ -1334,25 +1335,25 @@ void main() { isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': null, - 'imageQuality': null, + 'imageQuality': 100, 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': null, - 'imageQuality': null, + 'imageQuality': 100, 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': 10.0, - 'imageQuality': null, + 'imageQuality': 100, 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': 20.0, - 'imageQuality': null, + 'imageQuality': 100, 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { @@ -1431,7 +1432,7 @@ void main() { isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': null, - 'imageQuality': null, + 'imageQuality': 100, 'requestFullMetadata': true, }), ], @@ -1450,7 +1451,7 @@ void main() { isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': null, - 'imageQuality': null, + 'imageQuality': 100, 'requestFullMetadata': false, }), ], From 6f015f879f8ebc372ff9c3a3597475768a919c0e Mon Sep 17 00:00:00 2001 From: Piotr Mitkowski Date: Mon, 4 Jul 2022 08:30:16 +0200 Subject: [PATCH 6/7] PR remarks --- .../method_channel_image_picker.dart | 12 ++-- .../image_picker_platform.dart | 17 +++--- .../lib/src/types/image_options.dart | 41 ++++++++++++++ .../src/types/multi_image_picker_options.dart | 37 ++----------- .../new_method_channel_image_picker_test.dart | 55 +++++++++++++------ 5 files changed, 100 insertions(+), 62 deletions(-) create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/image_options.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 a3f2f5f0a8de..d215fa2684ee 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 @@ -237,17 +237,17 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override - Future?> getMultiImageWithOptions({ + Future> getMultiImageWithOptions({ MultiImagePickerOptions options = const MultiImagePickerOptions(), }) async { final List? paths = await _getMultiImagePath( - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - imageQuality: options.imageQuality, - requestFullMetadata: options.requestFullMetadata, + maxWidth: options.imageOptions.maxWidth, + maxHeight: options.imageOptions.maxHeight, + imageQuality: options.imageOptions.imageQuality, + requestFullMetadata: options.imageOptions.requestFullMetadata, ); if (paths == null) { - return null; + return []; } return paths.map((dynamic path) => XFile(path as String)).toList(); 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 18a8f3fb5564..a2618d5b419c 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 @@ -177,7 +177,6 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// 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. - @Deprecated('Use `getImageFromSource` instead.') Future getImage({ required ImageSource source, double? maxWidth, @@ -208,7 +207,6 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// a warning message will be logged. /// /// If no images were picked, the return value is null. - @Deprecated('Use `getMultiImageWithOptions` instead.') Future?> getMultiImage({ double? maxWidth, double? maxHeight, @@ -296,14 +294,15 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// The `options` argument controls additional settings that can be used when /// picking an image. See [MultiImagePickerOptions] for more details. /// - /// If no images were picked, the return value is null. - Future?> getMultiImageWithOptions({ + /// If no images were picked, returns an empty list. + Future> getMultiImageWithOptions({ MultiImagePickerOptions options = const MultiImagePickerOptions(), - }) { - return getMultiImage( - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - imageQuality: options.imageQuality, + }) async { + final List? pickedImages = await getMultiImage( + maxWidth: options.imageOptions.maxWidth, + maxHeight: options.imageOptions.maxHeight, + imageQuality: options.imageOptions.imageQuality, ); + return pickedImages ?? []; } } diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/image_options.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/image_options.dart new file mode 100644 index 000000000000..dfaa88ec2e90 --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/image_options.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. + +/// Specifies image-specific options for picking. +class ImageOptions { + /// Creates an instance with the given [maxHeight], [maxWidth], [imageQuality] + /// and [requestFullMetadata]. + const ImageOptions({ + this.maxHeight, + this.maxWidth, + this.imageQuality = 100, + this.requestFullMetadata = true, + }); + + /// The maximum width of the image, in pixels. + /// + /// If null, the image will only be resized if [maxHeight] is specified. + final double? maxWidth; + + /// The maximum height of the image, in pixels. + /// + /// If null, the image will only be resized if [maxWidth] is specified. + final double? maxHeight; + + /// Modifies the quality of the image, ranging from 0-100 where 100 is the + /// original/max quality. + /// + /// 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. + /// + /// Defaults to 100 (the original quality). + final int imageQuality; + + /// If true, requests full image metadata, which may require extra permissions + /// on some platforms, (e.g., NSPhotoLibraryUsageDescription on iOS). + // + // Defaults to true. + final bool requestFullMetadata; +} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart index ba3ebf0e1bb2..4d7971c59a81 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_image_picker_options.dart @@ -2,40 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:image_picker_platform_interface/src/types/image_options.dart'; + /// Specifies options for picking multiple images from the device's gallery. class MultiImagePickerOptions { - /// Creates an instance with the given [maxHeight], [maxWidth], [imageQuality] - /// and [requestFullMetadata]. + /// Creates an instance with the given [imageOptions]. const MultiImagePickerOptions({ - this.maxHeight, - this.maxWidth, - this.imageQuality = 100, - this.requestFullMetadata = true, + this.imageOptions = const ImageOptions(), }); - /// The maximum width of the image, in pixels. - /// - /// If null, the image will only be resized if [maxHeight] is specified. - final double? maxWidth; - - /// The maximum height of the image, in pixels. - /// - /// If null, the image will only be resized if [maxWidth] is specified. - final double? maxHeight; - - /// Modifies the quality of the image, ranging from 0-100 where 100 is the - /// original/max quality. - /// - /// 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 null, the image will be returned with the original quality. - final int imageQuality; - - /// If true, requests full image metadata, which may require extra permissions - /// on some platforms, (e.g., NSPhotoLibraryUsageDescription on iOS). - // - // Defaults to true. - final bool requestFullMetadata; + /// The image-specific options for picking. + final ImageOptions imageOptions; } 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 6c0019a08f68..8bc4314a5641 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 @@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker_platform_interface/image_picker_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/image_options.dart'; import 'package:image_picker_platform_interface/src/types/multi_image_picker_options.dart'; void main() { @@ -1298,34 +1299,46 @@ void main() { returnValue = ['0', '1']; await picker.getMultiImageWithOptions(); await picker.getMultiImageWithOptions( - options: const MultiImagePickerOptions(maxWidth: 10.0), + options: const MultiImagePickerOptions( + imageOptions: ImageOptions(maxWidth: 10.0), + ), ); await picker.getMultiImageWithOptions( - options: const MultiImagePickerOptions(maxHeight: 10.0), + options: const MultiImagePickerOptions( + imageOptions: ImageOptions(maxHeight: 10.0), + ), ); await picker.getMultiImageWithOptions( options: const MultiImagePickerOptions( - maxWidth: 10.0, - maxHeight: 20.0, + imageOptions: ImageOptions( + maxWidth: 10.0, + maxHeight: 20.0, + ), ), ); await picker.getMultiImageWithOptions( options: const MultiImagePickerOptions( - maxWidth: 10.0, - imageQuality: 70, + imageOptions: ImageOptions( + maxWidth: 10.0, + imageQuality: 70, + ), ), ); await picker.getMultiImageWithOptions( options: const MultiImagePickerOptions( - maxHeight: 10.0, - imageQuality: 70, + imageOptions: ImageOptions( + maxHeight: 10.0, + imageQuality: 70, + ), ), ); await picker.getMultiImageWithOptions( options: const MultiImagePickerOptions( - maxWidth: 10.0, - maxHeight: 20.0, - imageQuality: 70, + imageOptions: ImageOptions( + maxWidth: 10.0, + maxHeight: 20.0, + imageQuality: 70, + ), ), ); @@ -1382,14 +1395,18 @@ void main() { returnValue = ['0', '1']; expect( () => picker.getMultiImageWithOptions( - options: const MultiImagePickerOptions(maxWidth: -1.0), + options: const MultiImagePickerOptions( + imageOptions: ImageOptions(maxWidth: -1.0), + ), ), throwsArgumentError, ); expect( () => picker.getMultiImageWithOptions( - options: const MultiImagePickerOptions(maxHeight: -1.0), + options: const MultiImagePickerOptions( + imageOptions: ImageOptions(maxHeight: -1.0), + ), ), throwsArgumentError, ); @@ -1399,14 +1416,18 @@ void main() { returnValue = ['0', '1']; expect( () => picker.getMultiImageWithOptions( - options: const MultiImagePickerOptions(imageQuality: -1), + options: const MultiImagePickerOptions( + imageOptions: ImageOptions(imageQuality: -1), + ), ), throwsArgumentError, ); expect( () => picker.getMultiImageWithOptions( - options: const MultiImagePickerOptions(imageQuality: 101), + options: const MultiImagePickerOptions( + imageOptions: ImageOptions(imageQuality: 101), + ), ), throwsArgumentError, ); @@ -1442,7 +1463,9 @@ void main() { test('passes the request full metadata argument correctly', () async { returnValue = ['0', '1']; await picker.getMultiImageWithOptions( - options: const MultiImagePickerOptions(requestFullMetadata: false), + options: const MultiImagePickerOptions( + imageOptions: ImageOptions(requestFullMetadata: false), + ), ); expect( From d745335e4f91480d83a7d685b5e1e201f16d60a9 Mon Sep 17 00:00:00 2001 From: Piotr Mitkowski Date: Thu, 7 Jul 2022 10:40:13 +0200 Subject: [PATCH 7/7] PR remarks - restored nullability on imageQuality --- .../lib/src/types/image_options.dart | 6 +++--- .../test/new_method_channel_image_picker_test.dart | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/image_options.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/image_options.dart index dfaa88ec2e90..2cc01c92da1d 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/image_options.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/image_options.dart @@ -9,7 +9,7 @@ class ImageOptions { const ImageOptions({ this.maxHeight, this.maxWidth, - this.imageQuality = 100, + this.imageQuality, this.requestFullMetadata = true, }); @@ -30,8 +30,8 @@ class ImageOptions { /// compression is not supported for the image that is picked, a warning /// message will be logged. /// - /// Defaults to 100 (the original quality). - final int imageQuality; + /// If null, the image will be returned with the original quality. + final int? imageQuality; /// If true, requests full image metadata, which may require extra permissions /// on some platforms, (e.g., NSPhotoLibraryUsageDescription on iOS). 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 8bc4314a5641..27d7016d8143 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 @@ -1287,7 +1287,7 @@ void main() { isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': null, - 'imageQuality': 100, + 'imageQuality': null, 'requestFullMetadata': true, }), ], @@ -1348,25 +1348,25 @@ void main() { isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': null, - 'imageQuality': 100, + 'imageQuality': null, 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': null, - 'imageQuality': 100, + 'imageQuality': null, 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': 10.0, - 'imageQuality': 100, + 'imageQuality': null, 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { 'maxWidth': 10.0, 'maxHeight': 20.0, - 'imageQuality': 100, + 'imageQuality': null, 'requestFullMetadata': true, }), isMethodCall('pickMultiImage', arguments: { @@ -1453,7 +1453,7 @@ void main() { isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': null, - 'imageQuality': 100, + 'imageQuality': null, 'requestFullMetadata': true, }), ], @@ -1474,7 +1474,7 @@ void main() { isMethodCall('pickMultiImage', arguments: { 'maxWidth': null, 'maxHeight': null, - 'imageQuality': 100, + 'imageQuality': null, 'requestFullMetadata': false, }), ],