Skip to content

Commit c0cba0b

Browse files
authored
[image_picker] add getMedia method (flutter#3892)
Adds `getMedia` and `getMultipleMedia` methods to all platforms. fixes flutter#89159
1 parent 7869896 commit c0cba0b

File tree

10 files changed

+627
-66
lines changed

10 files changed

+627
-66
lines changed

packages/image_picker/image_picker/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.8.9
2+
3+
* Adds `getMedia` and `getMultipleMedia` methods.
4+
15
## 0.8.8
26

37
* Adds initial support for Windows, macOS, and Linux.

packages/image_picker/image_picker/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ When under high memory pressure the Android system may kill the MainActivity of
5959
the application using the image_picker. On Android the image_picker makes use
6060
of the default `Intent.ACTION_GET_CONTENT` or `MediaStore.ACTION_IMAGE_CAPTURE`
6161
intents. This means that while the intent is executing the source application
62-
is moved to the background and becomes eligable for cleanup when the system is
62+
is moved to the background and becomes eligible for cleanup when the system is
6363
low on memory. When the intent finishes executing, Android will restart the
6464
application. Since the data is never returned to the original call use the
6565
`ImagePicker.retrieveLostData()` method to retrieve the lost data. For example:
@@ -180,6 +180,10 @@ final XFile? galleryVideo =
180180
final XFile? cameraVideo = await picker.pickVideo(source: ImageSource.camera);
181181
// Pick multiple images.
182182
final List<XFile> images = await picker.pickMultiImage();
183+
// Pick singe image or video.
184+
final XFile? media = await picker.pickMedia();
185+
// Pick multiple images and videos.
186+
final List<XFile> medias = await picker.pickMultipleMedia();
183187
```
184188

185189
## Migrating to 0.8.2+

packages/image_picker/image_picker/example/lib/main.dart

Lines changed: 102 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'dart:io';
1010
import 'package:flutter/foundation.dart';
1111
import 'package:flutter/material.dart';
1212
import 'package:image_picker/image_picker.dart';
13+
import 'package:mime/mime.dart';
1314
import 'package:video_player/video_player.dart';
1415

1516
void main() {
@@ -38,10 +39,10 @@ class MyHomePage extends StatefulWidget {
3839
}
3940

4041
class _MyHomePageState extends State<MyHomePage> {
41-
List<XFile>? _imageFileList;
42+
List<XFile>? _mediaFileList;
4243

4344
void _setImageFileListFromFile(XFile? value) {
44-
_imageFileList = value == null ? null : <XFile>[value];
45+
_mediaFileList = value == null ? null : <XFile>[value];
4546
}
4647

4748
dynamic _pickImageError;
@@ -80,8 +81,12 @@ class _MyHomePageState extends State<MyHomePage> {
8081
}
8182
}
8283

83-
Future<void> _onImageButtonPressed(ImageSource source,
84-
{required BuildContext context, bool isMultiImage = false}) async {
84+
Future<void> _onImageButtonPressed(
85+
ImageSource source, {
86+
required BuildContext context,
87+
bool isMultiImage = false,
88+
bool isMedia = false,
89+
}) async {
8590
if (_controller != null) {
8691
await _controller!.setVolume(0.0);
8792
}
@@ -94,14 +99,42 @@ class _MyHomePageState extends State<MyHomePage> {
9499
await _displayPickImageDialog(context,
95100
(double? maxWidth, double? maxHeight, int? quality) async {
96101
try {
97-
final List<XFile> pickedFileList = await _picker.pickMultiImage(
102+
final List<XFile> pickedFileList = isMedia
103+
? await _picker.pickMultipleMedia(
104+
maxWidth: maxWidth,
105+
maxHeight: maxHeight,
106+
imageQuality: quality,
107+
)
108+
: await _picker.pickMultiImage(
109+
maxWidth: maxWidth,
110+
maxHeight: maxHeight,
111+
imageQuality: quality,
112+
);
113+
setState(() {
114+
_mediaFileList = pickedFileList;
115+
});
116+
} catch (e) {
117+
setState(() {
118+
_pickImageError = e;
119+
});
120+
}
121+
});
122+
} else if (isMedia) {
123+
await _displayPickImageDialog(context,
124+
(double? maxWidth, double? maxHeight, int? quality) async {
125+
try {
126+
final List<XFile> pickedFileList = <XFile>[];
127+
final XFile? media = await _picker.pickMedia(
98128
maxWidth: maxWidth,
99129
maxHeight: maxHeight,
100130
imageQuality: quality,
101131
);
102-
setState(() {
103-
_imageFileList = pickedFileList;
104-
});
132+
if (media != null) {
133+
pickedFileList.add(media);
134+
setState(() {
135+
_mediaFileList = pickedFileList;
136+
});
137+
}
105138
} catch (e) {
106139
setState(() {
107140
_pickImageError = e;
@@ -179,28 +212,34 @@ class _MyHomePageState extends State<MyHomePage> {
179212
if (retrieveError != null) {
180213
return retrieveError;
181214
}
182-
if (_imageFileList != null) {
215+
if (_mediaFileList != null) {
183216
return Semantics(
184217
label: 'image_picker_example_picked_images',
185218
child: ListView.builder(
186219
key: UniqueKey(),
187220
itemBuilder: (BuildContext context, int index) {
221+
final String? mime = lookupMimeType(_mediaFileList![index].path);
222+
188223
// Why network for web?
189224
// See https://pub.dev/packages/image_picker_for_web#limitations-on-the-web-platform
190225
return Semantics(
191226
label: 'image_picker_example_picked_image',
192227
child: kIsWeb
193-
? Image.network(_imageFileList![index].path)
194-
: Image.file(
195-
File(_imageFileList![index].path),
196-
errorBuilder: (BuildContext context, Object error,
197-
StackTrace? stackTrace) =>
198-
const Center(
199-
child: Text('This image type is not supported')),
200-
),
228+
? Image.network(_mediaFileList![index].path)
229+
: (mime == null || mime.startsWith('image/')
230+
? Image.file(
231+
File(_mediaFileList![index].path),
232+
errorBuilder: (BuildContext context, Object error,
233+
StackTrace? stackTrace) {
234+
return const Center(
235+
child:
236+
Text('This image type is not supported'));
237+
},
238+
)
239+
: _buildInlineVideoPlayer(index)),
201240
);
202241
},
203-
itemCount: _imageFileList!.length,
242+
itemCount: _mediaFileList!.length,
204243
),
205244
);
206245
} else if (_pickImageError != null) {
@@ -216,6 +255,17 @@ class _MyHomePageState extends State<MyHomePage> {
216255
}
217256
}
218257

258+
Widget _buildInlineVideoPlayer(int index) {
259+
final VideoPlayerController controller =
260+
VideoPlayerController.file(File(_mediaFileList![index].path));
261+
const double volume = kIsWeb ? 0.0 : 1.0;
262+
controller.setVolume(volume);
263+
controller.initialize();
264+
controller.setLooping(true);
265+
controller.play();
266+
return Center(child: AspectRatioVideo(controller));
267+
}
268+
219269
Widget _handlePreview() {
220270
if (isVideo) {
221271
return _previewVideo();
@@ -239,7 +289,7 @@ class _MyHomePageState extends State<MyHomePage> {
239289
if (response.files == null) {
240290
_setImageFileListFromFile(response.file);
241291
} else {
242-
_imageFileList = response.files;
292+
_mediaFileList = response.files;
243293
}
244294
});
245295
}
@@ -300,6 +350,39 @@ class _MyHomePageState extends State<MyHomePage> {
300350
child: const Icon(Icons.photo),
301351
),
302352
),
353+
Padding(
354+
padding: const EdgeInsets.only(top: 16.0),
355+
child: FloatingActionButton(
356+
onPressed: () {
357+
isVideo = false;
358+
_onImageButtonPressed(
359+
ImageSource.gallery,
360+
context: context,
361+
isMultiImage: true,
362+
isMedia: true,
363+
);
364+
},
365+
heroTag: 'multipleMedia',
366+
tooltip: 'Pick Multiple Media from gallery',
367+
child: const Icon(Icons.photo_library),
368+
),
369+
),
370+
Padding(
371+
padding: const EdgeInsets.only(top: 16.0),
372+
child: FloatingActionButton(
373+
onPressed: () {
374+
isVideo = false;
375+
_onImageButtonPressed(
376+
ImageSource.gallery,
377+
context: context,
378+
isMedia: true,
379+
);
380+
},
381+
heroTag: 'media',
382+
tooltip: 'Pick Single Media from gallery',
383+
child: const Icon(Icons.photo_library),
384+
),
385+
),
303386
Padding(
304387
padding: const EdgeInsets.only(top: 16.0),
305388
child: FloatingActionButton(

packages/image_picker/image_picker/example/lib/readme_excerpts.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ Future<List<XFile?>> readmePickExample() async {
4242
final XFile? cameraVideo = await picker.pickVideo(source: ImageSource.camera);
4343
// Pick multiple images.
4444
final List<XFile> images = await picker.pickMultiImage();
45+
// Pick singe image or video.
46+
final XFile? media = await picker.pickMedia();
47+
// Pick multiple images and videos.
48+
final List<XFile> medias = await picker.pickMultipleMedia();
4549
// #enddocregion Pick
4650

4751
// Return everything for the sanity check test.
@@ -50,7 +54,9 @@ Future<List<XFile?>> readmePickExample() async {
5054
photo,
5155
galleryVideo,
5256
cameraVideo,
53-
if (images.isEmpty) null else images.first
57+
if (images.isEmpty) null else images.first,
58+
media,
59+
if (medias.isEmpty) null else medias.first,
5460
];
5561
}
5662

packages/image_picker/image_picker/example/pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ dependencies:
1717
# The example app is bundled with the plugin so we use a path dependency on
1818
# the parent directory to use the current plugin's version.
1919
path: ../
20-
image_picker_platform_interface: ^2.7.0
20+
image_picker_platform_interface: ^2.8.0
21+
mime: ^1.0.4
2122
video_player: ^2.1.4
2223

2324
dev_dependencies:

packages/image_picker/image_picker/example/test/readme_excerpts_test.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ class FakeImagePicker extends ImagePickerPlatform {
5050
return <XFile>[XFile('multiImage')];
5151
}
5252

53+
@override
54+
Future<List<XFile>> getMedia({required MediaOptions options}) async {
55+
return options.allowMultiple
56+
? <XFile>[XFile('medias'), XFile('medias')]
57+
: <XFile>[XFile('media')];
58+
}
59+
5360
@override
5461
Future<XFile?> getVideo(
5562
{required ImageSource source,

0 commit comments

Comments
 (0)