@@ -14,6 +14,7 @@ import 'package:flutter_driver/driver_extension.dart';
1414import 'package:image_picker_android/image_picker_android.dart' ;
1515import 'package:image_picker_platform_interface/image_picker_platform_interface.dart' ;
1616// #enddocregion photo-picker-example
17+ import 'package:mime/mime.dart' ;
1718import 'package:video_player/video_player.dart' ;
1819
1920void appMain () {
@@ -62,7 +63,7 @@ class _MyHomePageState extends State<MyHomePage> {
6263 }
6364
6465 dynamic _pickImageError;
65- bool isVideo = false ;
66+ bool _isVideo = false ;
6667
6768 VideoPlayerController ? _controller;
6869 VideoPlayerController ? _toBeDisposed;
@@ -77,18 +78,10 @@ class _MyHomePageState extends State<MyHomePage> {
7778 if (file != null && mounted) {
7879 await _disposeVideoController ();
7980 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));
8583 _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 ;
9285 await controller.setVolume (volume);
9386 await controller.initialize ();
9487 await controller.setLooping (true );
@@ -101,12 +94,13 @@ class _MyHomePageState extends State<MyHomePage> {
10194 ImageSource source, {
10295 required BuildContext context,
10396 bool isMultiImage = false ,
97+ bool isMedia = false ,
10498 }) async {
10599 if (_controller != null ) {
106100 await _controller! .setVolume (0.0 );
107101 }
108102 if (context.mounted) {
109- if (isVideo ) {
103+ if (_isVideo ) {
110104 final XFile ? file = await _picker.getVideo (
111105 source: source, maxDuration: const Duration (seconds: 10 ));
112106 if (file != null && context.mounted) {
@@ -117,15 +111,54 @@ class _MyHomePageState extends State<MyHomePage> {
117111 await _displayPickImageDialog (context,
118112 (double ? maxWidth, double ? maxHeight, int ? quality) async {
119113 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+ );
125129 if (pickedFileList != null && context.mounted) {
126130 _showPickedSnackBar (context, pickedFileList);
127131 }
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+ }
129162 } catch (e) {
130163 setState (() => _pickImageError = e);
131164 }
@@ -207,18 +240,25 @@ class _MyHomePageState extends State<MyHomePage> {
207240 key: UniqueKey (),
208241 itemBuilder: (BuildContext context, int index) {
209242 final XFile image = _mediaFileList! [index];
243+ final String ? mime = lookupMimeType (_mediaFileList! [index].path);
210244 return Column (
211245 mainAxisSize: MainAxisSize .min,
212246 children: < Widget > [
213247 Text (image.name,
214248 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
217249 Semantics (
218250 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),
222262 ),
223263 ],
224264 );
@@ -239,8 +279,19 @@ class _MyHomePageState extends State<MyHomePage> {
239279 }
240280 }
241281
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+
242293 Widget _handlePreview () {
243- if (isVideo ) {
294+ if (_isVideo ) {
244295 return _previewVideo ();
245296 } else {
246297 return _previewImages ();
@@ -254,10 +305,10 @@ class _MyHomePageState extends State<MyHomePage> {
254305 }
255306 if (response.file != null ) {
256307 if (response.type == RetrieveType .video) {
257- isVideo = true ;
308+ _isVideo = true ;
258309 await _playVideo (response.file);
259310 } else {
260- isVideo = false ;
311+ _isVideo = false ;
261312 setState (() {
262313 if (response.files == null ) {
263314 _setImageFileListFromFile (response.file);
@@ -316,7 +367,7 @@ class _MyHomePageState extends State<MyHomePage> {
316367 child: FloatingActionButton (
317368 key: const Key ('image_picker_example_from_gallery' ),
318369 onPressed: () {
319- isVideo = false ;
370+ _isVideo = false ;
320371 _onImageButtonPressed (ImageSource .gallery, context: context);
321372 },
322373 heroTag: 'image0' ,
@@ -328,7 +379,40 @@ class _MyHomePageState extends State<MyHomePage> {
328379 padding: const EdgeInsets .only (top: 16.0 ),
329380 child: FloatingActionButton (
330381 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 ;
332416 _onImageButtonPressed (
333417 ImageSource .gallery,
334418 context: context,
@@ -344,7 +428,7 @@ class _MyHomePageState extends State<MyHomePage> {
344428 padding: const EdgeInsets .only (top: 16.0 ),
345429 child: FloatingActionButton (
346430 onPressed: () {
347- isVideo = false ;
431+ _isVideo = false ;
348432 _onImageButtonPressed (ImageSource .camera, context: context);
349433 },
350434 heroTag: 'image2' ,
@@ -357,7 +441,7 @@ class _MyHomePageState extends State<MyHomePage> {
357441 child: FloatingActionButton (
358442 backgroundColor: Colors .red,
359443 onPressed: () {
360- isVideo = true ;
444+ _isVideo = true ;
361445 _onImageButtonPressed (ImageSource .gallery, context: context);
362446 },
363447 heroTag: 'video0' ,
@@ -370,7 +454,7 @@ class _MyHomePageState extends State<MyHomePage> {
370454 child: FloatingActionButton (
371455 backgroundColor: Colors .red,
372456 onPressed: () {
373- isVideo = true ;
457+ _isVideo = true ;
374458 _onImageButtonPressed (ImageSource .camera, context: context);
375459 },
376460 heroTag: 'video1' ,
@@ -510,3 +594,7 @@ class AspectRatioVideoState extends State<AspectRatioVideo> {
510594 }
511595 }
512596}
597+
598+ T ? _firstOrNull <T >(List <T > list) {
599+ return list.isEmpty ? null : list.first;
600+ }
0 commit comments