import 'dart:io'; import 'dart:async'; import 'package:farm_tpf/presentation/custom_widgets/hoz_list_view.dart'; import 'package:farm_tpf/presentation/custom_widgets/shimmer_image.dart'; import 'package:farm_tpf/utils/const_color.dart'; import 'package:farm_tpf/utils/const_string.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:video_player/video_player.dart'; class WidgetMediaHelper extends StatefulWidget { @override _WidgetMediaHelperState createState() => _WidgetMediaHelperState(); } class _WidgetMediaHelperState extends State { PickedFile _imageFile; dynamic _pickImageError; bool isVideo = false; VideoPlayerController _controller; VideoPlayerController _toBeDisposed; String _retrieveDataError; final ImagePicker _picker = ImagePicker(); List items = [ ItemMediaVM('http://lorempixel.com/640/480', true), ItemMediaVM( 'https://s3.amazonaws.com/uifaces/faces/twitter/rickdt/128.jpg', true), ItemMediaVM('http://lorempixel.com/640/480/food', true), ItemMediaVM('http://lorempixel.com/640/480/animals', true), ItemMediaVM('http://lorempixel.com/640/480/fashion', true), ]; @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(8), child: Column( children: [ _actionButton(), SizedBox( height: 4.0, ), _buildListPoster(), 1 == 1 ? FutureBuilder( future: retrieveLostData(), builder: (BuildContext context, AsyncSnapshot snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: case ConnectionState.waiting: return const Text( 'You have not yet picked an image.', textAlign: TextAlign.center, ); case ConnectionState.done: return isVideo ? _previewVideo() : _previewImage(); default: if (snapshot.hasError) { return Text( 'Pick image/video error: ${snapshot.error}}', textAlign: TextAlign.center, ); } else { return const Text( 'You have not yet picked an image.', textAlign: TextAlign.center, ); } } }, ) : (isVideo ? _previewVideo() : _previewImage()), ], )); } _buildListPoster() { return WrapContentHozListView( itemBuilder: (context, index) { var item = items[index]; return _WidgetItemMedia(item); }, separatorBuilder: (context, index) { return SizedBox(width: 14); }, list: items, ); } Widget viewResult() { FutureBuilder( future: retrieveLostData(), builder: (BuildContext context, AsyncSnapshot snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: case ConnectionState.waiting: return const Text( 'You have not yet picked an image.', textAlign: TextAlign.center, ); case ConnectionState.done: return isVideo ? _previewVideo() : _previewImage(); default: if (snapshot.hasError) { return Text( 'Pick image/video error: ${snapshot.error}}', textAlign: TextAlign.center, ); } else { return const Text( 'You have not yet picked an image.', textAlign: TextAlign.center, ); } } }, ); } Widget multipleChoice() { return CupertinoAlertDialog( title: Text(label_title_select_media), actions: [ CupertinoDialogAction( child: const Text(label_select_image_from_library), onPressed: () { Navigator.pop(context, 'Discard'); isVideo = false; _onImageButtonPressed(ImageSource.gallery, context: context); }), CupertinoDialogAction( child: const Text(label_take_photo), onPressed: () { Navigator.pop(context, 'Discard'); isVideo = false; _onImageButtonPressed(ImageSource.camera, context: context); }), CupertinoDialogAction( child: const Text(label_select_video_from_library), onPressed: () { Navigator.pop(context, 'Discard'); isVideo = true; _onImageButtonPressed(ImageSource.gallery); }), CupertinoDialogAction( child: const Text(label_record_video), onPressed: () { Navigator.pop(context, 'Discard'); isVideo = true; _onImageButtonPressed(ImageSource.camera); }), CupertinoDialogAction( child: const Text(label_cancel), textStyle: TextStyle(fontWeight: FontWeight.bold), isDefaultAction: true, onPressed: () { Navigator.pop(context, 'Cancel'); }), ], ); } Widget _actionButton() { return SizedBox( width: double.infinity, height: 44, child: FlatButton( onPressed: () { showDialog( context: context, barrierDismissible: true, builder: (context) => Opacity( child: multipleChoice(), opacity: 1, )); }, color: COLOR_CONST.DEFAULT, shape: RoundedRectangleBorder( borderRadius: new BorderRadius.circular(7.0), ), child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.image, color: Colors.white), SizedBox( width: 8.0, ), Text( button_add_media, style: TextStyle( fontWeight: FontWeight.bold, color: COLOR_CONST.WHITE), ) ], ), )), ); } Future _playVideo(PickedFile file) async { if (file != null && mounted) { await _disposeVideoController(); _controller = VideoPlayerController.file(File(file.path)); await _controller.setVolume(1.0); await _controller.initialize(); await _controller.setLooping(true); await _controller.play(); setState(() {}); } } void _onImageButtonPressed(ImageSource source, {BuildContext context}) async { if (_controller != null) { await _controller.setVolume(0.0); } if (isVideo) { final PickedFile file = await _picker.getVideo( source: source, maxDuration: const Duration(seconds: 10)); await _playVideo(file); } else { await _displayPickImageDialog(context, (double maxWidth, double maxHeight, int quality) async { try { final pickedFile = await _picker.getImage( source: source, maxWidth: maxWidth, maxHeight: maxHeight, imageQuality: quality, ); setState(() { _imageFile = pickedFile; }); } catch (e) { setState(() { _pickImageError = e; }); } }); } } @override void deactivate() { if (_controller != null) { _controller.setVolume(0.0); _controller.pause(); } super.deactivate(); } @override void dispose() { _disposeVideoController(); super.dispose(); } Future _disposeVideoController() async { if (_toBeDisposed != null) { await _toBeDisposed.dispose(); } _toBeDisposed = _controller; _controller = null; } Widget _previewVideo() { final Text retrieveError = _getRetrieveErrorWidget(); if (retrieveError != null) { return retrieveError; } if (_controller == null) { return const Text( 'You have not yet picked a video', textAlign: TextAlign.center, ); } return Padding( padding: const EdgeInsets.all(10.0), child: AspectRatioVideo(_controller), ); } Widget _previewImage() { final Text retrieveError = _getRetrieveErrorWidget(); if (retrieveError != null) { return retrieveError; } if (_imageFile != null) { return Image.file(File(_imageFile.path), width: 100, height: 100); } else if (_pickImageError != null) { return Text( 'Pick image error: $_pickImageError', textAlign: TextAlign.center, ); } else { return const Text( 'You have not yet picked an image.', textAlign: TextAlign.center, ); } } Future retrieveLostData() async { final LostData response = await _picker.getLostData(); if (response.isEmpty) { return; } if (response.file != null) { if (response.type == RetrieveType.video) { isVideo = true; await _playVideo(response.file); } else { isVideo = false; setState(() { _imageFile = response.file; }); } } else { _retrieveDataError = response.exception.code; } } Text _getRetrieveErrorWidget() { if (_retrieveDataError != null) { final Text result = Text(_retrieveDataError); _retrieveDataError = null; return result; } return null; } Future _displayPickImageDialog( BuildContext context, OnPickImageCallback onPick) async { onPick(null, null, null); } } typedef void OnPickImageCallback( double maxWidth, double maxHeight, int quality); class AspectRatioVideo extends StatefulWidget { AspectRatioVideo(this.controller); final VideoPlayerController controller; @override AspectRatioVideoState createState() => AspectRatioVideoState(); } class AspectRatioVideoState extends State { VideoPlayerController get controller => widget.controller; bool initialized = false; void _onVideoControllerUpdate() { if (!mounted) { return; } if (initialized != controller.value.initialized) { initialized = controller.value.initialized; setState(() {}); } } @override void initState() { super.initState(); controller.addListener(_onVideoControllerUpdate); } @override void dispose() { controller.removeListener(_onVideoControllerUpdate); super.dispose(); } @override Widget build(BuildContext context) { if (initialized) { return Container( width: 100, height: 100, child: AspectRatio( aspectRatio: controller.value?.aspectRatio, child: VideoPlayer(controller), ), ); } else { return Container(); } } } class _WidgetItemMedia extends StatelessWidget { final ItemMediaVM item; _WidgetItemMedia(this.item); BuildContext _context; @override Widget build(BuildContext context) { _context = context; return GestureDetector( onTap: () { print("Show preview image or video"); }, child: Stack( alignment: Alignment.bottomCenter, overflow: Overflow.visible, children: [ Positioned( child: ClipRRect( borderRadius: BorderRadius.circular(8), child: ShimmerImage( item.photo, width: 93, height: 124, fit: BoxFit.cover, ), )), Positioned( top: -5, right: -5, child: IconButton( icon: Icon( Icons.cancel, color: Colors.redAccent, ), onPressed: () { print("On tap delete media"); }), ) ], )); } } class ItemMediaVM { String photo; bool isVideo; ItemMediaVM(this.photo, this.isVideo); }