video_player_page.dart 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import 'dart:io';
  2. import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
  3. import 'package:auto_route/auto_route.dart';
  4. import 'package:eitc_erm_dental_flutter/entity/history_item_info.dart';
  5. import 'package:eitc_erm_dental_flutter/funcs.dart';
  6. import 'package:eitc_erm_dental_flutter/pages/history/vm/history_view_model.dart';
  7. import 'package:eitc_erm_dental_flutter/pages/history/widget/history_view_title.dart';
  8. import 'package:flutter/material.dart';
  9. import 'package:flutter_riverpod/flutter_riverpod.dart';
  10. import 'package:flutter_screenutil/flutter_screenutil.dart';
  11. import 'package:flutter_vlc_player/flutter_vlc_player.dart';
  12. import '../../app_router.gr.dart';
  13. import 'widget/history_view_operation_view.dart';
  14. ///视频播放页面
  15. @RoutePage(name: "videoPlayerRoute")
  16. class VideoPlayerPage extends ConsumerStatefulWidget {
  17. final HistoryItemInfo? info;
  18. const VideoPlayerPage({super.key, required this.info});
  19. @override
  20. ConsumerState createState() => _VideoPlayerPageState();
  21. }
  22. class _VideoPlayerPageState extends ConsumerState<VideoPlayerPage> {
  23. VlcPlayerController? _playerController;
  24. bool _playVisible = false;
  25. Duration _totalDuration = const Duration();
  26. Duration _position = const Duration();
  27. @override
  28. void initState() {
  29. super.initState();
  30. //开启屏幕旋转
  31. screenEnableRotate();
  32. _initPlayerController();
  33. }
  34. ///初始化视频控制器
  35. void _initPlayerController() async {
  36. if (widget.info == null) {
  37. return;
  38. }
  39. _playerController = VlcPlayerController.file(
  40. File(widget.info!.path),
  41. hwAcc: HwAcc.auto,
  42. autoInitialize: true,
  43. autoPlay: true,
  44. options: VlcPlayerOptions(),
  45. );
  46. //循环播放,setLooping方法无效
  47. _playerController!.addListener(() async {
  48. VlcPlayerValue value = _playerController!.value;
  49. if (value.isInitialized && mounted) {
  50. //更新播放进度
  51. setState(() {
  52. _totalDuration = value.duration;
  53. _position = value.position;
  54. });
  55. }
  56. if (value.playingState == PlayingState.ended) {
  57. await _playerController!.stop();
  58. _playerController!.play();
  59. }
  60. });
  61. }
  62. @override
  63. void dispose() async {
  64. super.dispose();
  65. //关闭屏幕旋转
  66. screenDisableRotate();
  67. await _playerController?.stopRendererScanning();
  68. _playerController?.dispose();
  69. }
  70. @override
  71. Widget build(BuildContext context) {
  72. Widget videoView = (widget.info == null || _playerController == null)
  73. ? const SizedBox()
  74. : _getVideoView();
  75. return Scaffold(
  76. body: SafeArea(
  77. child: Container(
  78. color: Colors.black,
  79. child: Stack(
  80. children: [
  81. videoView,
  82. Align(
  83. alignment: Alignment.topLeft,
  84. child: HistoryViewTitle(
  85. name: widget.info?.name,
  86. ),
  87. ),
  88. HistoryViewOperationView(
  89. onUpload: () => _onUpload(context),
  90. onDelete: () => _onDelete(context),
  91. ),
  92. ],
  93. ),
  94. ),
  95. ),
  96. );
  97. }
  98. Widget _getVideoView() {
  99. return Stack(
  100. children: [
  101. GestureDetector(
  102. behavior: HitTestBehavior.opaque,
  103. onTap: _onTap,
  104. child: Stack(
  105. children: [
  106. _getVideoPlayer(),
  107. _getPlayVisible(),
  108. ],
  109. ),
  110. ),
  111. _getSeekBar()
  112. ],
  113. );
  114. }
  115. Widget _getVideoPlayer() {
  116. return Container(
  117. color: Colors.black,
  118. alignment: Alignment.center,
  119. child: SizedBox.expand(
  120. child: AspectRatio(
  121. aspectRatio: _playerController!.value.aspectRatio,
  122. child: VlcPlayer(
  123. controller: _playerController!,
  124. aspectRatio: 16 / 9,
  125. placeholder: const Center(child: CircularProgressIndicator()),
  126. ),
  127. ),
  128. ),
  129. );
  130. }
  131. Widget _getPlayVisible() {
  132. return Align(
  133. alignment: Alignment.center,
  134. child: Visibility(
  135. visible: _playVisible,
  136. child: Icon(
  137. size: 100.r,
  138. Icons.play_circle_outline,
  139. color: Colors.white60,
  140. )),
  141. );
  142. }
  143. Widget _getSeekBar() {
  144. return Visibility(
  145. visible: _totalDuration != Duration.zero,
  146. child: Align(
  147. alignment: Alignment.bottomCenter,
  148. child: Padding(
  149. padding: EdgeInsets.only(bottom: 20.h, left: 20.w, right: 20.w),
  150. child: ProgressBar(
  151. progress: _position,
  152. total: _totalDuration,
  153. baseBarColor: Colors.white,
  154. thumbColor: Colors.white,
  155. timeLabelTextStyle: const TextStyle(color: Colors.white),
  156. timeLabelLocation: TimeLabelLocation.sides,
  157. onSeek: (duration) => _playerController!.seekTo(duration),
  158. ),
  159. ),
  160. ));
  161. }
  162. void _onTap() async {
  163. if (_playerController == null) {
  164. return;
  165. }
  166. bool? bo = await _playerController!.isPlaying();
  167. if (bo != null && bo) {
  168. await _playerController!.pause();
  169. setState(() {
  170. _playVisible = true;
  171. });
  172. } else {
  173. await _playerController!.play();
  174. setState(() {
  175. _playVisible = false;
  176. });
  177. }
  178. }
  179. void _onUpload(BuildContext context) async {
  180. if (!await checkInternetWifi()) {
  181. return;
  182. }
  183. if (context.mounted) {
  184. context.pushRoute(UploadSelectClinicRoute(
  185. uploadList: [widget.info!], isFromView: true));
  186. }
  187. }
  188. void _onDelete(BuildContext context) async {
  189. if (widget.info == null) {
  190. return;
  191. }
  192. bool? bo = await showDeleteAlertDialog(context, getS().deleteVideoHint);
  193. if (bo == null || !bo) {
  194. return;
  195. }
  196. bool result =
  197. await ref.read(historyListProvider.notifier).delete([widget.info!]);
  198. if (result) {
  199. showToast(text: getS().deleteSuccess);
  200. if (context.mounted) {
  201. Navigator.pop(context, widget.info);
  202. }
  203. } else {
  204. showToast(text: getS().deleteFailed);
  205. }
  206. }
  207. }