import 'dart:io'; import 'package:audio_video_progress_bar/audio_video_progress_bar.dart'; import 'package:auto_route/annotations.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:eitc_erm_dental_flutter/pages/view/widget/preview_operation_view.dart'; import 'package:eitc_erm_dental_flutter/pages/view/widget/preview_title.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_vlc_player/flutter_vlc_player.dart'; import '../../entity/db/local_patient_info.dart'; import '../../funcs.dart'; import '../../global.dart'; ///视频预览页面 @RoutePage(name: "videoPreviewRoute") class VideoPreviewPage extends StatefulWidget { final LocalPatientInfo info; final String path; final String area; final DateTime time; final String mobile; final String wifi; final String deviceModel; const VideoPreviewPage( {super.key, required this.info, required this.path, required this.area, required this.time, required this.mobile, required this.wifi, required this.deviceModel}); @override State createState() => _VideoPreviewPageState(); } class _VideoPreviewPageState extends State { VlcPlayerController? _playerController; bool _playVisible = false; Duration _totalDuration = const Duration(); Duration _position = const Duration(); bool _isSaving = false; bool _isSaved = false; @override void initState() { super.initState(); _initPlayerController(); } ///初始化视频控制器 void _initPlayerController() async { _playerController = VlcPlayerController.file( File(widget.path), hwAcc: HwAcc.auto, autoInitialize: true, autoPlay: true, options: VlcPlayerOptions(), ); //循环播放,setLooping方法无效 _playerController!.addListener(() async { VlcPlayerValue value = _playerController!.value; if (value.isInitialized && mounted) { //更新播放进度 setState(() { _totalDuration = value.duration; _position = value.position; }); } if (value.playingState == PlayingState.ended) { await _playerController!.stop(); _playerController!.play(); } }); } @override void dispose() async { super.dispose(); _deleteCache(); await _playerController?.stopRendererScanning(); _playerController?.dispose(); } @override Widget build(BuildContext context) { Widget videoView = (_playerController == null) ? const SizedBox() : _getVideoView(); return PopScope( canPop: !_isSaving, child: Scaffold( body: SafeArea( child: Container( color: Colors.black, child: Stack( children: [ videoView, Align( alignment: Alignment.topLeft, child: PreviewTitle( title: getS().previewVideo, ), ), PreviewOperationView( onSave: _onSave, onCancel: _onCancel, ), ], ), ), ), )); } Widget _getVideoView() { return Stack( children: [ GestureDetector( behavior: HitTestBehavior.opaque, onTap: _onTap, child: Stack( children: [ _getVideoPlayer(), _getPlayVisible(), ], ), ), _getSeekBar() ], ); } Widget _getVideoPlayer() { return Container( color: Colors.black, alignment: Alignment.center, child: SizedBox.expand( child: AspectRatio( aspectRatio: _playerController!.value.aspectRatio, child: VlcPlayer( controller: _playerController!, aspectRatio: 16 / 9, placeholder: const Center(child: CircularProgressIndicator()), ), ), ), ); } Widget _getPlayVisible() { return Align( alignment: Alignment.center, child: Visibility( visible: _playVisible, child: Icon( size: 100.r, Icons.play_circle_outline, color: Colors.white60, )), ); } Widget _getSeekBar() { return Visibility( visible: _totalDuration != Duration.zero, child: Align( alignment: Alignment.bottomCenter, child: Padding( padding: EdgeInsets.only(bottom: 20.h, left: 20.w, right: 20.w), child: ProgressBar( progress: _position, total: _totalDuration, baseBarColor: Colors.white, thumbColor: Colors.white, timeLabelTextStyle: const TextStyle(color: Colors.white), timeLabelLocation: TimeLabelLocation.sides, onSeek: (duration) => _playerController!.seekTo(duration), ), ), )); } void _onTap() async { if (_playerController == null) { return; } bool? bo = await _playerController!.isPlaying(); if (bo != null && bo) { await _playerController!.pause(); setState(() { _playVisible = true; }); } else { await _playerController!.play(); setState(() { _playVisible = false; }); } } void _onSave() async { logd("保存"); setState(() { _isSaving = true; }); var cancelFunc = BotToast.showLoading(clickClose: false, crossPage: false); try { await videoChannel.invokeMethod("saveRecord", [widget.path, widget.path]); _isSaved = true; cancelFunc(); showToast(text: getS().saveSuccess); setState(() { _isSaving = false; }); if (mounted) { Navigator.pop(context); } } catch (e) { setState(() { _isSaving = false; }); cancelFunc(); showToast(text: getS().saveFailed); loge("保存视频异常", error: e); } } void _onCancel() { logd("取消"); Navigator.pop(context); } void _deleteCache() { if (widget.path.isEmpty || _isSaved) { return; } try { fileChannel.invokeMethod("deleteFile", widget.path); } catch (e) { loge("照片预览删除文件异常", error: e); } } }