@@ -14,6 +14,7 @@ import 'package:flutter_driver/driver_extension.dart';
14
14
import 'package:image_picker_android/image_picker_android.dart' ;
15
15
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart' ;
16
16
// #enddocregion photo-picker-example
17
+ import 'package:mime/mime.dart' ;
17
18
import 'package:video_player/video_player.dart' ;
18
19
19
20
void appMain () {
@@ -62,7 +63,7 @@ class _MyHomePageState extends State<MyHomePage> {
62
63
}
63
64
64
65
dynamic _pickImageError;
65
- bool isVideo = false ;
66
+ bool _isVideo = false ;
66
67
67
68
VideoPlayerController ? _controller;
68
69
VideoPlayerController ? _toBeDisposed;
@@ -77,18 +78,10 @@ class _MyHomePageState extends State<MyHomePage> {
77
78
if (file != null && mounted) {
78
79
await _disposeVideoController ();
79
80
late VideoPlayerController controller;
80
- if (kIsWeb) {
81
- controller = VideoPlayerController .network (file.path);
82
- } else {
83
- controller = VideoPlayerController .file (File (file.path));
84
- }
81
+
82
+ controller = VideoPlayerController .file (File (file.path));
85
83
_controller = controller;
86
- // In web, most browsers won't honor a programmatic call to .play
87
- // if the video has a sound track (and is not muted).
88
- // Mute the video so it auto-plays in web!
89
- // This is not needed if the call to .play is the result of user
90
- // interaction (clicking on a "play" button, for example).
91
- const double volume = kIsWeb ? 0.0 : 1.0 ;
84
+ const double volume = 1.0 ;
92
85
await controller.setVolume (volume);
93
86
await controller.initialize ();
94
87
await controller.setLooping (true );
@@ -101,12 +94,13 @@ class _MyHomePageState extends State<MyHomePage> {
101
94
ImageSource source, {
102
95
required BuildContext context,
103
96
bool isMultiImage = false ,
97
+ bool isMedia = false ,
104
98
}) async {
105
99
if (_controller != null ) {
106
100
await _controller! .setVolume (0.0 );
107
101
}
108
102
if (context.mounted) {
109
- if (isVideo ) {
103
+ if (_isVideo ) {
110
104
final XFile ? file = await _picker.getVideo (
111
105
source: source, maxDuration: const Duration (seconds: 10 ));
112
106
if (file != null && context.mounted) {
@@ -117,15 +111,54 @@ class _MyHomePageState extends State<MyHomePage> {
117
111
await _displayPickImageDialog (context,
118
112
(double ? maxWidth, double ? maxHeight, int ? quality) async {
119
113
try {
120
- final List <XFile >? pickedFileList = await _picker.getMultiImage (
121
- maxWidth: maxWidth,
122
- maxHeight: maxHeight,
123
- imageQuality: quality,
124
- );
114
+ final List <XFile >? pickedFileList = isMedia
115
+ ? await _picker.getMedia (
116
+ options: MediaOptions (
117
+ allowMultiple: isMultiImage,
118
+ imageOptions: ImageOptions (
119
+ maxWidth: maxWidth,
120
+ maxHeight: maxHeight,
121
+ imageQuality: quality,
122
+ )),
123
+ )
124
+ : await _picker.getMultiImage (
125
+ maxWidth: maxWidth,
126
+ maxHeight: maxHeight,
127
+ imageQuality: quality,
128
+ );
125
129
if (pickedFileList != null && context.mounted) {
126
130
_showPickedSnackBar (context, pickedFileList);
127
131
}
128
- setState (() => _mediaFileList = pickedFileList);
132
+ setState (() {
133
+ _mediaFileList = pickedFileList;
134
+ });
135
+ } catch (e) {
136
+ setState (() {
137
+ _pickImageError = e;
138
+ });
139
+ }
140
+ });
141
+ } else if (isMedia) {
142
+ await _displayPickImageDialog (context,
143
+ (double ? maxWidth, double ? maxHeight, int ? quality) async {
144
+ try {
145
+ final List <XFile > pickedFileList = < XFile > [];
146
+ final XFile ? media = _firstOrNull (await _picker.getMedia (
147
+ options: MediaOptions (
148
+ allowMultiple: isMultiImage,
149
+ imageOptions: ImageOptions (
150
+ maxWidth: maxWidth,
151
+ maxHeight: maxHeight,
152
+ imageQuality: quality,
153
+ )),
154
+ ));
155
+
156
+ if (media != null ) {
157
+ pickedFileList.add (media);
158
+ setState (() {
159
+ _mediaFileList = pickedFileList;
160
+ });
161
+ }
129
162
} catch (e) {
130
163
setState (() => _pickImageError = e);
131
164
}
@@ -207,18 +240,25 @@ class _MyHomePageState extends State<MyHomePage> {
207
240
key: UniqueKey (),
208
241
itemBuilder: (BuildContext context, int index) {
209
242
final XFile image = _mediaFileList! [index];
243
+ final String ? mime = lookupMimeType (_mediaFileList! [index].path);
210
244
return Column (
211
245
mainAxisSize: MainAxisSize .min,
212
246
children: < Widget > [
213
247
Text (image.name,
214
248
key: const Key ('image_picker_example_picked_image_name' )),
215
- // Why network for web?
216
- // See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform
217
249
Semantics (
218
250
label: 'image_picker_example_picked_image' ,
219
- child: kIsWeb
220
- ? Image .network (image.path)
221
- : Image .file (File (image.path)),
251
+ child: mime == null || mime.startsWith ('image/' )
252
+ ? Image .file (
253
+ File (_mediaFileList! [index].path),
254
+ errorBuilder: (BuildContext context, Object error,
255
+ StackTrace ? stackTrace) {
256
+ return const Center (
257
+ child:
258
+ Text ('This image type is not supported' ));
259
+ },
260
+ )
261
+ : _buildInlineVideoPlayer (index),
222
262
),
223
263
],
224
264
);
@@ -239,8 +279,19 @@ class _MyHomePageState extends State<MyHomePage> {
239
279
}
240
280
}
241
281
282
+ Widget _buildInlineVideoPlayer (int index) {
283
+ final VideoPlayerController controller =
284
+ VideoPlayerController .file (File (_mediaFileList! [index].path));
285
+ const double volume = 1.0 ;
286
+ controller.setVolume (volume);
287
+ controller.initialize ();
288
+ controller.setLooping (true );
289
+ controller.play ();
290
+ return Center (child: AspectRatioVideo (controller));
291
+ }
292
+
242
293
Widget _handlePreview () {
243
- if (isVideo ) {
294
+ if (_isVideo ) {
244
295
return _previewVideo ();
245
296
} else {
246
297
return _previewImages ();
@@ -254,10 +305,10 @@ class _MyHomePageState extends State<MyHomePage> {
254
305
}
255
306
if (response.file != null ) {
256
307
if (response.type == RetrieveType .video) {
257
- isVideo = true ;
308
+ _isVideo = true ;
258
309
await _playVideo (response.file);
259
310
} else {
260
- isVideo = false ;
311
+ _isVideo = false ;
261
312
setState (() {
262
313
if (response.files == null ) {
263
314
_setImageFileListFromFile (response.file);
@@ -316,7 +367,7 @@ class _MyHomePageState extends State<MyHomePage> {
316
367
child: FloatingActionButton (
317
368
key: const Key ('image_picker_example_from_gallery' ),
318
369
onPressed: () {
319
- isVideo = false ;
370
+ _isVideo = false ;
320
371
_onImageButtonPressed (ImageSource .gallery, context: context);
321
372
},
322
373
heroTag: 'image0' ,
@@ -328,7 +379,40 @@ class _MyHomePageState extends State<MyHomePage> {
328
379
padding: const EdgeInsets .only (top: 16.0 ),
329
380
child: FloatingActionButton (
330
381
onPressed: () {
331
- isVideo = false ;
382
+ _isVideo = false ;
383
+ _onImageButtonPressed (
384
+ ImageSource .gallery,
385
+ context: context,
386
+ isMultiImage: true ,
387
+ isMedia: true ,
388
+ );
389
+ },
390
+ heroTag: 'multipleMedia' ,
391
+ tooltip: 'Pick Multiple Media from gallery' ,
392
+ child: const Icon (Icons .photo_library),
393
+ ),
394
+ ),
395
+ Padding (
396
+ padding: const EdgeInsets .only (top: 16.0 ),
397
+ child: FloatingActionButton (
398
+ onPressed: () {
399
+ _isVideo = false ;
400
+ _onImageButtonPressed (
401
+ ImageSource .gallery,
402
+ context: context,
403
+ isMedia: true ,
404
+ );
405
+ },
406
+ heroTag: 'media' ,
407
+ tooltip: 'Pick Single Media from gallery' ,
408
+ child: const Icon (Icons .photo_library),
409
+ ),
410
+ ),
411
+ Padding (
412
+ padding: const EdgeInsets .only (top: 16.0 ),
413
+ child: FloatingActionButton (
414
+ onPressed: () {
415
+ _isVideo = false ;
332
416
_onImageButtonPressed (
333
417
ImageSource .gallery,
334
418
context: context,
@@ -344,7 +428,7 @@ class _MyHomePageState extends State<MyHomePage> {
344
428
padding: const EdgeInsets .only (top: 16.0 ),
345
429
child: FloatingActionButton (
346
430
onPressed: () {
347
- isVideo = false ;
431
+ _isVideo = false ;
348
432
_onImageButtonPressed (ImageSource .camera, context: context);
349
433
},
350
434
heroTag: 'image2' ,
@@ -357,7 +441,7 @@ class _MyHomePageState extends State<MyHomePage> {
357
441
child: FloatingActionButton (
358
442
backgroundColor: Colors .red,
359
443
onPressed: () {
360
- isVideo = true ;
444
+ _isVideo = true ;
361
445
_onImageButtonPressed (ImageSource .gallery, context: context);
362
446
},
363
447
heroTag: 'video0' ,
@@ -370,7 +454,7 @@ class _MyHomePageState extends State<MyHomePage> {
370
454
child: FloatingActionButton (
371
455
backgroundColor: Colors .red,
372
456
onPressed: () {
373
- isVideo = true ;
457
+ _isVideo = true ;
374
458
_onImageButtonPressed (ImageSource .camera, context: context);
375
459
},
376
460
heroTag: 'video1' ,
@@ -510,3 +594,7 @@ class AspectRatioVideoState extends State<AspectRatioVideo> {
510
594
}
511
595
}
512
596
}
597
+
598
+ T ? _firstOrNull <T >(List <T > list) {
599
+ return list.isEmpty ? null : list.first;
600
+ }
0 commit comments