[image_picker] Add limit parameter to pickMultiImage and pickMultipleMedia to ios and Android (#6201)
Adds limit parameter to `MediaOptions` and `MultiImagePickerOptions` and supports its use on iOS and Android. The `limit` argument defines how many images or media files can be select.
Fixes: [flutter/flutter#85772](https://github.com/flutter/flutter/issues/85772)
diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md
index 90f2406..c9f4b3b 100644
--- a/packages/image_picker/image_picker/CHANGELOG.md
+++ b/packages/image_picker/image_picker/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 1.1.0
+
+* Adds limit parameter to `MediaOptions` and `MultiImagePickerOptions` which limits
+ the number of media that can be selected.
+ * Currently supported only on iOS and Android.
+* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
+
## 1.0.8
* Updates minimum supported SDK version to Flutter 3.13/Dart 3.1.
diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart
index 2e1a3d7..a836c0a 100755
--- a/packages/image_picker/image_picker/example/lib/main.dart
+++ b/packages/image_picker/image_picker/example/lib/main.dart
@@ -56,6 +56,7 @@
final TextEditingController maxWidthController = TextEditingController();
final TextEditingController maxHeightController = TextEditingController();
final TextEditingController qualityController = TextEditingController();
+ final TextEditingController limitController = TextEditingController();
Future<void> _playVideo(XFile? file) async {
if (file != null && mounted) {
@@ -96,19 +97,21 @@
source: source, maxDuration: const Duration(seconds: 10));
await _playVideo(file);
} else if (isMultiImage) {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, true, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final List<XFile> pickedFileList = isMedia
? await _picker.pickMultipleMedia(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
+ limit: limit,
)
: await _picker.pickMultiImage(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
+ limit: limit,
);
setState(() {
_mediaFileList = pickedFileList;
@@ -120,8 +123,8 @@
}
});
} else if (isMedia) {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, false, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final List<XFile> pickedFileList = <XFile>[];
final XFile? media = await _picker.pickMedia(
@@ -142,8 +145,8 @@
}
});
} else {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, false, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final XFile? pickedFile = await _picker.pickImage(
source: source,
@@ -454,7 +457,7 @@
}
Future<void> _displayPickImageDialog(
- BuildContext context, OnPickImageCallback onPick) async {
+ BuildContext context, bool isMulti, OnPickImageCallback onPick) async {
return showDialog(
context: context,
builder: (BuildContext context) {
@@ -483,6 +486,13 @@
decoration: const InputDecoration(
hintText: 'Enter quality if desired'),
),
+ if (isMulti)
+ TextField(
+ controller: limitController,
+ keyboardType: TextInputType.number,
+ decoration: const InputDecoration(
+ hintText: 'Enter limit if desired'),
+ ),
],
),
actions: <Widget>[
@@ -504,7 +514,10 @@
final int? quality = qualityController.text.isNotEmpty
? int.parse(qualityController.text)
: null;
- onPick(width, height, quality);
+ final int? limit = limitController.text.isNotEmpty
+ ? int.parse(limitController.text)
+ : null;
+ onPick(width, height, quality, limit);
Navigator.of(context).pop();
}),
],
@@ -514,7 +527,7 @@
}
typedef OnPickImageCallback = void Function(
- double? maxWidth, double? maxHeight, int? quality);
+ double? maxWidth, double? maxHeight, int? quality, int? limit);
class AspectRatioVideo extends StatefulWidget {
const AspectRatioVideo(this.controller, {super.key});
diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml
index b41127e..b7ca08c 100644
--- a/packages/image_picker/image_picker/example/pubspec.yaml
+++ b/packages/image_picker/image_picker/example/pubspec.yaml
@@ -3,8 +3,8 @@
publish_to: none
environment:
- sdk: ^3.1.0
- flutter: ">=3.13.0"
+ sdk: ^3.3.0
+ flutter: ">=3.19.0"
dependencies:
flutter:
@@ -17,7 +17,7 @@
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
- image_picker_platform_interface: ^2.8.0
+ image_picker_platform_interface: ^2.10.0
mime: ^1.0.4
video_player: ^2.7.0
diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart
index 0ad4afc..246fe3a 100755
--- a/packages/image_picker/image_picker/lib/image_picker.dart
+++ b/packages/image_picker/image_picker/lib/image_picker.dart
@@ -128,6 +128,7 @@
double? maxWidth,
double? maxHeight,
int? imageQuality,
+ int? limit,
bool requestFullMetadata = true,
}) {
final ImageOptions imageOptions = ImageOptions.createAndValidate(
@@ -138,8 +139,9 @@
);
return platform.getMultiImageWithOptions(
- options: MultiImagePickerOptions(
+ options: MultiImagePickerOptions.createAndValidate(
imageOptions: imageOptions,
+ limit: limit,
),
);
}
@@ -186,7 +188,7 @@
bool requestFullMetadata = true,
}) async {
final List<XFile> listMedia = await platform.getMedia(
- options: MediaOptions(
+ options: MediaOptions.createAndValidate(
imageOptions: ImageOptions.createAndValidate(
maxHeight: maxHeight,
maxWidth: maxWidth,
@@ -239,10 +241,11 @@
double? maxWidth,
double? maxHeight,
int? imageQuality,
+ int? limit,
bool requestFullMetadata = true,
}) {
return platform.getMedia(
- options: MediaOptions(
+ options: MediaOptions.createAndValidate(
allowMultiple: true,
imageOptions: ImageOptions.createAndValidate(
maxHeight: maxHeight,
@@ -250,6 +253,7 @@
imageQuality: imageQuality,
requestFullMetadata: requestFullMetadata,
),
+ limit: limit,
),
);
}
diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml
index a0e3ce1..5854c9f 100755
--- a/packages/image_picker/image_picker/pubspec.yaml
+++ b/packages/image_picker/image_picker/pubspec.yaml
@@ -3,11 +3,11 @@
library, and taking new pictures with the camera.
repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
-version: 1.0.8
+version: 1.1.0
environment:
- sdk: ^3.1.0
- flutter: ">=3.13.0"
+ sdk: ^3.3.0
+ flutter: ">=3.19.0"
flutter:
plugin:
@@ -30,10 +30,10 @@
sdk: flutter
image_picker_android: ^0.8.7
image_picker_for_web: ">=2.2.0 <4.0.0"
- image_picker_ios: ^0.8.9+1
+ image_picker_ios: ^0.8.8
image_picker_linux: ^0.2.1
image_picker_macos: ^0.2.1
- image_picker_platform_interface: ^2.8.0
+ image_picker_platform_interface: ^2.10.0
image_picker_windows: ^0.2.1
dev_dependencies:
diff --git a/packages/image_picker/image_picker/test/image_picker_test.dart b/packages/image_picker/image_picker/test/image_picker_test.dart
index 4ff5b4e..766b380 100644
--- a/packages/image_picker/image_picker/test/image_picker_test.dart
+++ b/packages/image_picker/image_picker/test/image_picker_test.dart
@@ -431,7 +431,16 @@
imageQuality: 70,
);
await picker.pickMultiImage(
- maxWidth: 10.0, maxHeight: 20.0, imageQuality: 70);
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ );
+ await picker.pickMultiImage(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ limit: 5,
+ );
verifyInOrder(<Object>[
mockPlatform.getMultiImageWithOptions(
@@ -529,6 +538,29 @@
named: 'options',
),
),
+ mockPlatform.getMultiImageWithOptions(
+ options: argThat(
+ isInstanceOf<MultiImagePickerOptions>()
+ .having(
+ (MultiImagePickerOptions options) =>
+ options.imageOptions.maxWidth,
+ 'maxWidth',
+ equals(10.0))
+ .having(
+ (MultiImagePickerOptions options) =>
+ options.imageOptions.maxWidth,
+ 'maxHeight',
+ equals(10.0))
+ .having(
+ (MultiImagePickerOptions options) =>
+ options.imageOptions.imageQuality,
+ 'imageQuality',
+ equals(70))
+ .having((MultiImagePickerOptions options) => options.limit,
+ 'limit', equals(5)),
+ named: 'options',
+ ),
+ ),
]);
});
@@ -545,6 +577,24 @@
);
});
+ test('does not accept a limit argument lower than 2', () {
+ final ImagePicker picker = ImagePicker();
+ expect(
+ () => picker.pickMultiImage(limit: -1),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.pickMultiImage(limit: 0),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.pickMultiImage(limit: 1),
+ throwsArgumentError,
+ );
+ });
+
test('handles an empty image file response gracefully', () async {
final ImagePicker picker = ImagePicker();
@@ -620,7 +670,15 @@
imageQuality: 70,
);
await picker.pickMedia(
- maxWidth: 10.0, maxHeight: 20.0, imageQuality: 70);
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ );
+ await picker.pickMedia(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ );
verifyInOrder(<Object>[
mockPlatform.getMedia(
@@ -793,7 +851,16 @@
imageQuality: 70,
);
await picker.pickMultipleMedia(
- maxWidth: 10.0, maxHeight: 20.0, imageQuality: 70);
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ );
+ await picker.pickMultipleMedia(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ limit: 5,
+ );
verifyInOrder(<Object>[
mockPlatform.getMedia(
@@ -885,6 +952,27 @@
named: 'options',
),
),
+ mockPlatform.getMedia(
+ options: argThat(
+ isInstanceOf<MediaOptions>()
+ .having(
+ (MediaOptions options) => options.imageOptions.maxWidth,
+ 'maxWidth',
+ equals(10.0))
+ .having(
+ (MediaOptions options) => options.imageOptions.maxWidth,
+ 'maxHeight',
+ equals(10.0))
+ .having(
+ (MediaOptions options) =>
+ options.imageOptions.imageQuality,
+ 'imageQuality',
+ equals(70))
+ .having((MediaOptions options) => options.limit, 'limit',
+ equals(5)),
+ named: 'options',
+ ),
+ ),
]);
});
@@ -901,6 +989,24 @@
);
});
+ test('does not accept a limit argument lower than 2', () {
+ final ImagePicker picker = ImagePicker();
+ expect(
+ () => picker.pickMultipleMedia(limit: -1),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.pickMultipleMedia(limit: 0),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.pickMultipleMedia(limit: 1),
+ throwsArgumentError,
+ );
+ });
+
test('handles an empty image file response gracefully', () async {
final ImagePicker picker = ImagePicker();
diff --git a/packages/image_picker/image_picker_android/CHANGELOG.md b/packages/image_picker/image_picker_android/CHANGELOG.md
index 5ffcad5..9efc86c 100644
--- a/packages/image_picker/image_picker_android/CHANGELOG.md
+++ b/packages/image_picker/image_picker_android/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.10
+
+* Adds limit parameter to `MediaOptions` and `MultiImagePickerOptions` that sets a limit to how many media or image items can be selected.
+
## 0.8.9+6
* Updates minSdkVersion to 19.
diff --git a/packages/image_picker/image_picker_android/android/src/main/AndroidManifest.xml b/packages/image_picker/image_picker_android/android/src/main/AndroidManifest.xml
index 5d1773e..5f9bcd8 100755
--- a/packages/image_picker/image_picker_android/android/src/main/AndroidManifest.xml
+++ b/packages/image_picker/image_picker_android/android/src/main/AndroidManifest.xml
@@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="io.flutter.plugins.imagepicker">
<application>
@@ -11,5 +12,15 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/flutter_image_picker_file_paths" />
</provider>
+ <!-- Trigger Google Play services to install the backported photo picker module. -->
+ <service android:name="com.google.android.gms.metadata.ModuleDependencies"
+ android:enabled="false"
+ android:exported="false"
+ tools:ignore="MissingClass">
+ <intent-filter>
+ <action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
+ </intent-filter>
+ <meta-data android:name="photopicker_activity:0:required" android:value="" />
+ </service>
</application>
</manifest>
diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java
index 98b5560..96bf727 100644
--- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java
+++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java
@@ -297,8 +297,10 @@
Intent pickMediaIntent;
if (generalOptions.getUsePhotoPicker()) {
if (generalOptions.getAllowMultiple()) {
+ int limit = ImagePickerUtils.getLimitFromOption(generalOptions);
+
pickMediaIntent =
- new ActivityResultContracts.PickMultipleVisualMedia()
+ new ActivityResultContracts.PickMultipleVisualMedia(limit)
.createIntent(
activity,
new PickVisualMediaRequest.Builder()
@@ -426,13 +428,14 @@
public void chooseMultiImageFromGallery(
@NonNull ImageSelectionOptions options,
boolean usePhotoPicker,
+ int limit,
@NonNull Messages.Result<List<String>> result) {
if (!setPendingOptionsAndResult(options, null, result)) {
finishWithAlreadyActiveError(result);
return;
}
- launchMultiPickImageFromGalleryIntent(usePhotoPicker);
+ launchMultiPickImageFromGalleryIntent(usePhotoPicker, limit);
}
private void launchPickImageFromGalleryIntent(Boolean usePhotoPicker) {
@@ -452,11 +455,11 @@
activity.startActivityForResult(pickImageIntent, REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY);
}
- private void launchMultiPickImageFromGalleryIntent(Boolean usePhotoPicker) {
+ private void launchMultiPickImageFromGalleryIntent(Boolean usePhotoPicker, int limit) {
Intent pickMultiImageIntent;
if (usePhotoPicker) {
pickMultiImageIntent =
- new ActivityResultContracts.PickMultipleVisualMedia()
+ new ActivityResultContracts.PickMultipleVisualMedia(limit)
.createIntent(
activity,
new PickVisualMediaRequest.Builder()
diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java
index b5deb28..8096930 100644
--- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java
+++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java
@@ -125,7 +125,7 @@
this.messenger = messenger;
delegate = constructDelegate(activity);
- ImagePickerApi.setup(messenger, handler);
+ ImagePickerApi.setUp(messenger, handler);
observer = new LifeCycleObserver(activity);
if (registrar != null) {
// V1 embedding setup for activity listeners.
@@ -159,7 +159,7 @@
lifecycle = null;
}
- ImagePickerApi.setup(messenger, null);
+ ImagePickerApi.setUp(messenger, null);
if (application != null) {
application.unregisterActivityLifecycleCallbacks(observer);
@@ -317,7 +317,10 @@
setCameraDevice(delegate, source);
if (generalOptions.getAllowMultiple()) {
- delegate.chooseMultiImageFromGallery(options, generalOptions.getUsePhotoPicker(), result);
+ int limit = ImagePickerUtils.getLimitFromOption(generalOptions);
+
+ delegate.chooseMultiImageFromGallery(
+ options, generalOptions.getUsePhotoPicker(), limit, result);
} else {
switch (source.getType()) {
case GALLERY:
diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java
index 6a93c69f..d140564 100644
--- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java
+++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java
@@ -5,10 +5,13 @@
package io.flutter.plugins.imagepicker;
import android.Manifest;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.provider.MediaStore;
+import androidx.activity.result.contract.ActivityResultContracts;
import java.util.Arrays;
final class ImagePickerUtils {
@@ -54,4 +57,32 @@
boolean greatOrEqualM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
return greatOrEqualM && isPermissionPresentInManifest(context, Manifest.permission.CAMERA);
}
+
+ /**
+ * The system photo picker has a maximum limit of selectable items returned by
+ * [MediaStore.getPickImagesMaxLimit()] On devices supporting picker provided via
+ * [ACTION_SYSTEM_FALLBACK_PICK_IMAGES], the limit may be ignored if it's higher than the allowed
+ * limit. On devices not supporting the photo picker, the limit is ignored.
+ *
+ * @see MediaStore.EXTRA_PICK_IMAGES_MAX
+ */
+ @SuppressLint({"NewApi", "ClassVerificationFailure"})
+ static int getMaxItems() {
+ if (ActivityResultContracts.PickVisualMedia.isSystemPickerAvailable$activity_release()) {
+ return MediaStore.getPickImagesMaxLimit();
+ } else {
+ return Integer.MAX_VALUE;
+ }
+ }
+
+ static int getLimitFromOption(Messages.GeneralOptions generalOptions) {
+ Long limit = generalOptions.getLimit();
+ int effectiveLimit = getMaxItems();
+
+ if (limit != null && limit < effectiveLimit) {
+ effectiveLimit = Math.toIntExact(limit);
+ }
+
+ return effectiveLimit;
+ }
}
diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/Messages.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/Messages.java
index 8a19cfd..b987a22 100644
--- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/Messages.java
+++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/Messages.java
@@ -1,11 +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.
-// Autogenerated from Pigeon (v9.2.5), do not edit directly.
+// Autogenerated from Pigeon (v17.0.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
package io.flutter.plugins.imagepicker;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -14,6 +17,8 @@
import io.flutter.plugin.common.MessageCodec;
import io.flutter.plugin.common.StandardMessageCodec;
import java.io.ByteArrayOutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
@@ -55,6 +60,10 @@
return errorList;
}
+ @Target(METHOD)
+ @Retention(CLASS)
+ @interface CanIgnoreReturnValue {}
+
public enum SourceCamera {
REAR(0),
FRONT(1);
@@ -116,6 +125,16 @@
this.usePhotoPicker = setterArg;
}
+ private @Nullable Long limit;
+
+ public @Nullable Long getLimit() {
+ return limit;
+ }
+
+ public void setLimit(@Nullable Long setterArg) {
+ this.limit = setterArg;
+ }
+
/** Constructor is non-public to enforce null safety; use Builder. */
GeneralOptions() {}
@@ -123,6 +142,7 @@
private @Nullable Boolean allowMultiple;
+ @CanIgnoreReturnValue
public @NonNull Builder setAllowMultiple(@NonNull Boolean setterArg) {
this.allowMultiple = setterArg;
return this;
@@ -130,24 +150,35 @@
private @Nullable Boolean usePhotoPicker;
+ @CanIgnoreReturnValue
public @NonNull Builder setUsePhotoPicker(@NonNull Boolean setterArg) {
this.usePhotoPicker = setterArg;
return this;
}
+ private @Nullable Long limit;
+
+ @CanIgnoreReturnValue
+ public @NonNull Builder setLimit(@Nullable Long setterArg) {
+ this.limit = setterArg;
+ return this;
+ }
+
public @NonNull GeneralOptions build() {
GeneralOptions pigeonReturn = new GeneralOptions();
pigeonReturn.setAllowMultiple(allowMultiple);
pigeonReturn.setUsePhotoPicker(usePhotoPicker);
+ pigeonReturn.setLimit(limit);
return pigeonReturn;
}
}
@NonNull
ArrayList<Object> toList() {
- ArrayList<Object> toListResult = new ArrayList<Object>(2);
+ ArrayList<Object> toListResult = new ArrayList<Object>(3);
toListResult.add(allowMultiple);
toListResult.add(usePhotoPicker);
+ toListResult.add(limit);
return toListResult;
}
@@ -157,6 +188,9 @@
pigeonResult.setAllowMultiple((Boolean) allowMultiple);
Object usePhotoPicker = list.get(1);
pigeonResult.setUsePhotoPicker((Boolean) usePhotoPicker);
+ Object limit = list.get(2);
+ pigeonResult.setLimit(
+ (limit == null) ? null : ((limit instanceof Integer) ? (Integer) limit : (Long) limit));
return pigeonResult;
}
}
@@ -214,6 +248,7 @@
private @Nullable Double maxWidth;
+ @CanIgnoreReturnValue
public @NonNull Builder setMaxWidth(@Nullable Double setterArg) {
this.maxWidth = setterArg;
return this;
@@ -221,6 +256,7 @@
private @Nullable Double maxHeight;
+ @CanIgnoreReturnValue
public @NonNull Builder setMaxHeight(@Nullable Double setterArg) {
this.maxHeight = setterArg;
return this;
@@ -228,6 +264,7 @@
private @Nullable Long quality;
+ @CanIgnoreReturnValue
public @NonNull Builder setQuality(@NonNull Long setterArg) {
this.quality = setterArg;
return this;
@@ -288,6 +325,7 @@
private @Nullable ImageSelectionOptions imageSelectionOptions;
+ @CanIgnoreReturnValue
public @NonNull Builder setImageSelectionOptions(@NonNull ImageSelectionOptions setterArg) {
this.imageSelectionOptions = setterArg;
return this;
@@ -339,6 +377,7 @@
private @Nullable Long maxDurationSeconds;
+ @CanIgnoreReturnValue
public @NonNull Builder setMaxDurationSeconds(@Nullable Long setterArg) {
this.maxDurationSeconds = setterArg;
return this;
@@ -407,6 +446,7 @@
private @Nullable SourceType type;
+ @CanIgnoreReturnValue
public @NonNull Builder setType(@NonNull SourceType setterArg) {
this.type = setterArg;
return this;
@@ -414,6 +454,7 @@
private @Nullable SourceCamera camera;
+ @CanIgnoreReturnValue
public @NonNull Builder setCamera(@Nullable SourceCamera setterArg) {
this.camera = setterArg;
return this;
@@ -438,7 +479,7 @@
static @NonNull SourceSpecification fromList(@NonNull ArrayList<Object> list) {
SourceSpecification pigeonResult = new SourceSpecification();
Object type = list.get(0);
- pigeonResult.setType(type == null ? null : SourceType.values()[(int) type]);
+ pigeonResult.setType(SourceType.values()[(int) type]);
Object camera = list.get(1);
pigeonResult.setCamera(camera == null ? null : SourceCamera.values()[(int) camera]);
return pigeonResult;
@@ -483,6 +524,7 @@
private @Nullable String code;
+ @CanIgnoreReturnValue
public @NonNull Builder setCode(@NonNull String setterArg) {
this.code = setterArg;
return this;
@@ -490,6 +532,7 @@
private @Nullable String message;
+ @CanIgnoreReturnValue
public @NonNull Builder setMessage(@Nullable String setterArg) {
this.message = setterArg;
return this;
@@ -578,6 +621,7 @@
private @Nullable CacheRetrievalType type;
+ @CanIgnoreReturnValue
public @NonNull Builder setType(@NonNull CacheRetrievalType setterArg) {
this.type = setterArg;
return this;
@@ -585,6 +629,7 @@
private @Nullable CacheRetrievalError error;
+ @CanIgnoreReturnValue
public @NonNull Builder setError(@Nullable CacheRetrievalError setterArg) {
this.error = setterArg;
return this;
@@ -592,6 +637,7 @@
private @Nullable List<String> paths;
+ @CanIgnoreReturnValue
public @NonNull Builder setPaths(@NonNull List<String> setterArg) {
this.paths = setterArg;
return this;
@@ -618,7 +664,7 @@
static @NonNull CacheRetrievalResult fromList(@NonNull ArrayList<Object> list) {
CacheRetrievalResult pigeonResult = new CacheRetrievalResult();
Object type = list.get(0);
- pigeonResult.setType(type == null ? null : CacheRetrievalType.values()[(int) type]);
+ pigeonResult.setType(CacheRetrievalType.values()[(int) type]);
Object error = list.get(1);
pigeonResult.setError(
(error == null) ? null : CacheRetrievalError.fromList((ArrayList<Object>) error));
@@ -628,10 +674,28 @@
}
}
+ /** Asynchronous error handling return type for non-nullable API method returns. */
public interface Result<T> {
- @SuppressWarnings("UnknownNullness")
- void success(T result);
+ /** Success case callback method for handling returns. */
+ void success(@NonNull T result);
+ /** Failure case callback method for handling errors. */
+ void error(@NonNull Throwable error);
+ }
+ /** Asynchronous error handling return type for nullable API method returns. */
+ public interface NullableResult<T> {
+ /** Success case callback method for handling returns. */
+ void success(@Nullable T result);
+
+ /** Failure case callback method for handling errors. */
+ void error(@NonNull Throwable error);
+ }
+ /** Asynchronous error handling return type for void API method returns. */
+ public interface VoidResult {
+ /** Success case callback method for handling returns. */
+ void success();
+
+ /** Failure case callback method for handling errors. */
void error(@NonNull Throwable error);
}
@@ -734,13 +798,13 @@
return ImagePickerApiCodec.INSTANCE;
}
/** Sets up an instance of `ImagePickerApi` to handle messages through the `binaryMessenger`. */
- static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable ImagePickerApi api) {
+ static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable ImagePickerApi api) {
{
BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue();
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
- "dev.flutter.pigeon.ImagePickerApi.pickImages",
+ "dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickImages",
getCodec(),
taskQueue);
if (api != null) {
@@ -775,7 +839,7 @@
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
- "dev.flutter.pigeon.ImagePickerApi.pickVideos",
+ "dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickVideos",
getCodec(),
taskQueue);
if (api != null) {
@@ -808,7 +872,9 @@
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
- binaryMessenger, "dev.flutter.pigeon.ImagePickerApi.pickMedia", getCodec());
+ binaryMessenger,
+ "dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickMedia",
+ getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
@@ -841,7 +907,7 @@
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
- "dev.flutter.pigeon.ImagePickerApi.retrieveLostResults",
+ "dev.flutter.pigeon.image_picker_android.ImagePickerApi.retrieveLostResults",
getCodec(),
taskQueue);
if (api != null) {
diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java
index 92c988c..81546da 100644
--- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java
+++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java
@@ -160,7 +160,8 @@
ImagePickerDelegate delegate =
createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
- delegate.chooseMultiImageFromGallery(DEFAULT_IMAGE_OPTIONS, false, mockResult);
+ delegate.chooseMultiImageFromGallery(
+ DEFAULT_IMAGE_OPTIONS, false, Integer.MAX_VALUE, mockResult);
verifyFinishedWithAlreadyActiveError();
verifyNoMoreInteractions(mockResult);
@@ -207,7 +208,8 @@
public void chooseMultiImageFromGallery_launchesChooseFromGalleryIntent() {
ImagePickerDelegate delegate = createDelegate();
- delegate.chooseMultiImageFromGallery(DEFAULT_IMAGE_OPTIONS, true, mockResult);
+ delegate.chooseMultiImageFromGallery(
+ DEFAULT_IMAGE_OPTIONS, true, Integer.MAX_VALUE, mockResult);
verify(mockActivity)
.startActivityForResult(
@@ -220,7 +222,8 @@
public void chooseMultiImageFromGallery_withPhotoPicker_launchesChooseFromGalleryIntent() {
ImagePickerDelegate delegate = createDelegate();
- delegate.chooseMultiImageFromGallery(DEFAULT_IMAGE_OPTIONS, false, mockResult);
+ delegate.chooseMultiImageFromGallery(
+ DEFAULT_IMAGE_OPTIONS, false, Integer.MAX_VALUE, mockResult);
verify(mockActivity)
.startActivityForResult(
diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java
index b2c281c..cf088b5 100644
--- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java
+++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java
@@ -52,6 +52,19 @@
new GeneralOptions.Builder().setUsePhotoPicker(false).setAllowMultiple(false).build();
private static final GeneralOptions GENERAL_OPTIONS_ALLOW_MULTIPLE_DONT_USE_PHOTO_PICKER =
new GeneralOptions.Builder().setUsePhotoPicker(false).setAllowMultiple(true).build();
+ private static final GeneralOptions
+ GENERAL_OPTIONS_ALLOW_MULTIPLE_DONT_USE_PHOTO_PICKER_WITH_LIMIT =
+ new GeneralOptions.Builder()
+ .setUsePhotoPicker(false)
+ .setAllowMultiple(true)
+ .setLimit((long) 5)
+ .build();
+ private static final GeneralOptions GENERAL_OPTIONS_ALLOW_MULTIPLE_USE_PHOTO_PICKER_WITH_LIMIT =
+ new GeneralOptions.Builder()
+ .setUsePhotoPicker(true)
+ .setAllowMultiple(true)
+ .setLimit((long) 5)
+ .build();
private static final SourceSpecification SOURCE_GALLERY =
new SourceSpecification.Builder().setType(Messages.SourceType.GALLERY).build();
private static final SourceSpecification SOURCE_CAMERA_FRONT =
@@ -171,7 +184,8 @@
DEFAULT_IMAGE_OPTIONS,
GENERAL_OPTIONS_ALLOW_MULTIPLE_DONT_USE_PHOTO_PICKER,
mockResult);
- verify(mockImagePickerDelegate).chooseMultiImageFromGallery(any(), eq(false), any());
+ verify(mockImagePickerDelegate)
+ .chooseMultiImageFromGallery(any(), eq(false), eq(Integer.MAX_VALUE), any());
verifyNoInteractions(mockResult);
}
@@ -182,7 +196,30 @@
DEFAULT_IMAGE_OPTIONS,
GENERAL_OPTIONS_ALLOW_MULTIPLE_USE_PHOTO_PICKER,
mockResult);
- verify(mockImagePickerDelegate).chooseMultiImageFromGallery(any(), eq(true), any());
+ verify(mockImagePickerDelegate)
+ .chooseMultiImageFromGallery(any(), eq(true), eq(Integer.MAX_VALUE), any());
+ verifyNoInteractions(mockResult);
+ }
+
+ @Test
+ public void pickImages_usingPhotoPicker_withLimit5_invokesChooseMultiImageFromGallery() {
+ plugin.pickImages(
+ SOURCE_GALLERY,
+ DEFAULT_IMAGE_OPTIONS,
+ GENERAL_OPTIONS_ALLOW_MULTIPLE_USE_PHOTO_PICKER_WITH_LIMIT,
+ mockResult);
+ verify(mockImagePickerDelegate).chooseMultiImageFromGallery(any(), eq(true), eq(5), any());
+ verifyNoInteractions(mockResult);
+ }
+
+ @Test
+ public void pickImages_withLimit5_invokesChooseMultiImageFromGallery() {
+ plugin.pickImages(
+ SOURCE_GALLERY,
+ DEFAULT_IMAGE_OPTIONS,
+ GENERAL_OPTIONS_ALLOW_MULTIPLE_DONT_USE_PHOTO_PICKER_WITH_LIMIT,
+ mockResult);
+ verify(mockImagePickerDelegate).chooseMultiImageFromGallery(any(), eq(false), eq(5), any());
verifyNoInteractions(mockResult);
}
diff --git a/packages/image_picker/image_picker_android/example/lib/main.dart b/packages/image_picker/image_picker_android/example/lib/main.dart
index 94cbd7d..8218f2d 100755
--- a/packages/image_picker/image_picker_android/example/lib/main.dart
+++ b/packages/image_picker/image_picker_android/example/lib/main.dart
@@ -74,6 +74,7 @@
final TextEditingController maxWidthController = TextEditingController();
final TextEditingController maxHeightController = TextEditingController();
final TextEditingController qualityController = TextEditingController();
+ final TextEditingController limitController = TextEditingController();
Future<void> _playVideo(XFile? file) async {
if (file != null && mounted) {
@@ -109,8 +110,8 @@
}
await _playVideo(file);
} else if (isMultiImage) {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, true, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final ImageOptions imageOptions = ImageOptions(
maxWidth: maxWidth,
@@ -120,12 +121,15 @@
final List<XFile> pickedFileList = isMedia
? await _picker.getMedia(
options: MediaOptions(
- allowMultiple: isMultiImage,
- imageOptions: imageOptions),
+ allowMultiple: isMultiImage,
+ imageOptions: imageOptions,
+ limit: limit,
+ ),
)
: await _picker.getMultiImageWithOptions(
options: MultiImagePickerOptions(
imageOptions: imageOptions,
+ limit: limit,
),
);
if (pickedFileList.isNotEmpty && context.mounted) {
@@ -141,8 +145,8 @@
}
});
} else if (isMedia) {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, false, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final List<XFile> pickedFileList = <XFile>[];
final XFile? media = _firstOrNull(await _picker.getMedia(
@@ -166,8 +170,8 @@
}
});
} else {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, false, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final XFile? pickedFile = await _picker.getImageFromSource(
source: source,
@@ -481,7 +485,7 @@
}
Future<void> _displayPickImageDialog(
- BuildContext context, OnPickImageCallback onPick) async {
+ BuildContext context, bool isMulti, OnPickImageCallback onPick) async {
return showDialog(
context: context,
builder: (BuildContext context) {
@@ -509,6 +513,13 @@
decoration: const InputDecoration(
hintText: 'Enter quality if desired'),
),
+ if (isMulti)
+ TextField(
+ controller: limitController,
+ keyboardType: TextInputType.number,
+ decoration: const InputDecoration(
+ hintText: 'Enter limit if desired'),
+ ),
],
),
actions: <Widget>[
@@ -530,7 +541,10 @@
final int? quality = qualityController.text.isNotEmpty
? int.parse(qualityController.text)
: null;
- onPick(width, height, quality);
+ final int? limit = limitController.text.isNotEmpty
+ ? int.parse(limitController.text)
+ : null;
+ onPick(width, height, quality, limit);
Navigator.of(context).pop();
}),
],
@@ -547,7 +561,7 @@
}
typedef OnPickImageCallback = void Function(
- double? maxWidth, double? maxHeight, int? quality);
+ double? maxWidth, double? maxHeight, int? quality, int? limit);
class AspectRatioVideo extends StatefulWidget {
const AspectRatioVideo(this.controller, {super.key});
diff --git a/packages/image_picker/image_picker_android/example/pubspec.yaml b/packages/image_picker/image_picker_android/example/pubspec.yaml
index c2fa9e9..500b47c 100644
--- a/packages/image_picker/image_picker_android/example/pubspec.yaml
+++ b/packages/image_picker/image_picker_android/example/pubspec.yaml
@@ -3,8 +3,8 @@
publish_to: none
environment:
- sdk: ^3.1.0
- flutter: ">=3.13.0"
+ sdk: ^3.3.0
+ flutter: ">=3.19.0"
dependencies:
flutter:
@@ -19,7 +19,7 @@
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
- image_picker_platform_interface: ^2.8.0
+ image_picker_platform_interface: ^2.10.0
mime: ^1.0.4
video_player: ^2.1.4
diff --git a/packages/image_picker/image_picker_android/lib/image_picker_android.dart b/packages/image_picker/image_picker_android/lib/image_picker_android.dart
index c9e2c87..2bcebe2 100644
--- a/packages/image_picker/image_picker_android/lib/image_picker_android.dart
+++ b/packages/image_picker/image_picker_android/lib/image_picker_android.dart
@@ -67,6 +67,7 @@
double? maxWidth,
double? maxHeight,
int? imageQuality,
+ int? limit,
}) {
if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
throw ArgumentError.value(
@@ -81,6 +82,10 @@
throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative');
}
+ if (limit != null && limit < 2) {
+ throw ArgumentError.value(limit, 'limit', 'cannot be lower than 2');
+ }
+
return _hostApi.pickImages(
SourceSpecification(type: SourceType.gallery),
ImageSelectionOptions(
@@ -88,7 +93,10 @@
maxHeight: maxHeight,
quality: imageQuality ?? 100),
GeneralOptions(
- allowMultiple: true, usePhotoPicker: useAndroidPhotoPicker),
+ allowMultiple: true,
+ usePhotoPicker: useAndroidPhotoPicker,
+ limit: limit,
+ ),
);
}
@@ -210,15 +218,30 @@
}
@override
+ Future<List<XFile>> getMultiImageWithOptions({
+ MultiImagePickerOptions options = const MultiImagePickerOptions(),
+ }) async {
+ final List<dynamic> paths = await _getMultiImagePath(
+ maxWidth: options.imageOptions.maxWidth,
+ maxHeight: options.imageOptions.maxHeight,
+ imageQuality: options.imageOptions.imageQuality,
+ limit: options.limit,
+ );
+
+ if (paths.isEmpty) {
+ return <XFile>[];
+ }
+
+ return paths.map((dynamic path) => XFile(path as String)).toList();
+ }
+
+ @override
Future<List<XFile>> getMedia({
required MediaOptions options,
}) async {
return (await _hostApi.pickMedia(
_mediaOptionsToMediaSelectionOptions(options),
- GeneralOptions(
- allowMultiple: options.allowMultiple,
- usePhotoPicker: useAndroidPhotoPicker,
- ),
+ _mediaOptionsToGeneralOptions(options),
))
.map((String? path) => XFile(path!))
.toList();
@@ -243,6 +266,7 @@
final ImageSelectionOptions imageSelectionOptions =
_imageOptionsToImageSelectionOptionsWithValidator(
mediaOptions.imageOptions);
+
return MediaSelectionOptions(
imageSelectionOptions: imageSelectionOptions,
);
@@ -270,6 +294,29 @@
quality: imageQuality ?? 100, maxHeight: maxHeight, maxWidth: maxWidth);
}
+ GeneralOptions _mediaOptionsToGeneralOptions(MediaOptions options) {
+ final bool allowMultiple = options.allowMultiple;
+ final int? limit = options.limit;
+
+ if (!allowMultiple && limit != null) {
+ throw ArgumentError.value(
+ allowMultiple,
+ 'allowMultiple',
+ 'cannot be false, when limit is not null',
+ );
+ }
+
+ if (limit != null && limit < 2) {
+ throw ArgumentError.value(limit, 'limit', 'cannot be lower then 2');
+ }
+
+ return GeneralOptions(
+ allowMultiple: allowMultiple,
+ usePhotoPicker: useAndroidPhotoPicker,
+ limit: limit,
+ );
+ }
+
@override
Future<LostData> retrieveLostData() async {
final LostDataResponse result = await getLostData();
diff --git a/packages/image_picker/image_picker_android/lib/src/messages.g.dart b/packages/image_picker/image_picker_android/lib/src/messages.g.dart
index 476e80d..1466b15 100644
--- a/packages/image_picker/image_picker_android/lib/src/messages.g.dart
+++ b/packages/image_picker/image_picker_android/lib/src/messages.g.dart
@@ -1,9 +1,9 @@
// 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.
-// Autogenerated from Pigeon (v9.2.5), do not edit directly.
+// Autogenerated from Pigeon (v17.0.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
-// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
+// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
import 'dart:async';
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
@@ -11,6 +11,24 @@
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
import 'package:flutter/services.dart';
+PlatformException _createConnectionError(String channelName) {
+ return PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel: "$channelName".',
+ );
+}
+
+List<Object?> wrapResponse(
+ {Object? result, PlatformException? error, bool empty = false}) {
+ if (empty) {
+ return <Object?>[];
+ }
+ if (error == null) {
+ return <Object?>[result];
+ }
+ return <Object?>[error.code, error.message, error.details];
+}
+
enum SourceCamera {
rear,
front,
@@ -30,16 +48,20 @@
GeneralOptions({
required this.allowMultiple,
required this.usePhotoPicker,
+ this.limit,
});
bool allowMultiple;
bool usePhotoPicker;
+ int? limit;
+
Object encode() {
return <Object?>[
allowMultiple,
usePhotoPicker,
+ limit,
];
}
@@ -48,6 +70,7 @@
return GeneralOptions(
allowMultiple: result[0]! as bool,
usePhotoPicker: result[1]! as bool,
+ limit: result[2] as int?,
);
}
}
@@ -195,7 +218,7 @@
CacheRetrievalResult({
required this.type,
this.error,
- required this.paths,
+ this.paths = const <String>[],
});
/// The type of the retrieved data.
@@ -288,43 +311,43 @@
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
ImagePickerApi({BinaryMessenger? binaryMessenger})
- : _binaryMessenger = binaryMessenger;
- final BinaryMessenger? _binaryMessenger;
+ : __pigeon_binaryMessenger = binaryMessenger;
+ final BinaryMessenger? __pigeon_binaryMessenger;
- static const MessageCodec<Object?> codec = _ImagePickerApiCodec();
+ static const MessageCodec<Object?> pigeonChannelCodec =
+ _ImagePickerApiCodec();
/// Selects images and returns their paths.
///
/// Elements must not be null, by convention. See
/// https://github.com/flutter/flutter/issues/97848
- Future<List<String?>> pickImages(
- SourceSpecification arg_source,
- ImageSelectionOptions arg_options,
- GeneralOptions arg_generalOptions) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.ImagePickerApi.pickImages', codec,
- binaryMessenger: _binaryMessenger);
- final List<Object?>? replyList = await channel
- .send(<Object?>[arg_source, arg_options, arg_generalOptions])
- as List<Object?>?;
- if (replyList == null) {
+ Future<List<String?>> pickImages(SourceSpecification source,
+ ImageSelectionOptions options, GeneralOptions generalOptions) async {
+ const String __pigeon_channelName =
+ 'dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickImages';
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ __pigeon_channelName,
+ pigeonChannelCodec,
+ binaryMessenger: __pigeon_binaryMessenger,
+ );
+ final List<Object?>? __pigeon_replyList = await __pigeon_channel
+ .send(<Object?>[source, options, generalOptions]) as List<Object?>?;
+ if (__pigeon_replyList == null) {
+ throw _createConnectionError(__pigeon_channelName);
+ } else if (__pigeon_replyList.length > 1) {
throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
+ code: __pigeon_replyList[0]! as String,
+ message: __pigeon_replyList[1] as String?,
+ details: __pigeon_replyList[2],
);
- } else if (replyList.length > 1) {
- throw PlatformException(
- code: replyList[0]! as String,
- message: replyList[1] as String?,
- details: replyList[2],
- );
- } else if (replyList[0] == null) {
+ } else if (__pigeon_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
- return (replyList[0] as List<Object?>?)!.cast<String?>();
+ return (__pigeon_replyList[0] as List<Object?>?)!.cast<String?>();
}
}
@@ -332,34 +355,33 @@
///
/// Elements must not be null, by convention. See
/// https://github.com/flutter/flutter/issues/97848
- Future<List<String?>> pickVideos(
- SourceSpecification arg_source,
- VideoSelectionOptions arg_options,
- GeneralOptions arg_generalOptions) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.ImagePickerApi.pickVideos', codec,
- binaryMessenger: _binaryMessenger);
- final List<Object?>? replyList = await channel
- .send(<Object?>[arg_source, arg_options, arg_generalOptions])
- as List<Object?>?;
- if (replyList == null) {
+ Future<List<String?>> pickVideos(SourceSpecification source,
+ VideoSelectionOptions options, GeneralOptions generalOptions) async {
+ const String __pigeon_channelName =
+ 'dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickVideos';
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ __pigeon_channelName,
+ pigeonChannelCodec,
+ binaryMessenger: __pigeon_binaryMessenger,
+ );
+ final List<Object?>? __pigeon_replyList = await __pigeon_channel
+ .send(<Object?>[source, options, generalOptions]) as List<Object?>?;
+ if (__pigeon_replyList == null) {
+ throw _createConnectionError(__pigeon_channelName);
+ } else if (__pigeon_replyList.length > 1) {
throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
+ code: __pigeon_replyList[0]! as String,
+ message: __pigeon_replyList[1] as String?,
+ details: __pigeon_replyList[2],
);
- } else if (replyList.length > 1) {
- throw PlatformException(
- code: replyList[0]! as String,
- message: replyList[1] as String?,
- details: replyList[2],
- );
- } else if (replyList[0] == null) {
+ } else if (__pigeon_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
- return (replyList[0] as List<Object?>?)!.cast<String?>();
+ return (__pigeon_replyList[0] as List<Object?>?)!.cast<String?>();
}
}
@@ -367,55 +389,59 @@
///
/// Elements must not be null, by convention. See
/// https://github.com/flutter/flutter/issues/97848
- Future<List<String?>> pickMedia(
- MediaSelectionOptions arg_mediaSelectionOptions,
- GeneralOptions arg_generalOptions) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.ImagePickerApi.pickMedia', codec,
- binaryMessenger: _binaryMessenger);
- final List<Object?>? replyList = await channel
- .send(<Object?>[arg_mediaSelectionOptions, arg_generalOptions])
+ Future<List<String?>> pickMedia(MediaSelectionOptions mediaSelectionOptions,
+ GeneralOptions generalOptions) async {
+ const String __pigeon_channelName =
+ 'dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickMedia';
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ __pigeon_channelName,
+ pigeonChannelCodec,
+ binaryMessenger: __pigeon_binaryMessenger,
+ );
+ final List<Object?>? __pigeon_replyList = await __pigeon_channel
+ .send(<Object?>[mediaSelectionOptions, generalOptions])
as List<Object?>?;
- if (replyList == null) {
+ if (__pigeon_replyList == null) {
+ throw _createConnectionError(__pigeon_channelName);
+ } else if (__pigeon_replyList.length > 1) {
throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
+ code: __pigeon_replyList[0]! as String,
+ message: __pigeon_replyList[1] as String?,
+ details: __pigeon_replyList[2],
);
- } else if (replyList.length > 1) {
- throw PlatformException(
- code: replyList[0]! as String,
- message: replyList[1] as String?,
- details: replyList[2],
- );
- } else if (replyList[0] == null) {
+ } else if (__pigeon_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
- return (replyList[0] as List<Object?>?)!.cast<String?>();
+ return (__pigeon_replyList[0] as List<Object?>?)!.cast<String?>();
}
}
/// Returns results from a previous app session, if any.
Future<CacheRetrievalResult?> retrieveLostResults() async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.ImagePickerApi.retrieveLostResults', codec,
- binaryMessenger: _binaryMessenger);
- final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
- if (replyList == null) {
+ const String __pigeon_channelName =
+ 'dev.flutter.pigeon.image_picker_android.ImagePickerApi.retrieveLostResults';
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ __pigeon_channelName,
+ pigeonChannelCodec,
+ binaryMessenger: __pigeon_binaryMessenger,
+ );
+ final List<Object?>? __pigeon_replyList =
+ await __pigeon_channel.send(null) as List<Object?>?;
+ if (__pigeon_replyList == null) {
+ throw _createConnectionError(__pigeon_channelName);
+ } else if (__pigeon_replyList.length > 1) {
throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
- );
- } else if (replyList.length > 1) {
- throw PlatformException(
- code: replyList[0]! as String,
- message: replyList[1] as String?,
- details: replyList[2],
+ code: __pigeon_replyList[0]! as String,
+ message: __pigeon_replyList[1] as String?,
+ details: __pigeon_replyList[2],
);
} else {
- return (replyList[0] as CacheRetrievalResult?);
+ return (__pigeon_replyList[0] as CacheRetrievalResult?);
}
}
}
diff --git a/packages/image_picker/image_picker_android/pigeons/messages.dart b/packages/image_picker/image_picker_android/pigeons/messages.dart
index 9d264b5..7f39ae5 100644
--- a/packages/image_picker/image_picker_android/pigeons/messages.dart
+++ b/packages/image_picker/image_picker_android/pigeons/messages.dart
@@ -14,9 +14,10 @@
copyrightHeader: 'pigeons/copyright.txt',
))
class GeneralOptions {
- GeneralOptions(this.allowMultiple, this.usePhotoPicker);
+ GeneralOptions(this.allowMultiple, this.usePhotoPicker, this.limit);
bool allowMultiple;
bool usePhotoPicker;
+ int? limit;
}
/// Options for image selection and output.
diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml
index 7a98a4f..8f0606a 100755
--- a/packages/image_picker/image_picker_android/pubspec.yaml
+++ b/packages/image_picker/image_picker_android/pubspec.yaml
@@ -2,11 +2,11 @@
description: Android implementation of the image_picker plugin.
repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
-version: 0.8.9+6
+version: 0.8.10
environment:
- sdk: ^3.2.0
- flutter: ">=3.16.0"
+ sdk: ^3.3.0
+ flutter: ">=3.19.0"
flutter:
plugin:
@@ -21,13 +21,13 @@
flutter:
sdk: flutter
flutter_plugin_android_lifecycle: ^2.0.1
- image_picker_platform_interface: ^2.8.0
+ image_picker_platform_interface: ^2.10.0
dev_dependencies:
flutter_test:
sdk: flutter
mockito: 5.4.4
- pigeon: ^9.2.5
+ pigeon: ^17.0.0
topics:
- camera
diff --git a/packages/image_picker/image_picker_android/test/image_picker_android_test.dart b/packages/image_picker/image_picker_android/test/image_picker_android_test.dart
index 0b0cab4..172b135 100644
--- a/packages/image_picker/image_picker_android/test/image_picker_android_test.dart
+++ b/packages/image_picker/image_picker_android/test/image_picker_android_test.dart
@@ -156,6 +156,7 @@
expect(api.passedImageOptions?.maxWidth, null);
expect(api.passedImageOptions?.maxHeight, null);
expect(api.passedImageOptions?.quality, 100);
+ expect(api.limit, null);
});
test('passes image option arguments correctly', () async {
@@ -465,6 +466,7 @@
expect(api.passedImageOptions?.maxWidth, null);
expect(api.passedImageOptions?.maxHeight, null);
expect(api.passedImageOptions?.quality, 100);
+ expect(api.limit, null);
});
test('passes image option arguments correctly', () async {
@@ -681,6 +683,7 @@
expect(api.passedImageOptions?.maxWidth, null);
expect(api.passedImageOptions?.maxHeight, null);
expect(api.passedImageOptions?.quality, 100);
+ expect(api.limit, null);
});
test('passes image option arguments correctly', () async {
@@ -692,11 +695,13 @@
maxHeight: 20.0,
imageQuality: 70,
),
+ limit: 5,
));
expect(api.passedImageOptions?.maxWidth, 10.0);
expect(api.passedImageOptions?.maxHeight, 20.0);
expect(api.passedImageOptions?.quality, 70);
+ expect(api.limit, 5);
});
test('does not accept a negative width or height argument', () {
@@ -743,6 +748,37 @@
);
});
+ test('does not accept an invalid limit argument', () {
+ expect(
+ () => picker.getMedia(
+ options: const MediaOptions(
+ allowMultiple: true,
+ limit: -1,
+ ),
+ ),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getMedia(
+ options: const MediaOptions(
+ allowMultiple: true,
+ limit: 0,
+ ),
+ ),
+ throwsArgumentError,
+ );
+ });
+
+ test('does not accept a not null limit when allowMultiple is false', () {
+ expect(
+ () => picker.getMedia(
+ options: const MediaOptions(allowMultiple: false, limit: 5),
+ ),
+ throwsArgumentError,
+ );
+ });
+
test('handles an empty path response gracefully', () async {
api.returnValue = <String>[];
@@ -926,6 +962,7 @@
VideoSelectionOptions? passedVideoOptions;
bool? passedAllowMultiple;
bool? passedPhotoPickerFlag;
+ int? limit;
_LastPickType? lastCall;
@override
@@ -939,6 +976,7 @@
passedImageOptions = options;
passedAllowMultiple = generalOptions.allowMultiple;
passedPhotoPickerFlag = generalOptions.usePhotoPicker;
+ limit = generalOptions.limit;
return returnValue as List<String?>? ?? <String>[];
}
@@ -951,6 +989,7 @@
passedImageOptions = options.imageSelectionOptions;
passedPhotoPickerFlag = generalOptions.usePhotoPicker;
passedAllowMultiple = generalOptions.allowMultiple;
+ limit = generalOptions.limit;
return returnValue as List<String?>? ?? <String>[];
}
diff --git a/packages/image_picker/image_picker_android/test/test_api.g.dart b/packages/image_picker/image_picker_android/test/test_api.g.dart
index d3b6891..52aefcd 100644
--- a/packages/image_picker/image_picker_android/test/test_api.g.dart
+++ b/packages/image_picker/image_picker_android/test/test_api.g.dart
@@ -1,9 +1,9 @@
// 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.
-// Autogenerated from Pigeon (v9.2.5), do not edit directly.
+// Autogenerated from Pigeon (v17.0.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
-// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
+// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers
// ignore_for_file: avoid_relative_lib_imports
import 'dart:async';
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
@@ -69,7 +69,8 @@
abstract class TestHostImagePickerApi {
static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
TestDefaultBinaryMessengerBinding.instance;
- static const MessageCodec<Object?> codec = _TestHostImagePickerApiCodec();
+ static const MessageCodec<Object?> pigeonChannelCodec =
+ _TestHostImagePickerApiCodec();
/// Selects images and returns their paths.
///
@@ -98,111 +99,146 @@
static void setup(TestHostImagePickerApi? api,
{BinaryMessenger? binaryMessenger}) {
{
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.ImagePickerApi.pickImages', codec,
+ final BasicMessageChannel<Object?> __pigeon_channel = BasicMessageChannel<
+ Object?>(
+ 'dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickImages',
+ pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel, null);
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel,
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel,
(Object? message) async {
assert(message != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickImages was null.');
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickImages was null.');
final List<Object?> args = (message as List<Object?>?)!;
final SourceSpecification? arg_source =
(args[0] as SourceSpecification?);
assert(arg_source != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickImages was null, expected non-null SourceSpecification.');
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickImages was null, expected non-null SourceSpecification.');
final ImageSelectionOptions? arg_options =
(args[1] as ImageSelectionOptions?);
assert(arg_options != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickImages was null, expected non-null ImageSelectionOptions.');
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickImages was null, expected non-null ImageSelectionOptions.');
final GeneralOptions? arg_generalOptions =
(args[2] as GeneralOptions?);
assert(arg_generalOptions != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickImages was null, expected non-null GeneralOptions.');
- final List<String?> output = await api.pickImages(
- arg_source!, arg_options!, arg_generalOptions!);
- return <Object?>[output];
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickImages was null, expected non-null GeneralOptions.');
+ try {
+ final List<String?> output = await api.pickImages(
+ arg_source!, arg_options!, arg_generalOptions!);
+ return <Object?>[output];
+ } on PlatformException catch (e) {
+ return wrapResponse(error: e);
+ } catch (e) {
+ return wrapResponse(
+ error: PlatformException(code: 'error', message: e.toString()));
+ }
});
}
}
{
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.ImagePickerApi.pickVideos', codec,
+ final BasicMessageChannel<Object?> __pigeon_channel = BasicMessageChannel<
+ Object?>(
+ 'dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickVideos',
+ pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel, null);
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel,
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel,
(Object? message) async {
assert(message != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickVideos was null.');
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickVideos was null.');
final List<Object?> args = (message as List<Object?>?)!;
final SourceSpecification? arg_source =
(args[0] as SourceSpecification?);
assert(arg_source != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickVideos was null, expected non-null SourceSpecification.');
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickVideos was null, expected non-null SourceSpecification.');
final VideoSelectionOptions? arg_options =
(args[1] as VideoSelectionOptions?);
assert(arg_options != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickVideos was null, expected non-null VideoSelectionOptions.');
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickVideos was null, expected non-null VideoSelectionOptions.');
final GeneralOptions? arg_generalOptions =
(args[2] as GeneralOptions?);
assert(arg_generalOptions != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickVideos was null, expected non-null GeneralOptions.');
- final List<String?> output = await api.pickVideos(
- arg_source!, arg_options!, arg_generalOptions!);
- return <Object?>[output];
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickVideos was null, expected non-null GeneralOptions.');
+ try {
+ final List<String?> output = await api.pickVideos(
+ arg_source!, arg_options!, arg_generalOptions!);
+ return <Object?>[output];
+ } on PlatformException catch (e) {
+ return wrapResponse(error: e);
+ } catch (e) {
+ return wrapResponse(
+ error: PlatformException(code: 'error', message: e.toString()));
+ }
});
}
}
{
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.ImagePickerApi.pickMedia', codec,
+ final BasicMessageChannel<Object?> __pigeon_channel = BasicMessageChannel<
+ Object?>(
+ 'dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickMedia',
+ pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel, null);
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel,
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel,
(Object? message) async {
assert(message != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickMedia was null.');
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickMedia was null.');
final List<Object?> args = (message as List<Object?>?)!;
final MediaSelectionOptions? arg_mediaSelectionOptions =
(args[0] as MediaSelectionOptions?);
assert(arg_mediaSelectionOptions != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickMedia was null, expected non-null MediaSelectionOptions.');
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickMedia was null, expected non-null MediaSelectionOptions.');
final GeneralOptions? arg_generalOptions =
(args[1] as GeneralOptions?);
assert(arg_generalOptions != null,
- 'Argument for dev.flutter.pigeon.ImagePickerApi.pickMedia was null, expected non-null GeneralOptions.');
- final List<String?> output = await api.pickMedia(
- arg_mediaSelectionOptions!, arg_generalOptions!);
- return <Object?>[output];
+ 'Argument for dev.flutter.pigeon.image_picker_android.ImagePickerApi.pickMedia was null, expected non-null GeneralOptions.');
+ try {
+ final List<String?> output = await api.pickMedia(
+ arg_mediaSelectionOptions!, arg_generalOptions!);
+ return <Object?>[output];
+ } on PlatformException catch (e) {
+ return wrapResponse(error: e);
+ } catch (e) {
+ return wrapResponse(
+ error: PlatformException(code: 'error', message: e.toString()));
+ }
});
}
}
{
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.ImagePickerApi.retrieveLostResults', codec,
+ final BasicMessageChannel<Object?> __pigeon_channel = BasicMessageChannel<
+ Object?>(
+ 'dev.flutter.pigeon.image_picker_android.ImagePickerApi.retrieveLostResults',
+ pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel, null);
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel,
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel,
(Object? message) async {
- // ignore message
- final CacheRetrievalResult? output = api.retrieveLostResults();
- return <Object?>[output];
+ try {
+ final CacheRetrievalResult? output = api.retrieveLostResults();
+ return <Object?>[output];
+ } on PlatformException catch (e) {
+ return wrapResponse(error: e);
+ } catch (e) {
+ return wrapResponse(
+ error: PlatformException(code: 'error', message: e.toString()));
+ }
});
}
}
diff --git a/packages/image_picker/image_picker_ios/CHANGELOG.md b/packages/image_picker/image_picker_ios/CHANGELOG.md
index 566aab0..787524c 100644
--- a/packages/image_picker/image_picker_ios/CHANGELOG.md
+++ b/packages/image_picker/image_picker_ios/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.10
+
+* Adds limit parameter to `MediaOptions` and `MultiImagePickerOptions` that sets a limit to how many media or image items can be selected.
+
## 0.8.9+2
* Updates minimum iOS version to 12.0 and minimum Flutter version to 3.16.6.
diff --git a/packages/image_picker/image_picker_ios/example/ios/RunnerTests/ImagePickerPluginTests.m b/packages/image_picker/image_picker_ios/example/ios/RunnerTests/ImagePickerPluginTests.m
index 36ca8ec..d54d5c3 100644
--- a/packages/image_picker/image_picker_ios/example/ios/RunnerTests/ImagePickerPluginTests.m
+++ b/packages/image_picker/image_picker_ios/example/ios/RunnerTests/ImagePickerPluginTests.m
@@ -175,6 +175,7 @@
[plugin pickMultiImageWithMaxSize:[FLTMaxSize makeWithWidth:@(100) height:@(200)]
quality:@(50)
fullMetadata:YES
+ limit:nil
completion:^(NSArray<NSString *> *_Nullable result,
FlutterError *_Nullable error){
}];
@@ -198,7 +199,8 @@
[FLTMediaSelectionOptions makeWithMaxSize:[FLTMaxSize makeWithWidth:@(100) height:@(200)]
imageQuality:@(50)
requestFullMetadata:YES
- allowMultiple:YES];
+ allowMultiple:YES
+ limit:nil];
[plugin pickMediaWithMediaSelectionOptions:mediaSelectionOptions
completion:^(NSArray<NSString *> *_Nullable result,
@@ -236,6 +238,7 @@
[plugin pickMultiImageWithMaxSize:[[FLTMaxSize alloc] init]
quality:nil
fullMetadata:NO
+ limit:nil
completion:^(NSArray<NSString *> *_Nullable result,
FlutterError *_Nullable error){
}];
@@ -254,7 +257,8 @@
[FLTMediaSelectionOptions makeWithMaxSize:[FLTMaxSize makeWithWidth:@(100) height:@(200)]
imageQuality:@(50)
requestFullMetadata:YES
- allowMultiple:YES];
+ allowMultiple:YES
+ limit:nil];
[plugin pickMediaWithMediaSelectionOptions:mediaSelectionOptions
@@ -544,6 +548,7 @@
[plugin pickMultiImageWithMaxSize:[FLTMaxSize makeWithWidth:@100 height:@100]
quality:nil
fullMetadata:YES
+ limit:nil
completion:^(NSArray<NSString *> *result, FlutterError *error) {
XCTAssertNotNil(error);
XCTAssertEqualObjects(error.code, @"multiple_request");
@@ -552,6 +557,7 @@
[plugin pickMultiImageWithMaxSize:[FLTMaxSize makeWithWidth:@100 height:@100]
quality:nil
fullMetadata:YES
+ limit:nil
completion:^(NSArray<NSString *> *result, FlutterError *error){
}];
[self waitForExpectationsWithTimeout:30 handler:nil];
@@ -570,7 +576,8 @@
[FLTMediaSelectionOptions makeWithMaxSize:[FLTMaxSize makeWithWidth:@(100) height:@(200)]
imageQuality:@(50)
requestFullMetadata:YES
- allowMultiple:YES];
+ allowMultiple:YES
+ limit:nil];
XCTestExpectation *firstCallExpectation = [self expectationWithDescription:@"first call"];
[plugin pickMediaWithMediaSelectionOptions:options
completion:^(NSArray<NSString *> *result, FlutterError *error) {
@@ -608,4 +615,79 @@
[self waitForExpectationsWithTimeout:30 handler:nil];
}
+- (void)testPickMultiImageWithLimit {
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
+ [plugin pickMultiImageWithMaxSize:[[FLTMaxSize alloc] init]
+ quality:nil
+ fullMetadata:NO
+ limit:@(2)
+ completion:^(NSArray<NSString *> *_Nullable result,
+ FlutterError *_Nullable error){
+ }];
+ XCTAssertEqual(plugin.callContext.maxImageCount, 2);
+}
+
+- (void)testPickMediaWithLimitAllowsMultiple {
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
+ FLTMediaSelectionOptions *mediaSelectionOptions =
+ [FLTMediaSelectionOptions makeWithMaxSize:[FLTMaxSize makeWithWidth:@(100) height:@(200)]
+ imageQuality:nil
+ requestFullMetadata:NO
+ allowMultiple:YES
+ limit:@(2)];
+
+ [plugin pickMediaWithMediaSelectionOptions:mediaSelectionOptions
+ completion:^(NSArray<NSString *> *_Nullable result,
+ FlutterError *_Nullable error){
+ }];
+
+ XCTAssertEqual(plugin.callContext.maxImageCount, 2);
+}
+
+- (void)testPickMediaWithLimitMultipleNotAllowed {
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
+ FLTMediaSelectionOptions *mediaSelectionOptions =
+ [FLTMediaSelectionOptions makeWithMaxSize:[FLTMaxSize makeWithWidth:@(100) height:@(200)]
+ imageQuality:nil
+ requestFullMetadata:NO
+ allowMultiple:NO
+ limit:@(2)];
+
+ [plugin pickMediaWithMediaSelectionOptions:mediaSelectionOptions
+ completion:^(NSArray<NSString *> *_Nullable result,
+ FlutterError *_Nullable error){
+ }];
+
+ XCTAssertEqual(plugin.callContext.maxImageCount, 1);
+}
+
+- (void)testPickMultiImageWithoutLimit {
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
+ [plugin pickMultiImageWithMaxSize:[[FLTMaxSize alloc] init]
+ quality:nil
+ fullMetadata:NO
+ limit:nil
+ completion:^(NSArray<NSString *> *_Nullable result,
+ FlutterError *_Nullable error){
+ }];
+ XCTAssertEqual(plugin.callContext.maxImageCount, 0);
+}
+
+- (void)testPickMediaWithoutLimitAllowsMultiple {
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
+ FLTMediaSelectionOptions *mediaSelectionOptions =
+ [FLTMediaSelectionOptions makeWithMaxSize:[FLTMaxSize makeWithWidth:@(100) height:@(200)]
+ imageQuality:nil
+ requestFullMetadata:NO
+ allowMultiple:YES
+ limit:nil];
+
+ [plugin pickMediaWithMediaSelectionOptions:mediaSelectionOptions
+ completion:^(NSArray<NSString *> *_Nullable result,
+ FlutterError *_Nullable error){
+ }];
+
+ XCTAssertEqual(plugin.callContext.maxImageCount, 0);
+}
+
@end
diff --git a/packages/image_picker/image_picker_ios/example/lib/main.dart b/packages/image_picker/image_picker_ios/example/lib/main.dart
index 0f42b58..28d0ea2 100755
--- a/packages/image_picker/image_picker_ios/example/lib/main.dart
+++ b/packages/image_picker/image_picker_ios/example/lib/main.dart
@@ -56,6 +56,7 @@
final TextEditingController maxWidthController = TextEditingController();
final TextEditingController maxHeightController = TextEditingController();
final TextEditingController qualityController = TextEditingController();
+ final TextEditingController limitController = TextEditingController();
Future<void> _playVideo(XFile? file) async {
if (file != null && mounted) {
@@ -88,18 +89,20 @@
source: source, maxDuration: const Duration(seconds: 10));
await _playVideo(file);
} else if (isMultiImage) {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, true, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final List<XFile> pickedFileList = isMedia
? await _picker.getMedia(
options: MediaOptions(
- allowMultiple: isMultiImage,
- imageOptions: ImageOptions(
- maxWidth: maxWidth,
- maxHeight: maxHeight,
- imageQuality: quality,
- )),
+ allowMultiple: isMultiImage,
+ imageOptions: ImageOptions(
+ maxWidth: maxWidth,
+ maxHeight: maxHeight,
+ imageQuality: quality,
+ ),
+ limit: limit,
+ ),
)
: await _picker.getMultiImageWithOptions(
options: MultiImagePickerOptions(
@@ -108,6 +111,7 @@
maxHeight: maxHeight,
imageQuality: quality,
),
+ limit: limit,
),
);
setState(() {
@@ -120,18 +124,19 @@
}
});
} else if (isMedia) {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, false, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final List<XFile> pickedFileList = <XFile>[];
final XFile? media = _firstOrNull(await _picker.getMedia(
options: MediaOptions(
- allowMultiple: isMultiImage,
- imageOptions: ImageOptions(
- maxWidth: maxWidth,
- maxHeight: maxHeight,
- imageQuality: quality,
- )),
+ allowMultiple: isMultiImage,
+ imageOptions: ImageOptions(
+ maxWidth: maxWidth,
+ maxHeight: maxHeight,
+ imageQuality: quality,
+ ),
+ ),
));
if (media != null) {
@@ -145,8 +150,8 @@
}
});
} else {
- await _displayPickImageDialog(context,
- (double? maxWidth, double? maxHeight, int? quality) async {
+ await _displayPickImageDialog(context, false, (double? maxWidth,
+ double? maxHeight, int? quality, int? limit) async {
try {
final XFile? pickedFile = await _picker.getImageFromSource(
source: source,
@@ -400,7 +405,7 @@
}
Future<void> _displayPickImageDialog(
- BuildContext context, OnPickImageCallback onPick) async {
+ BuildContext context, bool isMulti, OnPickImageCallback onPick) async {
return showDialog(
context: context,
builder: (BuildContext context) {
@@ -428,6 +433,13 @@
decoration: const InputDecoration(
hintText: 'Enter quality if desired'),
),
+ if (isMulti)
+ TextField(
+ controller: limitController,
+ keyboardType: TextInputType.number,
+ decoration: const InputDecoration(
+ hintText: 'Enter limit if desired'),
+ ),
],
),
actions: <Widget>[
@@ -449,7 +461,10 @@
final int? quality = qualityController.text.isNotEmpty
? int.parse(qualityController.text)
: null;
- onPick(width, height, quality);
+ final int? limit = limitController.text.isNotEmpty
+ ? int.parse(limitController.text)
+ : null;
+ onPick(width, height, quality, limit);
Navigator.of(context).pop();
}),
],
@@ -459,7 +474,7 @@
}
typedef OnPickImageCallback = void Function(
- double? maxWidth, double? maxHeight, int? quality);
+ double? maxWidth, double? maxHeight, int? quality, int? limit);
class AspectRatioVideo extends StatefulWidget {
const AspectRatioVideo(this.controller, {super.key});
diff --git a/packages/image_picker/image_picker_ios/example/pubspec.yaml b/packages/image_picker/image_picker_ios/example/pubspec.yaml
index e4dd090..57c9e2d 100755
--- a/packages/image_picker/image_picker_ios/example/pubspec.yaml
+++ b/packages/image_picker/image_picker_ios/example/pubspec.yaml
@@ -3,8 +3,8 @@
publish_to: none
environment:
- sdk: ^3.2.3
- flutter: ">=3.16.6"
+ sdk: ^3.3.0
+ flutter: ">=3.19.0"
dependencies:
flutter:
@@ -16,7 +16,7 @@
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
- image_picker_platform_interface: ^2.8.0
+ image_picker_platform_interface: ^2.10.0
mime: ^1.0.4
video_player: ^2.1.4
diff --git a/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin.m
index 10081a8..c65542d 100644
--- a/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin.m
+++ b/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin.m
@@ -190,6 +190,7 @@
- (void)pickMultiImageWithMaxSize:(nonnull FLTMaxSize *)maxSize
quality:(nullable NSNumber *)imageQuality
fullMetadata:(BOOL)fullMetadata
+ limit:(nullable NSNumber *)limit
completion:(nonnull void (^)(NSArray<NSString *> *_Nullable,
FlutterError *_Nullable))completion {
[self cancelInProgressCall];
@@ -198,6 +199,7 @@
context.maxSize = maxSize;
context.imageQuality = imageQuality;
context.requestFullMetadata = fullMetadata;
+ context.maxImageCount = limit.intValue;
if (@available(iOS 14, *)) {
[self launchPHPickerWithContext:context];
@@ -219,8 +221,11 @@
context.imageQuality = [mediaSelectionOptions imageQuality];
context.requestFullMetadata = [mediaSelectionOptions requestFullMetadata];
context.includeVideo = YES;
+ NSNumber *limit = [mediaSelectionOptions limit];
if (!mediaSelectionOptions.allowMultiple) {
context.maxImageCount = 1;
+ } else if (limit != nil) {
+ context.maxImageCount = limit.intValue;
}
if (@available(iOS 14, *)) {
diff --git a/packages/image_picker/image_picker_ios/ios/Classes/messages.g.h b/packages/image_picker/image_picker_ios/ios/Classes/messages.g.h
index 593f882..de9a820 100644
--- a/packages/image_picker/image_picker_ios/ios/Classes/messages.g.h
+++ b/packages/image_picker/image_picker_ios/ios/Classes/messages.g.h
@@ -1,7 +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.
-// Autogenerated from Pigeon (v13.0.0), do not edit directly.
+// Autogenerated from Pigeon (v17.0.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import <Foundation/Foundation.h>
@@ -51,11 +51,13 @@
+ (instancetype)makeWithMaxSize:(FLTMaxSize *)maxSize
imageQuality:(nullable NSNumber *)imageQuality
requestFullMetadata:(BOOL)requestFullMetadata
- allowMultiple:(BOOL)allowMultiple;
+ allowMultiple:(BOOL)allowMultiple
+ limit:(nullable NSNumber *)limit;
@property(nonatomic, strong) FLTMaxSize *maxSize;
@property(nonatomic, strong, nullable) NSNumber *imageQuality;
@property(nonatomic, assign) BOOL requestFullMetadata;
@property(nonatomic, assign) BOOL allowMultiple;
+@property(nonatomic, strong, nullable) NSNumber *limit;
@end
@interface FLTSourceSpecification : NSObject
@@ -78,6 +80,7 @@
- (void)pickMultiImageWithMaxSize:(FLTMaxSize *)maxSize
quality:(nullable NSNumber *)imageQuality
fullMetadata:(BOOL)requestFullMetadata
+ limit:(nullable NSNumber *)limit
completion:(void (^)(NSArray<NSString *> *_Nullable,
FlutterError *_Nullable))completion;
- (void)pickVideoWithSource:(FLTSourceSpecification *)source
diff --git a/packages/image_picker/image_picker_ios/ios/Classes/messages.g.m b/packages/image_picker/image_picker_ios/ios/Classes/messages.g.m
index 1659cb8..a1f5794 100644
--- a/packages/image_picker/image_picker_ios/ios/Classes/messages.g.m
+++ b/packages/image_picker/image_picker_ios/ios/Classes/messages.g.m
@@ -1,7 +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.
-// Autogenerated from Pigeon (v13.0.0), do not edit directly.
+// Autogenerated from Pigeon (v17.0.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import "messages.g.h"
@@ -16,6 +16,20 @@
#error File requires ARC to be enabled.
#endif
+static NSArray *wrapResult(id result, FlutterError *error) {
+ if (error) {
+ return @[
+ error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null]
+ ];
+ }
+ return @[ result ?: [NSNull null] ];
+}
+
+static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
+ id result = array[key];
+ return (result == [NSNull null]) ? nil : result;
+}
+
@implementation FLTSourceCameraBox
- (instancetype)initWithValue:(FLTSourceCamera)value {
self = [super init];
@@ -36,19 +50,6 @@
}
@end
-static NSArray *wrapResult(id result, FlutterError *error) {
- if (error) {
- return @[
- error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null]
- ];
- }
- return @[ result ?: [NSNull null] ];
-}
-static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
- id result = array[key];
- return (result == [NSNull null]) ? nil : result;
-}
-
@interface FLTMaxSize ()
+ (FLTMaxSize *)fromList:(NSArray *)list;
+ (nullable FLTMaxSize *)nullableFromList:(NSArray *)list;
@@ -95,12 +96,14 @@
+ (instancetype)makeWithMaxSize:(FLTMaxSize *)maxSize
imageQuality:(nullable NSNumber *)imageQuality
requestFullMetadata:(BOOL)requestFullMetadata
- allowMultiple:(BOOL)allowMultiple {
+ allowMultiple:(BOOL)allowMultiple
+ limit:(nullable NSNumber *)limit {
FLTMediaSelectionOptions *pigeonResult = [[FLTMediaSelectionOptions alloc] init];
pigeonResult.maxSize = maxSize;
pigeonResult.imageQuality = imageQuality;
pigeonResult.requestFullMetadata = requestFullMetadata;
pigeonResult.allowMultiple = allowMultiple;
+ pigeonResult.limit = limit;
return pigeonResult;
}
+ (FLTMediaSelectionOptions *)fromList:(NSArray *)list {
@@ -109,6 +112,7 @@
pigeonResult.imageQuality = GetNullableObjectAtIndex(list, 1);
pigeonResult.requestFullMetadata = [GetNullableObjectAtIndex(list, 2) boolValue];
pigeonResult.allowMultiple = [GetNullableObjectAtIndex(list, 3) boolValue];
+ pigeonResult.limit = GetNullableObjectAtIndex(list, 4);
return pigeonResult;
}
+ (nullable FLTMediaSelectionOptions *)nullableFromList:(NSArray *)list {
@@ -120,6 +124,7 @@
self.imageQuality ?: [NSNull null],
@(self.requestFullMetadata),
@(self.allowMultiple),
+ self.limit ?: [NSNull null],
];
}
@end
@@ -244,18 +249,20 @@
codec:FLTImagePickerApiGetCodec()];
if (api) {
NSCAssert([api respondsToSelector:@selector
- (pickMultiImageWithMaxSize:quality:fullMetadata:completion:)],
+ (pickMultiImageWithMaxSize:quality:fullMetadata:limit:completion:)],
@"FLTImagePickerApi api (%@) doesn't respond to "
- @"@selector(pickMultiImageWithMaxSize:quality:fullMetadata:completion:)",
+ @"@selector(pickMultiImageWithMaxSize:quality:fullMetadata:limit:completion:)",
api);
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
NSArray *args = message;
FLTMaxSize *arg_maxSize = GetNullableObjectAtIndex(args, 0);
NSNumber *arg_imageQuality = GetNullableObjectAtIndex(args, 1);
BOOL arg_requestFullMetadata = [GetNullableObjectAtIndex(args, 2) boolValue];
+ NSNumber *arg_limit = GetNullableObjectAtIndex(args, 3);
[api pickMultiImageWithMaxSize:arg_maxSize
quality:arg_imageQuality
fullMetadata:arg_requestFullMetadata
+ limit:arg_limit
completion:^(NSArray<NSString *> *_Nullable output,
FlutterError *_Nullable error) {
callback(wrapResult(output, error));
diff --git a/packages/image_picker/image_picker_ios/lib/image_picker_ios.dart b/packages/image_picker/image_picker_ios/lib/image_picker_ios.dart
index 4c302ca..9616613 100644
--- a/packages/image_picker/image_picker_ios/lib/image_picker_ios.dart
+++ b/packages/image_picker/image_picker_ios/lib/image_picker_ios.dart
@@ -133,12 +133,19 @@
throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative');
}
+ final int? limit = options.limit;
+ if (limit != null && limit < 2) {
+ throw ArgumentError.value(limit, 'limit', 'cannot be lower than 2');
+ }
+
// TODO(stuartmorgan): Remove the cast once Pigeon supports non-nullable
// generics, https://github.com/flutter/flutter/issues/97848
return (await _hostApi.pickMultiImage(
- MaxSize(width: maxWidth, height: maxHeight),
- imageQuality,
- options.imageOptions.requestFullMetadata))
+ MaxSize(width: maxWidth, height: maxHeight),
+ imageQuality,
+ options.imageOptions.requestFullMetadata,
+ limit,
+ ))
.cast<String>();
}
@@ -210,11 +217,28 @@
MediaOptions mediaOptions) {
final MaxSize maxSize =
_imageOptionsToMaxSizeWithValidation(mediaOptions.imageOptions);
+
+ final bool allowMultiple = mediaOptions.allowMultiple;
+ final int? limit = mediaOptions.limit;
+
+ if (!allowMultiple && limit != null) {
+ throw ArgumentError.value(
+ allowMultiple,
+ 'allowMultiple',
+ 'cannot be false, when limit is not null',
+ );
+ }
+
+ if (limit != null && limit < 2) {
+ throw ArgumentError.value(limit, 'limit', 'cannot be lower than 2');
+ }
+
return MediaSelectionOptions(
maxSize: maxSize,
imageQuality: mediaOptions.imageOptions.imageQuality,
requestFullMetadata: mediaOptions.imageOptions.requestFullMetadata,
allowMultiple: mediaOptions.allowMultiple,
+ limit: mediaOptions.limit,
);
}
diff --git a/packages/image_picker/image_picker_ios/lib/src/messages.g.dart b/packages/image_picker/image_picker_ios/lib/src/messages.g.dart
index 0ab7d1b..b3e785a 100644
--- a/packages/image_picker/image_picker_ios/lib/src/messages.g.dart
+++ b/packages/image_picker/image_picker_ios/lib/src/messages.g.dart
@@ -1,9 +1,9 @@
// 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.
-// Autogenerated from Pigeon (v13.0.0), do not edit directly.
+// Autogenerated from Pigeon (v17.0.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
-// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
+// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
import 'dart:async';
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
@@ -11,6 +11,13 @@
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
import 'package:flutter/services.dart';
+PlatformException _createConnectionError(String channelName) {
+ return PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel: "$channelName".',
+ );
+}
+
List<Object?> wrapResponse(
{Object? result, PlatformException? error, bool empty = false}) {
if (empty) {
@@ -64,6 +71,7 @@
this.imageQuality,
required this.requestFullMetadata,
required this.allowMultiple,
+ this.limit,
});
MaxSize maxSize;
@@ -74,12 +82,15 @@
bool allowMultiple;
+ int? limit;
+
Object encode() {
return <Object?>[
maxSize.encode(),
imageQuality,
requestFullMetadata,
allowMultiple,
+ limit,
];
}
@@ -90,6 +101,7 @@
imageQuality: result[1] as int?,
requestFullMetadata: result[2]! as bool,
allowMultiple: result[3]! as bool,
+ limit: result[4] as int?,
);
}
}
@@ -158,117 +170,122 @@
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
ImagePickerApi({BinaryMessenger? binaryMessenger})
- : _binaryMessenger = binaryMessenger;
- final BinaryMessenger? _binaryMessenger;
+ : __pigeon_binaryMessenger = binaryMessenger;
+ final BinaryMessenger? __pigeon_binaryMessenger;
- static const MessageCodec<Object?> codec = _ImagePickerApiCodec();
+ static const MessageCodec<Object?> pigeonChannelCodec =
+ _ImagePickerApiCodec();
- Future<String?> pickImage(SourceSpecification arg_source, MaxSize arg_maxSize,
- int? arg_imageQuality, bool arg_requestFullMetadata) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage', codec,
- binaryMessenger: _binaryMessenger);
- final List<Object?>? replyList = await channel.send(<Object?>[
- arg_source,
- arg_maxSize,
- arg_imageQuality,
- arg_requestFullMetadata
- ]) as List<Object?>?;
- if (replyList == null) {
+ Future<String?> pickImage(SourceSpecification source, MaxSize maxSize,
+ int? imageQuality, bool requestFullMetadata) async {
+ const String __pigeon_channelName =
+ 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage';
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ __pigeon_channelName,
+ pigeonChannelCodec,
+ binaryMessenger: __pigeon_binaryMessenger,
+ );
+ final List<Object?>? __pigeon_replyList = await __pigeon_channel
+ .send(<Object?>[source, maxSize, imageQuality, requestFullMetadata])
+ as List<Object?>?;
+ if (__pigeon_replyList == null) {
+ throw _createConnectionError(__pigeon_channelName);
+ } else if (__pigeon_replyList.length > 1) {
throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
- );
- } else if (replyList.length > 1) {
- throw PlatformException(
- code: replyList[0]! as String,
- message: replyList[1] as String?,
- details: replyList[2],
+ code: __pigeon_replyList[0]! as String,
+ message: __pigeon_replyList[1] as String?,
+ details: __pigeon_replyList[2],
);
} else {
- return (replyList[0] as String?);
+ return (__pigeon_replyList[0] as String?);
}
}
- Future<List<String?>> pickMultiImage(MaxSize arg_maxSize,
- int? arg_imageQuality, bool arg_requestFullMetadata) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage',
- codec,
- binaryMessenger: _binaryMessenger);
- final List<Object?>? replyList = await channel.send(
- <Object?>[arg_maxSize, arg_imageQuality, arg_requestFullMetadata])
+ Future<List<String?>> pickMultiImage(MaxSize maxSize, int? imageQuality,
+ bool requestFullMetadata, int? limit) async {
+ const String __pigeon_channelName =
+ 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage';
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ __pigeon_channelName,
+ pigeonChannelCodec,
+ binaryMessenger: __pigeon_binaryMessenger,
+ );
+ final List<Object?>? __pigeon_replyList = await __pigeon_channel
+ .send(<Object?>[maxSize, imageQuality, requestFullMetadata, limit])
as List<Object?>?;
- if (replyList == null) {
+ if (__pigeon_replyList == null) {
+ throw _createConnectionError(__pigeon_channelName);
+ } else if (__pigeon_replyList.length > 1) {
throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
+ code: __pigeon_replyList[0]! as String,
+ message: __pigeon_replyList[1] as String?,
+ details: __pigeon_replyList[2],
);
- } else if (replyList.length > 1) {
- throw PlatformException(
- code: replyList[0]! as String,
- message: replyList[1] as String?,
- details: replyList[2],
- );
- } else if (replyList[0] == null) {
+ } else if (__pigeon_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
- return (replyList[0] as List<Object?>?)!.cast<String?>();
+ return (__pigeon_replyList[0] as List<Object?>?)!.cast<String?>();
}
}
Future<String?> pickVideo(
- SourceSpecification arg_source, int? arg_maxDurationSeconds) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo', codec,
- binaryMessenger: _binaryMessenger);
- final List<Object?>? replyList = await channel
- .send(<Object?>[arg_source, arg_maxDurationSeconds]) as List<Object?>?;
- if (replyList == null) {
+ SourceSpecification source, int? maxDurationSeconds) async {
+ const String __pigeon_channelName =
+ 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo';
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ __pigeon_channelName,
+ pigeonChannelCodec,
+ binaryMessenger: __pigeon_binaryMessenger,
+ );
+ final List<Object?>? __pigeon_replyList = await __pigeon_channel
+ .send(<Object?>[source, maxDurationSeconds]) as List<Object?>?;
+ if (__pigeon_replyList == null) {
+ throw _createConnectionError(__pigeon_channelName);
+ } else if (__pigeon_replyList.length > 1) {
throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
- );
- } else if (replyList.length > 1) {
- throw PlatformException(
- code: replyList[0]! as String,
- message: replyList[1] as String?,
- details: replyList[2],
+ code: __pigeon_replyList[0]! as String,
+ message: __pigeon_replyList[1] as String?,
+ details: __pigeon_replyList[2],
);
} else {
- return (replyList[0] as String?);
+ return (__pigeon_replyList[0] as String?);
}
}
/// Selects images and videos and returns their paths.
Future<List<String?>> pickMedia(
- MediaSelectionOptions arg_mediaSelectionOptions) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia', codec,
- binaryMessenger: _binaryMessenger);
- final List<Object?>? replyList = await channel
- .send(<Object?>[arg_mediaSelectionOptions]) as List<Object?>?;
- if (replyList == null) {
+ MediaSelectionOptions mediaSelectionOptions) async {
+ const String __pigeon_channelName =
+ 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia';
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ __pigeon_channelName,
+ pigeonChannelCodec,
+ binaryMessenger: __pigeon_binaryMessenger,
+ );
+ final List<Object?>? __pigeon_replyList = await __pigeon_channel
+ .send(<Object?>[mediaSelectionOptions]) as List<Object?>?;
+ if (__pigeon_replyList == null) {
+ throw _createConnectionError(__pigeon_channelName);
+ } else if (__pigeon_replyList.length > 1) {
throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
+ code: __pigeon_replyList[0]! as String,
+ message: __pigeon_replyList[1] as String?,
+ details: __pigeon_replyList[2],
);
- } else if (replyList.length > 1) {
- throw PlatformException(
- code: replyList[0]! as String,
- message: replyList[1] as String?,
- details: replyList[2],
- );
- } else if (replyList[0] == null) {
+ } else if (__pigeon_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
- return (replyList[0] as List<Object?>?)!.cast<String?>();
+ return (__pigeon_replyList[0] as List<Object?>?)!.cast<String?>();
}
}
}
diff --git a/packages/image_picker/image_picker_ios/pigeons/messages.dart b/packages/image_picker/image_picker_ios/pigeons/messages.dart
index 0e69598..d8ae895 100644
--- a/packages/image_picker/image_picker_ios/pigeons/messages.dart
+++ b/packages/image_picker/image_picker_ios/pigeons/messages.dart
@@ -26,12 +26,14 @@
this.imageQuality,
required this.requestFullMetadata,
required this.allowMultiple,
+ this.limit,
});
MaxSize maxSize;
int? imageQuality;
bool requestFullMetadata;
bool allowMultiple;
+ int? limit;
}
// Corresponds to `CameraDevice` from the platform interface package.
@@ -53,9 +55,9 @@
String? pickImage(SourceSpecification source, MaxSize maxSize,
int? imageQuality, bool requestFullMetadata);
@async
- @ObjCSelector('pickMultiImageWithMaxSize:quality:fullMetadata:')
+ @ObjCSelector('pickMultiImageWithMaxSize:quality:fullMetadata:limit:')
List<String?> pickMultiImage(
- MaxSize maxSize, int? imageQuality, bool requestFullMetadata);
+ MaxSize maxSize, int? imageQuality, bool requestFullMetadata, int? limit);
@async
@ObjCSelector('pickVideoWithSource:maxDuration:')
String? pickVideo(SourceSpecification source, int? maxDurationSeconds);
diff --git a/packages/image_picker/image_picker_ios/pubspec.yaml b/packages/image_picker/image_picker_ios/pubspec.yaml
index c1b3c8d..70d578b 100755
--- a/packages/image_picker/image_picker_ios/pubspec.yaml
+++ b/packages/image_picker/image_picker_ios/pubspec.yaml
@@ -2,11 +2,11 @@
description: iOS implementation of the image_picker plugin.
repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_ios
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
-version: 0.8.9+2
+version: 0.8.10
environment:
- sdk: ^3.2.3
- flutter: ">=3.16.6"
+ sdk: ^3.3.0
+ flutter: ">=3.19.0"
flutter:
plugin:
@@ -19,16 +19,16 @@
dependencies:
flutter:
sdk: flutter
- image_picker_platform_interface: ^2.8.0
+ image_picker_platform_interface: ^2.10.0
dev_dependencies:
flutter_test:
sdk: flutter
mockito: 5.4.4
- pigeon: ^13.0.0
+ pigeon: ^17.0.0
topics:
- camera
- image-picker
- files
- - file-selection
+ - file-selection
\ No newline at end of file
diff --git a/packages/image_picker/image_picker_ios/test/image_picker_ios_test.dart b/packages/image_picker/image_picker_ios/test/image_picker_ios_test.dart
index 77fa322..c2e5f74 100644
--- a/packages/image_picker/image_picker_ios/test/image_picker_ios_test.dart
+++ b/packages/image_picker/image_picker_ios/test/image_picker_ios_test.dart
@@ -61,12 +61,14 @@
MaxSize maxSize,
int? imageQuality,
bool requestFullMetadata,
+ int? limit,
) async {
calls.add(_LoggedMethodCall('pickMultiImage', arguments: <String, dynamic>{
'maxWidth': maxSize.width,
'maxHeight': maxSize.height,
'imageQuality': imageQuality,
'requestFullMetadata': requestFullMetadata,
+ 'limit': limit,
}));
return returnValue as List<String?>;
}
@@ -80,6 +82,7 @@
'imageQuality': mediaSelectionOptions.imageQuality,
'requestFullMetadata': mediaSelectionOptions.requestFullMetadata,
'allowMultiple': mediaSelectionOptions.allowMultiple,
+ 'limit': mediaSelectionOptions.limit,
}));
return returnValue as List<String?>;
}
@@ -329,6 +332,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
],
);
@@ -370,6 +374,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -377,6 +382,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -384,6 +390,7 @@
'maxHeight': 10.0,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -391,6 +398,7 @@
'maxHeight': 20.0,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -398,6 +406,7 @@
'maxHeight': null,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -405,6 +414,7 @@
'maxHeight': 10.0,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -412,6 +422,7 @@
'maxHeight': 20.0,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
}),
],
);
@@ -769,6 +780,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
],
);
@@ -810,6 +822,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -817,6 +830,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -824,6 +838,7 @@
'maxHeight': 10.0,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -831,6 +846,7 @@
'maxHeight': 20.0,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -838,6 +854,7 @@
'maxHeight': null,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -845,6 +862,7 @@
'maxHeight': 10.0,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -852,6 +870,7 @@
'maxHeight': 20.0,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
}),
],
);
@@ -903,7 +922,8 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
}),
],
);
@@ -959,6 +979,16 @@
imageQuality: 70,
),
));
+ await picker.getMedia(
+ options: MediaOptions(
+ allowMultiple: true,
+ imageOptions: ImageOptions.createAndValidate(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ ),
+ limit: 5,
+ ));
expect(
log.calls,
@@ -968,49 +998,64 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMedia', arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMedia', arguments: <String, dynamic>{
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': null,
'requestFullMetadata': true,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMedia', arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': null,
'requestFullMetadata': true,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMedia', arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': 70,
'requestFullMetadata': true,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMedia', arguments: <String, dynamic>{
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': 70,
'requestFullMetadata': true,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMedia', arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': 70,
'requestFullMetadata': true,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
+ }),
+ const _LoggedMethodCall('pickMedia', arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': 20.0,
+ 'imageQuality': 70,
+ 'requestFullMetadata': true,
+ 'allowMultiple': true,
+ 'limit': 5,
}),
],
);
@@ -1032,7 +1077,8 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': false,
- 'allowMultiple': true
+ 'allowMultiple': true,
+ 'limit': null,
}),
],
);
@@ -1053,7 +1099,8 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
- 'allowMultiple': false
+ 'allowMultiple': false,
+ 'limit': null,
}),
],
);
@@ -1101,6 +1148,36 @@
);
});
+ test('does not accept a invalid limit argument', () {
+ log.returnValue = <String>['0', '1'];
+ expect(
+ () => picker.getMedia(
+ options: const MediaOptions(
+ allowMultiple: true,
+ limit: -1,
+ )),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getMedia(
+ options: const MediaOptions(
+ allowMultiple: true,
+ limit: 0,
+ )),
+ throwsArgumentError,
+ );
+ });
+
+ test('does not accept a not null limit when allowMultiple is false', () {
+ expect(
+ () => picker.getMedia(
+ options: const MediaOptions(allowMultiple: false, limit: 5),
+ ),
+ throwsArgumentError,
+ );
+ });
+
test('handles a empty path response gracefully', () async {
log.returnValue = <String>[];
@@ -1501,6 +1578,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
],
);
@@ -1543,6 +1621,16 @@
),
),
);
+ await picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ ),
+ limit: 5,
+ ),
+ );
expect(
log.calls,
@@ -1553,6 +1641,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -1560,6 +1649,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -1567,6 +1657,7 @@
'maxHeight': 10.0,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -1574,6 +1665,7 @@
'maxHeight': 20.0,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -1581,6 +1673,7 @@
'maxHeight': null,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -1588,6 +1681,7 @@
'maxHeight': 10.0,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
@@ -1595,6 +1689,15 @@
'maxHeight': 20.0,
'imageQuality': 70,
'requestFullMetadata': true,
+ 'limit': null,
+ }),
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': 20.0,
+ 'imageQuality': 70,
+ 'requestFullMetadata': true,
+ 'limit': 5,
}),
],
);
@@ -1642,6 +1745,27 @@
);
});
+ test('does not accept a invalid limit argument', () {
+ log.returnValue = <String>['0', '1'];
+ expect(
+ () => picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ limit: -1,
+ ),
+ ),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ limit: 0,
+ ),
+ ),
+ throwsArgumentError,
+ );
+ });
+
test('handles an empty response', () async {
log.returnValue = <String>[];
@@ -1661,6 +1785,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': true,
+ 'limit': null,
}),
],
);
@@ -1683,6 +1808,7 @@
'maxHeight': null,
'imageQuality': null,
'requestFullMetadata': false,
+ 'limit': null,
}),
],
);
diff --git a/packages/image_picker/image_picker_ios/test/test_api.g.dart b/packages/image_picker/image_picker_ios/test/test_api.g.dart
index a2d0266..4208c68 100644
--- a/packages/image_picker/image_picker_ios/test/test_api.g.dart
+++ b/packages/image_picker/image_picker_ios/test/test_api.g.dart
@@ -1,9 +1,9 @@
// 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.
-// Autogenerated from Pigeon (v13.0.0), do not edit directly.
+// Autogenerated from Pigeon (v17.0.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
-// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
+// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers
// ignore_for_file: avoid_relative_lib_imports
import 'dart:async';
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
@@ -49,13 +49,14 @@
abstract class TestHostImagePickerApi {
static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
TestDefaultBinaryMessengerBinding.instance;
- static const MessageCodec<Object?> codec = _TestHostImagePickerApiCodec();
+ static const MessageCodec<Object?> pigeonChannelCodec =
+ _TestHostImagePickerApiCodec();
Future<String?> pickImage(SourceSpecification source, MaxSize maxSize,
int? imageQuality, bool requestFullMetadata);
Future<List<String?>> pickMultiImage(
- MaxSize maxSize, int? imageQuality, bool requestFullMetadata);
+ MaxSize maxSize, int? imageQuality, bool requestFullMetadata, int? limit);
Future<String?> pickVideo(
SourceSpecification source, int? maxDurationSeconds);
@@ -66,15 +67,17 @@
static void setup(TestHostImagePickerApi? api,
{BinaryMessenger? binaryMessenger}) {
{
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage', codec,
- binaryMessenger: binaryMessenger);
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage',
+ pigeonChannelCodec,
+ binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel, null);
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel,
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null.');
@@ -104,16 +107,17 @@
}
}
{
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ final BasicMessageChannel<Object?> __pigeon_channel = BasicMessageChannel<
+ Object?>(
'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage',
- codec,
+ pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel, null);
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel,
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage was null.');
@@ -125,9 +129,10 @@
final bool? arg_requestFullMetadata = (args[2] as bool?);
assert(arg_requestFullMetadata != null,
'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage was null, expected non-null bool.');
+ final int? arg_limit = (args[3] as int?);
try {
- final List<String?> output = await api.pickMultiImage(
- arg_maxSize!, arg_imageQuality, arg_requestFullMetadata!);
+ final List<String?> output = await api.pickMultiImage(arg_maxSize!,
+ arg_imageQuality, arg_requestFullMetadata!, arg_limit);
return <Object?>[output];
} on PlatformException catch (e) {
return wrapResponse(error: e);
@@ -139,15 +144,17 @@
}
}
{
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo', codec,
- binaryMessenger: binaryMessenger);
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo',
+ pigeonChannelCodec,
+ binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel, null);
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel,
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo was null.');
@@ -171,15 +178,17 @@
}
}
{
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia', codec,
- binaryMessenger: binaryMessenger);
+ final BasicMessageChannel<Object?> __pigeon_channel =
+ BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia',
+ pigeonChannelCodec,
+ binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel, null);
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler<Object?>(channel,
+ .setMockDecodedMessageHandler<Object?>(__pigeon_channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia was null.');