chatapp3-flutter/lib/modules/media/video_player_page.dart
2026-04-09 21:32:23 +08:00

315 lines
12 KiB
Dart

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<VideoPlayerPage> {
late VideoPlayerController _controller;
late Future<void> _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<Color>(SCGlobalConfig.businessLogicStrategy.getVideoPlayerLoadingIndicatorColor()),
),
],
),
);
} else {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(SCGlobalConfig.businessLogicStrategy.getVideoPlayerLoadingIndicatorColor()),
),
SizedBox(height: 16),
Text('loading...', style: TextStyle(color: SCGlobalConfig.businessLogicStrategy.getVideoPlayerTextColor())),
],
);
}
},
),
),
);
}
}