import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:yumi/app/constants/sc_global_config.dart'; import 'package:yumi/shared/tools/sc_path_utils.dart'; import 'package:video_player/video_player.dart'; class VideoPlayerPage extends StatefulWidget { final String videoUrl; const VideoPlayerPage({Key? key, required this.videoUrl}) : super(key: key); @override _VideoPlayerPageState createState() => _VideoPlayerPageState(); } class _VideoPlayerPageState extends State { late VideoPlayerController _controller; late Future _initializeVideoPlayerFuture; bool _isPlaying = false; bool _showControls = true; Duration _currentPosition = Duration.zero; Duration _totalDuration = Duration.zero; // 控制界面显示和隐藏的定时器 Timer? _hideControlsTimer; @override void initState() { super.initState(); _initializeVideoPlayer(); } void _initializeVideoPlayer() { final pathType = SCPathUtils.getPathType(widget.videoUrl); if (pathType == PathType.file) { _controller = VideoPlayerController.file(File(widget.videoUrl)); _initializeVideoPlayerFuture = _controller.initialize().then((_) { setState(() { _totalDuration = _controller.value.duration; }); }); } else if (pathType == PathType.network) { _controller = VideoPlayerController.networkUrl( Uri.parse(widget.videoUrl), ); _initializeVideoPlayerFuture = _controller.initialize().then((_) { setState(() { _totalDuration = _controller.value.duration; }); }); } // 添加监听器来更新进度 _controller.addListener(_updateProgress); } void _updateProgress() { if (mounted) { setState(() { _currentPosition = _controller.value.position; _totalDuration = _controller.value.duration; _isPlaying = _controller.value.isPlaying; }); } } void _togglePlayPause() { setState(() { if (_controller.value.isPlaying) { _controller.pause(); _isPlaying = false; } else { _controller.play(); _isPlaying = true; _resetHideControlsTimer(); } }); } void _seekToPosition(Duration position) { _controller.seekTo(position); } void _resetHideControlsTimer() { _hideControlsTimer?.cancel(); _hideControlsTimer = Timer(Duration(seconds: SCGlobalConfig.businessLogicStrategy.getVideoPlayerControlsDisplayDuration()), () { if (mounted && _controller.value.isPlaying) { setState(() { _showControls = false; }); } }); } void _toggleControls() { setState(() { _showControls = !_showControls; }); if (_showControls && _controller.value.isPlaying) { _resetHideControlsTimer(); } } String _formatDuration(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, '0'); final hours = twoDigits(duration.inHours); final minutes = twoDigits(duration.inMinutes.remainder(60)); final seconds = twoDigits(duration.inSeconds.remainder(60)); if (duration.inHours > 0) { return '$hours:$minutes:$seconds'; } else { return '$minutes:$seconds'; } } @override void dispose() { _hideControlsTimer?.cancel(); _controller.removeListener(_updateProgress); _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: SCGlobalConfig.businessLogicStrategy.getVideoPlayerBackgroundColor(), body: Center( child: FutureBuilder( future: _initializeVideoPlayerFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return GestureDetector( onTap: _toggleControls, child: Stack( alignment: Alignment.center, children: [ // 视频播放器 AspectRatio( aspectRatio: _controller.value.aspectRatio, child: VideoPlayer(_controller), ), // 控制界面 if (_showControls) ...[ // 半透明背景 Container(color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerControlsBackgroundColor()), // 播放/暂停按钮 IconButton( icon: Icon( _isPlaying ? Icons.pause : Icons.play_arrow, color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerIconColor(), size: 50, ), onPressed: _togglePlayPause, ), // 底部控制栏 Positioned( bottom: 0, left: 0, right: 0, child: Container( color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerBottomControlsBackgroundColor(), padding: const EdgeInsets.all(16), child: Column( children: [ // 进度条 Slider( value: _currentPosition.inMilliseconds.toDouble(), min: 0, max: _totalDuration.inMilliseconds.toDouble(), onChanged: (value) { final newPosition = Duration( milliseconds: value.toInt(), ); _seekToPosition(newPosition); }, onChangeStart: (_) { _hideControlsTimer?.cancel(); }, onChangeEnd: (_) { if (_controller.value.isPlaying) { _resetHideControlsTimer(); } }, activeColor: SCGlobalConfig.businessLogicStrategy.getVideoPlayerProgressBarActiveColor(), inactiveColor: SCGlobalConfig.businessLogicStrategy.getVideoPlayerProgressBarInactiveColor(), ), // 时间信息和控制按钮 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // 当前时间 Text( _formatDuration(_currentPosition), style: TextStyle( color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerTextColor(), fontSize: 14, ), ), // 控制按钮 Row( children: [ // 播放/暂停按钮 IconButton( icon: Icon( _isPlaying ? Icons.pause : Icons.play_arrow, color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerIconColor(), ), onPressed: _togglePlayPause, ), // 10秒前进 IconButton( icon: Icon( Icons.forward_5, color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerIconColor(), ), onPressed: () { final newPosition = _currentPosition + const Duration(seconds: 5); if (newPosition <= _totalDuration) { _seekToPosition(newPosition); } else { _seekToPosition(_totalDuration); } }, ), // 10秒后退 IconButton( icon: Icon( Icons.replay_5, color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerIconColor(), ), onPressed: () { final newPosition = _currentPosition - const Duration(seconds: 5); if (newPosition >= Duration.zero) { _seekToPosition(newPosition); } else { _seekToPosition(Duration.zero); } }, ), ], ), // 总时长 Text( _formatDuration(_totalDuration), style: TextStyle( color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerTextColor(), fontSize: 14, ), ), ], ), ], ), ), ), ] else if (!_controller.value.isPlaying) ...[ // 当视频暂停但控制界面隐藏时,显示播放按钮 IconButton( icon: Icon( Icons.play_arrow, color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerIconColor(), size: 50, ), onPressed: _togglePlayPause, ), ], // 加载指示器 if (snapshot.connectionState == ConnectionState.waiting) CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(SCGlobalConfig.businessLogicStrategy.getVideoPlayerLoadingIndicatorColor()), ), ], ), ); } else { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(SCGlobalConfig.businessLogicStrategy.getVideoPlayerLoadingIndicatorColor()), ), SizedBox(height: 16), Text('loading...', style: TextStyle(color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerTextColor())), ], ); } }, ), ), ); } }