video_widget.dart 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import 'dart:io' as io;
  2. import 'package:chewie/chewie.dart';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter/widgets.dart';
  6. import 'package:fluttertoast/fluttertoast.dart';
  7. import 'package:logging/logging.dart';
  8. import 'package:photos/models/file.dart';
  9. import 'package:photos/ui/thumbnail_widget.dart';
  10. import 'package:photos/ui/video_controls.dart';
  11. import 'package:photos/utils/file_util.dart';
  12. import 'package:photos/utils/toast_util.dart';
  13. import 'package:video_player/video_player.dart';
  14. import 'package:visibility_detector/visibility_detector.dart';
  15. class VideoWidget extends StatefulWidget {
  16. final File file;
  17. final bool autoPlay;
  18. final String tagPrefix;
  19. final Function(bool) playbackCallback;
  20. VideoWidget(
  21. this.file, {
  22. this.autoPlay = false,
  23. this.tagPrefix,
  24. this.playbackCallback,
  25. Key key,
  26. }) : super(key: key);
  27. @override
  28. _VideoWidgetState createState() => _VideoWidgetState();
  29. }
  30. class _VideoWidgetState extends State<VideoWidget> {
  31. final _logger = Logger("VideoWidget");
  32. VideoPlayerController _videoPlayerController;
  33. ChewieController _chewieController;
  34. double _progress;
  35. bool _isPlaying;
  36. @override
  37. void initState() {
  38. super.initState();
  39. if (widget.file.isRemoteFile()) {
  40. _loadNetworkVideo();
  41. } else if (widget.file.isSharedMediaToAppSandbox()) {
  42. final localFile = io.File(getSharedMediaFilePath(widget.file));
  43. if (localFile.existsSync()) {
  44. _logger.fine("loading from app cache");
  45. _setVideoPlayerController(file: localFile);
  46. } else if (widget.file.uploadedFileID != null) {
  47. _loadNetworkVideo();
  48. }
  49. } else {
  50. widget.file.getAsset().then((asset) async {
  51. if (asset == null || !(await asset.exists)) {
  52. if (widget.file.uploadedFileID != null) {
  53. _loadNetworkVideo();
  54. }
  55. } else {
  56. asset.getMediaUrl().then((url) {
  57. _setVideoPlayerController(url: url);
  58. });
  59. }
  60. });
  61. }
  62. }
  63. void _loadNetworkVideo() {
  64. getFileFromServer(
  65. widget.file,
  66. progressCallback: (count, total) {
  67. if (mounted) {
  68. setState(() {
  69. _progress = count / total;
  70. if (_progress == 1) {
  71. showToast("decrypting video...", toastLength: Toast.LENGTH_SHORT);
  72. }
  73. });
  74. }
  75. },
  76. ).then((file) {
  77. if (file != null) {
  78. _setVideoPlayerController(file: file);
  79. }
  80. });
  81. }
  82. @override
  83. void dispose() {
  84. if (_videoPlayerController != null) {
  85. _videoPlayerController.dispose();
  86. }
  87. if (_chewieController != null) {
  88. _chewieController.dispose();
  89. }
  90. super.dispose();
  91. }
  92. VideoPlayerController _setVideoPlayerController({String url, io.File file}) {
  93. VideoPlayerController videoPlayerController;
  94. if (url != null) {
  95. videoPlayerController = VideoPlayerController.network(url);
  96. } else {
  97. videoPlayerController = VideoPlayerController.file(file);
  98. }
  99. return _videoPlayerController = videoPlayerController
  100. ..initialize().whenComplete(() {
  101. if (mounted) {
  102. setState(() {});
  103. }
  104. });
  105. }
  106. @override
  107. Widget build(BuildContext context) {
  108. final content = _videoPlayerController != null &&
  109. _videoPlayerController.value.isInitialized
  110. ? _getVideoPlayer()
  111. : _getLoadingWidget();
  112. return VisibilityDetector(
  113. key: Key(widget.file.tag()),
  114. onVisibilityChanged: (info) {
  115. if (info.visibleFraction < 1) {
  116. if (mounted && _chewieController != null) {
  117. _chewieController.pause();
  118. }
  119. }
  120. },
  121. child: Hero(
  122. tag: widget.tagPrefix + widget.file.tag(),
  123. child: content,
  124. ),
  125. );
  126. }
  127. Widget _getLoadingWidget() {
  128. return Stack(children: [
  129. _getThumbnail(),
  130. Container(
  131. color: Colors.black12,
  132. constraints: BoxConstraints.expand(),
  133. ),
  134. Center(
  135. child: SizedBox.fromSize(
  136. size: Size.square(30),
  137. child: _progress == null || _progress == 1
  138. ? CupertinoActivityIndicator()
  139. : CircularProgressIndicator(
  140. value: _progress,
  141. valueColor: AlwaysStoppedAnimation<Color>(
  142. Color.fromRGBO(45, 194, 98, 1.0),
  143. ),
  144. ),
  145. ),
  146. ),
  147. ]);
  148. }
  149. Widget _getThumbnail() {
  150. return Container(
  151. child: ThumbnailWidget(
  152. widget.file,
  153. fit: BoxFit.contain,
  154. ),
  155. constraints: BoxConstraints.expand(),
  156. );
  157. }
  158. Widget _getVideoPlayer() {
  159. _videoPlayerController.addListener(() {
  160. if (_isPlaying != _videoPlayerController.value.isPlaying) {
  161. _isPlaying = _videoPlayerController.value.isPlaying;
  162. if (widget.playbackCallback != null) {
  163. widget.playbackCallback(_isPlaying);
  164. }
  165. }
  166. });
  167. _chewieController = ChewieController(
  168. videoPlayerController: _videoPlayerController,
  169. aspectRatio: _videoPlayerController.value.aspectRatio,
  170. autoPlay: widget.autoPlay,
  171. autoInitialize: true,
  172. looping: true,
  173. allowFullScreen: false,
  174. customControls: VideoControls(),
  175. );
  176. return Chewie(controller: _chewieController);
  177. }
  178. }