Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 06fc7d1

Browse files
authored
[image_picker_platform_interface] Add methods that return package:cross_file (#4072)
1 parent 7daf189 commit 06fc7d1

File tree

8 files changed

+735
-17
lines changed

8 files changed

+735
-17
lines changed

packages/image_picker/image_picker_platform_interface/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## 2.2.0
2+
3+
* Added new methods that return `XFile` (from `package:cross_file`)
4+
* `getImage` (will deprecate `pickImage`)
5+
* `getVideo` (will deprecate `pickVideo`)
6+
* `getMultiImage` (will deprecate `pickMultiImage`)
7+
8+
_`PickedFile` will also be marked as deprecated in an upcoming release._
9+
110
## 2.1.0
211

312
* Add `pickMultiImage` method.

packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44

55
export 'package:image_picker_platform_interface/src/platform_interface/image_picker_platform.dart';
66
export 'package:image_picker_platform_interface/src/types/types.dart';
7+
export 'package:cross_file/cross_file.dart';

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

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
2626
int? imageQuality,
2727
CameraDevice preferredCameraDevice = CameraDevice.rear,
2828
}) async {
29-
String? path = await _pickImagePath(
29+
String? path = await _getImagePath(
3030
source: source,
3131
maxWidth: maxWidth,
3232
maxHeight: maxHeight,
@@ -42,21 +42,17 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
4242
double? maxHeight,
4343
int? imageQuality,
4444
}) async {
45-
final List<dynamic>? paths = await _pickMultiImagePath(
45+
final List<dynamic>? paths = await _getMultiImagePath(
4646
maxWidth: maxWidth,
4747
maxHeight: maxHeight,
4848
imageQuality: imageQuality,
4949
);
5050
if (paths == null) return null;
5151

52-
final List<PickedFile> files = [];
53-
for (final path in paths) {
54-
files.add(PickedFile(path));
55-
}
56-
return files;
52+
return paths.map((path) => PickedFile(path)).toList();
5753
}
5854

59-
Future<List<dynamic>?> _pickMultiImagePath({
55+
Future<List<dynamic>?> _getMultiImagePath({
6056
double? maxWidth,
6157
double? maxHeight,
6258
int? imageQuality,
@@ -84,7 +80,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
8480
);
8581
}
8682

87-
Future<String?> _pickImagePath({
83+
Future<String?> _getImagePath({
8884
required ImageSource source,
8985
double? maxWidth,
9086
double? maxHeight,
@@ -122,15 +118,15 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
122118
CameraDevice preferredCameraDevice = CameraDevice.rear,
123119
Duration? maxDuration,
124120
}) async {
125-
final String? path = await _pickVideoPath(
121+
final String? path = await _getVideoPath(
126122
source: source,
127123
maxDuration: maxDuration,
128124
preferredCameraDevice: preferredCameraDevice,
129125
);
130126
return path != null ? PickedFile(path) : null;
131127
}
132128

133-
Future<String?> _pickVideoPath({
129+
Future<String?> _getVideoPath({
134130
required ImageSource source,
135131
CameraDevice preferredCameraDevice = CameraDevice.rear,
136132
Duration? maxDuration,
@@ -154,7 +150,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
154150
return LostData.empty();
155151
}
156152

157-
assert(result.containsKey('path') ^ result.containsKey('errorCode'));
153+
assert(result.containsKey('path') != result.containsKey('errorCode'));
158154

159155
final String? type = result['type'];
160156
assert(type == kTypeImage || type == kTypeVideo);
@@ -180,4 +176,88 @@ class MethodChannelImagePicker extends ImagePickerPlatform {
180176
type: retrieveType,
181177
);
182178
}
179+
180+
@override
181+
Future<XFile?> getImage({
182+
required ImageSource source,
183+
double? maxWidth,
184+
double? maxHeight,
185+
int? imageQuality,
186+
CameraDevice preferredCameraDevice = CameraDevice.rear,
187+
}) async {
188+
String? path = await _getImagePath(
189+
source: source,
190+
maxWidth: maxWidth,
191+
maxHeight: maxHeight,
192+
imageQuality: imageQuality,
193+
preferredCameraDevice: preferredCameraDevice,
194+
);
195+
return path != null ? XFile(path) : null;
196+
}
197+
198+
@override
199+
Future<List<XFile>?> getMultiImage({
200+
double? maxWidth,
201+
double? maxHeight,
202+
int? imageQuality,
203+
}) async {
204+
final List<dynamic>? paths = await _getMultiImagePath(
205+
maxWidth: maxWidth,
206+
maxHeight: maxHeight,
207+
imageQuality: imageQuality,
208+
);
209+
if (paths == null) return null;
210+
211+
return paths.map((path) => XFile(path)).toList();
212+
}
213+
214+
@override
215+
Future<XFile?> getVideo({
216+
required ImageSource source,
217+
CameraDevice preferredCameraDevice = CameraDevice.rear,
218+
Duration? maxDuration,
219+
}) async {
220+
final String? path = await _getVideoPath(
221+
source: source,
222+
maxDuration: maxDuration,
223+
preferredCameraDevice: preferredCameraDevice,
224+
);
225+
return path != null ? XFile(path) : null;
226+
}
227+
228+
@override
229+
Future<LostDataResponse> getLostData() async {
230+
final Map<String, dynamic>? result =
231+
await _channel.invokeMapMethod<String, dynamic>('retrieve');
232+
233+
if (result == null) {
234+
return LostDataResponse.empty();
235+
}
236+
237+
assert(result.containsKey('path') != result.containsKey('errorCode'));
238+
239+
final String? type = result['type'];
240+
assert(type == kTypeImage || type == kTypeVideo);
241+
242+
RetrieveType? retrieveType;
243+
if (type == kTypeImage) {
244+
retrieveType = RetrieveType.image;
245+
} else if (type == kTypeVideo) {
246+
retrieveType = RetrieveType.video;
247+
}
248+
249+
PlatformException? exception;
250+
if (result.containsKey('errorCode')) {
251+
exception = PlatformException(
252+
code: result['errorCode'], message: result['errorMessage']);
253+
}
254+
255+
final String? path = result['path'];
256+
257+
return LostDataResponse(
258+
file: path != null ? XFile(path) : null,
259+
exception: exception,
260+
type: retrieveType,
261+
);
262+
}
183263
}

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

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
import 'dart:async';
66

7+
import 'package:cross_file/cross_file.dart';
78
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
8-
99
import 'package:image_picker_platform_interface/src/method_channel/method_channel_image_picker.dart';
1010
import 'package:image_picker_platform_interface/src/types/types.dart';
1111

@@ -144,4 +144,111 @@ abstract class ImagePickerPlatform extends PlatformInterface {
144144
Future<LostData> retrieveLostData() {
145145
throw UnimplementedError('retrieveLostData() has not been implemented.');
146146
}
147+
148+
/// Returns an [XFile] with the image that was picked.
149+
///
150+
/// The `source` argument controls where the image comes from. This can
151+
/// be either [ImageSource.camera] or [ImageSource.gallery].
152+
///
153+
/// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used
154+
/// in addition to a size modification, of which the usage is explained below.
155+
///
156+
/// If specified, the image will be at most `maxWidth` wide and
157+
/// `maxHeight` tall. Otherwise the image will be returned at it's
158+
/// original width and height.
159+
///
160+
/// The `imageQuality` argument modifies the quality of the image, ranging from 0-100
161+
/// where 100 is the original/max quality. If `imageQuality` is null, the image with
162+
/// the original quality will be returned. Compression is only supported for certain
163+
/// image types such as JPEG. If compression is not supported for the image that is picked,
164+
/// a warning message will be logged.
165+
///
166+
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
167+
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
168+
/// Defaults to [CameraDevice.rear]. Note that Android has no documented parameter for an intent to specify if
169+
/// the front or rear camera should be opened, this function is not guaranteed
170+
/// to work on an Android device.
171+
///
172+
/// In Android, the MainActivity can be destroyed for various reasons. If that happens, the result will be lost
173+
/// in this call. You can then call [getLostData] when your app relaunches to retrieve the lost data.
174+
///
175+
/// If no images were picked, the return value is null.
176+
Future<XFile?> getImage({
177+
required ImageSource source,
178+
double? maxWidth,
179+
double? maxHeight,
180+
int? imageQuality,
181+
CameraDevice preferredCameraDevice = CameraDevice.rear,
182+
}) {
183+
throw UnimplementedError('getImage() has not been implemented.');
184+
}
185+
186+
/// Returns a [List<XFile>] with the images that were picked.
187+
///
188+
/// The images come from the [ImageSource.gallery].
189+
///
190+
/// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used
191+
/// in addition to a size modification, of which the usage is explained below.
192+
///
193+
/// If specified, the image will be at most `maxWidth` wide and
194+
/// `maxHeight` tall. Otherwise the image will be returned at it's
195+
/// original width and height.
196+
///
197+
/// The `imageQuality` argument modifies the quality of the images, ranging from 0-100
198+
/// where 100 is the original/max quality. If `imageQuality` is null, the images with
199+
/// the original quality will be returned. Compression is only supported for certain
200+
/// image types such as JPEG. If compression is not supported for the image that is picked,
201+
/// a warning message will be logged.
202+
///
203+
/// If no images were picked, the return value is null.
204+
Future<List<XFile>?> getMultiImage({
205+
double? maxWidth,
206+
double? maxHeight,
207+
int? imageQuality,
208+
}) {
209+
throw UnimplementedError('getMultiImage() has not been implemented.');
210+
}
211+
212+
/// Returns a [XFile] containing the video that was picked.
213+
///
214+
/// The [source] argument controls where the video comes from. This can
215+
/// be either [ImageSource.camera] or [ImageSource.gallery].
216+
///
217+
/// The [maxDuration] argument specifies the maximum duration of the captured video. If no [maxDuration] is specified,
218+
/// the maximum duration will be infinite.
219+
///
220+
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
221+
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
222+
/// Defaults to [CameraDevice.rear].
223+
///
224+
/// In Android, the MainActivity can be destroyed for various fo reasons. If that happens, the result will be lost
225+
/// in this call. You can then call [getLostData] when your app relaunches to retrieve the lost data.
226+
///
227+
/// If no images were picked, the return value is null.
228+
Future<XFile?> getVideo({
229+
required ImageSource source,
230+
CameraDevice preferredCameraDevice = CameraDevice.rear,
231+
Duration? maxDuration,
232+
}) {
233+
throw UnimplementedError('getVideo() has not been implemented.');
234+
}
235+
236+
/// Retrieve the lost [XFile] file when [getImage], [getMultiImage] or [getVideo] failed because the MainActivity is
237+
/// destroyed. (Android only)
238+
///
239+
/// Image or video can be lost if the MainActivity is destroyed. And there is no guarantee that the MainActivity is
240+
/// always alive. Call this method to retrieve the lost data and process the data according to your APP's business logic.
241+
///
242+
/// Returns a [LostDataResponse] object if successfully retrieved the lost data. The [LostDataResponse] object can
243+
/// represent either a successful image/video selection, or a failure.
244+
///
245+
/// Calling this on a non-Android platform will throw [UnimplementedError] exception.
246+
///
247+
/// See also:
248+
/// * [LostDataResponse], for what's included in the response.
249+
/// * [Android Activity Lifecycle](https://developer.android.com/reference/android/app/Activity.html), for more
250+
/// information on MainActivity destruction.
251+
Future<LostDataResponse> getLostData() {
252+
throw UnimplementedError('getLostData() has not been implemented.');
253+
}
147254
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:cross_file/cross_file.dart';
6+
import 'package:flutter/services.dart';
7+
import 'package:image_picker_platform_interface/src/types/types.dart';
8+
9+
/// The response object of [ImagePicker.getLostData].
10+
///
11+
/// Only applies to Android.
12+
/// See also:
13+
/// * [ImagePicker.getLostData] for more details on retrieving lost data.
14+
class LostDataResponse {
15+
/// Creates an instance with the given [file], [exception], and [type]. Any of
16+
/// the params may be null, but this is never considered to be empty.
17+
LostDataResponse({this.file, this.exception, this.type});
18+
19+
/// Initializes an instance with all member params set to null and considered
20+
/// to be empty.
21+
LostDataResponse.empty()
22+
: file = null,
23+
exception = null,
24+
type = null,
25+
_empty = true;
26+
27+
/// Whether it is an empty response.
28+
///
29+
/// An empty response should have [file], [exception] and [type] to be null.
30+
bool get isEmpty => _empty;
31+
32+
/// The file that was lost in a previous [getImage], [getMultiImage] or [getVideo] call due to MainActivity being destroyed.
33+
///
34+
/// Can be null if [exception] exists.
35+
final XFile? file;
36+
37+
/// The exception of the last [getImage], [getMultiImage] or [getVideo].
38+
///
39+
/// If the last [getImage], [getMultiImage] or [getVideo] threw some exception before the MainActivity destruction,
40+
/// this variable keeps that exception.
41+
/// You should handle this exception as if the [getImage], [getMultiImage] or [getVideo] got an exception when
42+
/// the MainActivity was not destroyed.
43+
///
44+
/// Note that it is not the exception that caused the destruction of the MainActivity.
45+
final PlatformException? exception;
46+
47+
/// Can either be [RetrieveType.image] or [RetrieveType.video];
48+
///
49+
/// If the lost data is empty, this will be null.
50+
final RetrieveType? type;
51+
52+
bool _empty = false;
53+
}

packages/image_picker/image_picker_platform_interface/lib/src/types/types.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export 'camera_device.dart';
66
export 'image_source.dart';
77
export 'retrieve_type.dart';
88
export 'picked_file/picked_file.dart';
9+
export 'lost_data_response.dart';
910

1011
/// Denotes that an image is being picked.
1112
const String kTypeImage = 'image';

packages/image_picker/image_picker_platform_interface/pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ repository: https://github.com/flutter/plugins/tree/master/packages/image_picker
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
55
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
66
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
7-
version: 2.1.0
7+
version: 2.2.0
88

99
environment:
1010
sdk: ">=2.12.0 <3.0.0"
@@ -16,6 +16,7 @@ dependencies:
1616
http: ^0.13.0
1717
meta: ^1.3.0
1818
plugin_platform_interface: ^2.0.0
19+
cross_file: ^0.3.1+1
1920

2021
dev_dependencies:
2122
flutter_test:

0 commit comments

Comments
 (0)