Description
Hey, awesome package! The video im using is 6 min so the un-smoothness of the slider track movement is unnoticable; I was just using this package cause its progress bar looks better than the default VideoProgressIndicator(). For some reason the video disappeared on my website when showing my friend (who was using chrome on a mac) when dragging the progress bar. I use chrome on linux, idk why it happened for him, but he sent me a short video (see below). I resolved this for myself by just using the slider in this part of your example, but i thought I'd still let you know.
Video:
https://github.com/timcreatedit/smooth_video_progress/assets/13493467/fb5ab9fb-7b8c-47af-b7b2-86b422b7f464
sidenote: facebook wouldn't let me download it cause "URL signature expired", so it a recording of a recording.
My website's code doesn't show the video player unless _controller.value.isInitialized
is true, so I hypothesize moving the progress bar causes this to be false.
Relevant Code:
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:smooth_video_progress/smooth_video_progress.dart';
class VideoPlayerWidget extends StatefulWidget {
final String filepath;
final double width;
VideoPlayerWidget(this.filepath, {required this.width});
@override
_VideoPlayerWidgetState createState() => _VideoPlayerWidgetState();
}
class _VideoPlayerWidgetState extends State<VideoPlayerWidget> {
late VideoPlayerController _controller;
late Duration _currentPosition;
bool showVideoControls = false;
bool showInitialPlayButton = true;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(widget.filepath,
videoPlayerOptions: VideoPlayerOptions(
mixWithOthers: true,
))
..addListener(() {
setState(() {
_currentPosition = _controller.value.position;
});
})
..initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
String formatTime(Duration duration) {
return duration.inHours == 0
? "${duration.inMinutes}:${duration.inSeconds.remainder(60).toString().padLeft(2, '0')}"
: "${duration.inHours}:${duration.inMinutes.remainder(60).toString().padLeft(2, '0')}:${duration.inSeconds.remainder(60).toString().padLeft(2, '0')}";
// if (duration.inHours == 0) {
// return "${duration.inMinutes}:${duration.inSeconds.toString().padLeft(2, '0')}";
// } else {
// return "${duration.inHours}:${duration.inMinutes.toString().padLeft(2, '0')}:${duration.inSeconds.toString().padLeft(2, '0')}";
// }
// // Format the duration into hh:mm:ss format
// String twoDigits(int n) => n.toString().padLeft(2, '0');
// String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
// String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
// return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
@override
Widget build(BuildContext context) {
return Container(
width: widget.width,
child: MouseRegion(
onEnter: (e) => setState(() {
if (!showInitialPlayButton) {
showVideoControls = true;
}
}),
onExit: (e) => setState(() {
showVideoControls = false;
}),
child: Stack(children: [
_controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Container(),
if (showInitialPlayButton)
Positioned.fill(
child: Center(
child: IconButton(
onPressed: () {
setState(() {
showInitialPlayButton = false;
showVideoControls = true;
_controller.play();
});
},
splashRadius: 0.01,
iconSize: widget.width * 0.20,
color: Theme.of(context).canvasColor.withOpacity(0.50),
icon: Icon(Icons.play_circle),
),
)),
if (showVideoControls)
Positioned.fill(
child: Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
height: 40,
child: Row(children: [
IconButton(
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
splashRadius: 0.01,
icon: Icon(
_controller.value.isPlaying
? Icons.pause
: Icons.play_arrow,
),
),
Text(
"${formatTime(_currentPosition)} / ${formatTime(_controller.value.duration)}",
style: TextStyle(
color: Theme.of(context).canvasColor)),
Expanded(
child: SmoothVideoProgress(
controller: _controller,
builder: (context, position, duration, _) =>
Slider(
min: 0,
max: duration.inMilliseconds.toDouble(),
value: position.inMilliseconds.toDouble(),
onChanged: (value) => _controller.seekTo(
Duration(milliseconds: value.toInt())),
onChangeStart: (_) => _controller.pause(),
onChangeEnd: (_) => _controller.play(),
),
),
// child: ValueListenableBuilder<VideoPlayerValue>(
// valueListenable: _controller,
// builder: (context, value, _) => Slider(
// min: 0,
// max: value.duration.inMilliseconds
// .toDouble(),
// value: value.position.inMilliseconds
// .toDouble(),
// onChanged: (value) => _controller.seekTo(
// Duration(milliseconds: value.toInt())),
// onChangeStart: (_) => _controller.pause(),
// onChangeEnd: (_) => _controller.play(),
// ),
// ),
),
])))),
])));
}
}