import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:video_player/video_player.dart'; class MaterialVideoProgressBar extends StatefulWidget { final VideoPlayerController controller; final VideoProgressColors colors; final Function() onDragStart; final Function() onDragEnd; final Function() onDragUpdate; MaterialVideoProgressBar( this.controller, { VideoProgressColors colors, this.onDragEnd, this.onDragStart, this.onDragUpdate, }) : colors = colors ?? new VideoProgressColors(); @override _VideoProgressBarState createState() { return new _VideoProgressBarState(); } } class _VideoProgressBarState extends State { VoidCallback listener; bool _controllerWasPlaying = false; _VideoProgressBarState() { listener = () { setState(() {}); }; } VideoPlayerController get controller => widget.controller; @override void initState() { super.initState(); controller.addListener(listener); } @override void deactivate() { controller.removeListener(listener); super.deactivate(); } @override Widget build(BuildContext context) { void seekToRelativePosition(Offset globalPosition) { final RenderBox box = context.findRenderObject(); final Offset tapPos = box.globalToLocal(globalPosition); final double relative = tapPos.dx / box.size.width; final Duration position = controller.value.duration * relative; controller.seekTo(position); } return new GestureDetector( child: (controller.value.isErroneous) ? new Text(controller.value.errorDescription) : new Center( child: new Container( height: MediaQuery.of(context).size.height / 2, width: MediaQuery.of(context).size.width, color: Colors.transparent, child: new CustomPaint( painter: new _ProgressBarPainter( controller.value, widget.colors, ), ), ), ), onHorizontalDragStart: (DragStartDetails details) { if (!controller.value.initialized) { return; } _controllerWasPlaying = controller.value.isPlaying; if (_controllerWasPlaying) { controller.pause(); } if (widget.onDragStart != null) { widget.onDragStart(); } }, onHorizontalDragUpdate: (DragUpdateDetails details) { if (!controller.value.initialized) { return; } seekToRelativePosition(details.globalPosition); if (widget.onDragUpdate != null) { widget.onDragUpdate(); } }, onHorizontalDragEnd: (DragEndDetails details) { if (_controllerWasPlaying) { controller.play(); } if (widget.onDragEnd != null) { widget.onDragEnd(); } }, onTapDown: (TapDownDetails details) { if (!controller.value.initialized) { return; } seekToRelativePosition(details.globalPosition); }, ); } } class _ProgressBarPainter extends CustomPainter { VideoPlayerValue value; VideoProgressColors colors; _ProgressBarPainter(this.value, this.colors); @override bool shouldRepaint(CustomPainter painter) { return true; } @override void paint(Canvas canvas, Size size) { final height = 2.0; canvas.drawRRect( new RRect.fromRectAndRadius( new Rect.fromPoints( new Offset(0.0, size.height / 2), new Offset(size.width, size.height / 2 + height), ), new Radius.circular(4.0), ), colors.disabledPaint, ); if (!value.initialized) { return; } final double playedPart = value.position.inMilliseconds / value.duration.inMilliseconds * size.width; for (DurationRange range in value.buffered) { final double start = range.startFraction(value.duration) * size.width; final double end = range.endFraction(value.duration) * size.width; canvas.drawRRect( new RRect.fromRectAndRadius( new Rect.fromPoints( new Offset(start, size.height / 2), new Offset(end, size.height / 2 + height), ), new Radius.circular(4.0), ), colors.bufferedPaint, ); } canvas.drawRRect( new RRect.fromRectAndRadius( new Rect.fromPoints( new Offset(0.0, size.height / 2), new Offset(playedPart, size.height / 2 + height), ), new Radius.circular(4.0), ), colors.playedPaint, ); canvas.drawCircle( new Offset(playedPart, size.height / 2 + height / 2), height * 3, colors.handlePaint, ); } }