mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt progress bar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -5,52 +5,6 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
/// This is where the current time and total time labels should appear in
|
||||
/// relation to the progress bar.
|
||||
enum TimeLabelLocation {
|
||||
/// The time is displayed above the progress bar.
|
||||
///
|
||||
/// | 01:23 05:00 |
|
||||
/// | -------O---------------- |
|
||||
above,
|
||||
|
||||
/// The time is displayed below the progress bar.
|
||||
///
|
||||
/// | -------O---------------- |
|
||||
/// | 01:23 05:00 |
|
||||
below,
|
||||
|
||||
/// The time is displayed on the sides of the progress bar.
|
||||
///
|
||||
/// | 01:23 -------O---------------- 05:00 |
|
||||
sides,
|
||||
|
||||
/// The time is not displayed.
|
||||
///
|
||||
/// | -------O---------------- |
|
||||
none,
|
||||
}
|
||||
|
||||
/// The time label on the right hand side can be shown as the [totalTime] or as
|
||||
/// the [remainingTime]. If the choice is [remainingTime] then this will be
|
||||
/// shown as a negative number.
|
||||
///
|
||||
///
|
||||
enum TimeLabelType {
|
||||
/// The time label on the right shows the total time.
|
||||
///
|
||||
/// | -------O---------------- |
|
||||
/// | 01:23 05:00 |
|
||||
totalTime,
|
||||
|
||||
/// The time label on the right shows the remaining time as a
|
||||
/// negative number.
|
||||
///
|
||||
/// | -------O---------------- |
|
||||
/// | 01:23 -03:37 |
|
||||
remainingTime,
|
||||
}
|
||||
|
||||
/// The shape of the progress bar at the left and right ends.
|
||||
enum BarCapShape {
|
||||
/// The left and right ends of the bar are round.
|
||||
@@ -83,20 +37,15 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
this.onDragUpdate,
|
||||
this.onDragEnd,
|
||||
this.barHeight = 5.0,
|
||||
this.baseBarColor,
|
||||
this.progressBarColor,
|
||||
this.bufferedBarColor,
|
||||
required this.baseBarColor,
|
||||
required this.progressBarColor,
|
||||
required this.bufferedBarColor,
|
||||
this.barCapShape = BarCapShape.round,
|
||||
this.thumbRadius = 10.0,
|
||||
this.thumbColor,
|
||||
required this.thumbColor,
|
||||
this.thumbGlowColor,
|
||||
this.thumbGlowRadius = 30.0,
|
||||
this.thumbCanPaintOutsideBar = true,
|
||||
this.timeLabelLocation,
|
||||
this.timeLabelType,
|
||||
this.timeLabelTextStyle,
|
||||
this.timeLabelPadding = 0.0,
|
||||
this.textScaleFactor = 1.0,
|
||||
});
|
||||
|
||||
/// The elapsed playing time of the media.
|
||||
@@ -173,20 +122,20 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
/// The color of the progress bar before playback has started.
|
||||
///
|
||||
/// By default it is a transparent version of your theme's primary color.
|
||||
final Color? baseBarColor;
|
||||
final Color baseBarColor;
|
||||
|
||||
/// The color of the progress bar to the left of the current playing
|
||||
/// [progress].
|
||||
///
|
||||
/// By default it is your theme's primary color.
|
||||
final Color? progressBarColor;
|
||||
final Color progressBarColor;
|
||||
|
||||
/// The color of the progress bar between the [progress] location and the
|
||||
/// [buffered] location.
|
||||
///
|
||||
/// By default it is a transparent version of your theme's primary color,
|
||||
/// a shade darker than [baseBarColor].
|
||||
final Color? bufferedBarColor;
|
||||
final Color bufferedBarColor;
|
||||
|
||||
/// The shape of the bar at the left and right ends.
|
||||
///
|
||||
@@ -200,7 +149,7 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
/// The color of the circle for the moveable progress bar thumb.
|
||||
///
|
||||
/// By default it is your theme's primary color.
|
||||
final Color? thumbColor;
|
||||
final Color thumbColor;
|
||||
|
||||
/// The color of the pressed-down effect of the moveable progress bar thumb.
|
||||
///
|
||||
@@ -230,36 +179,8 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
/// is happening during this time, though.
|
||||
final bool thumbCanPaintOutsideBar;
|
||||
|
||||
/// The location for the [progress] and [total] duration text labels.
|
||||
///
|
||||
/// By default the labels appear under the progress bar but you can also
|
||||
/// put them above, on the sides, or remove them altogether.
|
||||
final TimeLabelLocation? timeLabelLocation;
|
||||
|
||||
/// What to display for the time label on the right
|
||||
///
|
||||
/// The right time label can show the total time or the remaining time as a
|
||||
/// negative number. The default is [TimeLabelType.totalTime].
|
||||
final TimeLabelType? timeLabelType;
|
||||
|
||||
/// The [TextStyle] used by the time labels.
|
||||
///
|
||||
/// By default it is [TextTheme.bodyLarge].
|
||||
final TextStyle? timeLabelTextStyle;
|
||||
|
||||
/// The extra space between the time labels and the progress bar.
|
||||
///
|
||||
/// The default is 0.0. A positive number will move the labels further from
|
||||
/// the progress bar and a negative number will move them closer.
|
||||
final double timeLabelPadding;
|
||||
|
||||
final double textScaleFactor;
|
||||
|
||||
@override
|
||||
RenderObject createRenderObject(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final primaryColor = theme.colorScheme.primary;
|
||||
final textStyle = timeLabelTextStyle ?? theme.textTheme.bodyLarge;
|
||||
return _RenderProgressBar(
|
||||
progress: progress,
|
||||
total: total,
|
||||
@@ -269,30 +190,20 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
onDragUpdate: onDragUpdate,
|
||||
onDragEnd: onDragEnd,
|
||||
barHeight: barHeight,
|
||||
baseBarColor: baseBarColor ?? primaryColor.withValues(alpha: 0.24),
|
||||
progressBarColor: progressBarColor ?? primaryColor,
|
||||
bufferedBarColor:
|
||||
bufferedBarColor ?? primaryColor.withValues(alpha: 0.24),
|
||||
baseBarColor: baseBarColor,
|
||||
progressBarColor: progressBarColor,
|
||||
bufferedBarColor: bufferedBarColor,
|
||||
barCapShape: barCapShape,
|
||||
thumbRadius: thumbRadius,
|
||||
thumbColor: thumbColor ?? primaryColor,
|
||||
thumbGlowColor:
|
||||
thumbGlowColor ?? (thumbColor ?? primaryColor).withAlpha(80),
|
||||
thumbColor: thumbColor,
|
||||
thumbGlowColor: thumbGlowColor ?? thumbColor,
|
||||
thumbGlowRadius: thumbGlowRadius,
|
||||
thumbCanPaintOutsideBar: thumbCanPaintOutsideBar,
|
||||
timeLabelLocation: timeLabelLocation ?? TimeLabelLocation.below,
|
||||
timeLabelType: timeLabelType ?? TimeLabelType.totalTime,
|
||||
timeLabelTextStyle: textStyle,
|
||||
timeLabelPadding: timeLabelPadding,
|
||||
textScaleFactor: textScaleFactor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderObject renderObject) {
|
||||
final theme = Theme.of(context);
|
||||
final primaryColor = theme.colorScheme.primary;
|
||||
final textStyle = timeLabelTextStyle ?? theme.textTheme.bodyLarge;
|
||||
(renderObject as _RenderProgressBar)
|
||||
..total = total
|
||||
..progress = progress
|
||||
@@ -302,22 +213,15 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
..onDragUpdate = onDragUpdate
|
||||
..onDragEnd = onDragEnd
|
||||
..barHeight = barHeight
|
||||
..baseBarColor = baseBarColor ?? primaryColor.withValues(alpha: 0.24)
|
||||
..progressBarColor = progressBarColor ?? primaryColor
|
||||
..bufferedBarColor =
|
||||
bufferedBarColor ?? primaryColor.withValues(alpha: 0.24)
|
||||
..baseBarColor = baseBarColor
|
||||
..progressBarColor = progressBarColor
|
||||
..bufferedBarColor = bufferedBarColor
|
||||
..barCapShape = barCapShape
|
||||
..thumbRadius = thumbRadius
|
||||
..thumbColor = thumbColor ?? primaryColor
|
||||
..thumbGlowColor =
|
||||
thumbGlowColor ?? (thumbColor ?? primaryColor).withAlpha(80)
|
||||
..thumbColor = thumbColor
|
||||
..thumbGlowColor = thumbGlowColor ?? thumbColor
|
||||
..thumbGlowRadius = thumbGlowRadius
|
||||
..thumbCanPaintOutsideBar = thumbCanPaintOutsideBar
|
||||
..timeLabelLocation = timeLabelLocation ?? TimeLabelLocation.below
|
||||
..timeLabelType = timeLabelType ?? TimeLabelType.totalTime
|
||||
..timeLabelTextStyle = textStyle
|
||||
..timeLabelPadding = timeLabelPadding
|
||||
..textScaleFactor = textScaleFactor;
|
||||
..thumbCanPaintOutsideBar = thumbCanPaintOutsideBar;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -372,11 +276,7 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
ifFalse: 'false',
|
||||
showName: true,
|
||||
),
|
||||
)
|
||||
..add(StringProperty('timeLabelLocation', timeLabelLocation.toString()))
|
||||
..add(StringProperty('timeLabelType', timeLabelType.toString()))
|
||||
..add(DiagnosticsProperty('timeLabelTextStyle', timeLabelTextStyle))
|
||||
..add(DoubleProperty('timeLabelPadding', timeLabelPadding));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,11 +346,6 @@ class _RenderProgressBar extends RenderBox {
|
||||
required Color thumbGlowColor,
|
||||
double thumbGlowRadius = 30.0,
|
||||
bool thumbCanPaintOutsideBar = true,
|
||||
required TimeLabelLocation timeLabelLocation,
|
||||
required TimeLabelType timeLabelType,
|
||||
TextStyle? timeLabelTextStyle,
|
||||
double timeLabelPadding = 0.0,
|
||||
double textScaleFactor = 1.0,
|
||||
}) : _total = total,
|
||||
_buffered = buffered,
|
||||
_onSeek = onSeek,
|
||||
@@ -466,12 +361,7 @@ class _RenderProgressBar extends RenderBox {
|
||||
_thumbColor = thumbColor,
|
||||
_thumbGlowColor = thumbGlowColor,
|
||||
_thumbGlowRadius = thumbGlowRadius,
|
||||
_thumbCanPaintOutsideBar = thumbCanPaintOutsideBar,
|
||||
_timeLabelLocation = timeLabelLocation,
|
||||
_timeLabelType = timeLabelType,
|
||||
_timeLabelTextStyle = timeLabelTextStyle,
|
||||
_timeLabelPadding = timeLabelPadding,
|
||||
_textScaleFactor = textScaleFactor {
|
||||
_thumbCanPaintOutsideBar = thumbCanPaintOutsideBar {
|
||||
_drag = _EagerHorizontalDragGestureRecognizer()
|
||||
..onStart = _onDragStart
|
||||
..onUpdate = _onDragUpdate
|
||||
@@ -486,7 +376,6 @@ class _RenderProgressBar extends RenderBox {
|
||||
@override
|
||||
void dispose() {
|
||||
_drag?.dispose();
|
||||
_clearLabelCache();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -503,14 +392,6 @@ class _RenderProgressBar extends RenderBox {
|
||||
// time as a [progress] update there won't be a conflict.
|
||||
bool _userIsDraggingThumb = false;
|
||||
|
||||
// This padding is always used between the time labels and the progress bar
|
||||
// when the time labels are on the sides. Any user defined [timeLabelPadding]
|
||||
// is in addition to this.
|
||||
double get _defaultSidePadding {
|
||||
const minPadding = 5.0;
|
||||
return (_thumbCanPaintOutsideBar) ? thumbRadius + minPadding : minPadding;
|
||||
}
|
||||
|
||||
void _onDragStart(DragStartDetails details) {
|
||||
if (onDragStart == null) {
|
||||
return;
|
||||
@@ -565,20 +446,12 @@ class _RenderProgressBar extends RenderBox {
|
||||
// only one place to make changes.
|
||||
void _updateThumbPosition(Offset localPosition) {
|
||||
final dx = localPosition.dx;
|
||||
double lengthBefore = 0.0;
|
||||
double lengthAfter = 0.0;
|
||||
if (_timeLabelLocation == TimeLabelLocation.sides) {
|
||||
lengthBefore =
|
||||
_leftLabelSize.width + _defaultSidePadding + _timeLabelPadding;
|
||||
lengthAfter =
|
||||
_rightLabelSize.width + _defaultSidePadding + _timeLabelPadding;
|
||||
}
|
||||
// The paint used to draw the bar line draws half of the cap before the
|
||||
// start of the line (and after the end of the line). The cap radius is
|
||||
// equal to half of the line width, which in this case is the bar height.
|
||||
final barCapRadius = _barHeight / 2;
|
||||
double barStart = lengthBefore + barCapRadius;
|
||||
double barEnd = size.width - lengthAfter - barCapRadius;
|
||||
double barStart = barCapRadius;
|
||||
double barEnd = size.width - barCapRadius;
|
||||
final barWidth = barEnd - barStart;
|
||||
final position = (dx - barStart).clamp(0.0, barWidth);
|
||||
_thumbValue = (position / barWidth);
|
||||
@@ -596,9 +469,6 @@ class _RenderProgressBar extends RenderBox {
|
||||
if (_progress == clamp) {
|
||||
return;
|
||||
}
|
||||
if (_labelLengthDifferent(_progress, clamp)) {
|
||||
_clearLabelCache();
|
||||
}
|
||||
if (!_userIsDraggingThumb) {
|
||||
_progress = clamp;
|
||||
_thumbValue = _proportionOfTotal(clamp);
|
||||
@@ -606,60 +476,6 @@ class _RenderProgressBar extends RenderBox {
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
bool _labelLengthDifferent(Duration first, Duration second) {
|
||||
return (first.inMinutes < 10 && second.inMinutes >= 10) ||
|
||||
(first.inMinutes >= 10 && second.inMinutes < 10) ||
|
||||
(first.inHours == 0 && second.inHours != 0) ||
|
||||
(first.inHours != 0 && second.inHours == 0) ||
|
||||
(first.inHours < 10 && second.inHours >= 10) ||
|
||||
(first.inHours >= 10 && second.inHours < 10);
|
||||
}
|
||||
|
||||
TextPainter? _cachedLeftLabel;
|
||||
Size get _leftLabelSize {
|
||||
_cachedLeftLabel ??= _leftTimeLabel();
|
||||
return _cachedLeftLabel!.size;
|
||||
}
|
||||
|
||||
TextPainter? _cachedRightLabel;
|
||||
Size get _rightLabelSize {
|
||||
_cachedRightLabel ??= _rightTimeLabel();
|
||||
return _cachedRightLabel!.size;
|
||||
}
|
||||
|
||||
void _clearLabelCache() {
|
||||
_cachedLeftLabel?.dispose();
|
||||
_cachedRightLabel?.dispose();
|
||||
_cachedLeftLabel = null;
|
||||
_cachedRightLabel = null;
|
||||
}
|
||||
|
||||
TextPainter _leftTimeLabel() {
|
||||
final text = _getTimeString(progress);
|
||||
return _layoutText(text);
|
||||
}
|
||||
|
||||
TextPainter _rightTimeLabel() {
|
||||
switch (timeLabelType) {
|
||||
case TimeLabelType.totalTime:
|
||||
final text = _getTimeString(total);
|
||||
return _layoutText(text);
|
||||
case TimeLabelType.remainingTime:
|
||||
final remaining = total - progress;
|
||||
final text = '-${_getTimeString(remaining)}';
|
||||
return _layoutText(text);
|
||||
}
|
||||
}
|
||||
|
||||
TextPainter _layoutText(String text) {
|
||||
TextPainter textPainter = TextPainter(
|
||||
text: TextSpan(text: text, style: _timeLabelTextStyle),
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaler: TextScaler.linear(textScaleFactor),
|
||||
)..layout(minWidth: 0, maxWidth: double.infinity);
|
||||
return textPainter;
|
||||
}
|
||||
|
||||
/// The total time length of the media.
|
||||
Duration get total => _total;
|
||||
Duration _total;
|
||||
@@ -668,9 +484,6 @@ class _RenderProgressBar extends RenderBox {
|
||||
if (_total == clamp) {
|
||||
return;
|
||||
}
|
||||
if (_labelLengthDifferent(_total, clamp)) {
|
||||
_clearLabelCache();
|
||||
}
|
||||
_total = clamp;
|
||||
if (!_userIsDraggingThumb) {
|
||||
_thumbValue = _proportionOfTotal(progress);
|
||||
@@ -825,59 +638,6 @@ class _RenderProgressBar extends RenderBox {
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
/// The position of the duration text labels for the progress and total time.
|
||||
TimeLabelLocation get timeLabelLocation => _timeLabelLocation;
|
||||
TimeLabelLocation _timeLabelLocation;
|
||||
set timeLabelLocation(TimeLabelLocation value) {
|
||||
if (_timeLabelLocation == value) return;
|
||||
_timeLabelLocation = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
/// What to display for the time label on the right
|
||||
///
|
||||
/// The right time label can show the total time or the remaining time as a
|
||||
/// negative number. The default is [TimeLabelType.totalTime].
|
||||
TimeLabelType get timeLabelType => _timeLabelType;
|
||||
TimeLabelType _timeLabelType;
|
||||
set timeLabelType(TimeLabelType value) {
|
||||
if (_timeLabelType == value) return;
|
||||
_timeLabelType = value;
|
||||
_clearLabelCache();
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
/// The text style for the duration text labels. By default this style is
|
||||
/// taken from the theme's [textStyle.bodyText1].
|
||||
TextStyle? get timeLabelTextStyle => _timeLabelTextStyle;
|
||||
TextStyle? _timeLabelTextStyle;
|
||||
set timeLabelTextStyle(TextStyle? value) {
|
||||
if (_timeLabelTextStyle == value) return;
|
||||
_timeLabelTextStyle = value;
|
||||
_clearLabelCache();
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
/// The length of the radius for the circular thumb.
|
||||
double get timeLabelPadding => _timeLabelPadding;
|
||||
double _timeLabelPadding;
|
||||
set timeLabelPadding(double value) {
|
||||
if (_timeLabelPadding == value) return;
|
||||
_timeLabelPadding = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
/// The text scale factor for the `progress` and `total` text labels.
|
||||
/// By default the value is 1.0.
|
||||
double get textScaleFactor => _textScaleFactor;
|
||||
double _textScaleFactor;
|
||||
set textScaleFactor(double value) {
|
||||
if (_textScaleFactor == value) return;
|
||||
_textScaleFactor = value;
|
||||
_clearLabelCache();
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
// The smallest that this widget would ever want to be.
|
||||
static const _minDesiredWidth = 100.0;
|
||||
|
||||
@@ -888,10 +648,10 @@ class _RenderProgressBar extends RenderBox {
|
||||
double computeMaxIntrinsicWidth(double height) => _minDesiredWidth;
|
||||
|
||||
@override
|
||||
double computeMinIntrinsicHeight(double width) => _calculateDesiredHeight();
|
||||
double computeMinIntrinsicHeight(double width) => _heightWhenNoLabels();
|
||||
|
||||
@override
|
||||
double computeMaxIntrinsicHeight(double width) => _calculateDesiredHeight();
|
||||
double computeMaxIntrinsicHeight(double width) => _heightWhenNoLabels();
|
||||
|
||||
@override
|
||||
bool hitTestSelf(Offset position) => true;
|
||||
@@ -912,41 +672,15 @@ class _RenderProgressBar extends RenderBox {
|
||||
@override
|
||||
Size computeDryLayout(BoxConstraints constraints) {
|
||||
final desiredWidth = constraints.maxWidth;
|
||||
final desiredHeight = _calculateDesiredHeight();
|
||||
final desiredHeight = _heightWhenNoLabels();
|
||||
final desiredSize = Size(desiredWidth, desiredHeight);
|
||||
return constraints.constrain(desiredSize);
|
||||
}
|
||||
|
||||
// When changing these remember to keep the gesture recognizer for the
|
||||
// thumb in sync.
|
||||
double _calculateDesiredHeight() {
|
||||
switch (_timeLabelLocation) {
|
||||
case TimeLabelLocation.below:
|
||||
case TimeLabelLocation.above:
|
||||
return _heightWhenLabelsAboveOrBelow();
|
||||
case TimeLabelLocation.sides:
|
||||
return _heightWhenLabelsOnSides();
|
||||
default:
|
||||
return _heightWhenNoLabels();
|
||||
}
|
||||
}
|
||||
|
||||
double _heightWhenLabelsAboveOrBelow() {
|
||||
return _heightWhenNoLabels() + _textHeight() + _timeLabelPadding;
|
||||
}
|
||||
|
||||
double _heightWhenLabelsOnSides() {
|
||||
return max(_heightWhenNoLabels(), _textHeight());
|
||||
}
|
||||
|
||||
double _heightWhenNoLabels() {
|
||||
return max(2 * _thumbRadius, _barHeight);
|
||||
}
|
||||
|
||||
double _textHeight() {
|
||||
return _leftLabelSize.height;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isRepaintBoundary => true;
|
||||
|
||||
@@ -956,87 +690,11 @@ class _RenderProgressBar extends RenderBox {
|
||||
..save()
|
||||
..translate(offset.dx, offset.dy);
|
||||
|
||||
switch (_timeLabelLocation) {
|
||||
case TimeLabelLocation.above:
|
||||
case TimeLabelLocation.below:
|
||||
_drawProgressBarWithLabelsAboveOrBelow(canvas);
|
||||
break;
|
||||
case TimeLabelLocation.sides:
|
||||
_drawProgressBarWithLabelsOnSides(canvas);
|
||||
break;
|
||||
default:
|
||||
_drawProgressBarWithoutLabels(canvas);
|
||||
}
|
||||
_drawProgressBarWithoutLabels(canvas);
|
||||
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
/// Draw the progress bar and labels vertically aligned:
|
||||
///
|
||||
/// | -------O---------------- |
|
||||
/// | 01:23 05:00 |
|
||||
///
|
||||
/// Or like this:
|
||||
///
|
||||
/// | 01:23 05:00 |
|
||||
/// | -------O---------------- |
|
||||
void _drawProgressBarWithLabelsAboveOrBelow(Canvas canvas) {
|
||||
// calculate sizes
|
||||
final barWidth = size.width;
|
||||
final barHeight = _heightWhenNoLabels();
|
||||
|
||||
// whether to paint the labels below the progress bar or above it
|
||||
final isLabelBelow = _timeLabelLocation == TimeLabelLocation.below;
|
||||
|
||||
// current time label
|
||||
final labelDy = (isLabelBelow) ? barHeight + _timeLabelPadding : 0.0;
|
||||
final leftLabelOffset = Offset(0, labelDy);
|
||||
_leftTimeLabel().paint(canvas, leftLabelOffset);
|
||||
|
||||
// total or remaining time label
|
||||
final rightLabelDx = size.width - _rightLabelSize.width;
|
||||
final rightLabelOffset = Offset(rightLabelDx, labelDy);
|
||||
_rightTimeLabel().paint(canvas, rightLabelOffset);
|
||||
|
||||
// progress bar
|
||||
final barDy = (isLabelBelow)
|
||||
? 0.0
|
||||
: _leftLabelSize.height + _timeLabelPadding;
|
||||
_drawProgressBar(canvas, Offset(0, barDy), Size(barWidth, barHeight));
|
||||
}
|
||||
|
||||
/// Draw the progress bar and labels horizontally aligned:
|
||||
///
|
||||
/// | 01:23 -------O---------------- 05:00 |
|
||||
///
|
||||
void _drawProgressBarWithLabelsOnSides(Canvas canvas) {
|
||||
// left time label
|
||||
final leftLabelSize = _leftLabelSize;
|
||||
final verticalOffset = size.height / 2 - leftLabelSize.height / 2;
|
||||
final leftLabelOffset = Offset(0, verticalOffset);
|
||||
_leftTimeLabel().paint(canvas, leftLabelOffset);
|
||||
|
||||
// right time label
|
||||
final rightLabelSize = _rightLabelSize;
|
||||
final rightLabelWidth = rightLabelSize.width;
|
||||
final totalLabelDx = size.width - rightLabelWidth;
|
||||
final totalLabelOffset = Offset(totalLabelDx, verticalOffset);
|
||||
_rightTimeLabel().paint(canvas, totalLabelOffset);
|
||||
|
||||
// progress bar
|
||||
final leftLabelWidth = leftLabelSize.width;
|
||||
final barHeight = _heightWhenNoLabels();
|
||||
final barWidth =
|
||||
size.width -
|
||||
2 * _defaultSidePadding -
|
||||
2 * _timeLabelPadding -
|
||||
leftLabelWidth -
|
||||
rightLabelWidth;
|
||||
final barDy = size.height / 2 - barHeight / 2;
|
||||
final barDx = leftLabelWidth + _defaultSidePadding + _timeLabelPadding;
|
||||
_drawProgressBar(canvas, Offset(barDx, barDy), Size(barWidth, barHeight));
|
||||
}
|
||||
|
||||
/// Draw the progress bar without labels like this:
|
||||
///
|
||||
/// | -------O---------------- |
|
||||
@@ -1129,19 +787,6 @@ class _RenderProgressBar extends RenderBox {
|
||||
return (duration.inMilliseconds / total.inMilliseconds).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
String _getTimeString(Duration time) {
|
||||
final minutes = time.inMinutes
|
||||
.remainder(Duration.minutesPerHour)
|
||||
.toString();
|
||||
final seconds = time.inSeconds
|
||||
.remainder(Duration.secondsPerMinute)
|
||||
.toString()
|
||||
.padLeft(2, '0');
|
||||
return time.inHours > 0
|
||||
? "${time.inHours}:${minutes.padLeft(2, "0")}:$seconds"
|
||||
: "$minutes:$seconds";
|
||||
}
|
||||
|
||||
@override
|
||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||
super.describeSemanticsConfiguration(config);
|
||||
|
||||
@@ -128,9 +128,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
//播放器放缩
|
||||
bool interacting = false;
|
||||
|
||||
// 是否在调整固定进度条
|
||||
RxBool draggingFixedProgressBar = false.obs;
|
||||
|
||||
// 阅读器限制
|
||||
// Timer? _accessibilityDebounce;
|
||||
// double _lastAnnouncedValue = -1;
|
||||
@@ -1086,6 +1083,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
maxWidth = widget.maxWidth;
|
||||
maxHeight = widget.maxHeight;
|
||||
final Color primary = theme.colorScheme.primary;
|
||||
late final bufferedBarColor = primary.withValues(alpha: 0.4);
|
||||
const TextStyle textStyle = TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
@@ -1507,13 +1505,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
total: Duration(seconds: max),
|
||||
progressBarColor: primary,
|
||||
baseBarColor: const Color(0x33FFFFFF),
|
||||
bufferedBarColor: primary.withValues(alpha: 0.4),
|
||||
timeLabelLocation: TimeLabelLocation.none,
|
||||
bufferedBarColor: bufferedBarColor,
|
||||
thumbColor: primary,
|
||||
barHeight: 3.5,
|
||||
thumbRadius: draggingFixedProgressBar.value
|
||||
? 7
|
||||
: 2.5,
|
||||
thumbRadius: 2.5,
|
||||
);
|
||||
}),
|
||||
0,
|
||||
|
||||
@@ -30,10 +30,58 @@ class BottomControl extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
Color colorTheme = theme.colorScheme.primary;
|
||||
Color primary = theme.colorScheme.primary;
|
||||
final bufferedBarColor = primary.withValues(alpha: 0.4);
|
||||
//阅读器限制
|
||||
Timer? accessibilityDebounce;
|
||||
double lastAnnouncedValue = -1;
|
||||
void onDragStart(ThumbDragDetails duration) {
|
||||
feedBack();
|
||||
controller.onChangedSliderStart(duration.timeStamp);
|
||||
}
|
||||
|
||||
void onDragUpdate(ThumbDragDetails duration, int max) {
|
||||
if (controller.showSeekPreview) {
|
||||
controller.updatePreviewIndex(
|
||||
duration.timeStamp.inSeconds,
|
||||
);
|
||||
}
|
||||
double newProgress = duration.timeStamp.inSeconds / max;
|
||||
if ((newProgress - lastAnnouncedValue).abs() > 0.02) {
|
||||
accessibilityDebounce?.cancel();
|
||||
accessibilityDebounce = Timer(
|
||||
const Duration(milliseconds: 200),
|
||||
() {
|
||||
SemanticsService.announce(
|
||||
"${(newProgress * 100).round()}%",
|
||||
TextDirection.ltr,
|
||||
);
|
||||
lastAnnouncedValue = newProgress;
|
||||
},
|
||||
);
|
||||
}
|
||||
controller.onUpdatedSliderProgress(
|
||||
duration.timeStamp,
|
||||
);
|
||||
}
|
||||
|
||||
void onSeek(Duration duration, int max) {
|
||||
if (controller.showSeekPreview) {
|
||||
controller.showPreview.value = false;
|
||||
}
|
||||
controller
|
||||
..onChangedSliderEnd()
|
||||
..onChangedSlider(duration.inSeconds.toDouble())
|
||||
..seekTo(
|
||||
Duration(seconds: duration.inSeconds),
|
||||
isSeek: false,
|
||||
);
|
||||
SemanticsService.announce(
|
||||
"${(duration.inSeconds / max * 100).round()}%",
|
||||
TextDirection.ltr,
|
||||
);
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10, 0, 10, 12),
|
||||
child: Column(
|
||||
@@ -57,57 +105,15 @@ class BottomControl extends StatelessWidget {
|
||||
progress: Duration(seconds: value),
|
||||
buffered: Duration(seconds: buffer),
|
||||
total: Duration(seconds: max),
|
||||
progressBarColor: colorTheme,
|
||||
baseBarColor: Colors.white.withValues(alpha: 0.2),
|
||||
bufferedBarColor: colorTheme.withValues(alpha: 0.4),
|
||||
timeLabelLocation: TimeLabelLocation.none,
|
||||
thumbColor: colorTheme,
|
||||
progressBarColor: primary,
|
||||
baseBarColor: const Color(0x33FFFFFF),
|
||||
bufferedBarColor: bufferedBarColor,
|
||||
thumbColor: primary,
|
||||
barHeight: 3.5,
|
||||
thumbRadius: 7,
|
||||
onDragStart: (duration) {
|
||||
feedBack();
|
||||
controller.onChangedSliderStart(duration.timeStamp);
|
||||
},
|
||||
onDragUpdate: (duration) {
|
||||
if (controller.showSeekPreview) {
|
||||
controller.updatePreviewIndex(
|
||||
duration.timeStamp.inSeconds,
|
||||
);
|
||||
}
|
||||
double newProgress = duration.timeStamp.inSeconds / max;
|
||||
if ((newProgress - lastAnnouncedValue).abs() > 0.02) {
|
||||
accessibilityDebounce?.cancel();
|
||||
accessibilityDebounce = Timer(
|
||||
const Duration(milliseconds: 200),
|
||||
() {
|
||||
SemanticsService.announce(
|
||||
"${(newProgress * 100).round()}%",
|
||||
TextDirection.ltr,
|
||||
);
|
||||
lastAnnouncedValue = newProgress;
|
||||
},
|
||||
);
|
||||
}
|
||||
controller.onUpdatedSliderProgress(
|
||||
duration.timeStamp,
|
||||
);
|
||||
},
|
||||
onSeek: (duration) {
|
||||
if (controller.showSeekPreview) {
|
||||
controller.showPreview.value = false;
|
||||
}
|
||||
controller
|
||||
..onChangedSliderEnd()
|
||||
..onChangedSlider(duration.inSeconds.toDouble())
|
||||
..seekTo(
|
||||
Duration(seconds: duration.inSeconds),
|
||||
isSeek: false,
|
||||
);
|
||||
SemanticsService.announce(
|
||||
"${(duration.inSeconds / max * 100).round()}%",
|
||||
TextDirection.ltr,
|
||||
);
|
||||
},
|
||||
onDragStart: onDragStart,
|
||||
onDragUpdate: (e) => onDragUpdate(e, max),
|
||||
onSeek: (e) => onSeek(e, max),
|
||||
);
|
||||
if (Utils.isDesktop) {
|
||||
return MouseRegion(
|
||||
|
||||
Reference in New Issue
Block a user