Skip to content

Commit c8174d6

Browse files
danielroekfotiDim
authored andcommitted
[image_picker_platform_interface] Added pickMultiImage (flutter#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
1 parent fd1b2e9 commit c8174d6

File tree

5 files changed

+229
-5
lines changed

5 files changed

+229
-5
lines changed

packages/image_picker/image_picker_platform_interface/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.1.0
2+
3+
* Add `pickMultiImage` method.
4+
15
## 2.0.1
26

37
* Update platform_plugin_interface version requirement.

packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,54 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
3636
return path != null ? PickedFile(path) : null;
3737
}
3838

39+
@override
40+
Future<List<PickedFile>?> pickMultiImage({
41+
double? maxWidth,
42+
double? maxHeight,
43+
int? imageQuality,
44+
}) async {
45+
final List<dynamic>? paths = await _pickMultiImagePath(
46+
maxWidth: maxWidth,
47+
maxHeight: maxHeight,
48+
imageQuality: imageQuality,
49+
);
50+
if (paths == null) return null;
51+
52+
final List<PickedFile> files = [];
53+
for (final path in paths) {
54+
files.add(PickedFile(path));
55+
}
56+
return files;
57+
}
58+
59+
Future<List<dynamic>?> _pickMultiImagePath({
60+
double? maxWidth,
61+
double? maxHeight,
62+
int? imageQuality,
63+
}) {
64+
if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
65+
throw ArgumentError.value(
66+
imageQuality, 'imageQuality', 'must be between 0 and 100');
67+
}
68+
69+
if (maxWidth != null && maxWidth < 0) {
70+
throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative');
71+
}
72+
73+
if (maxHeight != null && maxHeight < 0) {
74+
throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative');
75+
}
76+
77+
return _channel.invokeMethod<List<dynamic>?>(
78+
'pickMultiImage',
79+
<String, dynamic>{
80+
'maxWidth': maxWidth,
81+
'maxHeight': maxHeight,
82+
'imageQuality': imageQuality,
83+
},
84+
);
85+
}
86+
3987
Future<String?> _pickImagePath({
4088
required ImageSource source,
4189
double? maxWidth,
@@ -74,7 +122,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
74122
CameraDevice preferredCameraDevice = CameraDevice.rear,
75123
Duration? maxDuration,
76124
}) async {
77-
String? path = await _pickVideoPath(
125+
final String? path = await _pickVideoPath(
78126
source: source,
79127
maxDuration: maxDuration,
80128
preferredCameraDevice: preferredCameraDevice,

packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ abstract class ImagePickerPlatform extends PlatformInterface {
5454
///
5555
/// The `imageQuality` argument modifies the quality of the image, ranging from 0-100
5656
/// where 100 is the original/max quality. If `imageQuality` is null, the image with
57-
/// the original quality will be returned. Compression is only supportted for certain
57+
/// the original quality will be returned. Compression is only supported for certain
5858
/// image types such as JPEG. If compression is not supported for the image that is picked,
59-
/// an warning message will be logged.
59+
/// a warning message will be logged.
6060
///
6161
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
6262
/// 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 @@ abstract class ImagePickerPlatform extends PlatformInterface {
7878
throw UnimplementedError('pickImage() has not been implemented.');
7979
}
8080

81+
/// Returns a [List<PickedFile>] with the images that were picked.
82+
///
83+
/// The images come from the [ImageSource.gallery].
84+
///
85+
/// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used
86+
/// in addition to a size modification, of which the usage is explained below.
87+
///
88+
/// If specified, the image will be at most `maxWidth` wide and
89+
/// `maxHeight` tall. Otherwise the image will be returned at it's
90+
/// original width and height.
91+
///
92+
/// The `imageQuality` argument modifies the quality of the images, ranging from 0-100
93+
/// where 100 is the original/max quality. If `imageQuality` is null, the images with
94+
/// the original quality will be returned. Compression is only supported for certain
95+
/// image types such as JPEG. If compression is not supported for the image that is picked,
96+
/// a warning message will be logged.
97+
///
98+
/// If no images were picked, the return value is null.
99+
Future<List<PickedFile>?> pickMultiImage({
100+
double? maxWidth,
101+
double? maxHeight,
102+
int? imageQuality,
103+
}) {
104+
throw UnimplementedError('pickMultiImage() has not been implemented.');
105+
}
106+
81107
/// Returns a [PickedFile] containing the video that was picked.
82108
///
83109
/// The [source] argument controls where the video comes from. This can

packages/image_picker/image_picker_platform_interface/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: A common platform interface for the image_picker plugin.
33
homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_platform_interface
44
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
55
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
6-
version: 2.0.1
6+
version: 2.1.0
77

88
dependencies:
99
flutter:

packages/image_picker/image_picker_platform_interface/test/new_method_channel_image_picker_test.dart

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ void main() {
1515
MethodChannelImagePicker picker = MethodChannelImagePicker();
1616

1717
final List<MethodCall> log = <MethodCall>[];
18+
dynamic returnValue = '';
1819

1920
setUp(() {
21+
returnValue = '';
2022
picker.channel.setMockMethodCallHandler((MethodCall methodCall) async {
2123
log.add(methodCall);
22-
return '';
24+
return returnValue;
2325
});
2426

2527
log.clear();
@@ -139,6 +141,29 @@ void main() {
139141
);
140142
});
141143

144+
test('does not accept a invalid imageQuality argument', () {
145+
expect(
146+
() => picker.pickImage(imageQuality: -1, source: ImageSource.gallery),
147+
throwsArgumentError,
148+
);
149+
150+
expect(
151+
() =>
152+
picker.pickImage(imageQuality: 101, source: ImageSource.gallery),
153+
throwsArgumentError,
154+
);
155+
156+
expect(
157+
() => picker.pickImage(imageQuality: -1, source: ImageSource.camera),
158+
throwsArgumentError,
159+
);
160+
161+
expect(
162+
() => picker.pickImage(imageQuality: 101, source: ImageSource.camera),
163+
throwsArgumentError,
164+
);
165+
});
166+
142167
test('does not accept a negative width or height argument', () {
143168
expect(
144169
() => picker.pickImage(source: ImageSource.camera, maxWidth: -1.0),
@@ -196,6 +221,127 @@ void main() {
196221
});
197222
});
198223

224+
group('#pickMultiImage', () {
225+
test('calls the method correctly', () async {
226+
returnValue = ['0', '1'];
227+
await picker.pickMultiImage();
228+
229+
expect(
230+
log,
231+
<Matcher>[
232+
isMethodCall('pickMultiImage', arguments: <String, dynamic>{
233+
'maxWidth': null,
234+
'maxHeight': null,
235+
'imageQuality': null,
236+
}),
237+
],
238+
);
239+
});
240+
241+
test('passes the width and height arguments correctly', () async {
242+
returnValue = ['0', '1'];
243+
await picker.pickMultiImage();
244+
await picker.pickMultiImage(
245+
maxWidth: 10.0,
246+
);
247+
await picker.pickMultiImage(
248+
maxHeight: 10.0,
249+
);
250+
await picker.pickMultiImage(
251+
maxWidth: 10.0,
252+
maxHeight: 20.0,
253+
);
254+
await picker.pickMultiImage(
255+
maxWidth: 10.0,
256+
imageQuality: 70,
257+
);
258+
await picker.pickMultiImage(
259+
maxHeight: 10.0,
260+
imageQuality: 70,
261+
);
262+
await picker.pickMultiImage(
263+
maxWidth: 10.0,
264+
maxHeight: 20.0,
265+
imageQuality: 70,
266+
);
267+
268+
expect(
269+
log,
270+
<Matcher>[
271+
isMethodCall('pickMultiImage', arguments: <String, dynamic>{
272+
'maxWidth': null,
273+
'maxHeight': null,
274+
'imageQuality': null,
275+
}),
276+
isMethodCall('pickMultiImage', arguments: <String, dynamic>{
277+
'maxWidth': 10.0,
278+
'maxHeight': null,
279+
'imageQuality': null,
280+
}),
281+
isMethodCall('pickMultiImage', arguments: <String, dynamic>{
282+
'maxWidth': null,
283+
'maxHeight': 10.0,
284+
'imageQuality': null,
285+
}),
286+
isMethodCall('pickMultiImage', arguments: <String, dynamic>{
287+
'maxWidth': 10.0,
288+
'maxHeight': 20.0,
289+
'imageQuality': null,
290+
}),
291+
isMethodCall('pickMultiImage', arguments: <String, dynamic>{
292+
'maxWidth': 10.0,
293+
'maxHeight': null,
294+
'imageQuality': 70,
295+
}),
296+
isMethodCall('pickMultiImage', arguments: <String, dynamic>{
297+
'maxWidth': null,
298+
'maxHeight': 10.0,
299+
'imageQuality': 70,
300+
}),
301+
isMethodCall('pickMultiImage', arguments: <String, dynamic>{
302+
'maxWidth': 10.0,
303+
'maxHeight': 20.0,
304+
'imageQuality': 70,
305+
}),
306+
],
307+
);
308+
});
309+
310+
test('does not accept a negative width or height argument', () {
311+
returnValue = ['0', '1'];
312+
expect(
313+
() => picker.pickMultiImage(maxWidth: -1.0),
314+
throwsArgumentError,
315+
);
316+
317+
expect(
318+
() => picker.pickMultiImage(maxHeight: -1.0),
319+
throwsArgumentError,
320+
);
321+
});
322+
323+
test('does not accept a invalid imageQuality argument', () {
324+
returnValue = ['0', '1'];
325+
expect(
326+
() => picker.pickMultiImage(imageQuality: -1),
327+
throwsArgumentError,
328+
);
329+
330+
expect(
331+
() => picker.pickMultiImage(imageQuality: 101),
332+
throwsArgumentError,
333+
);
334+
});
335+
336+
test('handles a null image path response gracefully', () async {
337+
picker.channel
338+
.setMockMethodCallHandler((MethodCall methodCall) => null);
339+
340+
expect(await picker.pickMultiImage(), isNull);
341+
expect(await picker.pickMultiImage(), isNull);
342+
});
343+
});
344+
199345
group('#pickVideoPath', () {
200346
test('passes the image source argument correctly', () async {
201347
await picker.pickVideo(source: ImageSource.camera);

0 commit comments

Comments
 (0)