LocalVideoPlayer.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:flutter/material.dart';
  4. import 'package:video_player/video_player.dart';
  5. import 'package:flutter/services.dart';
  6. import 'package:screen/screen.dart';
  7. class LocalVideoPlayer extends StatefulWidget {
  8. final String source;
  9. bool isFullScreen;
  10. LocalVideoPlayer(this.source, {this.isFullScreen = false});
  11. @override
  12. _LocalVideoPlayerState createState() => _LocalVideoPlayerState();
  13. }
  14. class _LocalVideoPlayerState extends State<LocalVideoPlayer> {
  15. VideoPlayerController controller;
  16. VoidCallback listener;
  17. bool hideBottom = true;
  18. @override
  19. void initState() {
  20. super.initState();
  21. listener = () {
  22. if (!mounted) {
  23. return;
  24. }
  25. setState(() {});
  26. };
  27. File _sourceFile = File('file://${widget.source}');
  28. controller = VideoPlayerController.file(_sourceFile);
  29. controller.initialize();
  30. controller.setLooping(true);
  31. controller.addListener(listener);
  32. controller.play();
  33. Screen.keepOn(true);
  34. if (widget.isFullScreen) {
  35. SystemChrome.setEnabledSystemUIOverlays([]);
  36. SystemChrome.setPreferredOrientations([
  37. DeviceOrientation.landscapeLeft,
  38. DeviceOrientation.landscapeRight,
  39. ]);
  40. }
  41. }
  42. @override
  43. void dispose() {
  44. controller.dispose();
  45. Screen.keepOn(false);
  46. if (widget.isFullScreen) {
  47. SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
  48. SystemChrome.setPreferredOrientations([
  49. DeviceOrientation.portraitUp,
  50. DeviceOrientation.portraitDown,
  51. DeviceOrientation.landscapeLeft,
  52. DeviceOrientation.landscapeRight,
  53. ]);
  54. }
  55. super.dispose();
  56. }
  57. @override
  58. Widget build(BuildContext context) {
  59. return Scaffold(
  60. body: PlayView(
  61. controller,
  62. allowFullScreen: !widget.isFullScreen,
  63. ),
  64. );
  65. }
  66. }
  67. class PlayView extends StatefulWidget {
  68. VideoPlayerController controller;
  69. bool allowFullScreen;
  70. PlayView(this.controller, {this.allowFullScreen = true});
  71. @override
  72. _PlayViewState createState() => _PlayViewState();
  73. }
  74. class _PlayViewState extends State<PlayView> {
  75. VideoPlayerController get controller => widget.controller;
  76. bool hideBottom = true;
  77. void onClickPlay() {
  78. if (!controller.value.initialized) {
  79. return;
  80. }
  81. setState(() {
  82. hideBottom = false;
  83. });
  84. if (controller.value.isPlaying) {
  85. controller.pause();
  86. } else {
  87. Future.delayed(const Duration(seconds: 3), () {
  88. if (!mounted) {
  89. return;
  90. }
  91. if (!controller.value.initialized) {
  92. return;
  93. }
  94. if (controller.value.isPlaying && !hideBottom) {
  95. setState(() {
  96. hideBottom = true;
  97. });
  98. }
  99. });
  100. controller.play();
  101. }
  102. }
  103. void onClickFullScreen() {
  104. if (MediaQuery.of(context).orientation == Orientation.portrait) {
  105. // current portrait , enter fullscreen
  106. SystemChrome.setEnabledSystemUIOverlays([]);
  107. SystemChrome.setPreferredOrientations([
  108. DeviceOrientation.landscapeLeft,
  109. DeviceOrientation.landscapeRight,
  110. ]);
  111. Navigator.of(context)
  112. .push(PageRouteBuilder(
  113. settings: RouteSettings(isInitialRoute: false),
  114. pageBuilder: (
  115. BuildContext context,
  116. Animation<double> animation,
  117. Animation<double> secondaryAnimation,
  118. ) {
  119. return AnimatedBuilder(
  120. animation: animation,
  121. builder: (BuildContext context, Widget child) {
  122. return Scaffold(
  123. resizeToAvoidBottomPadding: false,
  124. body: PlayView(controller),
  125. );
  126. },
  127. );
  128. },
  129. ))
  130. .then((value) {
  131. // exit fullscreen
  132. SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
  133. SystemChrome.setPreferredOrientations([
  134. DeviceOrientation.portraitUp,
  135. DeviceOrientation.portraitDown,
  136. DeviceOrientation.landscapeLeft,
  137. DeviceOrientation.landscapeRight,
  138. ]);
  139. });
  140. }
  141. }
  142. void onClickExitFullScreen() {
  143. if (MediaQuery.of(context).orientation == Orientation.landscape) {
  144. // current landscape , exit fullscreen
  145. Navigator.of(context).pop();
  146. }
  147. }
  148. @override
  149. Widget build(BuildContext context) {
  150. Color primaryColor = Theme.of(context).primaryColor;
  151. if (controller.value.initialized) {
  152. final Size size = controller.value.size;
  153. return GestureDetector(
  154. child: Container(
  155. color: Colors.black,
  156. child: Stack(
  157. children: <Widget>[
  158. Center(
  159. child: AspectRatio(
  160. aspectRatio: size.width / size.height,
  161. child: VideoPlayer(controller),
  162. )),
  163. Align(
  164. alignment: Alignment.bottomCenter,
  165. child: hideBottom
  166. ? Container()
  167. : Opacity(
  168. opacity: 0.8,
  169. child: Container(
  170. height: 30.0,
  171. color: Colors.grey,
  172. child: Row(
  173. mainAxisSize: MainAxisSize.max,
  174. children: <Widget>[
  175. GestureDetector(
  176. child: Container(
  177. child: controller.value.isPlaying
  178. ? Icon(
  179. Icons.pause,
  180. color: primaryColor,
  181. )
  182. : Icon(
  183. Icons.play_arrow,
  184. color: primaryColor,
  185. ),
  186. ),
  187. onTap: onClickPlay,
  188. ),
  189. Container(
  190. padding: EdgeInsets.symmetric(horizontal: 5.0),
  191. child: Center(
  192. child: Text(
  193. '${controller.value.position.toString().split('.')[0]}',
  194. style: TextStyle(color: Colors.white),
  195. ),
  196. )),
  197. Expanded(
  198. child: VideoProgressIndicator(
  199. controller,
  200. allowScrubbing: true,
  201. padding: EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0),
  202. colors: VideoProgressColors(playedColor: primaryColor),
  203. )),
  204. Container(
  205. padding: EdgeInsets.symmetric(horizontal: 5.0),
  206. child: Center(
  207. child: Text(
  208. '${controller.value.duration.toString().split('.')[0]}',
  209. style: TextStyle(color: Colors.white),
  210. ),
  211. )),
  212. Container(
  213. child: widget.allowFullScreen
  214. ? Container(
  215. child: MediaQuery.of(context).orientation == Orientation.portrait
  216. ? GestureDetector(
  217. child: Icon(
  218. Icons.fullscreen,
  219. color: primaryColor,
  220. ),
  221. onTap: onClickFullScreen,
  222. )
  223. : GestureDetector(
  224. child: Icon(
  225. Icons.fullscreen_exit,
  226. color: primaryColor,
  227. ),
  228. onTap: onClickExitFullScreen,
  229. ),
  230. )
  231. : Container(),
  232. )
  233. ],
  234. )),
  235. )),
  236. Align(
  237. alignment: Alignment.center,
  238. child: controller.value.isPlaying
  239. ? Container()
  240. : Icon(
  241. Icons.play_circle_filled,
  242. color: primaryColor,
  243. size: 48.0,
  244. ),
  245. )
  246. ],
  247. )),
  248. onTap: onClickPlay,
  249. );
  250. } else if (controller.value.hasError && !controller.value.isPlaying) {
  251. return Container(
  252. color: Colors.black,
  253. child: Center(
  254. child: RaisedButton(
  255. onPressed: () {
  256. controller.initialize();
  257. controller.setLooping(true);
  258. controller.play();
  259. },
  260. shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
  261. child: Text('play error, try again!'),
  262. ),
  263. ),
  264. );
  265. } else {
  266. return Container(
  267. color: Colors.black,
  268. child: Center(
  269. child: CircularProgressIndicator(),
  270. ),
  271. );
  272. }
  273. }
  274. }