import 'dart:io'; import 'dart:async'; 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(); @override Widget build(BuildContext context) { return Container( child: Column( children: [ _actionButton(), 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()), ], )); } 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: 55, 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: Row( children: [ Icon(Icons.image), 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(); } } }