From 1a5afbf2edb9981b779695fc998dd159c4f8e9ef Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 20:15:09 +0000 Subject: [PATCH 01/15] I've added the `pickMultiVideo` feature to `image_picker`. --- .../image_picker/image_picker/CHANGELOG.md | 7 +- .../image_picker/example/pubspec.yaml | 10 ++ .../image_picker/lib/image_picker.dart | 39 ++++ .../image_picker/image_picker/pubspec.yaml | 12 +- .../image_picker/test/image_picker_test.dart | 26 +++ .../test/image_picker_test.mocks.dart | 16 +- .../image_picker_android/CHANGELOG.md | 8 + .../imagepicker/ImagePickerDelegate.java | 56 ++++++ .../imagepicker/ImagePickerPlugin.java | 4 +- .../image_picker_android/example/pubspec.yaml | 4 + .../lib/image_picker_android.dart | 31 ++++ .../image_picker_android/pubspec.yaml | 6 +- .../test/image_picker_android_test.dart | 27 +++ .../image_picker_for_web/CHANGELOG.md | 7 +- .../image_picker_for_web/example/pubspec.yaml | 4 + .../lib/image_picker_for_web.dart | 11 ++ .../image_picker_for_web/pubspec.yaml | 6 +- .../image_picker_ios/CHANGELOG.md | 7 +- .../image_picker_ios/example/pubspec.yaml | 4 + .../image_picker_ios/FLTImagePickerPlugin.m | 20 +++ .../include/image_picker_ios/messages.g.h | 59 +++---- .../Sources/image_picker_ios/messages.g.m | 166 ++++++++---------- .../lib/image_picker_ios.dart | 17 ++ .../image_picker_ios/lib/src/messages.g.dart | 103 ++++++----- .../image_picker_ios/pigeons/messages.dart | 3 + .../image_picker_ios/pubspec.yaml | 6 +- .../test/image_picker_ios_test.dart | 49 ++++++ .../image_picker_ios/test/test_api.g.dart | 165 ++++++++--------- .../image_picker_linux/CHANGELOG.md | 7 +- .../image_picker_linux/example/pubspec.yaml | 4 + .../lib/image_picker_linux.dart | 10 ++ .../image_picker_linux/pubspec.yaml | 6 +- .../test/image_picker_linux_test.dart | 11 ++ .../image_picker_macos/CHANGELOG.md | 7 +- .../image_picker_macos/example/pubspec.yaml | 4 + .../lib/image_picker_macos.dart | 13 ++ .../image_picker_macos/pubspec.yaml | 6 +- .../test/image_picker_macos_test.dart | 11 ++ .../CHANGELOG.md | 7 +- .../method_channel_image_picker.dart | 28 +++ .../image_picker_platform.dart | 15 ++ .../src/types/multi_video_picker_options.dart | 23 +++ .../lib/src/types/types.dart | 1 + .../pubspec.yaml | 2 +- .../image_picker_windows/CHANGELOG.md | 7 +- .../image_picker_windows/example/pubspec.yaml | 4 + .../lib/image_picker_windows.dart | 10 ++ .../image_picker_windows/pubspec.yaml | 6 +- .../test/image_picker_windows_test.dart | 11 ++ 49 files changed, 780 insertions(+), 286 deletions(-) create mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/multi_video_picker_options.dart diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 55ba7213d31..fad8ec0cf43 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,5 +1,10 @@ -## NEXT +## 1.3.0 +* feat: Add pickMultiVideo. + +## 1.2.0 + +* feat: Add pickMultiVideo. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 1.1.2 diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index fb36a9fd71d..aa2d82c9639 100644 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -31,3 +31,13 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_android: {path: ../../../../packages/image_picker/image_picker_android} + image_picker_for_web: {path: ../../../../packages/image_picker/image_picker_for_web} + image_picker_ios: {path: ../../../../packages/image_picker/image_picker_ios} + image_picker_linux: {path: ../../../../packages/image_picker/image_picker_linux} + image_picker_macos: {path: ../../../../packages/image_picker/image_picker_macos} + image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} + image_picker_windows: {path: ../../../../packages/image_picker/image_picker_windows} diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart index 3e51cc13dac..a905be609a4 100755 --- a/packages/image_picker/image_picker/lib/image_picker.dart +++ b/packages/image_picker/image_picker/lib/image_picker.dart @@ -298,6 +298,45 @@ class ImagePicker { ); } + /// Returns a [List] of the videos that were picked. + /// + /// The returned [List] is intended to be used within a single app session. + /// Do not save the file path and use it across sessions. + /// + /// The `source` argument controls where the videos come from. This can + /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// + /// The [maxDuration] argument specifies the maximum duration of the captured videos. + /// If no [maxDuration] is specified, the maximum duration will be infinite. + /// + /// Use `preferredCameraDevice` to specify the camera to use when the `source` is + /// [ImageSource.camera]. The `preferredCameraDevice` is ignored when `source` is + /// [ImageSource.gallery]. It is also ignored if the chosen camera is not supported + /// on the device. Defaults to [CameraDevice.rear]. + /// + /// The `limit` parameter modifies the maximum number of videos that can be selected. + /// This value may be ignored by platforms that cannot support it. + /// + /// In Android, the MainActivity can be destroyed for various reasons. If that happens, + /// the result will be lost in this call. You can then call [retrieveLostData] when your + /// app relaunches to retrieve the lost data. + /// + /// The method could throw [PlatformException] if the app does not have permission to access + /// the camera or photos gallery, no camera is available, plugin is already in use, + /// temporary file could not be created and video could not be cached (iOS only), + /// plugin activity could not be allocated (Android only) or due to an unknown error. + Future> pickMultiVideo({ + Duration? maxDuration, + int? limit, + }) { + return platform.getMultiVideoWithOptions( + options: MultiVideoPickerOptions( + maxDuration: maxDuration, + limit: limit, + ), + ); + } + /// Retrieve the lost [XFile] when [pickImage], [pickMultiImage] or [pickVideo] failed because the MainActivity /// is destroyed. (Android only) /// diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 4c3e4666422..4343d7cee76 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image 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.1.2 +version: 1.3.0 environment: sdk: ^3.6.0 @@ -49,3 +49,13 @@ topics: - image-picker - files - file-selection +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_android: {path: ../../../packages/image_picker/image_picker_android} + image_picker_for_web: {path: ../../../packages/image_picker/image_picker_for_web} + image_picker_ios: {path: ../../../packages/image_picker/image_picker_ios} + image_picker_linux: {path: ../../../packages/image_picker/image_picker_linux} + image_picker_macos: {path: ../../../packages/image_picker/image_picker_macos} + image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} + image_picker_windows: {path: ../../../packages/image_picker/image_picker_windows} 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 766b3808998..870f8a78b3e 100644 --- a/packages/image_picker/image_picker/test/image_picker_test.dart +++ b/packages/image_picker/image_picker/test/image_picker_test.dart @@ -397,6 +397,32 @@ void main() { expect(response.exception!.message, 'test_error_message'); }); }); + + group('#pickMultiVideo', () { + setUp(() { + when(mockPlatform.getMultiVideoWithOptions( + options: any, + )).thenAnswer((Invocation _) async => []); + }); + + test('passes the arguments correctly', () async { + final ImagePicker picker = ImagePicker(); + await picker.pickMultiVideo(); + await picker.pickMultiVideo(maxDuration: const Duration(seconds: 10)); + await picker.pickMultiVideo( + limit: 5, + ); + + verifyInOrder([ + mockPlatform.getMultiVideoWithOptions(), + mockPlatform.getMultiVideoWithOptions( + options: const MultiVideoPickerOptions( + maxDuration: Duration(seconds: 10))), + mockPlatform.getMultiVideoWithOptions( + options: const MultiVideoPickerOptions(limit: 5)), + ]); + }); + }); }); group('#Multi images', () { diff --git a/packages/image_picker/image_picker/test/image_picker_test.mocks.dart b/packages/image_picker/image_picker/test/image_picker_test.mocks.dart index dcd89d9ac45..4277592f06b 100644 --- a/packages/image_picker/image_picker/test/image_picker_test.mocks.dart +++ b/packages/image_picker/image_picker/test/image_picker_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.4 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in image_picker/test/image_picker_test.dart. // Do not manually edit this file. @@ -19,6 +19,7 @@ import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types @@ -248,6 +249,19 @@ class MockImagePickerPlatform extends _i1.Mock returnValue: _i4.Future>.value(<_i5.XFile>[]), ) as _i4.Future>); + @override + _i4.Future> getMultiVideoWithOptions( + {_i2.MultiVideoPickerOptions? options = + const _i2.MultiVideoPickerOptions()}) => + (super.noSuchMethod( + Invocation.method( + #getMultiVideoWithOptions, + [], + {#options: options}, + ), + returnValue: _i4.Future>.value(<_i5.XFile>[]), + ) as _i4.Future>); + @override bool supportsImageSource(_i2.ImageSource? source) => (super.noSuchMethod( Invocation.method( diff --git a/packages/image_picker/image_picker_android/CHANGELOG.md b/packages/image_picker/image_picker_android/CHANGELOG.md index d6907a111b8..e8617dec165 100644 --- a/packages/image_picker/image_picker_android/CHANGELOG.md +++ b/packages/image_picker/image_picker_android/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.8.14 + +* feat: Add pickMultiVideo. + +## 0.8.13 + +* feat: Add pickMultiVideo. + ## 0.8.12+24 * Updates `androidx.activity:activity` to 1.10.1. 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 c0fe90327b9..5fc5e9e1002 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 @@ -35,6 +35,7 @@ import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Collectors; /** * A delegate class doing the heavy lifting for the plugin. @@ -81,6 +82,7 @@ public class ImagePickerDelegate @VisibleForTesting static final int REQUEST_CAMERA_IMAGE_PERMISSION = 2345; @VisibleForTesting static final int REQUEST_CODE_CHOOSE_MULTI_IMAGE_FROM_GALLERY = 2346; @VisibleForTesting static final int REQUEST_CODE_CHOOSE_MEDIA_FROM_GALLERY = 2347; + @VisibleForTesting static final int REQUEST_CODE_CHOOSE_MULTI_VIDEO_FROM_GALLERY = 2348; @VisibleForTesting static final int REQUEST_CODE_CHOOSE_VIDEO_FROM_GALLERY = 2352; @VisibleForTesting static final int REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA = 2353; @@ -474,6 +476,38 @@ private void launchMultiPickImageFromGalleryIntent(Boolean usePhotoPicker, int l pickMultiImageIntent, REQUEST_CODE_CHOOSE_MULTI_IMAGE_FROM_GALLERY); } + public void chooseMultiVideoFromGallery( + @NonNull VideoSelectionOptions options, + boolean usePhotoPicker, + int limit, + @NonNull Messages.Result> result) { + if (!setPendingOptionsAndResult(null, options, result)) { + finishWithAlreadyActiveError(result); + return; + } + + launchMultiPickVideoFromGalleryIntent(usePhotoPicker, limit); + } + + private void launchMultiPickVideoFromGalleryIntent(Boolean usePhotoPicker, int limit) { + Intent pickMultiVideoIntent; + if (usePhotoPicker) { + pickMultiVideoIntent = + new ActivityResultContracts.PickMultipleVisualMedia(limit) + .createIntent( + activity, + new PickVisualMediaRequest.Builder() + .setMediaType(ActivityResultContracts.PickVisualMedia.VideoOnly.INSTANCE) + .build()); + } else { + pickMultiVideoIntent = new Intent(Intent.ACTION_GET_CONTENT); + pickMultiVideoIntent.setType("video/*"); + pickMultiVideoIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + } + activity.startActivityForResult( + pickMultiVideoIntent, REQUEST_CODE_CHOOSE_MULTI_VIDEO_FROM_GALLERY); + } + public void takeImageWithCamera( @NonNull ImageSelectionOptions options, @NonNull Messages.Result> result) { if (!setPendingOptionsAndResult(options, null, result)) { @@ -617,6 +651,9 @@ public boolean onActivityResult( case REQUEST_CODE_CHOOSE_MULTI_IMAGE_FROM_GALLERY: handlerRunnable = () -> handleChooseMultiImageResult(resultCode, data); break; + case REQUEST_CODE_CHOOSE_MULTI_VIDEO_FROM_GALLERY: + handlerRunnable = () -> handleChooseMultiVideoResult(resultCode, data); + break; case REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA: handlerRunnable = () -> handleCaptureImageResult(resultCode); break; @@ -696,6 +733,25 @@ private void handleChooseImageResult(int resultCode, Intent data) { finishWithSuccess(null); } + private void handleChooseMultiVideoResult(int resultCode, Intent intent) { + if (resultCode == Activity.RESULT_OK && intent != null) { + ArrayList paths = getPathsFromIntent(intent, false); + // If there's no valid Uri, return an error + if (paths == null) { + finishWithError( + "missing_valid_video_uri", "Cannot find at least one of the selected videos."); + return; + } + + finishWithListSuccess( + paths.stream().map(p -> p.getPath()).collect(Collectors.toCollection(ArrayList::new))); + return; + } + + // User cancelled choosing a picture. + finishWithSuccess(null); + } + public class MediaPath { public MediaPath(@NonNull String path, @Nullable String mimeType) { this.path = path; 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 264921db4f4..c082da62ce1 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 @@ -339,7 +339,9 @@ public void pickVideos( setCameraDevice(delegate, source); if (generalOptions.getAllowMultiple()) { - result.error(new RuntimeException("Multi-video selection is not implemented")); + int limit = ImagePickerUtils.getLimitFromOption(generalOptions); + delegate.chooseMultiVideoFromGallery( + options, generalOptions.getUsePhotoPicker(), limit, result); } else { switch (source.getType()) { case GALLERY: diff --git a/packages/image_picker/image_picker_android/example/pubspec.yaml b/packages/image_picker/image_picker_android/example/pubspec.yaml index dbaed90f770..a1b2d037613 100644 --- a/packages/image_picker/image_picker_android/example/pubspec.yaml +++ b/packages/image_picker/image_picker_android/example/pubspec.yaml @@ -33,3 +33,7 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} 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 5fa164b2d0f..6411acd092c 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 @@ -135,6 +135,21 @@ class ImagePickerAndroid extends ImagePickerPlatform { return paths.isEmpty ? null : paths.first; } + Future> _getMultiVideoPath({ + Duration? maxDuration, + int? limit, + }) { + return _hostApi.pickVideos( + SourceSpecification(type: SourceType.gallery), + VideoSelectionOptions(maxDurationSeconds: maxDuration?.inSeconds), + GeneralOptions( + allowMultiple: true, + usePhotoPicker: useAndroidPhotoPicker, + limit: limit, + ), + ); + } + @override Future pickVideo({ required ImageSource source, @@ -261,6 +276,22 @@ class ImagePickerAndroid extends ImagePickerPlatform { return path != null ? XFile(path) : null; } + @override + Future> getMultiVideoWithOptions({ + MultiVideoPickerOptions options = const MultiVideoPickerOptions(), + }) async { + final List paths = await _getMultiVideoPath( + maxDuration: options.maxDuration, + limit: options.limit, + ); + + if (paths.isEmpty) { + return []; + } + + return paths.map((String path) => XFile(path)).toList(); + } + MediaSelectionOptions _mediaOptionsToMediaSelectionOptions( MediaOptions mediaOptions) { final ImageSelectionOptions imageSelectionOptions = diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml index 1008f98e3ea..2c1bbb8788e 100755 --- a/packages/image_picker/image_picker_android/pubspec.yaml +++ b/packages/image_picker/image_picker_android/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_android 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.12+24 +version: 0.8.14 environment: sdk: ^3.6.0 @@ -34,3 +34,7 @@ topics: - image-picker - files - file-selection +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} 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 75dc312226b..e7628d72d71 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 @@ -602,6 +602,33 @@ void main() { }); }); + group('#getMultiVideoWithOptions', () { + test('calls the method correctly', () async { + const List fakePaths = ['/foo.mp4', 'bar.mp4']; + api.returnValue = fakePaths; + final List result = + await picker.getMultiVideoWithOptions(options: const MultiVideoPickerOptions()); + + expect(result.length, 2); + expect(result[0].path, fakePaths[0]); + expect(api.lastCall, _LastPickType.video); + expect(api.passedAllowMultiple, true); + }); + + test('passes the arguments correctly', () async { + api.returnValue = []; + await picker.getMultiVideoWithOptions( + options: const MultiVideoPickerOptions( + maxDuration: Duration(seconds: 10), + limit: 5, + )); + + expect(api.passedSource?.type, SourceType.gallery); + expect(api.passedVideoOptions?.maxDurationSeconds, 10); + expect(api.limit, 5); + }); + }); + group('#getLostData', () { test('getLostData get success response', () async { api.returnValue = CacheRetrievalResult( diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index 09da6c33550..ff289bd4085 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,5 +1,10 @@ -## NEXT +## 3.2.0 +* feat: Add pickMultiVideo. + +## 3.1.0 + +* feat: Add pickMultiVideo. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 3.0.6 diff --git a/packages/image_picker/image_picker_for_web/example/pubspec.yaml b/packages/image_picker/image_picker_for_web/example/pubspec.yaml index eb008ca43c2..4080c85efe0 100644 --- a/packages/image_picker/image_picker_for_web/example/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/example/pubspec.yaml @@ -18,3 +18,7 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index 0241e0750a7..3b515babeb3 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -114,6 +114,17 @@ class ImagePickerPlugin extends ImagePickerPlatform { return files.isEmpty ? null : files.first; } + @override + Future> getMultiVideoWithOptions({ + MultiVideoPickerOptions options = const MultiVideoPickerOptions(), + }) async { + final List files = await getFiles( + accept: _kAcceptVideoMimeType, + multiple: true, + ); + return files; + } + /// Injects a file input, and returns a list of XFile media that the user selected locally. @override Future> getMedia({ diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index e2bbb034406..53a76b9c730 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_for_web description: Web platform implementation of image_picker repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_for_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 3.0.6 +version: 3.2.0 environment: sdk: ^3.6.0 @@ -34,3 +34,7 @@ topics: - image-picker - files - file-selection +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_ios/CHANGELOG.md b/packages/image_picker/image_picker_ios/CHANGELOG.md index de2edfd411f..460eadf44ac 100644 --- a/packages/image_picker/image_picker_ios/CHANGELOG.md +++ b/packages/image_picker/image_picker_ios/CHANGELOG.md @@ -1,5 +1,10 @@ -## NEXT +## 0.8.14 +* feat: Add pickMultiVideo. + +## 0.8.13 + +* feat: Add pickMultiVideo. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 0.8.12+2 diff --git a/packages/image_picker/image_picker_ios/example/pubspec.yaml b/packages/image_picker/image_picker_ios/example/pubspec.yaml index ea8242982e0..2937543cba5 100755 --- a/packages/image_picker/image_picker_ios/example/pubspec.yaml +++ b/packages/image_picker/image_picker_ios/example/pubspec.yaml @@ -28,3 +28,7 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m index fd88b8c4696..8f2bd39f6fb 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m @@ -282,6 +282,26 @@ - (void)pickVideoWithSource:(nonnull FLTSourceSpecification *)source } } +- (void)pickMultiVideoWithMaxDuration:(nullable NSNumber *)maxDurationSeconds + limit:(nullable NSNumber *)limit + completion:(nonnull void (^)(NSArray *_Nullable, + FlutterError *_Nullable))completion { + [self cancelInProgressCall]; + FLTImagePickerMethodCallContext *context = + [[FLTImagePickerMethodCallContext alloc] initWithResult:completion]; + context.maxImageCount = limit.intValue; + context.includeVideo = YES; + + if (@available(iOS 14, *)) { + [self launchPHPickerWithContext:context]; + } else { + // Camera is ignored for gallery mode, so the value here is arbitrary. + [self launchUIImagePickerWithSource:[FLTSourceSpecification makeWithType:FLTSourceTypeGallery + camera:FLTSourceCameraRear] + context:context]; + } +} + #pragma mark - /// If a call is still in progress, cancels it by returning an error and then clearing state. diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/messages.g.h b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/messages.g.h index ccf84379506..9d4cb28552f 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/messages.g.h +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/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 (v22.4.1), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @@ -40,30 +40,32 @@ typedef NS_ENUM(NSUInteger, FLTSourceType) { @class FLTSourceSpecification; @interface FLTMaxSize : NSObject -+ (instancetype)makeWithWidth:(nullable NSNumber *)width height:(nullable NSNumber *)height; -@property(nonatomic, strong, nullable) NSNumber *width; -@property(nonatomic, strong, nullable) NSNumber *height; ++ (instancetype)makeWithWidth:(nullable NSNumber *)width + height:(nullable NSNumber *)height; +@property(nonatomic, strong, nullable) NSNumber * width; +@property(nonatomic, strong, nullable) NSNumber * height; @end @interface FLTMediaSelectionOptions : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; + (instancetype)makeWithMaxSize:(FLTMaxSize *)maxSize - imageQuality:(nullable NSNumber *)imageQuality - requestFullMetadata:(BOOL)requestFullMetadata - 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; + imageQuality:(nullable NSNumber *)imageQuality + requestFullMetadata:(BOOL )requestFullMetadata + 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 /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithType:(FLTSourceType)type camera:(FLTSourceCamera)camera; ++ (instancetype)makeWithType:(FLTSourceType)type + camera:(FLTSourceCamera)camera; @property(nonatomic, assign) FLTSourceType type; @property(nonatomic, assign) FLTSourceCamera camera; @end @@ -72,31 +74,16 @@ typedef NS_ENUM(NSUInteger, FLTSourceType) { NSObject *FLTGetMessagesCodec(void); @protocol FLTImagePickerApi -- (void)pickImageWithSource:(FLTSourceSpecification *)source - maxSize:(FLTMaxSize *)maxSize - quality:(nullable NSNumber *)imageQuality - fullMetadata:(BOOL)requestFullMetadata - completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)pickMultiImageWithMaxSize:(FLTMaxSize *)maxSize - quality:(nullable NSNumber *)imageQuality - fullMetadata:(BOOL)requestFullMetadata - limit:(nullable NSNumber *)limit - completion:(void (^)(NSArray *_Nullable, - FlutterError *_Nullable))completion; -- (void)pickVideoWithSource:(FLTSourceSpecification *)source - maxDuration:(nullable NSNumber *)maxDurationSeconds - completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; +- (void)pickImageWithSource:(FLTSourceSpecification *)source maxSize:(FLTMaxSize *)maxSize quality:(nullable NSNumber *)imageQuality fullMetadata:(BOOL)requestFullMetadata completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; +- (void)pickMultiImageWithMaxSize:(FLTMaxSize *)maxSize quality:(nullable NSNumber *)imageQuality fullMetadata:(BOOL)requestFullMetadata limit:(nullable NSNumber *)limit completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; +- (void)pickVideoWithSource:(FLTSourceSpecification *)source maxDuration:(nullable NSNumber *)maxDurationSeconds completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; +- (void)pickMultiVideoWithMaxDuration:(nullable NSNumber *)maxDurationSeconds limit:(nullable NSNumber *)limit completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; /// Selects images and videos and returns their paths. -- (void)pickMediaWithMediaSelectionOptions:(FLTMediaSelectionOptions *)mediaSelectionOptions - completion:(void (^)(NSArray *_Nullable, - FlutterError *_Nullable))completion; +- (void)pickMediaWithMediaSelectionOptions:(FLTMediaSelectionOptions *)mediaSelectionOptions completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; @end -extern void SetUpFLTImagePickerApi(id binaryMessenger, - NSObject *_Nullable api); +extern void SetUpFLTImagePickerApi(id binaryMessenger, NSObject *_Nullable api); -extern void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger, - NSObject *_Nullable api, - NSString *messageChannelSuffix); +extern void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger, NSObject *_Nullable api, NSString *messageChannelSuffix); NS_ASSUME_NONNULL_END diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/messages.g.m b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/messages.g.m index f2d8395caff..b5677888a0a 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/messages.g.m +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/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 (v22.4.1), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "./include/image_picker_ios/messages.g.h" @@ -69,8 +69,9 @@ + (nullable FLTSourceSpecification *)nullableFromList:(NSArray *)list; @end @implementation FLTMaxSize -+ (instancetype)makeWithWidth:(nullable NSNumber *)width height:(nullable NSNumber *)height { - FLTMaxSize *pigeonResult = [[FLTMaxSize alloc] init]; ++ (instancetype)makeWithWidth:(nullable NSNumber *)width + height:(nullable NSNumber *)height { + FLTMaxSize* pigeonResult = [[FLTMaxSize alloc] init]; pigeonResult.width = width; pigeonResult.height = height; return pigeonResult; @@ -94,11 +95,11 @@ + (nullable FLTMaxSize *)nullableFromList:(NSArray *)list { @implementation FLTMediaSelectionOptions + (instancetype)makeWithMaxSize:(FLTMaxSize *)maxSize - imageQuality:(nullable NSNumber *)imageQuality - requestFullMetadata:(BOOL)requestFullMetadata - allowMultiple:(BOOL)allowMultiple - limit:(nullable NSNumber *)limit { - FLTMediaSelectionOptions *pigeonResult = [[FLTMediaSelectionOptions alloc] init]; + imageQuality:(nullable NSNumber *)imageQuality + requestFullMetadata:(BOOL )requestFullMetadata + allowMultiple:(BOOL )allowMultiple + limit:(nullable NSNumber *)limit { + FLTMediaSelectionOptions* pigeonResult = [[FLTMediaSelectionOptions alloc] init]; pigeonResult.maxSize = maxSize; pigeonResult.imageQuality = imageQuality; pigeonResult.requestFullMetadata = requestFullMetadata; @@ -130,8 +131,9 @@ + (nullable FLTMediaSelectionOptions *)nullableFromList:(NSArray *)list { @end @implementation FLTSourceSpecification -+ (instancetype)makeWithType:(FLTSourceType)type camera:(FLTSourceCamera)camera { - FLTSourceSpecification *pigeonResult = [[FLTSourceSpecification alloc] init]; ++ (instancetype)makeWithType:(FLTSourceType)type + camera:(FLTSourceCamera)camera { + FLTSourceSpecification* pigeonResult = [[FLTSourceSpecification alloc] init]; pigeonResult.type = type; pigeonResult.camera = camera; return pigeonResult; @@ -162,15 +164,11 @@ - (nullable id)readValueOfType:(UInt8)type { switch (type) { case 129: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[FLTSourceCameraBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FLTSourceCameraBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 130: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[FLTSourceTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FLTSourceTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 131: return [FLTMaxSize fromList:[self readValue]]; @@ -226,112 +224,96 @@ - (FlutterStandardReader *)readerWithData:(NSData *)data { static FlutterStandardMessageCodec *sSharedObject = nil; static dispatch_once_t sPred = 0; dispatch_once(&sPred, ^{ - FLTMessagesPigeonCodecReaderWriter *readerWriter = - [[FLTMessagesPigeonCodecReaderWriter alloc] init]; + FLTMessagesPigeonCodecReaderWriter *readerWriter = [[FLTMessagesPigeonCodecReaderWriter alloc] init]; sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; }); return sSharedObject; } -void SetUpFLTImagePickerApi(id binaryMessenger, - NSObject *api) { +void SetUpFLTImagePickerApi(id binaryMessenger, NSObject *api) { SetUpFLTImagePickerApiWithSuffix(binaryMessenger, api, @""); } -void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger, - NSObject *api, - NSString *messageChannelSuffix) { - messageChannelSuffix = messageChannelSuffix.length > 0 - ? [NSString stringWithFormat:@".%@", messageChannelSuffix] - : @""; +void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger, NSObject *api, NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 ? [NSString stringWithFormat: @".%@", messageChannelSuffix] : @""; { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector - (pickImageWithSource:maxSize:quality:fullMetadata:completion:)], - @"FLTImagePickerApi api (%@) doesn't respond to " - @"@selector(pickImageWithSource:maxSize:quality:fullMetadata:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(pickImageWithSource:maxSize:quality:fullMetadata:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickImageWithSource:maxSize:quality:fullMetadata:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FLTSourceSpecification *arg_source = GetNullableObjectAtIndex(args, 0); FLTMaxSize *arg_maxSize = GetNullableObjectAtIndex(args, 1); NSNumber *arg_imageQuality = GetNullableObjectAtIndex(args, 2); BOOL arg_requestFullMetadata = [GetNullableObjectAtIndex(args, 3) boolValue]; - [api pickImageWithSource:arg_source - maxSize:arg_maxSize - quality:arg_imageQuality - fullMetadata:arg_requestFullMetadata - completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickImageWithSource:arg_source maxSize:arg_maxSize quality:arg_imageQuality fullMetadata:arg_requestFullMetadata completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; } } { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.image_picker_ios." - @"ImagePickerApi.pickMultiImage", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector - (pickMultiImageWithMaxSize:quality:fullMetadata:limit:completion:)], - @"FLTImagePickerApi api (%@) doesn't respond to " - @"@selector(pickMultiImageWithMaxSize:quality:fullMetadata:limit:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(pickMultiImageWithMaxSize:quality:fullMetadata:limit:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @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 *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickMultiImageWithMaxSize:arg_maxSize quality:arg_imageQuality fullMetadata:arg_requestFullMetadata limit:arg_limit completion:^(NSArray *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; } } { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(pickVideoWithSource:maxDuration:completion:)], - @"FLTImagePickerApi api (%@) doesn't respond to " - @"@selector(pickVideoWithSource:maxDuration:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(pickVideoWithSource:maxDuration:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickVideoWithSource:maxDuration:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FLTSourceSpecification *arg_source = GetNullableObjectAtIndex(args, 0); NSNumber *arg_maxDurationSeconds = GetNullableObjectAtIndex(args, 1); - [api pickVideoWithSource:arg_source - maxDuration:arg_maxDurationSeconds - completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickVideoWithSource:arg_source maxDuration:arg_maxDurationSeconds completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo", messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(pickMultiVideoWithMaxDuration:limit:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickMultiVideoWithMaxDuration:limit:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSNumber *arg_maxDurationSeconds = GetNullableObjectAtIndex(args, 0); + NSNumber *arg_limit = GetNullableObjectAtIndex(args, 1); + [api pickMultiVideoWithMaxDuration:arg_maxDurationSeconds limit:arg_limit completion:^(NSArray *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -339,27 +321,19 @@ void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger } /// Selects images and videos and returns their paths. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(pickMediaWithMediaSelectionOptions:completion:)], - @"FLTImagePickerApi api (%@) doesn't respond to " - @"@selector(pickMediaWithMediaSelectionOptions:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(pickMediaWithMediaSelectionOptions:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickMediaWithMediaSelectionOptions:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FLTMediaSelectionOptions *arg_mediaSelectionOptions = GetNullableObjectAtIndex(args, 0); - [api pickMediaWithMediaSelectionOptions:arg_mediaSelectionOptions - completion:^(NSArray *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickMediaWithMediaSelectionOptions:arg_mediaSelectionOptions completion:^(NSArray *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; 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 ea188cb4ad6..2b1fb54b3ae 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 @@ -322,4 +322,21 @@ class ImagePickerIOS extends ImagePickerPlatform { ); return path != null ? XFile(path) : null; } + + @override + Future> getMultiVideoWithOptions({ + MultiVideoPickerOptions options = const MultiVideoPickerOptions(), + }) async { + final List paths = await _pickMultiVideoAsPath( + options: options, + ); + return paths.map((String path) => XFile(path)).toList(); + } + + Future> _pickMultiVideoAsPath({ + MultiVideoPickerOptions options = const MultiVideoPickerOptions(), + }) { + return _hostApi.pickMultiVideo( + options.maxDuration?.inSeconds, options.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 63a245a1a67..2e640296eba 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,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 (v22.4.1), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), 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, no_leading_underscores_for_local_identifiers @@ -18,8 +18,7 @@ PlatformException _createConnectionError(String channelName) { ); } -List wrapResponse( - {Object? result, PlatformException? error, bool empty = false}) { +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -132,6 +131,7 @@ class SourceSpecification { } } + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -139,19 +139,19 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is SourceCamera) { + } else if (value is SourceCamera) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is SourceType) { + } else if (value is SourceType) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is MaxSize) { + } else if (value is MaxSize) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is MediaSelectionOptions) { + } else if (value is MediaSelectionOptions) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is SourceSpecification) { + } else if (value is SourceSpecification) { buffer.putUint8(133); writeValue(buffer, value.encode()); } else { @@ -184,30 +184,24 @@ class ImagePickerApi { /// Constructor for [ImagePickerApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - ImagePickerApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + ImagePickerApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); final String pigeonVar_messageChannelSuffix; - Future pickImage(SourceSpecification source, MaxSize maxSize, - int? imageQuality, bool requestFullMetadata) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future pickImage(SourceSpecification source, MaxSize maxSize, int? imageQuality, bool requestFullMetadata) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = await pigeonVar_channel - .send([source, maxSize, imageQuality, requestFullMetadata]) - as List?; + final List? pigeonVar_replyList = + await pigeonVar_channel.send([source, maxSize, imageQuality, requestFullMetadata]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -221,19 +215,15 @@ class ImagePickerApi { } } - Future> pickMultiImage(MaxSize maxSize, int? imageQuality, - bool requestFullMetadata, int? limit) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future> pickMultiImage(MaxSize maxSize, int? imageQuality, bool requestFullMetadata, int? limit) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = await pigeonVar_channel - .send([maxSize, imageQuality, requestFullMetadata, limit]) - as List?; + final List? pigeonVar_replyList = + await pigeonVar_channel.send([maxSize, imageQuality, requestFullMetadata, limit]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -252,18 +242,15 @@ class ImagePickerApi { } } - Future pickVideo( - SourceSpecification source, int? maxDurationSeconds) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future pickVideo(SourceSpecification source, int? maxDurationSeconds) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = await pigeonVar_channel - .send([source, maxDurationSeconds]) as List?; + final List? pigeonVar_replyList = + await pigeonVar_channel.send([source, maxDurationSeconds]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -277,19 +264,43 @@ class ImagePickerApi { } } + Future> pickMultiVideo(int? maxDurationSeconds, int? limit) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([maxDurationSeconds, limit]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as List?)!.cast(); + } + } + /// Selects images and videos and returns their paths. - Future> pickMedia( - MediaSelectionOptions mediaSelectionOptions) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future> pickMedia(MediaSelectionOptions mediaSelectionOptions) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = await pigeonVar_channel - .send([mediaSelectionOptions]) as List?; + final List? pigeonVar_replyList = + await pigeonVar_channel.send([mediaSelectionOptions]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { diff --git a/packages/image_picker/image_picker_ios/pigeons/messages.dart b/packages/image_picker/image_picker_ios/pigeons/messages.dart index c8dd34fa569..45b98c2bcf2 100644 --- a/packages/image_picker/image_picker_ios/pigeons/messages.dart +++ b/packages/image_picker/image_picker_ios/pigeons/messages.dart @@ -63,6 +63,9 @@ abstract class ImagePickerApi { @async @ObjCSelector('pickVideoWithSource:maxDuration:') String? pickVideo(SourceSpecification source, int? maxDurationSeconds); + @async + @ObjCSelector('pickMultiVideoWithMaxDuration:limit:') + List pickMultiVideo(int? maxDurationSeconds, int? limit); /// Selects images and videos and returns their paths. @async diff --git a/packages/image_picker/image_picker_ios/pubspec.yaml b/packages/image_picker/image_picker_ios/pubspec.yaml index 8bae216660d..b6ccefaeb79 100755 --- a/packages/image_picker/image_picker_ios/pubspec.yaml +++ b/packages/image_picker/image_picker_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_ios 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.12+2 +version: 0.8.14 environment: sdk: ^3.6.0 @@ -32,3 +32,7 @@ topics: - image-picker - files - file-selection +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} 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 c84b2554301..e23d2f02f80 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 @@ -97,6 +97,16 @@ class _ApiLogger implements TestHostImagePickerApi { })); return returnValue as String?; } + + @override + Future> pickMultiVideo( + int? maxDurationSeconds, int? limit) async { + calls.add(_LoggedMethodCall('pickMultiVideo', arguments: { + 'maxDuration': maxDurationSeconds, + 'limit': limit, + })); + return returnValue as List; + } } void main() { @@ -142,6 +152,45 @@ void main() { ], ); }); + }); + + group('#getMultiVideoWithOptions', () { + test('calls the method correctly', () async { + log.returnValue = ['/foo.mp4', 'bar.mp4']; + await picker.getMultiVideoWithOptions( + options: const MultiVideoPickerOptions()); + + expect( + log.calls, + <_LoggedMethodCall>[ + const _LoggedMethodCall('pickMultiVideo', + arguments: { + 'maxDuration': null, + 'limit': null, + }), + ], + ); + }); + + test('passes the arguments correctly', () async { + log.returnValue = []; + await picker.getMultiVideoWithOptions( + options: const MultiVideoPickerOptions( + maxDuration: Duration(seconds: 10), + limit: 5, + )); + + expect( + log.calls, + <_LoggedMethodCall>[ + const _LoggedMethodCall('pickMultiVideo', + arguments: { + 'maxDuration': 10, + 'limit': 5, + }), + ], + ); + }); test('passes the width and height arguments correctly', () async { await picker.pickImage(source: ImageSource.camera); 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 46dc4e4e85d..0667efd836b 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,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 (v22.4.1), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), 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, no_leading_underscores_for_local_identifiers // ignore_for_file: avoid_relative_lib_imports @@ -13,6 +13,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker_ios/src/messages.g.dart'; + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -20,19 +21,19 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is SourceCamera) { + } else if (value is SourceCamera) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is SourceType) { + } else if (value is SourceType) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is MaxSize) { + } else if (value is MaxSize) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is MediaSelectionOptions) { + } else if (value is MediaSelectionOptions) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is SourceSpecification) { + } else if (value is SourceSpecification) { buffer.putUint8(133); writeValue(buffer, value.encode()); } else { @@ -62,48 +63,34 @@ class _PigeonCodec extends StandardMessageCodec { } abstract class TestHostImagePickerApi { - static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => - TestDefaultBinaryMessengerBinding.instance; + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - Future pickImage(SourceSpecification source, MaxSize maxSize, - int? imageQuality, bool requestFullMetadata); + Future pickImage(SourceSpecification source, MaxSize maxSize, int? imageQuality, bool requestFullMetadata); + + Future> pickMultiImage(MaxSize maxSize, int? imageQuality, bool requestFullMetadata, int? limit); - Future> pickMultiImage( - MaxSize maxSize, int? imageQuality, bool requestFullMetadata, int? limit); + Future pickVideo(SourceSpecification source, int? maxDurationSeconds); - Future pickVideo( - SourceSpecification source, int? maxDurationSeconds); + Future> pickMultiVideo(int? maxDurationSeconds, int? limit); /// Selects images and videos and returns their paths. Future> pickMedia(MediaSelectionOptions mediaSelectionOptions); - static void setUp( - TestHostImagePickerApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(TestHostImagePickerApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, - (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null.'); final List args = (message as List?)!; - final SourceSpecification? arg_source = - (args[0] as SourceSpecification?); + final SourceSpecification? arg_source = (args[0] as SourceSpecification?); assert(arg_source != null, 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null, expected non-null SourceSpecification.'); final MaxSize? arg_maxSize = (args[1] as MaxSize?); @@ -114,34 +101,26 @@ abstract class TestHostImagePickerApi { assert(arg_requestFullMetadata != null, 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null, expected non-null bool.'); try { - final String? output = await api.pickImage(arg_source!, - arg_maxSize!, arg_imageQuality, arg_requestFullMetadata!); + final String? output = await api.pickImage(arg_source!, arg_maxSize!, arg_imageQuality, arg_requestFullMetadata!); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, - (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage was null.'); final List args = (message as List?)!; final MaxSize? arg_maxSize = (args[0] as MaxSize?); assert(arg_maxSize != null, @@ -152,83 +131,87 @@ abstract class TestHostImagePickerApi { '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 output = await api.pickMultiImage(arg_maxSize!, - arg_imageQuality, arg_requestFullMetadata!, arg_limit); + final List output = await api.pickMultiImage(arg_maxSize!, arg_imageQuality, arg_requestFullMetadata!, arg_limit); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, - (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo was null.'); final List args = (message as List?)!; - final SourceSpecification? arg_source = - (args[0] as SourceSpecification?); + final SourceSpecification? arg_source = (args[0] as SourceSpecification?); assert(arg_source != null, 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo was null, expected non-null SourceSpecification.'); final int? arg_maxDurationSeconds = (args[1] as int?); try { - final String? output = - await api.pickVideo(arg_source!, arg_maxDurationSeconds); + final String? output = await api.pickVideo(arg_source!, arg_maxDurationSeconds); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo was null.'); + final List args = (message as List?)!; + final int? arg_maxDurationSeconds = (args[0] as int?); + final int? arg_limit = (args[1] as int?); + try { + final List output = await api.pickMultiVideo(arg_maxDurationSeconds, arg_limit); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, - (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia was null.'); final List args = (message as List?)!; - final MediaSelectionOptions? arg_mediaSelectionOptions = - (args[0] as MediaSelectionOptions?); + final MediaSelectionOptions? arg_mediaSelectionOptions = (args[0] as MediaSelectionOptions?); assert(arg_mediaSelectionOptions != null, 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia was null, expected non-null MediaSelectionOptions.'); try { - final List output = - await api.pickMedia(arg_mediaSelectionOptions!); + final List output = await api.pickMedia(arg_mediaSelectionOptions!); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/packages/image_picker/image_picker_linux/CHANGELOG.md b/packages/image_picker/image_picker_linux/CHANGELOG.md index 9902a5e91af..a1625c2d176 100644 --- a/packages/image_picker/image_picker_linux/CHANGELOG.md +++ b/packages/image_picker/image_picker_linux/CHANGELOG.md @@ -1,5 +1,10 @@ -## NEXT +## 0.2.3 +* feat: Add pickMultiVideo. + +## 0.2.2 + +* feat: Add pickMultiVideo. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 0.2.1+2 diff --git a/packages/image_picker/image_picker_linux/example/pubspec.yaml b/packages/image_picker/image_picker_linux/example/pubspec.yaml index 62b9960ec20..f626818de09 100644 --- a/packages/image_picker/image_picker_linux/example/pubspec.yaml +++ b/packages/image_picker/image_picker_linux/example/pubspec.yaml @@ -27,3 +27,7 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_linux/lib/image_picker_linux.dart b/packages/image_picker/image_picker_linux/lib/image_picker_linux.dart index 207338989b8..86f1a359107 100644 --- a/packages/image_picker/image_picker_linux/lib/image_picker_linux.dart +++ b/packages/image_picker/image_picker_linux/lib/image_picker_linux.dart @@ -155,6 +155,16 @@ class ImagePickerLinux extends CameraDelegatingImagePickerPlatform { return files; } + @override + Future> getMultiVideoWithOptions( + {MultiVideoPickerOptions options = const MultiVideoPickerOptions()}) async { + const XTypeGroup typeGroup = + XTypeGroup(label: 'Videos', mimeTypes: ['video/*']); + final List files = + await fileSelector.openFiles(acceptedTypeGroups: [typeGroup]); + return files; + } + // `maxWidth`, `maxHeight`, and `imageQuality` arguments are not currently // supported. If any of these arguments are supplied, they will be silently // ignored. diff --git a/packages/image_picker/image_picker_linux/pubspec.yaml b/packages/image_picker/image_picker_linux/pubspec.yaml index 4d3180f7323..dfc1a499b61 100644 --- a/packages/image_picker/image_picker_linux/pubspec.yaml +++ b/packages/image_picker/image_picker_linux/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_linux description: Linux platform implementation of image_picker repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_linux issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.2.1+2 +version: 0.2.3 environment: sdk: ^3.6.0 @@ -32,3 +32,7 @@ topics: - image-picker - files - file-selection +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_linux/test/image_picker_linux_test.dart b/packages/image_picker/image_picker_linux/test/image_picker_linux_test.dart index b8a92eef168..23818bf9c15 100644 --- a/packages/image_picker/image_picker_linux/test/image_picker_linux_test.dart +++ b/packages/image_picker/image_picker_linux/test/image_picker_linux_test.dart @@ -124,6 +124,17 @@ void main() { await expectLater( plugin.getVideo(source: ImageSource.camera), throwsStateError); }); + + test('getMultiVideoWithOptions passes the accepted type groups correctly', + () async { + await plugin.getMultiVideoWithOptions(); + + final VerificationResult result = verify( + mockFileSelectorPlatform.openFiles( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect( + capturedTypeGroups(result)[0].mimeTypes, ['video/*']); + }); }); group('media', () { diff --git a/packages/image_picker/image_picker_macos/CHANGELOG.md b/packages/image_picker/image_picker_macos/CHANGELOG.md index 2e404db2c53..6eec3f2039d 100644 --- a/packages/image_picker/image_picker_macos/CHANGELOG.md +++ b/packages/image_picker/image_picker_macos/CHANGELOG.md @@ -1,5 +1,10 @@ -## NEXT +## 0.2.3 +* feat: Add pickMultiVideo. + +## 0.2.2 + +* feat: Add pickMultiVideo. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 0.2.1+2 diff --git a/packages/image_picker/image_picker_macos/example/pubspec.yaml b/packages/image_picker/image_picker_macos/example/pubspec.yaml index 3d5514c1d3f..06f8093e306 100644 --- a/packages/image_picker/image_picker_macos/example/pubspec.yaml +++ b/packages/image_picker/image_picker_macos/example/pubspec.yaml @@ -27,3 +27,7 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_macos/lib/image_picker_macos.dart b/packages/image_picker/image_picker_macos/lib/image_picker_macos.dart index 9e9447a5710..e5ffa00ce19 100644 --- a/packages/image_picker/image_picker_macos/lib/image_picker_macos.dart +++ b/packages/image_picker/image_picker_macos/lib/image_picker_macos.dart @@ -160,6 +160,19 @@ class ImagePickerMacOS extends CameraDelegatingImagePickerPlatform { return files; } + @override + Future> getMultiVideoWithOptions( + {MultiVideoPickerOptions options = const MultiVideoPickerOptions()}) async { + // TODO(stuartmorgan): Add a native implementation that can use + // PHPickerViewController on macOS 13+, with this as a fallback for + // older OS versions: https://github.com/flutter/flutter/issues/125829. + const XTypeGroup typeGroup = + XTypeGroup(uniformTypeIdentifiers: ['public.movie']); + final List files = + await fileSelector.openFiles(acceptedTypeGroups: [typeGroup]); + return files; + } + // `maxWidth`, `maxHeight`, and `imageQuality` arguments are not currently // supported. If any of these arguments are supplied, they will be silently // ignored. diff --git a/packages/image_picker/image_picker_macos/pubspec.yaml b/packages/image_picker/image_picker_macos/pubspec.yaml index b9d7cdb1605..2877cdb13e2 100644 --- a/packages/image_picker/image_picker_macos/pubspec.yaml +++ b/packages/image_picker/image_picker_macos/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_macos description: macOS platform implementation of image_picker repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_macos issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.2.1+2 +version: 0.2.3 environment: sdk: ^3.6.0 @@ -32,3 +32,7 @@ topics: - image-picker - files - file-selection +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_macos/test/image_picker_macos_test.dart b/packages/image_picker/image_picker_macos/test/image_picker_macos_test.dart index 7e94161d4a4..ee8b473017a 100644 --- a/packages/image_picker/image_picker_macos/test/image_picker_macos_test.dart +++ b/packages/image_picker/image_picker_macos/test/image_picker_macos_test.dart @@ -130,6 +130,17 @@ void main() { await expectLater( plugin.getVideo(source: ImageSource.camera), throwsStateError); }); + + test('getMultiVideoWithOptions passes the accepted type groups correctly', + () async { + await plugin.getMultiVideoWithOptions(); + + final VerificationResult result = verify( + mockFileSelectorPlatform.openFiles( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect(capturedTypeGroups(result)[0].uniformTypeIdentifiers, + ['public.movie']); + }); }); group('media', () { diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 5f0ee50c6c7..19d46bad04c 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,5 +1,10 @@ -## NEXT +## 2.12.0 +* feat: Add pickMultiVideo. + +## 2.11.0 + +* feat: Add pickMultiVideo. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 2.10.1 diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart index 943ea760995..998bf5693ce 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart @@ -35,6 +35,21 @@ class MethodChannelImagePicker extends ImagePickerPlatform { return path != null ? PickedFile(path) : null; } + @override + Future> getMultiVideoWithOptions({ + MultiVideoPickerOptions options = const MultiVideoPickerOptions(), + }) async { + final List? paths = await _getMultiVideoPath( + maxDuration: options.maxDuration, + limit: options.limit, + ); + if (paths == null) { + return []; + } + + return paths.map((dynamic path) => XFile(path as String)).toList(); + } + @override Future?> pickMultiImage({ double? maxWidth, @@ -85,6 +100,19 @@ class MethodChannelImagePicker extends ImagePickerPlatform { ); } + Future?> _getMultiVideoPath({ + Duration? maxDuration, + int? limit, + }) { + return _channel.invokeMethod?>( + 'pickMultiVideo', + { + 'maxDuration': maxDuration?.inSeconds, + 'limit': limit, + }, + ); + } + Future _getImagePath({ required ImageSource source, double? maxWidth, diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart index a31fbbab322..9fadbdf266c 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart @@ -322,6 +322,21 @@ abstract class ImagePickerPlatform extends PlatformInterface { return pickedImages ?? []; } + /// Returns a [List] with the videos that were picked. + /// + /// The `source` argument controls where the video comes from. This can + /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// + /// The `options` argument controls additional settings that can be used when + /// picking a video. See [VideoPickerOptions] for more details. + /// + /// If no videos were picked, returns an empty list. + Future> getMultiVideoWithOptions({ + MultiVideoPickerOptions options = const MultiVideoPickerOptions(), + }) { + throw UnimplementedError('getMultiVideoWithOptions() has not been implemented.'); + } + /// Returns true if the implementation supports [source]. /// /// Defaults to true for the original image sources, `gallery` and `camera`, diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_video_picker_options.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_video_picker_options.dart new file mode 100644 index 00000000000..66149b9c3d3 --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/multi_video_picker_options.dart @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; + +/// Specifies options for picking multiple videos. +@immutable +class MultiVideoPickerOptions { + /// Creates an instance with the given options. + const MultiVideoPickerOptions({ + this.maxDuration, + this.limit, + }); + + /// The maximum duration of the picked video. + final Duration? maxDuration; + + /// The maximum number of videos that can be selected. + /// + /// This value may be ignored by platforms that cannot support it. + final int? limit; +} diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart index 0339d98b575..c830b37a74d 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart @@ -12,6 +12,7 @@ export 'media_selection_type.dart'; export 'multi_image_picker_options.dart'; export 'picked_file/picked_file.dart'; export 'retrieve_type.dart'; +export 'multi_video_picker_options.dart'; /// Denotes that an image is being picked. const String kTypeImage = 'image'; diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 22280b9d797..21dbc26beda 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/image_picker/ issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.10.1 +version: 2.12.0 environment: sdk: ^3.6.0 diff --git a/packages/image_picker/image_picker_windows/CHANGELOG.md b/packages/image_picker/image_picker_windows/CHANGELOG.md index e11526a4462..a8373a89db2 100644 --- a/packages/image_picker/image_picker_windows/CHANGELOG.md +++ b/packages/image_picker/image_picker_windows/CHANGELOG.md @@ -1,5 +1,10 @@ -## NEXT +## 0.2.3 +* feat: Add pickMultiVideo. + +## 0.2.2 + +* feat: Add pickMultiVideo. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 0.2.1+1 diff --git a/packages/image_picker/image_picker_windows/example/pubspec.yaml b/packages/image_picker/image_picker_windows/example/pubspec.yaml index b09c095f886..515d13111c1 100644 --- a/packages/image_picker/image_picker_windows/example/pubspec.yaml +++ b/packages/image_picker/image_picker_windows/example/pubspec.yaml @@ -27,3 +27,7 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_windows/lib/image_picker_windows.dart b/packages/image_picker/image_picker_windows/lib/image_picker_windows.dart index e9e414628c9..9257dadbee9 100644 --- a/packages/image_picker/image_picker_windows/lib/image_picker_windows.dart +++ b/packages/image_picker/image_picker_windows/lib/image_picker_windows.dart @@ -184,6 +184,16 @@ class ImagePickerWindows extends CameraDelegatingImagePickerPlatform { return files; } + @override + Future> getMultiVideoWithOptions( + {MultiVideoPickerOptions options = const MultiVideoPickerOptions()}) async { + const XTypeGroup typeGroup = + XTypeGroup(label: 'Videos', extensions: videoFormats); + final List files = + await fileSelector.openFiles(acceptedTypeGroups: [typeGroup]); + return files; + } + // `maxWidth`, `maxHeight`, and `imageQuality` arguments are not // supported on Windows. If any of these arguments is supplied, // they will be silently ignored by the Windows version of the plugin. diff --git a/packages/image_picker/image_picker_windows/pubspec.yaml b/packages/image_picker/image_picker_windows/pubspec.yaml index 18637c1b8b6..eacc42e8e96 100644 --- a/packages/image_picker/image_picker_windows/pubspec.yaml +++ b/packages/image_picker/image_picker_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_windows description: Windows platform implementation of image_picker repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.2.1+1 +version: 0.2.3 environment: sdk: ^3.6.0 @@ -32,3 +32,7 @@ topics: - image-picker - files - file-selection +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart b/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart index 6da0873af5b..39b13195700 100644 --- a/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart +++ b/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart @@ -127,6 +127,17 @@ void main() { await expectLater( plugin.getVideo(source: ImageSource.camera), throwsStateError); }); + + test('getMultiVideoWithOptions passes the accepted type groups correctly', + () async { + await plugin.getMultiVideoWithOptions(); + + final VerificationResult result = verify( + mockFileSelectorPlatform.openFiles( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect(capturedTypeGroups(result)[0].extensions, + ImagePickerWindows.videoFormats); + }); }); group('media', () { From 3ac98cd31f67497300915240008f6cfa5ab1b7cb Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 7 Aug 2025 14:13:00 -0400 Subject: [PATCH 02/15] Minor cleanup (analysis, autoformat, stale comments, changelog/version issues) --- .../image_picker/image_picker/CHANGELOG.md | 6 +- .../image_picker/lib/image_picker.dart | 31 ++-- .../image_picker/image_picker/pubspec.yaml | 2 +- .../image_picker_android/CHANGELOG.md | 6 +- .../image_picker_android/pubspec.yaml | 2 +- .../test/image_picker_android_test.dart | 3 +- .../image_picker_for_web/CHANGELOG.md | 6 +- .../image_picker_for_web/pubspec.yaml | 2 +- .../image_picker_ios/CHANGELOG.md | 6 +- .../include/image_picker_ios/messages.g.h | 61 ++++--- .../Sources/image_picker_ios/messages.g.m | 168 ++++++++++++------ .../image_picker_ios/lib/src/messages.g.dart | 87 +++++---- .../image_picker_ios/pubspec.yaml | 2 +- .../test/image_picker_ios_test.dart | 3 +- .../image_picker_ios/test/test_api.g.dart | 161 +++++++++++------ .../image_picker_linux/CHANGELOG.md | 6 +- .../lib/image_picker_linux.dart | 7 +- .../image_picker_linux/pubspec.yaml | 2 +- .../test/image_picker_linux_test.dart | 3 +- .../image_picker_macos/CHANGELOG.md | 6 +- .../lib/image_picker_macos.dart | 7 +- .../image_picker_macos/pubspec.yaml | 2 +- .../CHANGELOG.md | 5 +- .../image_picker_platform.dart | 6 +- .../lib/src/types/types.dart | 2 +- .../pubspec.yaml | 2 +- .../image_picker_windows/CHANGELOG.md | 6 +- .../lib/image_picker_windows.dart | 7 +- .../image_picker_windows/pubspec.yaml | 2 +- .../test/image_picker_windows_test.dart | 20 +-- 30 files changed, 364 insertions(+), 265 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index fad8ec0cf43..8c8f1d4a29c 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,10 +1,6 @@ -## 1.3.0 - -* feat: Add pickMultiVideo. - ## 1.2.0 -* feat: Add pickMultiVideo. +* Adds `pickMultiVideo` to allow selecting multiple videos from the gallery. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 1.1.2 diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart index a905be609a4..b5473d6f0eb 100755 --- a/packages/image_picker/image_picker/lib/image_picker.dart +++ b/packages/image_picker/image_picker/lib/image_picker.dart @@ -300,31 +300,20 @@ class ImagePicker { /// Returns a [List] of the videos that were picked. /// - /// The returned [List] is intended to be used within a single app session. - /// Do not save the file path and use it across sessions. - /// - /// The `source` argument controls where the videos come from. This can - /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// The returned [List] is intended to be used within a single app + /// session. Do not save the file path and use it across sessions. /// - /// The [maxDuration] argument specifies the maximum duration of the captured videos. - /// If no [maxDuration] is specified, the maximum duration will be infinite. + /// The videos come from the gallery. /// - /// Use `preferredCameraDevice` to specify the camera to use when the `source` is - /// [ImageSource.camera]. The `preferredCameraDevice` is ignored when `source` is - /// [ImageSource.gallery]. It is also ignored if the chosen camera is not supported - /// on the device. Defaults to [CameraDevice.rear]. + /// The [maxDuration] argument specifies the maximum duration of the captured + /// videos. If no [maxDuration] is specified, the maximum duration will be + /// infinite. This value may be ignored by platforms that cannot support it. /// - /// The `limit` parameter modifies the maximum number of videos that can be selected. - /// This value may be ignored by platforms that cannot support it. + /// The `limit` parameter modifies the maximum number of videos that can be + /// selected. This value may be ignored by platforms that cannot support it. /// - /// In Android, the MainActivity can be destroyed for various reasons. If that happens, - /// the result will be lost in this call. You can then call [retrieveLostData] when your - /// app relaunches to retrieve the lost data. - /// - /// The method could throw [PlatformException] if the app does not have permission to access - /// the camera or photos gallery, no camera is available, plugin is already in use, - /// temporary file could not be created and video could not be cached (iOS only), - /// plugin activity could not be allocated (Android only) or due to an unknown error. + /// The method can throw a [PlatformException] if the video selection process + /// fails. Future> pickMultiVideo({ Duration? maxDuration, int? limit, diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 4343d7cee76..bf5ab7eabab 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image 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.3.0 +version: 1.2.0 environment: sdk: ^3.6.0 diff --git a/packages/image_picker/image_picker_android/CHANGELOG.md b/packages/image_picker/image_picker_android/CHANGELOG.md index e8617dec165..f6d0faf90c5 100644 --- a/packages/image_picker/image_picker_android/CHANGELOG.md +++ b/packages/image_picker/image_picker_android/CHANGELOG.md @@ -1,10 +1,6 @@ -## 0.8.14 - -* feat: Add pickMultiVideo. - ## 0.8.13 -* feat: Add pickMultiVideo. +* Adds support for `getMultiVideo`. ## 0.8.12+24 diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml index 2c1bbb8788e..846af93e7df 100755 --- a/packages/image_picker/image_picker_android/pubspec.yaml +++ b/packages/image_picker/image_picker_android/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_android 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.14 +version: 0.8.13 environment: sdk: ^3.6.0 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 e7628d72d71..9d8a4790685 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 @@ -606,8 +606,7 @@ void main() { test('calls the method correctly', () async { const List fakePaths = ['/foo.mp4', 'bar.mp4']; api.returnValue = fakePaths; - final List result = - await picker.getMultiVideoWithOptions(options: const MultiVideoPickerOptions()); + final List result = await picker.getMultiVideoWithOptions(); expect(result.length, 2); expect(result[0].path, fakePaths[0]); diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index ff289bd4085..88a137c1419 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,10 +1,6 @@ -## 3.2.0 - -* feat: Add pickMultiVideo. - ## 3.1.0 -* feat: Add pickMultiVideo. +* Adds support for `getMultiVideo`. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 3.0.6 diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index 53a76b9c730..e16f0faa698 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_for_web description: Web platform implementation of image_picker repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_for_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 3.2.0 +version: 3.1.0 environment: sdk: ^3.6.0 diff --git a/packages/image_picker/image_picker_ios/CHANGELOG.md b/packages/image_picker/image_picker_ios/CHANGELOG.md index 460eadf44ac..b2460762b18 100644 --- a/packages/image_picker/image_picker_ios/CHANGELOG.md +++ b/packages/image_picker/image_picker_ios/CHANGELOG.md @@ -1,10 +1,6 @@ -## 0.8.14 - -* feat: Add pickMultiVideo. - ## 0.8.13 -* feat: Add pickMultiVideo. +* Adds support for `getMultiVideo`. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 0.8.12+2 diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/messages.g.h b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/messages.g.h index 9d4cb28552f..bda30017db9 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/messages.g.h +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/messages.g.h @@ -40,32 +40,30 @@ typedef NS_ENUM(NSUInteger, FLTSourceType) { @class FLTSourceSpecification; @interface FLTMaxSize : NSObject -+ (instancetype)makeWithWidth:(nullable NSNumber *)width - height:(nullable NSNumber *)height; -@property(nonatomic, strong, nullable) NSNumber * width; -@property(nonatomic, strong, nullable) NSNumber * height; ++ (instancetype)makeWithWidth:(nullable NSNumber *)width height:(nullable NSNumber *)height; +@property(nonatomic, strong, nullable) NSNumber *width; +@property(nonatomic, strong, nullable) NSNumber *height; @end @interface FLTMediaSelectionOptions : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; + (instancetype)makeWithMaxSize:(FLTMaxSize *)maxSize - imageQuality:(nullable NSNumber *)imageQuality - requestFullMetadata:(BOOL )requestFullMetadata - 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; + imageQuality:(nullable NSNumber *)imageQuality + requestFullMetadata:(BOOL)requestFullMetadata + 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 /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithType:(FLTSourceType)type - camera:(FLTSourceCamera)camera; ++ (instancetype)makeWithType:(FLTSourceType)type camera:(FLTSourceCamera)camera; @property(nonatomic, assign) FLTSourceType type; @property(nonatomic, assign) FLTSourceCamera camera; @end @@ -74,16 +72,35 @@ typedef NS_ENUM(NSUInteger, FLTSourceType) { NSObject *FLTGetMessagesCodec(void); @protocol FLTImagePickerApi -- (void)pickImageWithSource:(FLTSourceSpecification *)source maxSize:(FLTMaxSize *)maxSize quality:(nullable NSNumber *)imageQuality fullMetadata:(BOOL)requestFullMetadata completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)pickMultiImageWithMaxSize:(FLTMaxSize *)maxSize quality:(nullable NSNumber *)imageQuality fullMetadata:(BOOL)requestFullMetadata limit:(nullable NSNumber *)limit completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; -- (void)pickVideoWithSource:(FLTSourceSpecification *)source maxDuration:(nullable NSNumber *)maxDurationSeconds completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)pickMultiVideoWithMaxDuration:(nullable NSNumber *)maxDurationSeconds limit:(nullable NSNumber *)limit completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; +- (void)pickImageWithSource:(FLTSourceSpecification *)source + maxSize:(FLTMaxSize *)maxSize + quality:(nullable NSNumber *)imageQuality + fullMetadata:(BOOL)requestFullMetadata + completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; +- (void)pickMultiImageWithMaxSize:(FLTMaxSize *)maxSize + quality:(nullable NSNumber *)imageQuality + fullMetadata:(BOOL)requestFullMetadata + limit:(nullable NSNumber *)limit + completion:(void (^)(NSArray *_Nullable, + FlutterError *_Nullable))completion; +- (void)pickVideoWithSource:(FLTSourceSpecification *)source + maxDuration:(nullable NSNumber *)maxDurationSeconds + completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; +- (void)pickMultiVideoWithMaxDuration:(nullable NSNumber *)maxDurationSeconds + limit:(nullable NSNumber *)limit + completion:(void (^)(NSArray *_Nullable, + FlutterError *_Nullable))completion; /// Selects images and videos and returns their paths. -- (void)pickMediaWithMediaSelectionOptions:(FLTMediaSelectionOptions *)mediaSelectionOptions completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; +- (void)pickMediaWithMediaSelectionOptions:(FLTMediaSelectionOptions *)mediaSelectionOptions + completion:(void (^)(NSArray *_Nullable, + FlutterError *_Nullable))completion; @end -extern void SetUpFLTImagePickerApi(id binaryMessenger, NSObject *_Nullable api); +extern void SetUpFLTImagePickerApi(id binaryMessenger, + NSObject *_Nullable api); -extern void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger, NSObject *_Nullable api, NSString *messageChannelSuffix); +extern void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); NS_ASSUME_NONNULL_END diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/messages.g.m b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/messages.g.m index b5677888a0a..8f766fb7fef 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/messages.g.m +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/messages.g.m @@ -69,9 +69,8 @@ + (nullable FLTSourceSpecification *)nullableFromList:(NSArray *)list; @end @implementation FLTMaxSize -+ (instancetype)makeWithWidth:(nullable NSNumber *)width - height:(nullable NSNumber *)height { - FLTMaxSize* pigeonResult = [[FLTMaxSize alloc] init]; ++ (instancetype)makeWithWidth:(nullable NSNumber *)width height:(nullable NSNumber *)height { + FLTMaxSize *pigeonResult = [[FLTMaxSize alloc] init]; pigeonResult.width = width; pigeonResult.height = height; return pigeonResult; @@ -95,11 +94,11 @@ + (nullable FLTMaxSize *)nullableFromList:(NSArray *)list { @implementation FLTMediaSelectionOptions + (instancetype)makeWithMaxSize:(FLTMaxSize *)maxSize - imageQuality:(nullable NSNumber *)imageQuality - requestFullMetadata:(BOOL )requestFullMetadata - allowMultiple:(BOOL )allowMultiple - limit:(nullable NSNumber *)limit { - FLTMediaSelectionOptions* pigeonResult = [[FLTMediaSelectionOptions alloc] init]; + imageQuality:(nullable NSNumber *)imageQuality + requestFullMetadata:(BOOL)requestFullMetadata + allowMultiple:(BOOL)allowMultiple + limit:(nullable NSNumber *)limit { + FLTMediaSelectionOptions *pigeonResult = [[FLTMediaSelectionOptions alloc] init]; pigeonResult.maxSize = maxSize; pigeonResult.imageQuality = imageQuality; pigeonResult.requestFullMetadata = requestFullMetadata; @@ -131,9 +130,8 @@ + (nullable FLTMediaSelectionOptions *)nullableFromList:(NSArray *)list { @end @implementation FLTSourceSpecification -+ (instancetype)makeWithType:(FLTSourceType)type - camera:(FLTSourceCamera)camera { - FLTSourceSpecification* pigeonResult = [[FLTSourceSpecification alloc] init]; ++ (instancetype)makeWithType:(FLTSourceType)type camera:(FLTSourceCamera)camera { + FLTSourceSpecification *pigeonResult = [[FLTSourceSpecification alloc] init]; pigeonResult.type = type; pigeonResult.camera = camera; return pigeonResult; @@ -164,11 +162,15 @@ - (nullable id)readValueOfType:(UInt8)type { switch (type) { case 129: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil : [[FLTSourceCameraBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil + ? nil + : [[FLTSourceCameraBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 130: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil : [[FLTSourceTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil + ? nil + : [[FLTSourceTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 131: return [FLTMaxSize fromList:[self readValue]]; @@ -224,96 +226,140 @@ - (FlutterStandardReader *)readerWithData:(NSData *)data { static FlutterStandardMessageCodec *sSharedObject = nil; static dispatch_once_t sPred = 0; dispatch_once(&sPred, ^{ - FLTMessagesPigeonCodecReaderWriter *readerWriter = [[FLTMessagesPigeonCodecReaderWriter alloc] init]; + FLTMessagesPigeonCodecReaderWriter *readerWriter = + [[FLTMessagesPigeonCodecReaderWriter alloc] init]; sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; }); return sSharedObject; } -void SetUpFLTImagePickerApi(id binaryMessenger, NSObject *api) { +void SetUpFLTImagePickerApi(id binaryMessenger, + NSObject *api) { SetUpFLTImagePickerApiWithSuffix(binaryMessenger, api, @""); } -void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger, NSObject *api, NSString *messageChannelSuffix) { - messageChannelSuffix = messageChannelSuffix.length > 0 ? [NSString stringWithFormat: @".%@", messageChannelSuffix] : @""; +void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger, + NSObject *api, + NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage", messageChannelSuffix] + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage", + messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(pickImageWithSource:maxSize:quality:fullMetadata:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickImageWithSource:maxSize:quality:fullMetadata:completion:)", api); + NSCAssert([api respondsToSelector:@selector + (pickImageWithSource:maxSize:quality:fullMetadata:completion:)], + @"FLTImagePickerApi api (%@) doesn't respond to " + @"@selector(pickImageWithSource:maxSize:quality:fullMetadata:completion:)", + api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FLTSourceSpecification *arg_source = GetNullableObjectAtIndex(args, 0); FLTMaxSize *arg_maxSize = GetNullableObjectAtIndex(args, 1); NSNumber *arg_imageQuality = GetNullableObjectAtIndex(args, 2); BOOL arg_requestFullMetadata = [GetNullableObjectAtIndex(args, 3) boolValue]; - [api pickImageWithSource:arg_source maxSize:arg_maxSize quality:arg_imageQuality fullMetadata:arg_requestFullMetadata completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickImageWithSource:arg_source + maxSize:arg_maxSize + quality:arg_imageQuality + fullMetadata:arg_requestFullMetadata + completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; } } { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage", messageChannelSuffix] + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.image_picker_ios." + @"ImagePickerApi.pickMultiImage", + messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(pickMultiImageWithMaxSize:quality:fullMetadata:limit:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickMultiImageWithMaxSize:quality:fullMetadata:limit:completion:)", api); + NSCAssert([api respondsToSelector:@selector + (pickMultiImageWithMaxSize:quality:fullMetadata:limit:completion:)], + @"FLTImagePickerApi api (%@) doesn't respond to " + @"@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 *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickMultiImageWithMaxSize:arg_maxSize + quality:arg_imageQuality + fullMetadata:arg_requestFullMetadata + limit:arg_limit + completion:^(NSArray *_Nullable output, + FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; } } { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo", messageChannelSuffix] + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo", + messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(pickVideoWithSource:maxDuration:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickVideoWithSource:maxDuration:completion:)", api); + NSCAssert([api respondsToSelector:@selector(pickVideoWithSource:maxDuration:completion:)], + @"FLTImagePickerApi api (%@) doesn't respond to " + @"@selector(pickVideoWithSource:maxDuration:completion:)", + api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FLTSourceSpecification *arg_source = GetNullableObjectAtIndex(args, 0); NSNumber *arg_maxDurationSeconds = GetNullableObjectAtIndex(args, 1); - [api pickVideoWithSource:arg_source maxDuration:arg_maxDurationSeconds completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickVideoWithSource:arg_source + maxDuration:arg_maxDurationSeconds + completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; } } { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo", messageChannelSuffix] + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.image_picker_ios." + @"ImagePickerApi.pickMultiVideo", + messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(pickMultiVideoWithMaxDuration:limit:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickMultiVideoWithMaxDuration:limit:completion:)", api); + NSCAssert([api respondsToSelector:@selector(pickMultiVideoWithMaxDuration:limit:completion:)], + @"FLTImagePickerApi api (%@) doesn't respond to " + @"@selector(pickMultiVideoWithMaxDuration:limit:completion:)", + api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; NSNumber *arg_maxDurationSeconds = GetNullableObjectAtIndex(args, 0); NSNumber *arg_limit = GetNullableObjectAtIndex(args, 1); - [api pickMultiVideoWithMaxDuration:arg_maxDurationSeconds limit:arg_limit completion:^(NSArray *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickMultiVideoWithMaxDuration:arg_maxDurationSeconds + limit:arg_limit + completion:^(NSArray *_Nullable output, + FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -321,19 +367,27 @@ void SetUpFLTImagePickerApiWithSuffix(id binaryMessenger } /// Selects images and videos and returns their paths. { - FlutterBasicMessageChannel *channel = - [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia", messageChannelSuffix] + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia", + messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FLTGetMessagesCodec()]; + codec:FLTGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(pickMediaWithMediaSelectionOptions:completion:)], @"FLTImagePickerApi api (%@) doesn't respond to @selector(pickMediaWithMediaSelectionOptions:completion:)", api); + NSCAssert([api respondsToSelector:@selector(pickMediaWithMediaSelectionOptions:completion:)], + @"FLTImagePickerApi api (%@) doesn't respond to " + @"@selector(pickMediaWithMediaSelectionOptions:completion:)", + api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FLTMediaSelectionOptions *arg_mediaSelectionOptions = GetNullableObjectAtIndex(args, 0); - [api pickMediaWithMediaSelectionOptions:arg_mediaSelectionOptions completion:^(NSArray *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api pickMediaWithMediaSelectionOptions:arg_mediaSelectionOptions + completion:^(NSArray *_Nullable output, + FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; 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 2e640296eba..14112c77c44 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 @@ -18,7 +18,8 @@ PlatformException _createConnectionError(String channelName) { ); } -List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -131,7 +132,6 @@ class SourceSpecification { } } - class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -139,19 +139,19 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is SourceCamera) { + } else if (value is SourceCamera) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is SourceType) { + } else if (value is SourceType) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is MaxSize) { + } else if (value is MaxSize) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is MediaSelectionOptions) { + } else if (value is MediaSelectionOptions) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is SourceSpecification) { + } else if (value is SourceSpecification) { buffer.putUint8(133); writeValue(buffer, value.encode()); } else { @@ -184,24 +184,30 @@ class ImagePickerApi { /// Constructor for [ImagePickerApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - ImagePickerApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + ImagePickerApi( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); final String pigeonVar_messageChannelSuffix; - Future pickImage(SourceSpecification source, MaxSize maxSize, int? imageQuality, bool requestFullMetadata) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + Future pickImage(SourceSpecification source, MaxSize maxSize, + int? imageQuality, bool requestFullMetadata) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([source, maxSize, imageQuality, requestFullMetadata]) as List?; + final List? pigeonVar_replyList = await pigeonVar_channel + .send([source, maxSize, imageQuality, requestFullMetadata]) + as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -215,15 +221,19 @@ class ImagePickerApi { } } - Future> pickMultiImage(MaxSize maxSize, int? imageQuality, bool requestFullMetadata, int? limit) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + Future> pickMultiImage(MaxSize maxSize, int? imageQuality, + bool requestFullMetadata, int? limit) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([maxSize, imageQuality, requestFullMetadata, limit]) as List?; + final List? pigeonVar_replyList = await pigeonVar_channel + .send([maxSize, imageQuality, requestFullMetadata, limit]) + as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -242,15 +252,18 @@ class ImagePickerApi { } } - Future pickVideo(SourceSpecification source, int? maxDurationSeconds) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + Future pickVideo( + SourceSpecification source, int? maxDurationSeconds) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([source, maxDurationSeconds]) as List?; + final List? pigeonVar_replyList = await pigeonVar_channel + .send([source, maxDurationSeconds]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -264,15 +277,18 @@ class ImagePickerApi { } } - Future> pickMultiVideo(int? maxDurationSeconds, int? limit) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + Future> pickMultiVideo( + int? maxDurationSeconds, int? limit) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([maxDurationSeconds, limit]) as List?; + final List? pigeonVar_replyList = await pigeonVar_channel + .send([maxDurationSeconds, limit]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -292,15 +308,18 @@ class ImagePickerApi { } /// Selects images and videos and returns their paths. - Future> pickMedia(MediaSelectionOptions mediaSelectionOptions) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + Future> pickMedia( + MediaSelectionOptions mediaSelectionOptions) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([mediaSelectionOptions]) as List?; + final List? pigeonVar_replyList = await pigeonVar_channel + .send([mediaSelectionOptions]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { diff --git a/packages/image_picker/image_picker_ios/pubspec.yaml b/packages/image_picker/image_picker_ios/pubspec.yaml index b6ccefaeb79..3fc83551e26 100755 --- a/packages/image_picker/image_picker_ios/pubspec.yaml +++ b/packages/image_picker/image_picker_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_ios 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.14 +version: 0.8.13 environment: sdk: ^3.6.0 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 e23d2f02f80..d46225b2bd1 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 @@ -157,8 +157,7 @@ void main() { group('#getMultiVideoWithOptions', () { test('calls the method correctly', () async { log.returnValue = ['/foo.mp4', 'bar.mp4']; - await picker.getMultiVideoWithOptions( - options: const MultiVideoPickerOptions()); + await picker.getMultiVideoWithOptions(); expect( log.calls, 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 0667efd836b..caa53c799e2 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 @@ -13,7 +13,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker_ios/src/messages.g.dart'; - class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -21,19 +20,19 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is SourceCamera) { + } else if (value is SourceCamera) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is SourceType) { + } else if (value is SourceType) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is MaxSize) { + } else if (value is MaxSize) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is MediaSelectionOptions) { + } else if (value is MediaSelectionOptions) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is SourceSpecification) { + } else if (value is SourceSpecification) { buffer.putUint8(133); writeValue(buffer, value.encode()); } else { @@ -63,34 +62,50 @@ class _PigeonCodec extends StandardMessageCodec { } abstract class TestHostImagePickerApi { - static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance; + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - Future pickImage(SourceSpecification source, MaxSize maxSize, int? imageQuality, bool requestFullMetadata); + Future pickImage(SourceSpecification source, MaxSize maxSize, + int? imageQuality, bool requestFullMetadata); - Future> pickMultiImage(MaxSize maxSize, int? imageQuality, bool requestFullMetadata, int? limit); + Future> pickMultiImage( + MaxSize maxSize, int? imageQuality, bool requestFullMetadata, int? limit); - Future pickVideo(SourceSpecification source, int? maxDurationSeconds); + Future pickVideo( + SourceSpecification source, int? maxDurationSeconds); Future> pickMultiVideo(int? maxDurationSeconds, int? limit); /// Selects images and videos and returns their paths. Future> pickMedia(MediaSelectionOptions mediaSelectionOptions); - static void setUp(TestHostImagePickerApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { - messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp( + TestHostImagePickerApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage$messageChannelSuffix', pigeonChannelCodec, + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null.'); final List args = (message as List?)!; - final SourceSpecification? arg_source = (args[0] as SourceSpecification?); + final SourceSpecification? arg_source = + (args[0] as SourceSpecification?); assert(arg_source != null, 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null, expected non-null SourceSpecification.'); final MaxSize? arg_maxSize = (args[1] as MaxSize?); @@ -101,26 +116,34 @@ abstract class TestHostImagePickerApi { assert(arg_requestFullMetadata != null, 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickImage was null, expected non-null bool.'); try { - final String? output = await api.pickImage(arg_source!, arg_maxSize!, arg_imageQuality, arg_requestFullMetadata!); + final String? output = await api.pickImage(arg_source!, + arg_maxSize!, arg_imageQuality, arg_requestFullMetadata!); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage$messageChannelSuffix', pigeonChannelCodec, + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiImage was null.'); final List args = (message as List?)!; final MaxSize? arg_maxSize = (args[0] as MaxSize?); assert(arg_maxSize != null, @@ -131,87 +154,115 @@ abstract class TestHostImagePickerApi { '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 output = await api.pickMultiImage(arg_maxSize!, arg_imageQuality, arg_requestFullMetadata!, arg_limit); + final List output = await api.pickMultiImage(arg_maxSize!, + arg_imageQuality, arg_requestFullMetadata!, arg_limit); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo$messageChannelSuffix', pigeonChannelCodec, + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo was null.'); final List args = (message as List?)!; - final SourceSpecification? arg_source = (args[0] as SourceSpecification?); + final SourceSpecification? arg_source = + (args[0] as SourceSpecification?); assert(arg_source != null, 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickVideo was null, expected non-null SourceSpecification.'); final int? arg_maxDurationSeconds = (args[1] as int?); try { - final String? output = await api.pickVideo(arg_source!, arg_maxDurationSeconds); + final String? output = + await api.pickVideo(arg_source!, arg_maxDurationSeconds); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo$messageChannelSuffix', pigeonChannelCodec, + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMultiVideo was null.'); final List args = (message as List?)!; final int? arg_maxDurationSeconds = (args[0] as int?); final int? arg_limit = (args[1] as int?); try { - final List output = await api.pickMultiVideo(arg_maxDurationSeconds, arg_limit); + final List output = + await api.pickMultiVideo(arg_maxDurationSeconds, arg_limit); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia$messageChannelSuffix', pigeonChannelCodec, + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia was null.'); + 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia was null.'); final List args = (message as List?)!; - final MediaSelectionOptions? arg_mediaSelectionOptions = (args[0] as MediaSelectionOptions?); + final MediaSelectionOptions? arg_mediaSelectionOptions = + (args[0] as MediaSelectionOptions?); assert(arg_mediaSelectionOptions != null, 'Argument for dev.flutter.pigeon.image_picker_ios.ImagePickerApi.pickMedia was null, expected non-null MediaSelectionOptions.'); try { - final List output = await api.pickMedia(arg_mediaSelectionOptions!); + final List output = + await api.pickMedia(arg_mediaSelectionOptions!); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/packages/image_picker/image_picker_linux/CHANGELOG.md b/packages/image_picker/image_picker_linux/CHANGELOG.md index a1625c2d176..b36e38594e8 100644 --- a/packages/image_picker/image_picker_linux/CHANGELOG.md +++ b/packages/image_picker/image_picker_linux/CHANGELOG.md @@ -1,10 +1,6 @@ -## 0.2.3 - -* feat: Add pickMultiVideo. - ## 0.2.2 -* feat: Add pickMultiVideo. +* Adds support for `getMultiVideo`. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 0.2.1+2 diff --git a/packages/image_picker/image_picker_linux/lib/image_picker_linux.dart b/packages/image_picker/image_picker_linux/lib/image_picker_linux.dart index 86f1a359107..deacebaf4e7 100644 --- a/packages/image_picker/image_picker_linux/lib/image_picker_linux.dart +++ b/packages/image_picker/image_picker_linux/lib/image_picker_linux.dart @@ -157,11 +157,12 @@ class ImagePickerLinux extends CameraDelegatingImagePickerPlatform { @override Future> getMultiVideoWithOptions( - {MultiVideoPickerOptions options = const MultiVideoPickerOptions()}) async { + {MultiVideoPickerOptions options = + const MultiVideoPickerOptions()}) async { const XTypeGroup typeGroup = XTypeGroup(label: 'Videos', mimeTypes: ['video/*']); - final List files = - await fileSelector.openFiles(acceptedTypeGroups: [typeGroup]); + final List files = await fileSelector + .openFiles(acceptedTypeGroups: [typeGroup]); return files; } diff --git a/packages/image_picker/image_picker_linux/pubspec.yaml b/packages/image_picker/image_picker_linux/pubspec.yaml index dfc1a499b61..b111423530e 100644 --- a/packages/image_picker/image_picker_linux/pubspec.yaml +++ b/packages/image_picker/image_picker_linux/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_linux description: Linux platform implementation of image_picker repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_linux issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.2.3 +version: 0.2.2 environment: sdk: ^3.6.0 diff --git a/packages/image_picker/image_picker_linux/test/image_picker_linux_test.dart b/packages/image_picker/image_picker_linux/test/image_picker_linux_test.dart index 23818bf9c15..c9fd87868c6 100644 --- a/packages/image_picker/image_picker_linux/test/image_picker_linux_test.dart +++ b/packages/image_picker/image_picker_linux/test/image_picker_linux_test.dart @@ -132,8 +132,7 @@ void main() { final VerificationResult result = verify( mockFileSelectorPlatform.openFiles( acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); - expect( - capturedTypeGroups(result)[0].mimeTypes, ['video/*']); + expect(capturedTypeGroups(result)[0].mimeTypes, ['video/*']); }); }); diff --git a/packages/image_picker/image_picker_macos/CHANGELOG.md b/packages/image_picker/image_picker_macos/CHANGELOG.md index 6eec3f2039d..f01f238643c 100644 --- a/packages/image_picker/image_picker_macos/CHANGELOG.md +++ b/packages/image_picker/image_picker_macos/CHANGELOG.md @@ -1,10 +1,6 @@ -## 0.2.3 - -* feat: Add pickMultiVideo. - ## 0.2.2 -* feat: Add pickMultiVideo. +* Adds support for `getMultiVideo`. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 0.2.1+2 diff --git a/packages/image_picker/image_picker_macos/lib/image_picker_macos.dart b/packages/image_picker/image_picker_macos/lib/image_picker_macos.dart index e5ffa00ce19..9ca69f40a09 100644 --- a/packages/image_picker/image_picker_macos/lib/image_picker_macos.dart +++ b/packages/image_picker/image_picker_macos/lib/image_picker_macos.dart @@ -162,14 +162,15 @@ class ImagePickerMacOS extends CameraDelegatingImagePickerPlatform { @override Future> getMultiVideoWithOptions( - {MultiVideoPickerOptions options = const MultiVideoPickerOptions()}) async { + {MultiVideoPickerOptions options = + const MultiVideoPickerOptions()}) async { // TODO(stuartmorgan): Add a native implementation that can use // PHPickerViewController on macOS 13+, with this as a fallback for // older OS versions: https://github.com/flutter/flutter/issues/125829. const XTypeGroup typeGroup = XTypeGroup(uniformTypeIdentifiers: ['public.movie']); - final List files = - await fileSelector.openFiles(acceptedTypeGroups: [typeGroup]); + final List files = await fileSelector + .openFiles(acceptedTypeGroups: [typeGroup]); return files; } diff --git a/packages/image_picker/image_picker_macos/pubspec.yaml b/packages/image_picker/image_picker_macos/pubspec.yaml index 2877cdb13e2..9562e677061 100644 --- a/packages/image_picker/image_picker_macos/pubspec.yaml +++ b/packages/image_picker/image_picker_macos/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_macos description: macOS platform implementation of image_picker repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_macos issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.2.3 +version: 0.2.2 environment: sdk: ^3.6.0 diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 19d46bad04c..8dde2aefe90 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,10 +1,7 @@ -## 2.12.0 - -* feat: Add pickMultiVideo. ## 2.11.0 -* feat: Add pickMultiVideo. +* Adds `getMultiVideo` method. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 2.10.1 diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart index 9fadbdf266c..410ffce4813 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart @@ -324,8 +324,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// Returns a [List] with the videos that were picked. /// - /// The `source` argument controls where the video comes from. This can - /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// The videos come from the [ImageSource.gallery]. /// /// The `options` argument controls additional settings that can be used when /// picking a video. See [VideoPickerOptions] for more details. @@ -334,7 +333,8 @@ abstract class ImagePickerPlatform extends PlatformInterface { Future> getMultiVideoWithOptions({ MultiVideoPickerOptions options = const MultiVideoPickerOptions(), }) { - throw UnimplementedError('getMultiVideoWithOptions() has not been implemented.'); + throw UnimplementedError( + 'getMultiVideoWithOptions() has not been implemented.'); } /// Returns true if the implementation supports [source]. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart index c830b37a74d..9d8fde59302 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart @@ -10,9 +10,9 @@ export 'lost_data_response.dart'; export 'media_options.dart'; export 'media_selection_type.dart'; export 'multi_image_picker_options.dart'; +export 'multi_video_picker_options.dart'; export 'picked_file/picked_file.dart'; export 'retrieve_type.dart'; -export 'multi_video_picker_options.dart'; /// Denotes that an image is being picked. const String kTypeImage = 'image'; diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 21dbc26beda..1ebf4ebd08e 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/image_picker/ issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.12.0 +version: 2.11.0 environment: sdk: ^3.6.0 diff --git a/packages/image_picker/image_picker_windows/CHANGELOG.md b/packages/image_picker/image_picker_windows/CHANGELOG.md index a8373a89db2..c23ac2edd36 100644 --- a/packages/image_picker/image_picker_windows/CHANGELOG.md +++ b/packages/image_picker/image_picker_windows/CHANGELOG.md @@ -1,10 +1,6 @@ -## 0.2.3 - -* feat: Add pickMultiVideo. - ## 0.2.2 -* feat: Add pickMultiVideo. +* Adds support for `getMultiVideo`. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 0.2.1+1 diff --git a/packages/image_picker/image_picker_windows/lib/image_picker_windows.dart b/packages/image_picker/image_picker_windows/lib/image_picker_windows.dart index 9257dadbee9..5fc3b063509 100644 --- a/packages/image_picker/image_picker_windows/lib/image_picker_windows.dart +++ b/packages/image_picker/image_picker_windows/lib/image_picker_windows.dart @@ -186,11 +186,12 @@ class ImagePickerWindows extends CameraDelegatingImagePickerPlatform { @override Future> getMultiVideoWithOptions( - {MultiVideoPickerOptions options = const MultiVideoPickerOptions()}) async { + {MultiVideoPickerOptions options = + const MultiVideoPickerOptions()}) async { const XTypeGroup typeGroup = XTypeGroup(label: 'Videos', extensions: videoFormats); - final List files = - await fileSelector.openFiles(acceptedTypeGroups: [typeGroup]); + final List files = await fileSelector + .openFiles(acceptedTypeGroups: [typeGroup]); return files; } diff --git a/packages/image_picker/image_picker_windows/pubspec.yaml b/packages/image_picker/image_picker_windows/pubspec.yaml index eacc42e8e96..46e77c14711 100644 --- a/packages/image_picker/image_picker_windows/pubspec.yaml +++ b/packages/image_picker/image_picker_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_windows description: Windows platform implementation of image_picker repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.2.3 +version: 0.2.2 environment: sdk: ^3.6.0 diff --git a/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart b/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart index 39b13195700..98b4646374d 100644 --- a/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart +++ b/packages/image_picker/image_picker_windows/test/image_picker_windows_test.dart @@ -128,16 +128,16 @@ void main() { plugin.getVideo(source: ImageSource.camera), throwsStateError); }); - test('getMultiVideoWithOptions passes the accepted type groups correctly', - () async { - await plugin.getMultiVideoWithOptions(); - - final VerificationResult result = verify( - mockFileSelectorPlatform.openFiles( - acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); - expect(capturedTypeGroups(result)[0].extensions, - ImagePickerWindows.videoFormats); - }); + test('getMultiVideoWithOptions passes the accepted type groups correctly', + () async { + await plugin.getMultiVideoWithOptions(); + + final VerificationResult result = verify( + mockFileSelectorPlatform.openFiles( + acceptedTypeGroups: captureAnyNamed('acceptedTypeGroups'))); + expect(capturedTypeGroups(result)[0].extensions, + ImagePickerWindows.videoFormats); + }); }); group('media', () { From 528a6e7c8795a071ee1f320b483273d6bcfe631b Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 7 Aug 2025 17:00:18 -0400 Subject: [PATCH 03/15] Rework examples for testing and to reduce drift --- .../image_picker/example/lib/main.dart | 63 ++++--- .../example/lib/main.dart | 95 ++++++---- .../image_picker_ios/example/lib/main.dart | 176 +++++++++++------- .../image_picker_linux/example/lib/main.dart | 156 ++++++++++------ .../image_picker_macos/example/lib/main.dart | 156 ++++++++++------ .../example/lib/main.dart | 156 ++++++++++------ 6 files changed, 498 insertions(+), 304 deletions(-) diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index a836c0a8433..932ac994b0c 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -61,7 +61,7 @@ class _MyHomePageState extends State { Future _playVideo(XFile? file) async { if (file != null && mounted) { await _disposeVideoController(); - late VideoPlayerController controller; + final VideoPlayerController controller; if (kIsWeb) { controller = VideoPlayerController.networkUrl(Uri.parse(file.path)); } else { @@ -85,7 +85,7 @@ class _MyHomePageState extends State { Future _onImageButtonPressed( ImageSource source, { required BuildContext context, - bool isMultiImage = false, + bool allowMultiple = false, bool isMedia = false, }) async { if (_controller != null) { @@ -93,10 +93,17 @@ class _MyHomePageState extends State { } if (context.mounted) { if (isVideo) { - final XFile? file = await _picker.pickVideo( - source: source, maxDuration: const Duration(seconds: 10)); - await _playVideo(file); - } else if (isMultiImage) { + final List files; + if (allowMultiple) { + files = await _picker.pickMultiVideo(); + } else { + final XFile? file = await _picker.pickVideo( + source: source, maxDuration: const Duration(seconds: 10)); + files = [if (file != null) file]; + } + // Just play the first file, to keep the example simple. + await _playVideo(files.first); + } else if (allowMultiple) { await _displayPickImageDialog(context, true, (double? maxWidth, double? maxHeight, int? quality, int? limit) async { try { @@ -349,7 +356,7 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'image0', - tooltip: 'Pick Image from gallery', + tooltip: 'Pick image from gallery', child: const Icon(Icons.photo), ), ), @@ -361,12 +368,11 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, - isMedia: true, + allowMultiple: true, ); }, - heroTag: 'multipleMedia', - tooltip: 'Pick Multiple Media from gallery', + heroTag: 'image1', + tooltip: 'Pick multiple images', child: const Icon(Icons.photo_library), ), ), @@ -382,8 +388,8 @@ class _MyHomePageState extends State { ); }, heroTag: 'media', - tooltip: 'Pick Single Media from gallery', - child: const Icon(Icons.photo_library), + tooltip: 'Pick item from gallery', + child: const Icon(Icons.photo_outlined), ), ), Padding( @@ -394,12 +400,13 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, + allowMultiple: true, + isMedia: true, ); }, - heroTag: 'image1', - tooltip: 'Pick Multiple Image from gallery', - child: const Icon(Icons.photo_library), + heroTag: 'multipleMedia', + tooltip: 'Pick multiple items', + child: const Icon(Icons.photo_library_outlined), ), ), if (_picker.supportsImageSource(ImageSource.camera)) @@ -411,7 +418,7 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'image2', - tooltip: 'Take a Photo', + tooltip: 'Take a photo', child: const Icon(Icons.camera_alt), ), ), @@ -424,7 +431,21 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'video0', - tooltip: 'Pick Video from gallery', + tooltip: 'Pick video from gallery', + child: const Icon(Icons.video_file), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton( + backgroundColor: Colors.red, + onPressed: () { + isVideo = true; + _onImageButtonPressed(ImageSource.gallery, + context: context, allowMultiple: true); + }, + heroTag: 'video1', + tooltip: 'Pick multiple videos', child: const Icon(Icons.video_library), ), ), @@ -437,8 +458,8 @@ class _MyHomePageState extends State { isVideo = true; _onImageButtonPressed(ImageSource.camera, context: context); }, - heroTag: 'video1', - tooltip: 'Take a Video', + heroTag: 'video2', + tooltip: 'Take a video', child: const Icon(Icons.videocam), ), ), 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 c28c7729df9..0ff8717ed2e 100755 --- a/packages/image_picker/image_picker_android/example/lib/main.dart +++ b/packages/image_picker/image_picker_android/example/lib/main.dart @@ -79,12 +79,10 @@ class _MyHomePageState extends State { Future _playVideo(XFile? file) async { if (file != null && mounted) { await _disposeVideoController(); - late VideoPlayerController controller; - - controller = VideoPlayerController.file(File(file.path)); + final VideoPlayerController controller = + VideoPlayerController.file(File(file.path)); _controller = controller; - const double volume = 1.0; - await controller.setVolume(volume); + await controller.setVolume(1.0); await controller.initialize(); await controller.setLooping(true); await controller.play(); @@ -95,7 +93,7 @@ class _MyHomePageState extends State { Future _onImageButtonPressed( ImageSource source, { required BuildContext context, - bool isMultiImage = false, + bool allowMultiple = false, bool isMedia = false, }) async { if (_controller != null) { @@ -103,13 +101,20 @@ class _MyHomePageState extends State { } if (context.mounted) { if (_isVideo) { - final XFile? file = await _picker.getVideo( - source: source, maxDuration: const Duration(seconds: 10)); - if (file != null && context.mounted) { - _showPickedSnackBar(context, [file]); + final List files; + if (allowMultiple) { + files = await _picker.getMultiVideoWithOptions(); + } else { + final XFile? file = await _picker.getVideo( + source: source, maxDuration: const Duration(seconds: 10)); + files = [if (file != null) file]; + } + if (files.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, files); + // Just play the first file, to keep the example simple. + await _playVideo(files.first); } - await _playVideo(file); - } else if (isMultiImage) { + } else if (allowMultiple) { await _displayPickImageDialog(context, true, (double? maxWidth, double? maxHeight, int? quality, int? limit) async { try { @@ -121,7 +126,7 @@ class _MyHomePageState extends State { final List pickedFileList = isMedia ? await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, + allowMultiple: allowMultiple, imageOptions: imageOptions, limit: limit, ), @@ -151,7 +156,7 @@ class _MyHomePageState extends State { final List pickedFileList = []; final XFile? media = _firstOrNull(await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, + allowMultiple: allowMultiple, imageOptions: ImageOptions( maxWidth: maxWidth, maxHeight: maxHeight, @@ -290,8 +295,7 @@ class _MyHomePageState extends State { Widget _buildInlineVideoPlayer(int index) { final VideoPlayerController controller = VideoPlayerController.file(File(_mediaFileList![index].path)); - const double volume = 1.0; - controller.setVolume(volume); + controller.setVolume(1.0); controller.initialize(); controller.setLooping(true); controller.play(); @@ -314,7 +318,7 @@ class _MyHomePageState extends State { if (response.file != null) { if (response.type == RetrieveType.video) { _isVideo = true; - await _playVideo(response.file); + await _playVideo(response.files?.firstOrNull); } else { _isVideo = false; setState(() { @@ -380,8 +384,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'image0', - tooltip: 'Pick Image from gallery', - label: const Text('Pick Image from gallery'), + tooltip: 'Pick image from gallery', + label: const Text('Pick image from gallery'), icon: const Icon(Icons.photo), ), ), @@ -393,13 +397,12 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, - isMedia: true, + allowMultiple: true, ); }, - heroTag: 'multipleMedia', - tooltip: 'Pick Multiple Media from gallery', - label: const Text('Pick Multiple Media from gallery'), + heroTag: 'image1', + tooltip: 'Pick multiple images', + label: const Text('Pick multiple images'), icon: const Icon(Icons.photo_library), ), ), @@ -415,9 +418,9 @@ class _MyHomePageState extends State { ); }, heroTag: 'media', - tooltip: 'Pick Single Media from gallery', - label: const Text('Pick Single Media from gallery'), - icon: const Icon(Icons.photo_library), + tooltip: 'Pick item from gallery', + label: const Text('Pick item from gallery'), + icon: const Icon(Icons.photo_outlined), ), ), Padding( @@ -428,13 +431,14 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, + allowMultiple: true, + isMedia: true, ); }, - heroTag: 'image1', - tooltip: 'Pick Multiple Image from gallery', - label: const Text('Pick Multiple Image from gallery'), - icon: const Icon(Icons.photo_library), + heroTag: 'multipleMedia', + tooltip: 'Pick multiple items', + label: const Text('Pick multiple items'), + icon: const Icon(Icons.photo_library_outlined), ), ), Padding( @@ -445,8 +449,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'image2', - tooltip: 'Take a Photo', - label: const Text('Take a Photo'), + tooltip: 'Take a photo', + label: const Text('Take a photo'), icon: const Icon(Icons.camera_alt), ), ), @@ -459,8 +463,23 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'video0', - tooltip: 'Pick Video from gallery', - label: const Text('Pick Video from gallery'), + tooltip: 'Pick video from gallery', + label: const Text('Pick video from gallery'), + icon: const Icon(Icons.video_file), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + backgroundColor: Colors.red, + onPressed: () { + _isVideo = true; + _onImageButtonPressed(ImageSource.gallery, + context: context, allowMultiple: true); + }, + heroTag: 'video0', + tooltip: 'Pick multiple videos', + label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), ), ), @@ -473,8 +492,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'video1', - tooltip: 'Take a Video', - label: const Text('Take a Video'), + tooltip: 'Take a video', + label: const Text('Take a video'), icon: const Icon(Icons.videocam), ), ), 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 e91b87e60d6..98e80daf41e 100755 --- a/packages/image_picker/image_picker_ios/example/lib/main.dart +++ b/packages/image_picker/image_picker_ios/example/lib/main.dart @@ -7,7 +7,6 @@ import 'dart:async'; import 'dart:io'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; import 'package:mime/mime.dart'; @@ -61,12 +60,10 @@ class _MyHomePageState extends State { Future _playVideo(XFile? file) async { if (file != null && mounted) { await _disposeVideoController(); - late VideoPlayerController controller; - - controller = VideoPlayerController.file(File(file.path)); + final VideoPlayerController controller = + VideoPlayerController.file(File(file.path)); _controller = controller; - const double volume = 1.0; - await controller.setVolume(volume); + await controller.setVolume(1.0); await controller.initialize(); await controller.setLooping(true); await controller.play(); @@ -77,7 +74,7 @@ class _MyHomePageState extends State { Future _onImageButtonPressed( ImageSource source, { required BuildContext context, - bool isMultiImage = false, + bool allowMultiple = false, bool isMedia = false, }) async { if (_controller != null) { @@ -85,35 +82,45 @@ class _MyHomePageState extends State { } if (context.mounted) { if (_isVideo) { - final XFile? file = await _picker.getVideo( - source: source, maxDuration: const Duration(seconds: 10)); - await _playVideo(file); - } else if (isMultiImage) { + final List files; + if (allowMultiple) { + files = await _picker.getMultiVideoWithOptions(); + } else { + final XFile? file = await _picker.getVideo( + source: source, maxDuration: const Duration(seconds: 10)); + files = [if (file != null) file]; + } + if (files.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, files); + // Just play the first file, to keep the example simple. + await _playVideo(files.first); + } + } else if (allowMultiple) { await _displayPickImageDialog(context, true, (double? maxWidth, double? maxHeight, int? quality, int? limit) async { try { + final ImageOptions imageOptions = ImageOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ); final List pickedFileList = isMedia ? await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - ), + allowMultiple: allowMultiple, + imageOptions: imageOptions, limit: limit, ), ) : await _picker.getMultiImageWithOptions( options: MultiImagePickerOptions( - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - ), + imageOptions: imageOptions, limit: limit, ), ); + if (pickedFileList.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, pickedFileList); + } setState(() { _mediaFileList = pickedFileList; }); @@ -130,13 +137,12 @@ class _MyHomePageState extends State { final List pickedFileList = []; final XFile? media = _firstOrNull(await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - ), - ), + allowMultiple: allowMultiple, + imageOptions: ImageOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + )), )); if (media != null) { @@ -161,13 +167,12 @@ class _MyHomePageState extends State { imageQuality: quality, ), ); - setState(() { - _setImageFileListFromFile(pickedFile); - }); + if (pickedFile != null && context.mounted) { + _showPickedSnackBar(context, [pickedFile]); + } + setState(() => _setImageFileListFromFile(pickedFile)); } catch (e) { - setState(() { - _pickImageError = e; - }); + setState(() => _pickImageError = e); } }); } @@ -228,19 +233,28 @@ class _MyHomePageState extends State { child: ListView.builder( key: UniqueKey(), itemBuilder: (BuildContext context, int index) { + final XFile image = _mediaFileList![index]; final String? mime = lookupMimeType(_mediaFileList![index].path); - return Semantics( - label: 'image_picker_example_picked_image', - child: mime == null || mime.startsWith('image/') - ? Image.file( - File(_mediaFileList![index].path), - errorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return const Center( - child: Text('This image type is not supported')); - }, - ) - : _buildInlineVideoPlayer(index), + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(image.name, + key: const Key('image_picker_example_picked_image_name')), + Semantics( + label: 'image_picker_example_picked_image', + child: mime == null || mime.startsWith('image/') + ? Image.file( + File(_mediaFileList![index].path), + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return const Center( + child: + Text('This image type is not supported')); + }, + ) + : _buildInlineVideoPlayer(index), + ), + ], ); }, itemCount: _mediaFileList!.length, @@ -262,8 +276,7 @@ class _MyHomePageState extends State { Widget _buildInlineVideoPlayer(int index) { final VideoPlayerController controller = VideoPlayerController.file(File(_mediaFileList![index].path)); - const double volume = kIsWeb ? 0.0 : 1.0; - controller.setVolume(volume); + controller.setVolume(1.0); controller.initialize(); controller.setLooping(true); controller.play(); @@ -290,7 +303,6 @@ class _MyHomePageState extends State { ), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, children: [ Semantics( label: 'image_picker_example_from_gallery', @@ -301,8 +313,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'image0', - tooltip: 'Pick Image from gallery', - label: const Text('Pick Image from gallery'), + tooltip: 'Pick image from gallery', + label: const Text('Pick image from gallery'), icon: const Icon(Icons.photo), ), ), @@ -314,13 +326,12 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, - isMedia: true, + allowMultiple: true, ); }, - heroTag: 'multipleMedia', - tooltip: 'Pick Multiple Media from gallery', - label: const Text('Pick Multiple Media from gallery'), + heroTag: 'image1', + tooltip: 'Pick multiple images', + label: const Text('Pick multiple images'), icon: const Icon(Icons.photo_library), ), ), @@ -336,9 +347,9 @@ class _MyHomePageState extends State { ); }, heroTag: 'media', - tooltip: 'Pick Single Media from gallery', - label: const Text('Pick Single Media from gallery'), - icon: const Icon(Icons.photo_library), + tooltip: 'Pick item from gallery', + label: const Text('Pick item from gallery'), + icon: const Icon(Icons.photo_outlined), ), ), Padding( @@ -349,13 +360,14 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, + allowMultiple: true, + isMedia: true, ); }, - heroTag: 'image1', - tooltip: 'Pick Multiple Image from gallery', - label: const Text('Pick Multiple Image from gallery'), - icon: const Icon(Icons.photo_library), + heroTag: 'multipleMedia', + tooltip: 'Pick multiple items', + label: const Text('Pick multiple items'), + icon: const Icon(Icons.photo_library_outlined), ), ), Padding( @@ -366,8 +378,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'image2', - tooltip: 'Take a Photo', - label: const Text('Take a Photo'), + tooltip: 'Take a photo', + label: const Text('Take a photo'), icon: const Icon(Icons.camera_alt), ), ), @@ -380,8 +392,23 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'video0', - tooltip: 'Pick Video from gallery', - label: const Text('Pick Video from gallery'), + tooltip: 'Pick video from gallery', + label: const Text('Pick video from gallery'), + icon: const Icon(Icons.video_file), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + backgroundColor: Colors.red, + onPressed: () { + _isVideo = true; + _onImageButtonPressed(ImageSource.gallery, + context: context, allowMultiple: true); + }, + heroTag: 'video0', + tooltip: 'Pick multiple videos', + label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), ), ), @@ -394,8 +421,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'video1', - tooltip: 'Take a Video', - label: const Text('Take a Video'), + tooltip: 'Take a video', + label: const Text('Take a video'), icon: const Icon(Icons.videocam), ), ), @@ -480,6 +507,13 @@ class _MyHomePageState extends State { ); }); } + + void _showPickedSnackBar(BuildContext context, List files) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text('Picked: ${files.map((XFile it) => it.name).join(',')}'), + duration: const Duration(seconds: 2), + )); + } } typedef OnPickImageCallback = void Function( diff --git a/packages/image_picker/image_picker_linux/example/lib/main.dart b/packages/image_picker/image_picker_linux/example/lib/main.dart index acec8f8b360..863c777e8b4 100644 --- a/packages/image_picker/image_picker_linux/example/lib/main.dart +++ b/packages/image_picker/image_picker_linux/example/lib/main.dart @@ -74,7 +74,7 @@ class _MyHomePageState extends State { Future _onImageButtonPressed( ImageSource source, { required BuildContext context, - bool isMultiImage = false, + bool allowMultiple = false, bool isMedia = false, }) async { if (_controller != null) { @@ -82,32 +82,43 @@ class _MyHomePageState extends State { } if (context.mounted) { if (_isVideo) { - final XFile? file = await _picker.getVideo( - source: source, maxDuration: const Duration(seconds: 10)); - await _playVideo(file); - } else if (isMultiImage) { + final List files; + if (allowMultiple) { + files = await _picker.getMultiVideoWithOptions(); + } else { + final XFile? file = await _picker.getVideo( + source: source, maxDuration: const Duration(seconds: 10)); + files = [if (file != null) file]; + } + if (files.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, files); + // Just play the first file, to keep the example simple. + await _playVideo(files.first); + } + } else if (allowMultiple) { await _displayPickImageDialog(context, (double? maxWidth, double? maxHeight, int? quality) async { try { + final ImageOptions imageOptions = ImageOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ); final List pickedFileList = isMedia ? await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - )), + allowMultiple: allowMultiple, + imageOptions: imageOptions, + ), ) : await _picker.getMultiImageWithOptions( options: MultiImagePickerOptions( - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - ), + imageOptions: imageOptions, ), ); + if (pickedFileList.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, pickedFileList); + } setState(() { _mediaFileList = pickedFileList; }); @@ -124,7 +135,7 @@ class _MyHomePageState extends State { final List pickedFileList = []; final XFile? media = _firstOrNull(await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, + allowMultiple: allowMultiple, imageOptions: ImageOptions( maxWidth: maxWidth, maxHeight: maxHeight, @@ -154,13 +165,12 @@ class _MyHomePageState extends State { imageQuality: quality, ), ); - setState(() { - _setImageFileListFromFile(pickedFile); - }); + if (pickedFile != null && context.mounted) { + _showPickedSnackBar(context, [pickedFile]); + } + setState(() => _setImageFileListFromFile(pickedFile)); } catch (e) { - setState(() { - _pickImageError = e; - }); + setState(() => _pickImageError = e); } }); } @@ -221,19 +231,28 @@ class _MyHomePageState extends State { child: ListView.builder( key: UniqueKey(), itemBuilder: (BuildContext context, int index) { + final XFile image = _mediaFileList![index]; final String? mime = lookupMimeType(_mediaFileList![index].path); - return Semantics( - label: 'image_picker_example_picked_image', - child: mime == null || mime.startsWith('image/') - ? Image.file( - File(_mediaFileList![index].path), - errorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return const Center( - child: Text('This image type is not supported')); - }, - ) - : _buildInlineVideoPlayer(index), + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(image.name, + key: const Key('image_picker_example_picked_image_name')), + Semantics( + label: 'image_picker_example_picked_image', + child: mime == null || mime.startsWith('image/') + ? Image.file( + File(_mediaFileList![index].path), + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return const Center( + child: + Text('This image type is not supported')); + }, + ) + : _buildInlineVideoPlayer(index), + ), + ], ); }, itemCount: _mediaFileList!.length, @@ -255,8 +274,7 @@ class _MyHomePageState extends State { Widget _buildInlineVideoPlayer(int index) { final VideoPlayerController controller = VideoPlayerController.file(File(_mediaFileList![index].path)); - const double volume = 1.0; - controller.setVolume(volume); + controller.setVolume(1.0); controller.initialize(); controller.setLooping(true); controller.play(); @@ -293,8 +311,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'image0', - tooltip: 'Pick Image from gallery', - label: const Text('Pick Image from gallery'), + tooltip: 'Pick image from gallery', + label: const Text('Pick image from gallery'), icon: const Icon(Icons.photo), ), ), @@ -306,13 +324,12 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, - isMedia: true, + allowMultiple: true, ); }, - heroTag: 'multipleMedia', - tooltip: 'Pick Multiple Media from gallery', - label: const Text('Pick Multiple Media from gallery'), + heroTag: 'image1', + tooltip: 'Pick multiple images', + label: const Text('Pick multiple images'), icon: const Icon(Icons.photo_library), ), ), @@ -328,9 +345,9 @@ class _MyHomePageState extends State { ); }, heroTag: 'media', - tooltip: 'Pick Single Media from gallery', - label: const Text('Pick Single Media from gallery'), - icon: const Icon(Icons.photo_library), + tooltip: 'Pick item from gallery', + label: const Text('Pick item from gallery'), + icon: const Icon(Icons.photo_outlined), ), ), Padding( @@ -341,13 +358,14 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, + allowMultiple: true, + isMedia: true, ); }, - heroTag: 'image1', - tooltip: 'Pick Multiple Image from gallery', - label: const Text('Pick Multiple Image from gallery'), - icon: const Icon(Icons.photo_library), + heroTag: 'multipleMedia', + tooltip: 'Pick multiple items', + label: const Text('Pick multiple items'), + icon: const Icon(Icons.photo_library_outlined), ), ), if (_picker.supportsImageSource(ImageSource.camera)) @@ -359,8 +377,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'image2', - tooltip: 'Take a Photo', - label: const Text('Take a Photo'), + tooltip: 'Take a photo', + label: const Text('Take a photo'), icon: const Icon(Icons.camera_alt), ), ), @@ -373,8 +391,23 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'video0', - tooltip: 'Pick Video from gallery', - label: const Text('Pick Video from gallery'), + tooltip: 'Pick video from gallery', + label: const Text('Pick video from gallery'), + icon: const Icon(Icons.video_file), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + backgroundColor: Colors.red, + onPressed: () { + _isVideo = true; + _onImageButtonPressed(ImageSource.gallery, + context: context, allowMultiple: true); + }, + heroTag: 'video0', + tooltip: 'Pick multiple videos', + label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), ), ), @@ -388,8 +421,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'video1', - tooltip: 'Take a Video', - label: const Text('Take a Video'), + tooltip: 'Take a video', + label: const Text('Take a video'), icon: const Icon(Icons.videocam), ), ), @@ -464,6 +497,13 @@ class _MyHomePageState extends State { ); }); } + + void _showPickedSnackBar(BuildContext context, List files) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text('Picked: ${files.map((XFile it) => it.name).join(',')}'), + duration: const Duration(seconds: 2), + )); + } } typedef OnPickImageCallback = void Function( diff --git a/packages/image_picker/image_picker_macos/example/lib/main.dart b/packages/image_picker/image_picker_macos/example/lib/main.dart index acec8f8b360..863c777e8b4 100644 --- a/packages/image_picker/image_picker_macos/example/lib/main.dart +++ b/packages/image_picker/image_picker_macos/example/lib/main.dart @@ -74,7 +74,7 @@ class _MyHomePageState extends State { Future _onImageButtonPressed( ImageSource source, { required BuildContext context, - bool isMultiImage = false, + bool allowMultiple = false, bool isMedia = false, }) async { if (_controller != null) { @@ -82,32 +82,43 @@ class _MyHomePageState extends State { } if (context.mounted) { if (_isVideo) { - final XFile? file = await _picker.getVideo( - source: source, maxDuration: const Duration(seconds: 10)); - await _playVideo(file); - } else if (isMultiImage) { + final List files; + if (allowMultiple) { + files = await _picker.getMultiVideoWithOptions(); + } else { + final XFile? file = await _picker.getVideo( + source: source, maxDuration: const Duration(seconds: 10)); + files = [if (file != null) file]; + } + if (files.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, files); + // Just play the first file, to keep the example simple. + await _playVideo(files.first); + } + } else if (allowMultiple) { await _displayPickImageDialog(context, (double? maxWidth, double? maxHeight, int? quality) async { try { + final ImageOptions imageOptions = ImageOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ); final List pickedFileList = isMedia ? await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - )), + allowMultiple: allowMultiple, + imageOptions: imageOptions, + ), ) : await _picker.getMultiImageWithOptions( options: MultiImagePickerOptions( - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - ), + imageOptions: imageOptions, ), ); + if (pickedFileList.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, pickedFileList); + } setState(() { _mediaFileList = pickedFileList; }); @@ -124,7 +135,7 @@ class _MyHomePageState extends State { final List pickedFileList = []; final XFile? media = _firstOrNull(await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, + allowMultiple: allowMultiple, imageOptions: ImageOptions( maxWidth: maxWidth, maxHeight: maxHeight, @@ -154,13 +165,12 @@ class _MyHomePageState extends State { imageQuality: quality, ), ); - setState(() { - _setImageFileListFromFile(pickedFile); - }); + if (pickedFile != null && context.mounted) { + _showPickedSnackBar(context, [pickedFile]); + } + setState(() => _setImageFileListFromFile(pickedFile)); } catch (e) { - setState(() { - _pickImageError = e; - }); + setState(() => _pickImageError = e); } }); } @@ -221,19 +231,28 @@ class _MyHomePageState extends State { child: ListView.builder( key: UniqueKey(), itemBuilder: (BuildContext context, int index) { + final XFile image = _mediaFileList![index]; final String? mime = lookupMimeType(_mediaFileList![index].path); - return Semantics( - label: 'image_picker_example_picked_image', - child: mime == null || mime.startsWith('image/') - ? Image.file( - File(_mediaFileList![index].path), - errorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return const Center( - child: Text('This image type is not supported')); - }, - ) - : _buildInlineVideoPlayer(index), + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(image.name, + key: const Key('image_picker_example_picked_image_name')), + Semantics( + label: 'image_picker_example_picked_image', + child: mime == null || mime.startsWith('image/') + ? Image.file( + File(_mediaFileList![index].path), + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return const Center( + child: + Text('This image type is not supported')); + }, + ) + : _buildInlineVideoPlayer(index), + ), + ], ); }, itemCount: _mediaFileList!.length, @@ -255,8 +274,7 @@ class _MyHomePageState extends State { Widget _buildInlineVideoPlayer(int index) { final VideoPlayerController controller = VideoPlayerController.file(File(_mediaFileList![index].path)); - const double volume = 1.0; - controller.setVolume(volume); + controller.setVolume(1.0); controller.initialize(); controller.setLooping(true); controller.play(); @@ -293,8 +311,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'image0', - tooltip: 'Pick Image from gallery', - label: const Text('Pick Image from gallery'), + tooltip: 'Pick image from gallery', + label: const Text('Pick image from gallery'), icon: const Icon(Icons.photo), ), ), @@ -306,13 +324,12 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, - isMedia: true, + allowMultiple: true, ); }, - heroTag: 'multipleMedia', - tooltip: 'Pick Multiple Media from gallery', - label: const Text('Pick Multiple Media from gallery'), + heroTag: 'image1', + tooltip: 'Pick multiple images', + label: const Text('Pick multiple images'), icon: const Icon(Icons.photo_library), ), ), @@ -328,9 +345,9 @@ class _MyHomePageState extends State { ); }, heroTag: 'media', - tooltip: 'Pick Single Media from gallery', - label: const Text('Pick Single Media from gallery'), - icon: const Icon(Icons.photo_library), + tooltip: 'Pick item from gallery', + label: const Text('Pick item from gallery'), + icon: const Icon(Icons.photo_outlined), ), ), Padding( @@ -341,13 +358,14 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, + allowMultiple: true, + isMedia: true, ); }, - heroTag: 'image1', - tooltip: 'Pick Multiple Image from gallery', - label: const Text('Pick Multiple Image from gallery'), - icon: const Icon(Icons.photo_library), + heroTag: 'multipleMedia', + tooltip: 'Pick multiple items', + label: const Text('Pick multiple items'), + icon: const Icon(Icons.photo_library_outlined), ), ), if (_picker.supportsImageSource(ImageSource.camera)) @@ -359,8 +377,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'image2', - tooltip: 'Take a Photo', - label: const Text('Take a Photo'), + tooltip: 'Take a photo', + label: const Text('Take a photo'), icon: const Icon(Icons.camera_alt), ), ), @@ -373,8 +391,23 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'video0', - tooltip: 'Pick Video from gallery', - label: const Text('Pick Video from gallery'), + tooltip: 'Pick video from gallery', + label: const Text('Pick video from gallery'), + icon: const Icon(Icons.video_file), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + backgroundColor: Colors.red, + onPressed: () { + _isVideo = true; + _onImageButtonPressed(ImageSource.gallery, + context: context, allowMultiple: true); + }, + heroTag: 'video0', + tooltip: 'Pick multiple videos', + label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), ), ), @@ -388,8 +421,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'video1', - tooltip: 'Take a Video', - label: const Text('Take a Video'), + tooltip: 'Take a video', + label: const Text('Take a video'), icon: const Icon(Icons.videocam), ), ), @@ -464,6 +497,13 @@ class _MyHomePageState extends State { ); }); } + + void _showPickedSnackBar(BuildContext context, List files) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text('Picked: ${files.map((XFile it) => it.name).join(',')}'), + duration: const Duration(seconds: 2), + )); + } } typedef OnPickImageCallback = void Function( diff --git a/packages/image_picker/image_picker_windows/example/lib/main.dart b/packages/image_picker/image_picker_windows/example/lib/main.dart index acec8f8b360..863c777e8b4 100644 --- a/packages/image_picker/image_picker_windows/example/lib/main.dart +++ b/packages/image_picker/image_picker_windows/example/lib/main.dart @@ -74,7 +74,7 @@ class _MyHomePageState extends State { Future _onImageButtonPressed( ImageSource source, { required BuildContext context, - bool isMultiImage = false, + bool allowMultiple = false, bool isMedia = false, }) async { if (_controller != null) { @@ -82,32 +82,43 @@ class _MyHomePageState extends State { } if (context.mounted) { if (_isVideo) { - final XFile? file = await _picker.getVideo( - source: source, maxDuration: const Duration(seconds: 10)); - await _playVideo(file); - } else if (isMultiImage) { + final List files; + if (allowMultiple) { + files = await _picker.getMultiVideoWithOptions(); + } else { + final XFile? file = await _picker.getVideo( + source: source, maxDuration: const Duration(seconds: 10)); + files = [if (file != null) file]; + } + if (files.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, files); + // Just play the first file, to keep the example simple. + await _playVideo(files.first); + } + } else if (allowMultiple) { await _displayPickImageDialog(context, (double? maxWidth, double? maxHeight, int? quality) async { try { + final ImageOptions imageOptions = ImageOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ); final List pickedFileList = isMedia ? await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - )), + allowMultiple: allowMultiple, + imageOptions: imageOptions, + ), ) : await _picker.getMultiImageWithOptions( options: MultiImagePickerOptions( - imageOptions: ImageOptions( - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: quality, - ), + imageOptions: imageOptions, ), ); + if (pickedFileList.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, pickedFileList); + } setState(() { _mediaFileList = pickedFileList; }); @@ -124,7 +135,7 @@ class _MyHomePageState extends State { final List pickedFileList = []; final XFile? media = _firstOrNull(await _picker.getMedia( options: MediaOptions( - allowMultiple: isMultiImage, + allowMultiple: allowMultiple, imageOptions: ImageOptions( maxWidth: maxWidth, maxHeight: maxHeight, @@ -154,13 +165,12 @@ class _MyHomePageState extends State { imageQuality: quality, ), ); - setState(() { - _setImageFileListFromFile(pickedFile); - }); + if (pickedFile != null && context.mounted) { + _showPickedSnackBar(context, [pickedFile]); + } + setState(() => _setImageFileListFromFile(pickedFile)); } catch (e) { - setState(() { - _pickImageError = e; - }); + setState(() => _pickImageError = e); } }); } @@ -221,19 +231,28 @@ class _MyHomePageState extends State { child: ListView.builder( key: UniqueKey(), itemBuilder: (BuildContext context, int index) { + final XFile image = _mediaFileList![index]; final String? mime = lookupMimeType(_mediaFileList![index].path); - return Semantics( - label: 'image_picker_example_picked_image', - child: mime == null || mime.startsWith('image/') - ? Image.file( - File(_mediaFileList![index].path), - errorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return const Center( - child: Text('This image type is not supported')); - }, - ) - : _buildInlineVideoPlayer(index), + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(image.name, + key: const Key('image_picker_example_picked_image_name')), + Semantics( + label: 'image_picker_example_picked_image', + child: mime == null || mime.startsWith('image/') + ? Image.file( + File(_mediaFileList![index].path), + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return const Center( + child: + Text('This image type is not supported')); + }, + ) + : _buildInlineVideoPlayer(index), + ), + ], ); }, itemCount: _mediaFileList!.length, @@ -255,8 +274,7 @@ class _MyHomePageState extends State { Widget _buildInlineVideoPlayer(int index) { final VideoPlayerController controller = VideoPlayerController.file(File(_mediaFileList![index].path)); - const double volume = 1.0; - controller.setVolume(volume); + controller.setVolume(1.0); controller.initialize(); controller.setLooping(true); controller.play(); @@ -293,8 +311,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'image0', - tooltip: 'Pick Image from gallery', - label: const Text('Pick Image from gallery'), + tooltip: 'Pick image from gallery', + label: const Text('Pick image from gallery'), icon: const Icon(Icons.photo), ), ), @@ -306,13 +324,12 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, - isMedia: true, + allowMultiple: true, ); }, - heroTag: 'multipleMedia', - tooltip: 'Pick Multiple Media from gallery', - label: const Text('Pick Multiple Media from gallery'), + heroTag: 'image1', + tooltip: 'Pick multiple images', + label: const Text('Pick multiple images'), icon: const Icon(Icons.photo_library), ), ), @@ -328,9 +345,9 @@ class _MyHomePageState extends State { ); }, heroTag: 'media', - tooltip: 'Pick Single Media from gallery', - label: const Text('Pick Single Media from gallery'), - icon: const Icon(Icons.photo_library), + tooltip: 'Pick item from gallery', + label: const Text('Pick item from gallery'), + icon: const Icon(Icons.photo_outlined), ), ), Padding( @@ -341,13 +358,14 @@ class _MyHomePageState extends State { _onImageButtonPressed( ImageSource.gallery, context: context, - isMultiImage: true, + allowMultiple: true, + isMedia: true, ); }, - heroTag: 'image1', - tooltip: 'Pick Multiple Image from gallery', - label: const Text('Pick Multiple Image from gallery'), - icon: const Icon(Icons.photo_library), + heroTag: 'multipleMedia', + tooltip: 'Pick multiple items', + label: const Text('Pick multiple items'), + icon: const Icon(Icons.photo_library_outlined), ), ), if (_picker.supportsImageSource(ImageSource.camera)) @@ -359,8 +377,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'image2', - tooltip: 'Take a Photo', - label: const Text('Take a Photo'), + tooltip: 'Take a photo', + label: const Text('Take a photo'), icon: const Icon(Icons.camera_alt), ), ), @@ -373,8 +391,23 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context); }, heroTag: 'video0', - tooltip: 'Pick Video from gallery', - label: const Text('Pick Video from gallery'), + tooltip: 'Pick video from gallery', + label: const Text('Pick video from gallery'), + icon: const Icon(Icons.video_file), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + backgroundColor: Colors.red, + onPressed: () { + _isVideo = true; + _onImageButtonPressed(ImageSource.gallery, + context: context, allowMultiple: true); + }, + heroTag: 'video0', + tooltip: 'Pick multiple videos', + label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), ), ), @@ -388,8 +421,8 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.camera, context: context); }, heroTag: 'video1', - tooltip: 'Take a Video', - label: const Text('Take a Video'), + tooltip: 'Take a video', + label: const Text('Take a video'), icon: const Icon(Icons.videocam), ), ), @@ -464,6 +497,13 @@ class _MyHomePageState extends State { ); }); } + + void _showPickedSnackBar(BuildContext context, List files) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text('Picked: ${files.map((XFile it) => it.name).join(',')}'), + duration: const Duration(seconds: 2), + )); + } } typedef OnPickImageCallback = void Function( From f2c219cc9d5860e6e79658bb08c66bad3c88e9d5 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 7 Aug 2025 17:00:52 -0400 Subject: [PATCH 04/15] Android: Fix API version issue and add native tests --- .../imagepicker/ImagePickerDelegate.java | 4 +-- .../imagepicker/ImagePickerPluginTest.java | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) 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 5fc5e9e1002..50b0a40d62b 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 @@ -35,7 +35,6 @@ import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.stream.Collectors; /** * A delegate class doing the heavy lifting for the plugin. @@ -743,8 +742,7 @@ private void handleChooseMultiVideoResult(int resultCode, Intent intent) { return; } - finishWithListSuccess( - paths.stream().map(p -> p.getPath()).collect(Collectors.toCollection(ArrayList::new))); + handleMediaResult(paths); return; } 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 dc1f9dd502f..94239955fdd 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 @@ -299,6 +299,41 @@ public void pickVideos_whenSourceIsCamera_invokesTakeImageWithCamera_FrontCamera verify(mockImagePickerDelegate).setCameraDevice(eq(ImagePickerDelegate.CameraDevice.FRONT)); } + @Test + public void pickVideos_invokesChooseMultiVideoFromGallery() { + plugin.pickVideos( + SOURCE_GALLERY, + DEFAULT_VIDEO_OPTIONS, + GENERAL_OPTIONS_ALLOW_MULTIPLE_DONT_USE_PHOTO_PICKER, + mockResult); + verify(mockImagePickerDelegate) + .chooseMultiVideoFromGallery(any(), eq(false), eq(Integer.MAX_VALUE), any()); + verifyNoInteractions(mockResult); + } + + @Test + public void pickVideos_usingPhotoPicker_invokesChooseMultiVideoFromGallery() { + plugin.pickVideos( + SOURCE_GALLERY, + DEFAULT_VIDEO_OPTIONS, + GENERAL_OPTIONS_ALLOW_MULTIPLE_USE_PHOTO_PICKER, + mockResult); + verify(mockImagePickerDelegate) + .chooseMultiVideoFromGallery(any(), eq(true), eq(Integer.MAX_VALUE), any()); + verifyNoInteractions(mockResult); + } + + @Test + public void pickVideos_withLimit5_invokesChooseMultiVideoFromGallery() { + plugin.pickVideos( + SOURCE_GALLERY, + DEFAULT_VIDEO_OPTIONS, + GENERAL_OPTIONS_ALLOW_MULTIPLE_DONT_USE_PHOTO_PICKER_WITH_LIMIT, + mockResult); + verify(mockImagePickerDelegate).chooseMultiVideoFromGallery(any(), eq(false), eq(5), any()); + verifyNoInteractions(mockResult); + } + @Test public void onConstructor_whenContextTypeIsActivity_shouldNotCrash() { new ImagePickerPlugin(mockImagePickerDelegate, mockActivity); From 47086bbb8727df52ec35a9861c2dd52d4a4108f5 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 8 Aug 2025 10:51:31 -0400 Subject: [PATCH 05/15] iOS: Fix, and unify some older code flows --- .../ios/RunnerTests/ImagePickerPluginTests.m | 42 ++++++++-- .../image_picker_ios/FLTImagePickerPlugin.m | 83 +++++++++---------- .../FLTImagePickerPlugin_Test.h | 14 +++- 3 files changed, 85 insertions(+), 54 deletions(-) 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 eb6bcd29b84..99bdbb30cf1 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 @@ -310,6 +310,18 @@ - (void)testPickingVideoWithDuration { XCTAssertEqual(controller.videoMaximumDuration, 95); } +- (void)testPickingMultiVideoWithDuration { + FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init]; + + [plugin + pickMultiVideoWithMaxDuration:@(95) + limit:nil + completion:^(NSArray *result, FlutterError *_Nullable error){ + }]; + + XCTAssertEqual(plugin.callContext.maxDuration, 95); +} + - (void)testViewController { UIWindow *window = [UIWindow new]; MockViewController *vc1 = [MockViewController new]; @@ -603,7 +615,7 @@ - (void)testPickMultiImageWithLimit { completion:^(NSArray *_Nullable result, FlutterError *_Nullable error){ }]; - XCTAssertEqual(plugin.callContext.maxImageCount, 2); + XCTAssertEqual(plugin.callContext.maxItemCount, 2); } - (void)testPickMediaWithLimitAllowsMultiple { @@ -620,7 +632,7 @@ - (void)testPickMediaWithLimitAllowsMultiple { FlutterError *_Nullable error){ }]; - XCTAssertEqual(plugin.callContext.maxImageCount, 2); + XCTAssertEqual(plugin.callContext.maxItemCount, 2); } - (void)testPickMediaWithLimitMultipleNotAllowed { @@ -637,7 +649,7 @@ - (void)testPickMediaWithLimitMultipleNotAllowed { FlutterError *_Nullable error){ }]; - XCTAssertEqual(plugin.callContext.maxImageCount, 1); + XCTAssertEqual(plugin.callContext.maxItemCount, 1); } - (void)testPickMultiImageWithoutLimit { @@ -649,7 +661,7 @@ - (void)testPickMultiImageWithoutLimit { completion:^(NSArray *_Nullable result, FlutterError *_Nullable error){ }]; - XCTAssertEqual(plugin.callContext.maxImageCount, 0); + XCTAssertEqual(plugin.callContext.maxItemCount, 0); } - (void)testPickMediaWithoutLimitAllowsMultiple { @@ -666,7 +678,27 @@ - (void)testPickMediaWithoutLimitAllowsMultiple { FlutterError *_Nullable error){ }]; - XCTAssertEqual(plugin.callContext.maxImageCount, 0); + XCTAssertEqual(plugin.callContext.maxItemCount, 0); +} + +- (void)testPickMultiVideoWithLimit { + FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init]; + [plugin pickMultiVideoWithMaxDuration:nil + limit:@(2) + completion:^(NSArray *_Nullable result, + FlutterError *_Nullable error){ + }]; + XCTAssertEqual(plugin.callContext.maxItemCount, 2); +} + +- (void)testPickMultiVideoWithoutLimit { + FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init]; + [plugin pickMultiVideoWithMaxDuration:nil + limit:nil + completion:^(NSArray *_Nullable result, + FlutterError *_Nullable error){ + }]; + XCTAssertEqual(plugin.callContext.maxItemCount, 0); } @end diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m index 8f2bd39f6fb..678d848659b 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m @@ -98,14 +98,15 @@ - (void)launchPHPickerWithContext:(nonnull FLTImagePickerMethodCallContext *)con API_AVAILABLE(ios(14)) { PHPickerConfiguration *config = [[PHPickerConfiguration alloc] initWithPhotoLibrary:PHPhotoLibrary.sharedPhotoLibrary]; - config.selectionLimit = context.maxImageCount; + config.selectionLimit = context.maxItemCount; + NSMutableArray *filters = [[NSMutableArray alloc] init]; + if (context.includeImages) { + [filters addObject:[PHPickerFilter imagesFilter]]; + } if (context.includeVideo) { - config.filter = [PHPickerFilter anyFilterMatchingSubfilters:@[ - [PHPickerFilter imagesFilter], [PHPickerFilter videosFilter] - ]]; - } else { - config.filter = [PHPickerFilter imagesFilter]; + [filters addObject:[PHPickerFilter videosFilter]]; } + config.filter = [PHPickerFilter anyFilterMatchingSubfilters:filters]; PHPickerViewController *pickerViewController = [[PHPickerViewController alloc] initWithConfiguration:config]; @@ -121,12 +122,19 @@ - (void)launchUIImagePickerWithSource:(nonnull FLTSourceSpecification *)source UIImagePickerController *imagePickerController = [self createImagePickerController]; imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; imagePickerController.delegate = self; + NSMutableArray *mediaTypes = [[NSMutableArray alloc] init]; + if (context) { + [mediaTypes addObject:(NSString *)kUTTypeImage]; + } if (context.includeVideo) { - imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage, (NSString *)kUTTypeMovie ]; - - } else { - imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage ]; + [mediaTypes addObject:(NSString *)kUTTypeMovie]; + imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; } + imagePickerController.mediaTypes = mediaTypes; + if (context.maxDuration != 0.0) { + imagePickerController.videoMaximumDuration = context.maxDuration; + } + self.callContext = context; switch (source.type) { @@ -167,9 +175,10 @@ - (void)pickImageWithSource:(nonnull FLTSourceSpecification *)source } completion(paths.firstObject, error); }]; + context.includeImages = YES; context.maxSize = maxSize; context.imageQuality = imageQuality; - context.maxImageCount = 1; + context.maxItemCount = 1; context.requestFullMetadata = fullMetadata; if (source.type == FLTSourceTypeGallery) { // Capture is not possible with PHPicker @@ -192,10 +201,11 @@ - (void)pickMultiImageWithMaxSize:(nonnull FLTMaxSize *)maxSize [self cancelInProgressCall]; FLTImagePickerMethodCallContext *context = [[FLTImagePickerMethodCallContext alloc] initWithResult:completion]; + context.includeImages = YES; context.maxSize = maxSize; context.imageQuality = imageQuality; context.requestFullMetadata = fullMetadata; - context.maxImageCount = limit.intValue; + context.maxItemCount = limit.intValue; if (@available(iOS 14, *)) { [self launchPHPickerWithContext:context]; @@ -216,12 +226,13 @@ - (void)pickMediaWithMediaSelectionOptions:(nonnull FLTMediaSelectionOptions *)m context.maxSize = [mediaSelectionOptions maxSize]; context.imageQuality = [mediaSelectionOptions imageQuality]; context.requestFullMetadata = [mediaSelectionOptions requestFullMetadata]; + context.includeImages = YES; context.includeVideo = YES; NSNumber *limit = [mediaSelectionOptions limit]; if (!mediaSelectionOptions.allowMultiple) { - context.maxImageCount = 1; + context.maxItemCount = 1; } else if (limit != nil) { - context.maxImageCount = limit.intValue; + context.maxItemCount = limit.intValue; } if (@available(iOS 14, *)) { @@ -248,37 +259,18 @@ - (void)pickVideoWithSource:(nonnull FLTSourceSpecification *)source } completion(paths.firstObject, error); }]; - context.maxImageCount = 1; - - UIImagePickerController *imagePickerController = [self createImagePickerController]; - imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; - imagePickerController.delegate = self; - imagePickerController.mediaTypes = @[ - (NSString *)kUTTypeMovie, (NSString *)kUTTypeAVIMovie, (NSString *)kUTTypeVideo, - (NSString *)kUTTypeMPEG4 - ]; - imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; - - if (maxDurationSeconds) { - NSTimeInterval max = [maxDurationSeconds doubleValue]; - imagePickerController.videoMaximumDuration = max; - } - - self.callContext = context; + context.includeVideo = YES; + context.maxItemCount = 1; + context.maxDuration = maxDurationSeconds.doubleValue; - switch (source.type) { - case FLTSourceTypeCamera: - [self checkCameraAuthorizationWithImagePicker:imagePickerController - camera:[self cameraDeviceForSource:source]]; - break; - case FLTSourceTypeGallery: - [self checkPhotoAuthorizationWithImagePicker:imagePickerController]; - break; - default: - [self sendCallResultWithError:[FlutterError errorWithCode:@"invalid_source" - message:@"Invalid video source." - details:nil]]; - break; + if (source.type == FLTSourceTypeGallery) { // Capture is not possible with PHPicker + if (@available(iOS 14, *)) { + [self launchPHPickerWithContext:context]; + } else { + [self launchUIImagePickerWithSource:source context:context]; + } + } else { + [self launchUIImagePickerWithSource:source context:context]; } } @@ -289,8 +281,9 @@ - (void)pickMultiVideoWithMaxDuration:(nullable NSNumber *)maxDurationSeconds [self cancelInProgressCall]; FLTImagePickerMethodCallContext *context = [[FLTImagePickerMethodCallContext alloc] initWithResult:completion]; - context.maxImageCount = limit.intValue; context.includeVideo = YES; + context.maxItemCount = limit.intValue; + context.maxDuration = maxDurationSeconds.doubleValue; if (@available(iOS 14, *)) { [self launchPHPickerWithContext:context]; diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerPlugin_Test.h b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerPlugin_Test.h index 845cdcf878a..55d04c6f3f3 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerPlugin_Test.h +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerPlugin_Test.h @@ -33,13 +33,19 @@ typedef void (^FlutterResultAdapter)(NSArray *_Nullable, FlutterErro /// If nil, no resampling is done. @property(nonatomic, strong, nullable) NSNumber *imageQuality; -/// Maximum number of images to select. 0 indicates no maximum. -@property(nonatomic, assign) int maxImageCount; +/// Maximum number of items to select. 0 indicates no maximum. +@property(nonatomic, assign) int maxItemCount; -/// Whether the image should be picked with full metadata (requires gallery permissions) +/// Whether the image should be picked with full metadata (requires gallery permissions). @property(nonatomic, assign) BOOL requestFullMetadata; -/// Whether the picker should include videos in the list*/ +/// Maximum duration for videos. 0 indicates no maximum. +@property(nonatomic, assign) NSTimeInterval maxDuration; + +/// Whether the picker should include images in the list. +@property(nonatomic, assign) BOOL includeImages; + +/// Whether the picker should include videos in the list. @property(nonatomic, assign) BOOL includeVideo; @end From acfbfd1d6129fcce4ef12e399106b37642eb2724 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 8 Aug 2025 11:17:09 -0400 Subject: [PATCH 06/15] Simplify iOS Dart code --- .../image_picker_ios/lib/image_picker_ios.dart | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) 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 2b1fb54b3ae..ee9243fc000 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 @@ -327,16 +327,9 @@ class ImagePickerIOS extends ImagePickerPlatform { Future> getMultiVideoWithOptions({ MultiVideoPickerOptions options = const MultiVideoPickerOptions(), }) async { - final List paths = await _pickMultiVideoAsPath( - options: options, - ); - return paths.map((String path) => XFile(path)).toList(); - } - - Future> _pickMultiVideoAsPath({ - MultiVideoPickerOptions options = const MultiVideoPickerOptions(), - }) { - return _hostApi.pickMultiVideo( - options.maxDuration?.inSeconds, options.limit); + return (await _hostApi.pickMultiVideo( + options.maxDuration?.inSeconds, options.limit)) + .map((String path) => XFile(path)) + .toList(); } } From 100beeff1121ca5063db213425565b59d4ca010b Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 8 Aug 2025 11:36:51 -0400 Subject: [PATCH 07/15] Fix hero tags --- packages/image_picker/image_picker/example/lib/main.dart | 6 +++--- .../image_picker/image_picker_android/example/lib/main.dart | 6 +++--- .../image_picker/image_picker_ios/example/lib/main.dart | 6 +++--- .../image_picker/image_picker_linux/example/lib/main.dart | 6 +++--- .../image_picker/image_picker_macos/example/lib/main.dart | 6 +++--- .../image_picker/image_picker_windows/example/lib/main.dart | 6 +++--- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index 932ac994b0c..7e91ce299dc 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -430,7 +430,7 @@ class _MyHomePageState extends State { isVideo = true; _onImageButtonPressed(ImageSource.gallery, context: context); }, - heroTag: 'video0', + heroTag: 'video', tooltip: 'Pick video from gallery', child: const Icon(Icons.video_file), ), @@ -444,7 +444,7 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context, allowMultiple: true); }, - heroTag: 'video1', + heroTag: 'multiVideo', tooltip: 'Pick multiple videos', child: const Icon(Icons.video_library), ), @@ -458,7 +458,7 @@ class _MyHomePageState extends State { isVideo = true; _onImageButtonPressed(ImageSource.camera, context: context); }, - heroTag: 'video2', + heroTag: 'takeVideo', tooltip: 'Take a video', child: const Icon(Icons.videocam), ), 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 0ff8717ed2e..dea02fa2320 100755 --- a/packages/image_picker/image_picker_android/example/lib/main.dart +++ b/packages/image_picker/image_picker_android/example/lib/main.dart @@ -462,7 +462,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.gallery, context: context); }, - heroTag: 'video0', + heroTag: 'video', tooltip: 'Pick video from gallery', label: const Text('Pick video from gallery'), icon: const Icon(Icons.video_file), @@ -477,7 +477,7 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context, allowMultiple: true); }, - heroTag: 'video0', + heroTag: 'multiVideo', tooltip: 'Pick multiple videos', label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), @@ -491,7 +491,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.camera, context: context); }, - heroTag: 'video1', + heroTag: 'takeVideo', tooltip: 'Take a video', label: const Text('Take a video'), icon: const Icon(Icons.videocam), 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 98e80daf41e..dceeb09cd87 100755 --- a/packages/image_picker/image_picker_ios/example/lib/main.dart +++ b/packages/image_picker/image_picker_ios/example/lib/main.dart @@ -391,7 +391,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.gallery, context: context); }, - heroTag: 'video0', + heroTag: 'video', tooltip: 'Pick video from gallery', label: const Text('Pick video from gallery'), icon: const Icon(Icons.video_file), @@ -406,7 +406,7 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context, allowMultiple: true); }, - heroTag: 'video0', + heroTag: 'multiVideo', tooltip: 'Pick multiple videos', label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), @@ -420,7 +420,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.camera, context: context); }, - heroTag: 'video1', + heroTag: 'takeVideo', tooltip: 'Take a video', label: const Text('Take a video'), icon: const Icon(Icons.videocam), diff --git a/packages/image_picker/image_picker_linux/example/lib/main.dart b/packages/image_picker/image_picker_linux/example/lib/main.dart index 863c777e8b4..b62d3913397 100644 --- a/packages/image_picker/image_picker_linux/example/lib/main.dart +++ b/packages/image_picker/image_picker_linux/example/lib/main.dart @@ -390,7 +390,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.gallery, context: context); }, - heroTag: 'video0', + heroTag: 'video', tooltip: 'Pick video from gallery', label: const Text('Pick video from gallery'), icon: const Icon(Icons.video_file), @@ -405,7 +405,7 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context, allowMultiple: true); }, - heroTag: 'video0', + heroTag: 'multiVideo', tooltip: 'Pick multiple videos', label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), @@ -420,7 +420,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.camera, context: context); }, - heroTag: 'video1', + heroTag: 'takeVideo', tooltip: 'Take a video', label: const Text('Take a video'), icon: const Icon(Icons.videocam), diff --git a/packages/image_picker/image_picker_macos/example/lib/main.dart b/packages/image_picker/image_picker_macos/example/lib/main.dart index 863c777e8b4..b62d3913397 100644 --- a/packages/image_picker/image_picker_macos/example/lib/main.dart +++ b/packages/image_picker/image_picker_macos/example/lib/main.dart @@ -390,7 +390,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.gallery, context: context); }, - heroTag: 'video0', + heroTag: 'video', tooltip: 'Pick video from gallery', label: const Text('Pick video from gallery'), icon: const Icon(Icons.video_file), @@ -405,7 +405,7 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context, allowMultiple: true); }, - heroTag: 'video0', + heroTag: 'multiVideo', tooltip: 'Pick multiple videos', label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), @@ -420,7 +420,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.camera, context: context); }, - heroTag: 'video1', + heroTag: 'takeVideo', tooltip: 'Take a video', label: const Text('Take a video'), icon: const Icon(Icons.videocam), diff --git a/packages/image_picker/image_picker_windows/example/lib/main.dart b/packages/image_picker/image_picker_windows/example/lib/main.dart index 863c777e8b4..b62d3913397 100644 --- a/packages/image_picker/image_picker_windows/example/lib/main.dart +++ b/packages/image_picker/image_picker_windows/example/lib/main.dart @@ -390,7 +390,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.gallery, context: context); }, - heroTag: 'video0', + heroTag: 'video', tooltip: 'Pick video from gallery', label: const Text('Pick video from gallery'), icon: const Icon(Icons.video_file), @@ -405,7 +405,7 @@ class _MyHomePageState extends State { _onImageButtonPressed(ImageSource.gallery, context: context, allowMultiple: true); }, - heroTag: 'video0', + heroTag: 'multiVideo', tooltip: 'Pick multiple videos', label: const Text('Pick multiple videos'), icon: const Icon(Icons.video_library), @@ -420,7 +420,7 @@ class _MyHomePageState extends State { _isVideo = true; _onImageButtonPressed(ImageSource.camera, context: context); }, - heroTag: 'video1', + heroTag: 'takeVideo', tooltip: 'Take a video', label: const Text('Take a video'), icon: const Icon(Icons.videocam), From 25f9458937464d1eac31a9c04a697793ad04a232 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 8 Aug 2025 11:39:30 -0400 Subject: [PATCH 08/15] Fix unguarded .first --- packages/image_picker/image_picker/example/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index 7e91ce299dc..f1ec8b76341 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -102,7 +102,7 @@ class _MyHomePageState extends State { files = [if (file != null) file]; } // Just play the first file, to keep the example simple. - await _playVideo(files.first); + await _playVideo(files.firstOrNull); } else if (allowMultiple) { await _displayPickImageDialog(context, true, (double? maxWidth, double? maxHeight, int? quality, int? limit) async { From 0c60fd7f57f86682db9e8d62acec94fcdcebc845 Mon Sep 17 00:00:00 2001 From: stuartmorgan-g Date: Fri, 8 Aug 2025 11:40:00 -0400 Subject: [PATCH 09/15] Update packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../io/flutter/plugins/imagepicker/ImagePickerDelegate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 50b0a40d62b..c76d6b63670 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 @@ -746,7 +746,7 @@ private void handleChooseMultiVideoResult(int resultCode, Intent intent) { return; } - // User cancelled choosing a picture. + // User cancelled choosing a video. finishWithSuccess(null); } From c3040d22e0724273c918aacef7373f931fe7e2b6 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 10 Aug 2025 07:55:58 -0400 Subject: [PATCH 10/15] Fix unit test expectation handling --- .../image_picker/test/image_picker_test.dart | 29 ++++++++++++++----- .../lib/image_picker_android.dart | 26 +++++------------ .../test/image_picker_android_test.dart | 1 + 3 files changed, 30 insertions(+), 26 deletions(-) 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 870f8a78b3e..9613d29f1d2 100644 --- a/packages/image_picker/image_picker/test/image_picker_test.dart +++ b/packages/image_picker/image_picker/test/image_picker_test.dart @@ -401,7 +401,7 @@ void main() { group('#pickMultiVideo', () { setUp(() { when(mockPlatform.getMultiVideoWithOptions( - options: any, + options: anyNamed('options'), )).thenAnswer((Invocation _) async => []); }); @@ -409,17 +409,30 @@ void main() { final ImagePicker picker = ImagePicker(); await picker.pickMultiVideo(); await picker.pickMultiVideo(maxDuration: const Duration(seconds: 10)); - await picker.pickMultiVideo( - limit: 5, - ); + await picker.pickMultiVideo(limit: 5); verifyInOrder([ - mockPlatform.getMultiVideoWithOptions(), mockPlatform.getMultiVideoWithOptions( - options: const MultiVideoPickerOptions( - maxDuration: Duration(seconds: 10))), + options: argThat( + isInstanceOf(), + named: 'options', + )), mockPlatform.getMultiVideoWithOptions( - options: const MultiVideoPickerOptions(limit: 5)), + options: argThat( + isInstanceOf().having( + (MultiVideoPickerOptions options) => options.maxDuration, + 'maxDuration', + equals(const Duration(seconds: 10))), + named: 'options', + )), + mockPlatform.getMultiVideoWithOptions( + options: argThat( + isInstanceOf().having( + (MultiVideoPickerOptions options) => options.limit, + 'limit', + equals(5)), + named: 'options', + )), ]); }); }); 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 6411acd092c..1e19561e7d5 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 @@ -135,21 +135,6 @@ class ImagePickerAndroid extends ImagePickerPlatform { return paths.isEmpty ? null : paths.first; } - Future> _getMultiVideoPath({ - Duration? maxDuration, - int? limit, - }) { - return _hostApi.pickVideos( - SourceSpecification(type: SourceType.gallery), - VideoSelectionOptions(maxDurationSeconds: maxDuration?.inSeconds), - GeneralOptions( - allowMultiple: true, - usePhotoPicker: useAndroidPhotoPicker, - limit: limit, - ), - ); - } - @override Future pickVideo({ required ImageSource source, @@ -280,9 +265,14 @@ class ImagePickerAndroid extends ImagePickerPlatform { Future> getMultiVideoWithOptions({ MultiVideoPickerOptions options = const MultiVideoPickerOptions(), }) async { - final List paths = await _getMultiVideoPath( - maxDuration: options.maxDuration, - limit: options.limit, + final List paths = await _hostApi.pickVideos( + SourceSpecification(type: SourceType.gallery), + VideoSelectionOptions(maxDurationSeconds: options.maxDuration?.inSeconds), + GeneralOptions( + allowMultiple: true, + usePhotoPicker: useAndroidPhotoPicker, + limit: options.limit, + ), ); if (paths.isEmpty) { 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 9d8a4790685..b0d84854418 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 @@ -1031,6 +1031,7 @@ class _FakeImagePickerApi implements ImagePickerApi { passedVideoOptions = options; passedAllowMultiple = generalOptions.allowMultiple; passedPhotoPickerFlag = generalOptions.usePhotoPicker; + limit = generalOptions.limit; return returnValue as List? ?? []; } From b5d0098b168542f3dcde9ada936fe3e866eef3b9 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 10 Aug 2025 14:25:59 -0400 Subject: [PATCH 11/15] Revert part of app-facing example change --- .../image_picker_ios/example/lib/main.dart | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) 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 dceeb09cd87..8d355cea62e 100755 --- a/packages/image_picker/image_picker_ios/example/lib/main.dart +++ b/packages/image_picker/image_picker_ios/example/lib/main.dart @@ -235,26 +235,18 @@ class _MyHomePageState extends State { itemBuilder: (BuildContext context, int index) { final XFile image = _mediaFileList![index]; final String? mime = lookupMimeType(_mediaFileList![index].path); - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text(image.name, - key: const Key('image_picker_example_picked_image_name')), - Semantics( - label: 'image_picker_example_picked_image', - child: mime == null || mime.startsWith('image/') - ? Image.file( - File(_mediaFileList![index].path), - errorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return const Center( - child: - Text('This image type is not supported')); - }, - ) - : _buildInlineVideoPlayer(index), - ), - ], + return Semantics( + label: 'image_picker_example_picked_image', + child: mime == null || mime.startsWith('image/') + ? Image.file( + File(_mediaFileList![index].path), + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return const Center( + child: Text('This image type is not supported')); + }, + ) + : _buildInlineVideoPlayer(index), ); }, itemCount: _mediaFileList!.length, From 21a2c50dddafa054b86526b6c933604adb4d5293 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 11 Aug 2025 10:50:06 -0400 Subject: [PATCH 12/15] Analysis fix --- packages/image_picker/image_picker_ios/example/lib/main.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 8d355cea62e..99a73e99ffe 100755 --- a/packages/image_picker/image_picker_ios/example/lib/main.dart +++ b/packages/image_picker/image_picker_ios/example/lib/main.dart @@ -234,12 +234,12 @@ class _MyHomePageState extends State { key: UniqueKey(), itemBuilder: (BuildContext context, int index) { final XFile image = _mediaFileList![index]; - final String? mime = lookupMimeType(_mediaFileList![index].path); + final String? mime = lookupMimeType(image.path); return Semantics( label: 'image_picker_example_picked_image', child: mime == null || mime.startsWith('image/') ? Image.file( - File(_mediaFileList![index].path), + File(image.path), errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { return const Center( From 9ebcff3bed6819e11c2d5e075512f371c311ecb2 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 11 Aug 2025 12:38:33 -0400 Subject: [PATCH 13/15] Fix UIImagePicker code path --- .../Sources/image_picker_ios/FLTImagePickerPlugin.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m index 678d848659b..d5ed37d73ad 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m @@ -123,7 +123,7 @@ - (void)launchUIImagePickerWithSource:(nonnull FLTSourceSpecification *)source imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; imagePickerController.delegate = self; NSMutableArray *mediaTypes = [[NSMutableArray alloc] init]; - if (context) { + if (context.includeImages) { [mediaTypes addObject:(NSString *)kUTTypeImage]; } if (context.includeVideo) { From caa52f6e7ea23649b0a23a99aa0b3b807f9abce7 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 15 Aug 2025 09:55:11 -0400 Subject: [PATCH 14/15] Update to published platform interface --- .../image_picker/example/pubspec.yaml | 3 +- .../image_picker/image_picker/pubspec.yaml | 3 +- .../image_picker_android/example/pubspec.yaml | 6 +--- .../image_picker_android/pubspec.yaml | 6 +--- .../image_picker_for_web/example/pubspec.yaml | 6 +--- .../image_picker_for_web/pubspec.yaml | 6 +--- .../image_picker_ios/example/pubspec.yaml | 6 +--- .../image_picker_ios/pubspec.yaml | 6 +--- .../image_picker_linux/example/pubspec.yaml | 6 +--- .../image_picker_linux/pubspec.yaml | 6 +--- .../image_picker_macos/example/pubspec.yaml | 6 +--- .../image_picker_macos/pubspec.yaml | 6 +--- .../CHANGELOG.md | 3 +- .../method_channel_image_picker.dart | 28 ------------------- .../image_picker_platform.dart | 2 +- .../test/image_picker_platform_test.dart | 12 ++++++++ .../image_picker_windows/example/pubspec.yaml | 6 +--- .../image_picker_windows/pubspec.yaml | 6 +--- 18 files changed, 28 insertions(+), 95 deletions(-) diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index aa2d82c9639..465d9315513 100644 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: # 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.10.0 + image_picker_platform_interface: ^2.11.0 mime: ^1.0.4 video_player: ^2.7.0 @@ -39,5 +39,4 @@ dependency_overrides: image_picker_ios: {path: ../../../../packages/image_picker/image_picker_ios} image_picker_linux: {path: ../../../../packages/image_picker/image_picker_linux} image_picker_macos: {path: ../../../../packages/image_picker/image_picker_macos} - image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} image_picker_windows: {path: ../../../../packages/image_picker/image_picker_windows} diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index bf5ab7eabab..5276b47dcda 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: image_picker_ios: ^0.8.8 image_picker_linux: ^0.2.1 image_picker_macos: ^0.2.1 - image_picker_platform_interface: ^2.10.0 + image_picker_platform_interface: ^2.11.0 image_picker_windows: ^0.2.1 dev_dependencies: @@ -57,5 +57,4 @@ dependency_overrides: image_picker_ios: {path: ../../../packages/image_picker/image_picker_ios} image_picker_linux: {path: ../../../packages/image_picker/image_picker_linux} image_picker_macos: {path: ../../../packages/image_picker/image_picker_macos} - image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} image_picker_windows: {path: ../../../packages/image_picker/image_picker_windows} diff --git a/packages/image_picker/image_picker_android/example/pubspec.yaml b/packages/image_picker/image_picker_android/example/pubspec.yaml index a1b2d037613..9df61214efc 100644 --- a/packages/image_picker/image_picker_android/example/pubspec.yaml +++ b/packages/image_picker/image_picker_android/example/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: # 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.10.0 + image_picker_platform_interface: ^2.11.0 mime: ^2.0.0 video_player: ^2.1.4 @@ -33,7 +33,3 @@ dev_dependencies: flutter: uses-material-design: true -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml index 846af93e7df..b6cade1ae3b 100755 --- a/packages/image_picker/image_picker_android/pubspec.yaml +++ b/packages/image_picker/image_picker_android/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^2.0.1 - image_picker_platform_interface: ^2.10.0 + image_picker_platform_interface: ^2.11.0 dev_dependencies: flutter_test: @@ -34,7 +34,3 @@ topics: - image-picker - files - file-selection -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_for_web/example/pubspec.yaml b/packages/image_picker/image_picker_for_web/example/pubspec.yaml index 4080c85efe0..ff13bae933c 100644 --- a/packages/image_picker/image_picker_for_web/example/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/example/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: sdk: flutter image_picker_for_web: path: ../ - image_picker_platform_interface: ^2.8.0 + image_picker_platform_interface: ^2.11.0 web: ^1.0.0 dev_dependencies: @@ -18,7 +18,3 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index e16f0faa698..98e86decbb3 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - image_picker_platform_interface: ^2.9.0 + image_picker_platform_interface: ^2.11.0 mime: ">=1.0.4 <3.0.0" web: ">=0.5.1 <2.0.0" @@ -34,7 +34,3 @@ topics: - image-picker - files - file-selection -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_ios/example/pubspec.yaml b/packages/image_picker/image_picker_ios/example/pubspec.yaml index 2937543cba5..1d1c431aa68 100755 --- a/packages/image_picker/image_picker_ios/example/pubspec.yaml +++ b/packages/image_picker/image_picker_ios/example/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: # 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.10.0 + image_picker_platform_interface: ^2.11.0 mime: ^2.0.0 video_player: ^2.1.4 @@ -28,7 +28,3 @@ dev_dependencies: flutter: uses-material-design: true -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_ios/pubspec.yaml b/packages/image_picker/image_picker_ios/pubspec.yaml index 3fc83551e26..84b8d372b1f 100755 --- a/packages/image_picker/image_picker_ios/pubspec.yaml +++ b/packages/image_picker/image_picker_ios/pubspec.yaml @@ -19,7 +19,7 @@ flutter: dependencies: flutter: sdk: flutter - image_picker_platform_interface: ^2.10.0 + image_picker_platform_interface: ^2.11.0 dev_dependencies: flutter_test: @@ -32,7 +32,3 @@ topics: - image-picker - files - file-selection -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_linux/example/pubspec.yaml b/packages/image_picker/image_picker_linux/example/pubspec.yaml index f626818de09..b1626f31057 100644 --- a/packages/image_picker/image_picker_linux/example/pubspec.yaml +++ b/packages/image_picker/image_picker_linux/example/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: # 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.11.0 mime: ^2.0.0 video_player: ^2.1.4 @@ -27,7 +27,3 @@ dev_dependencies: flutter: uses-material-design: true -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_linux/pubspec.yaml b/packages/image_picker/image_picker_linux/pubspec.yaml index b111423530e..ba1d4c4d71f 100644 --- a/packages/image_picker/image_picker_linux/pubspec.yaml +++ b/packages/image_picker/image_picker_linux/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: file_selector_platform_interface: ^2.2.0 flutter: sdk: flutter - image_picker_platform_interface: ^2.8.0 + image_picker_platform_interface: ^2.11.0 dev_dependencies: build_runner: ^2.1.5 @@ -32,7 +32,3 @@ topics: - image-picker - files - file-selection -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_macos/example/pubspec.yaml b/packages/image_picker/image_picker_macos/example/pubspec.yaml index 06f8093e306..4a61fe59517 100644 --- a/packages/image_picker/image_picker_macos/example/pubspec.yaml +++ b/packages/image_picker/image_picker_macos/example/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: # 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.11.0 mime: ^2.0.0 video_player: ^2.1.4 @@ -27,7 +27,3 @@ dev_dependencies: flutter: uses-material-design: true -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_macos/pubspec.yaml b/packages/image_picker/image_picker_macos/pubspec.yaml index 9562e677061..a9322ac481b 100644 --- a/packages/image_picker/image_picker_macos/pubspec.yaml +++ b/packages/image_picker/image_picker_macos/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: file_selector_platform_interface: ^2.3.0 flutter: sdk: flutter - image_picker_platform_interface: ^2.8.0 + image_picker_platform_interface: ^2.11.0 dev_dependencies: build_runner: ^2.1.5 @@ -32,7 +32,3 @@ topics: - image-picker - files - file-selection -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 8dde2aefe90..c87ceb07905 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,7 +1,6 @@ - ## 2.11.0 -* Adds `getMultiVideo` method. +* Adds `getMultiVideoWithOptions` method. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 2.10.1 diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart index 998bf5693ce..943ea760995 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/method_channel/method_channel_image_picker.dart @@ -35,21 +35,6 @@ class MethodChannelImagePicker extends ImagePickerPlatform { return path != null ? PickedFile(path) : null; } - @override - Future> getMultiVideoWithOptions({ - MultiVideoPickerOptions options = const MultiVideoPickerOptions(), - }) async { - final List? paths = await _getMultiVideoPath( - maxDuration: options.maxDuration, - limit: options.limit, - ); - if (paths == null) { - return []; - } - - return paths.map((dynamic path) => XFile(path as String)).toList(); - } - @override Future?> pickMultiImage({ double? maxWidth, @@ -100,19 +85,6 @@ class MethodChannelImagePicker extends ImagePickerPlatform { ); } - Future?> _getMultiVideoPath({ - Duration? maxDuration, - int? limit, - }) { - return _channel.invokeMethod?>( - 'pickMultiVideo', - { - 'maxDuration': maxDuration?.inSeconds, - 'limit': limit, - }, - ); - } - Future _getImagePath({ required ImageSource source, double? maxWidth, diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart index 410ffce4813..51074c864b2 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/platform_interface/image_picker_platform.dart @@ -327,7 +327,7 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// The videos come from the [ImageSource.gallery]. /// /// The `options` argument controls additional settings that can be used when - /// picking a video. See [VideoPickerOptions] for more details. + /// picking a video. See [MultiVideoPickerOptions] for more details. /// /// If no videos were picked, returns an empty list. Future> getMultiVideoWithOptions({ diff --git a/packages/image_picker/image_picker_platform_interface/test/image_picker_platform_test.dart b/packages/image_picker/image_picker_platform_interface/test/image_picker_platform_test.dart index 89dc1ae382d..c25f7ae9fe5 100644 --- a/packages/image_picker/image_picker_platform_interface/test/image_picker_platform_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/image_picker_platform_test.dart @@ -76,6 +76,18 @@ void main() { fakePath); }); }); + + test( + 'Default implementation of getMultiVideoWithOptions should throw ' + 'unimplemented error', () { + final FakeCameraDelegatingImagePickerPlatform implementation = + FakeCameraDelegatingImagePickerPlatform(); + + expect( + () => implementation.getMultiVideoWithOptions(), + throwsUnimplementedError, + ); + }); } class FakeImagePickerPlatform extends ImagePickerPlatform {} diff --git a/packages/image_picker/image_picker_windows/example/pubspec.yaml b/packages/image_picker/image_picker_windows/example/pubspec.yaml index 515d13111c1..3368e8d5640 100644 --- a/packages/image_picker/image_picker_windows/example/pubspec.yaml +++ b/packages/image_picker/image_picker_windows/example/pubspec.yaml @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - image_picker_platform_interface: ^2.8.0 + image_picker_platform_interface: ^2.11.0 image_picker_windows: # When depending on this package from a real application you should use: # image_picker_windows: ^x.y.z @@ -27,7 +27,3 @@ dev_dependencies: flutter: uses-material-design: true -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../../packages/image_picker/image_picker_platform_interface} diff --git a/packages/image_picker/image_picker_windows/pubspec.yaml b/packages/image_picker/image_picker_windows/pubspec.yaml index 46e77c14711..92e3a75717e 100644 --- a/packages/image_picker/image_picker_windows/pubspec.yaml +++ b/packages/image_picker/image_picker_windows/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: file_selector_windows: ^0.9.0 flutter: sdk: flutter - image_picker_platform_interface: ^2.8.0 + image_picker_platform_interface: ^2.11.0 dev_dependencies: build_runner: ^2.1.5 @@ -32,7 +32,3 @@ topics: - image-picker - files - file-selection -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_platform_interface: {path: ../../../packages/image_picker/image_picker_platform_interface} From 05e12dff3500767c7df8c4a6120fe4b992ff3694 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sat, 16 Aug 2025 07:00:15 -0400 Subject: [PATCH 15/15] Update to published dependencies --- .../image_picker/example/pubspec.yaml | 9 -------- .../image_picker/image_picker/pubspec.yaml | 21 ++++++------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index 465d9315513..b69c9124cea 100644 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -31,12 +31,3 @@ dev_dependencies: flutter: uses-material-design: true -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_android: {path: ../../../../packages/image_picker/image_picker_android} - image_picker_for_web: {path: ../../../../packages/image_picker/image_picker_for_web} - image_picker_ios: {path: ../../../../packages/image_picker/image_picker_ios} - image_picker_linux: {path: ../../../../packages/image_picker/image_picker_linux} - image_picker_macos: {path: ../../../../packages/image_picker/image_picker_macos} - image_picker_windows: {path: ../../../../packages/image_picker/image_picker_windows} diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 5276b47dcda..28cef5b855e 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -28,13 +28,13 @@ flutter: dependencies: flutter: sdk: flutter - image_picker_android: ^0.8.7 - image_picker_for_web: ">=2.2.0 <4.0.0" - image_picker_ios: ^0.8.8 - image_picker_linux: ^0.2.1 - image_picker_macos: ^0.2.1 + image_picker_android: ^0.8.13 + image_picker_for_web: ^3.1.0 + image_picker_ios: ^0.8.13 + image_picker_linux: ^0.2.2 + image_picker_macos: ^0.2.2 image_picker_platform_interface: ^2.11.0 - image_picker_windows: ^0.2.1 + image_picker_windows: ^0.2.2 dev_dependencies: build_runner: ^2.1.10 @@ -49,12 +49,3 @@ topics: - image-picker - files - file-selection -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins -dependency_overrides: - image_picker_android: {path: ../../../packages/image_picker/image_picker_android} - image_picker_for_web: {path: ../../../packages/image_picker/image_picker_for_web} - image_picker_ios: {path: ../../../packages/image_picker/image_picker_ios} - image_picker_linux: {path: ../../../packages/image_picker/image_picker_linux} - image_picker_macos: {path: ../../../packages/image_picker/image_picker_macos} - image_picker_windows: {path: ../../../packages/image_picker/image_picker_windows}