Skip to content

Commit

Permalink
[image_picker] getMedia platform changes (#4174)
Browse files Browse the repository at this point in the history
Adds `getMedia` and `getMultipleMedia` methods to  image_picker_platform_interface.

precursor to #3892

part of flutter/flutter#89159
  • Loading branch information
tarrinneal authored Jun 9, 2023
1 parent ecf2b68 commit 6565f17
Show file tree
Hide file tree
Showing 12 changed files with 316 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.8.0

* Adds `getMedia` method.

## 2.7.0

* Adds `CameraDelegatingImagePickerPlatform` as a base class for platform
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,30 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
return paths.map((dynamic path) => XFile(path as String)).toList();
}

@override
Future<List<XFile>> getMedia({
required MediaOptions options,
}) async {
final ImageOptions imageOptions = options.imageOptions;

final Map<String, dynamic> args = <String, dynamic>{
'maxImageWidth': imageOptions.maxWidth,
'maxImageHeight': imageOptions.maxHeight,
'imageQuality': imageOptions.imageQuality,
'allowMultiple': options.allowMultiple,
};

final List<XFile>? paths = await _channel
.invokeMethod<List<dynamic>?>(
'pickMedia',
args,
)
.then((List<dynamic>? paths) =>
paths?.map((dynamic path) => XFile(path as String)).toList());

return paths ?? <XFile>[];
}

