video_widget.dart 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. VideoWidget(
  20. this.file, {
  21. this.autoPlay = false,
  22. this.tagPrefix,
  23. Key key,
  24. }) : super(key: key);
  25. @override
  26. _VideoWidgetState createState() => _VideoWidgetState();
  27. }
  28. class _VideoWidgetState extends State<VideoWidget> {
  29. Logger _logger = Logger("VideoWidget");
  30. VideoPlayerController _videoPlayerController;
  31. ChewieController _chewieController;
  32. double _progress;
  33. @override
  34. void initState() {
  35. super.initState();
  36. if (widget.file.localID == null) {
  37. _loadNetworkVideo();
  38. } else {
  39. widget.file.getAsset().then((asset) async {
  40. if (asset == null || !(await asset.exists)) {
  41. if (widget.file.uploadedFileID != null) {
  42. _loadNetworkVideo();
  43. }
  44. } else {
  45. asset.getMediaUrl().then((url) {
  46. _setVideoPlayerController(url: url);
  47. });
  48. }
  49. });
  50. }
  51. }
  52. void _loadNetworkVideo() {
  53. if (!widget.file.isEncrypted) {
  54. _setVideoPlayerController(url: widget.file.getStreamUrl());
  55. _videoPlayerController.addListener(() {
  56. if (_videoPlayerController.value.hasError) {
  57. _logger.warning(_videoPlayerController.value.errorDescription);
  58. showToast(
  59. "The video has not been processed yet. Downloading the original one...",
  60. toastLength: Toast.LENGTH_SHORT);
  61. _setVideoPlayerController(url: widget.file.getDownloadUrl());
  62. }
  63. });
  64. } else {
  65. getFileFromServer(
  66. widget.file,
  67. progressCallback: (count, total) {
  68. setState(() {
  69. _progress = count / total;
  70. if (_progress == 1) {
  71. showToast("Decrypting video...", toastLength: Toast.LENGTH_SHORT);
  72. }
  73. });
  74. },
  75. ).then((file) {
  76. _setVideoPlayerController(file: file);
  77. });
  78. }
  79. }
  80. @override
  81. void dispose() {
  82. if (_videoPlayerController != null) {
  83. _videoPlayerController.dispose();
  84. }
  85. if (_chewieController != null) {
  86. _chewieController.dispose();
  87. }
  88. super.dispose();
  89. }
  90. VideoPlayerController _setVideoPlayerController({String url, io.File file}) {
  91. var videoPlayerController;
  92. if (url != null) {
  93. videoPlayerController = VideoPlayerController.network(url);
  94. } else {
  95. videoPlayerController = VideoPlayerController.file(file);
  96. }
  97. return _videoPlayerController = videoPlayerController
  98. ..initialize().whenComplete(() {
  99. if (mounted) {
  100. setState(() {});
  101. }
  102. });
  103. }
  104. @override
  105. Widget build(BuildContext context) {
  106. final content = _videoPlayerController != null &&
  107. _videoPlayerController.value.initialized
  108. ? _getVideoPlayer()
  109. : _getLoadingWidget();
  110. return VisibilityDetector(
  111. key: Key(widget.file.tag()),
  112. onVisibilityChanged: (info) {
  113. if (info.visibleFraction < 1) {
  114. if (mounted && _chewieController != null) {
  115. _chewieController.pause();
  116. }
  117. }
  118. },
  119. child: Hero(
  120. tag: widget.tagPrefix + widget.file.tag(),
  121. child: content,
  122. ),
  123. );
  124. }
  125. Widget _getLoadingWidget() {
  126. return Stack(children: [
  127. _getThumbnail(),
  128. Container(
  129. color: Colors.black12,
  130. constraints: BoxConstraints.expand(),
  131. ),
  132. Center(
  133. child: SizedBox.fromSize(
  134. size: Size.square(30),
  135. child: _progress == null || _progress == 1
  136. ? CupertinoActivityIndicator()
  137. : CircularProgressIndicator(value: _progress),
  138. ),
  139. ),
  140. ]);
  141. }
  142. Widget _getThumbnail() {
  143. return Container(
  144. child: ThumbnailWidget(
  145. widget.file,
  146. fit: BoxFit.contain,
  147. ),
  148. constraints: BoxConstraints.expand(),
  149. );
  150. }
  151. Widget _getVideoPlayer() {
  152. _chewieController = ChewieController(
  153. videoPlayerController: _videoPlayerController,
  154. aspectRatio: _videoPlayerController.value.aspectRatio,
  155. autoPlay: widget.autoPlay,
  156. autoInitialize: true,
  157. looping: true,
  158. allowFullScreen: false,
  159. customControls: VideoControls(),
  160. );
  161. return Chewie(controller: _chewieController);
  162. }
  163. }