You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
4.7 KiB

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:video_player/video_player.dart';
import 'chewie_progress_colors.dart';
class MaterialVideoProgressBar extends StatefulWidget {
MaterialVideoProgressBar(
this.controller, {
ChewieProgressColors colors,
this.onDragEnd,
this.onDragStart,
this.onDragUpdate,
}) : colors = colors ?? ChewieProgressColors();
final VideoPlayerController controller;
final ChewieProgressColors colors;
final Function() onDragStart;
final Function() onDragEnd;
final Function() onDragUpdate;
@override
_VideoProgressBarState createState() {
return _VideoProgressBarState();
}
}
class _VideoProgressBarState extends State<MaterialVideoProgressBar> {
_VideoProgressBarState() {
listener = () {
setState(() {});
};
}
VoidCallback listener;
bool _controllerWasPlaying = false;
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 box = context.findRenderObject() as RenderBox;
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 GestureDetector(
child: Center(
child: Container(
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width,
color: Colors.transparent,
child: CustomPaint(
painter: _ProgressBarPainter(
controller.value,
widget.colors,
),
),
),
),
onHorizontalDragStart: (DragStartDetails details) {
if (!controller.value.isInitialized) {
return;
}
_controllerWasPlaying = controller.value.isPlaying;
if (_controllerWasPlaying) {
controller.pause();
}
if (widget.onDragStart != null) {
widget.onDragStart();
}
},
onHorizontalDragUpdate: (DragUpdateDetails details) {
if (!controller.value.isInitialized) {
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.isInitialized) {
return;
}
seekToRelativePosition(details.globalPosition);
},
);
}
}
class _ProgressBarPainter extends CustomPainter {
_ProgressBarPainter(this.value, this.colors);
VideoPlayerValue value;
ChewieProgressColors colors;
@override
bool shouldRepaint(CustomPainter painter) {
return true;
}
@override
void paint(Canvas canvas, Size size) {
final height = 2.0;
canvas.drawRRect(
RRect.fromRectAndRadius(
Rect.fromPoints(
Offset(0.0, size.height / 2),
Offset(size.width, size.height / 2 + height),
),
Radius.circular(4.0),
),
colors.backgroundPaint,
);
if (!value.isInitialized) {
return;
}
final double playedPartPercent =
value.position.inMilliseconds / value.duration.inMilliseconds;
final double playedPart =
playedPartPercent > 1 ? size.width : playedPartPercent * 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(
RRect.fromRectAndRadius(
Rect.fromPoints(
Offset(start, size.height / 2),
Offset(end, size.height / 2 + height),
),
Radius.circular(4.0),
),
colors.bufferedPaint,
);
}
canvas.drawRRect(
RRect.fromRectAndRadius(
Rect.fromPoints(
Offset(0.0, size.height / 2),
Offset(playedPart, size.height / 2 + height),
),
Radius.circular(4.0),
),
colors.playedPaint,
);
canvas.drawCircle(
Offset(playedPart, size.height / 2 + height / 2),
height * 3,
colors.handlePaint,
);
}
}