@override
Future<XFile?> getVideo({
required ImageSource source,
Expand Down Expand Up @@ -280,13 +304,21 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
assert(result.containsKey('path') != result.containsKey('errorCode'));

final String? type = result['type'] as String?;
assert(type == kTypeImage || type == kTypeVideo);
assert(
type == kTypeImage || type == kTypeVideo || type == kTypeMedia,
);

RetrieveType? retrieveType;
if (type == kTypeImage) {
retrieveType = RetrieveType.image;
} else if (type == kTypeVideo) {
retrieveType = RetrieveType.video;
switch (type) {
case kTypeImage:
retrieveType = RetrieveType.image;
break;
case kTypeVideo:
retrieveType = RetrieveType.video;
break;
case kTypeMedia:
retrieveType = RetrieveType.media;
break;
}

PlatformException? exception;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,24 @@ abstract class ImagePickerPlatform extends PlatformInterface {
throw UnimplementedError('getMultiImage() has not been implemented.');
}

/// Returns a [List<XFile>] with the images and/or videos that were picked.
/// The images and videos come from the gallery.
///
/// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and
/// above only support HEIC images if used in addition to a size modification,
/// of which the usage is explained below.
///
/// 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 [getLostData] when your app relaunches to retrieve the lost data.
///
/// If no images or videos were picked, the return value is an empty list.
Future<List<XFile>> getMedia({
required MediaOptions options,
}) {
throw UnimplementedError('getMedia() has not been implemented.');
}

/// Returns a [XFile] containing the video that was picked.
///
/// The [source] argument controls where the video comes from. This can
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,40 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'types.dart';

/// Specifies options for picking a single image from the device's camera or gallery.
///
/// This class inheritance is a byproduct of the api changing over time.
/// It exists solely to avoid breaking changes.
class ImagePickerOptions extends ImageOptions {
/// Creates an instance with the given [maxHeight], [maxWidth], [imageQuality],
/// [referredCameraDevice] and [requestFullMetadata].
const ImagePickerOptions({
super.maxHeight,
super.maxWidth,
super.imageQuality,
super.requestFullMetadata,
this.preferredCameraDevice = CameraDevice.rear,
}) : super();

/// Creates an instance with the given [maxHeight], [maxWidth], [imageQuality],
/// [referredCameraDevice] and [requestFullMetadata].
ImagePickerOptions.createAndValidate({
super.maxHeight,
super.maxWidth,
super.imageQuality,
super.requestFullMetadata,
this.preferredCameraDevice = CameraDevice.rear,
}) : super.createAndValidate();

/// Used to specify the camera to use when the `source` is [ImageSource.camera].
///
/// Ignored if the source is not [ImageSource.camera], or the chosen camera is not
/// supported on the device. Defaults to [CameraDevice.rear].
final CameraDevice preferredCameraDevice;
}

/// Specifies image-specific options for picking.
class ImageOptions {
/// Creates an instance with the given [maxHeight], [maxWidth], [imageQuality]
Expand All @@ -13,6 +47,18 @@ class ImageOptions {
this.requestFullMetadata = true,
});

/// Creates an instance with the given [maxHeight], [maxWidth], [imageQuality]
/// and [requestFullMetadata]. Throws if options are not valid.
ImageOptions.createAndValidate({
this.maxHeight,
this.maxWidth,
this.imageQuality,
this.requestFullMetadata = true,
}) {
_validateOptions(
maxWidth: maxWidth, maxHeight: maxHeight, imageQuality: imageQuality);
}

/// The maximum width of the image, in pixels.
///
/// If null, the image will only be resized if [maxHeight] is specified.
Expand All @@ -38,4 +84,19 @@ class ImageOptions {
//
// Defaults to true.
final bool requestFullMetadata;

/// Validates that all values are within required ranges. Throws if not.
static void _validateOptions(
{double? maxWidth, final double? maxHeight, int? imageQuality}) {
if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
throw ArgumentError.value(
imageQuality, 'imageQuality', 'must be between 0 and 100');
}
if (maxWidth != null && maxWidth < 0) {
throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative');
}
if (maxHeight != null && maxHeight < 0) {
throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative');
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class LostDataResponse {
/// An empty response should have [file], [exception] and [type] to be null.
bool get isEmpty => _empty;

/// The file that was lost in a previous [getImage], [getMultiImage] or [getVideo] call due to MainActivity being destroyed.
/// The file that was lost in a previous [getImage], [getMultiImage],
/// [getVideo] or [getMedia] call due to MainActivity being destroyed.
///
/// Can be null if [exception] exists.
final XFile? file;
Expand All @@ -51,7 +52,7 @@ class LostDataResponse {
/// Note that it is not the exception that caused the destruction of the MainActivity.
final PlatformException? exception;

/// Can either be [RetrieveType.image] or [RetrieveType.video];
/// Can either be [RetrieveType.image], [RetrieveType.video], or [RetrieveType.media].
///
/// If the lost data is empty, this will be null.
final RetrieveType? type;
Expand Down
Original file line number Diff line number Diff line change
@@ -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';

import '../../image_picker_platform_interface.dart';

/// Specifies options for selecting items when using [ImagePickerPlatform.getMedia].
@immutable
class MediaOptions {
/// Construct a new MediaOptions instance.
const MediaOptions({
this.imageOptions = const ImageOptions(),
required this.allowMultiple,
});

/// Options that will apply to images upon selection.
final ImageOptions imageOptions;

/// Whether to allow for selecting multiple media.
final bool allowMultiple;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../../image_picker_platform_interface.dart';

/// The type of media to allow the user to select with [ImagePickerPlatform.getMedia].
enum MediaSelectionType {
/// Static pictures.
image,

/// Videos.
video,
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ enum RetrieveType {
image,

/// A video. See [ImagePicker.pickVideo].
video
video,

/// Either a video or a static picture. See [ImagePicker.pickMedia].
media,
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
export 'camera_delegate.dart';
export 'camera_device.dart';
export 'image_options.dart';
export 'image_picker_options.dart';
export 'image_source.dart';
export 'lost_data_response.dart';
export 'media_options.dart';
export 'media_selection_type.dart';
export 'multi_image_picker_options.dart';
export 'picked_file/picked_file.dart';
export 'retrieve_type.dart';
Expand All @@ -17,3 +18,6 @@ const String kTypeImage = 'image';

/// Denotes that a video is being picked.
const String kTypeVideo = 'video';

/// Denotes that either a video or image is being picked.
const String kTypeMedia = 'media';
Original file line number Diff line number Diff line change
Expand Up @@ -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.7.0
version: 2.8.0

environment:
sdk: ">=2.18.0 <4.0.0"
Expand Down
Loading

0 comments on commit 6565f17

Please sign in to comment.