mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-01 08:38:18 +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/material.dart';
|
||||||
import 'package:flutter/rendering.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.
|
/// The shape of the progress bar at the left and right ends.
|
||||||
enum BarCapShape {
|
enum BarCapShape {
|
||||||
/// The left and right ends of the bar are round.
|
/// The left and right ends of the bar are round.
|
||||||
@@ -83,20 +37,15 @@ class ProgressBar extends LeafRenderObjectWidget {
|
|||||||
this.onDragUpdate,
|
this.onDragUpdate,
|
||||||
this.onDragEnd,
|
this.onDragEnd,
|
||||||
this.barHeight = 5.0,
|
this.barHeight = 5.0,
|
||||||
this.baseBarColor,
|
required this.baseBarColor,
|
||||||
this.progressBarColor,
|
required this.progressBarColor,
|
||||||
this.bufferedBarColor,
|
required this.bufferedBarColor,
|
||||||
this.barCapShape = BarCapShape.round,
|
this.barCapShape = BarCapShape.round,
|
||||||
this.thumbRadius = 10.0,
|
this.thumbRadius = 10.0,
|
||||||
this.thumbColor,
|
required this.thumbColor,
|
||||||
this.thumbGlowColor,
|
this.thumbGlowColor,
|
||||||
this.thumbGlowRadius = 30.0,
|
this.thumbGlowRadius = 30.0,
|
||||||
this.thumbCanPaintOutsideBar = true,
|
this.thumbCanPaintOutsideBar = true,
|
||||||
this.timeLabelLocation,
|
|
||||||
this.timeLabelType,
|
|
||||||
this.timeLabelTextStyle,
|
|
||||||
this.timeLabelPadding = 0.0,
|
|
||||||
this.textScaleFactor = 1.0,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The elapsed playing time of the media.
|
/// 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.
|
/// The color of the progress bar before playback has started.
|
||||||
///
|
///
|
||||||
/// By default it is a transparent version of your theme's primary color.
|
/// 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
|
/// The color of the progress bar to the left of the current playing
|
||||||
/// [progress].
|
/// [progress].
|
||||||
///
|
///
|
||||||
/// By default it is your theme's primary color.
|
/// 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
|
/// The color of the progress bar between the [progress] location and the
|
||||||
/// [buffered] location.
|
/// [buffered] location.
|
||||||
///
|
///
|
||||||
/// By default it is a transparent version of your theme's primary color,
|
/// By default it is a transparent version of your theme's primary color,
|
||||||
/// a shade darker than [baseBarColor].
|
/// a shade darker than [baseBarColor].
|
||||||
final Color? bufferedBarColor;
|
final Color bufferedBarColor;
|
||||||
|
|
||||||
/// The shape of the bar at the left and right ends.
|
/// 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.
|
/// The color of the circle for the moveable progress bar thumb.
|
||||||
///
|
///
|
||||||
/// By default it is your theme's primary color.
|
/// 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.
|
/// 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.
|
/// is happening during this time, though.
|
||||||
final bool thumbCanPaintOutsideBar;
|
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
|
@override
|
||||||
RenderObject createRenderObject(BuildContext context) {
|
RenderObject createRenderObject(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
|
||||||
final primaryColor = theme.colorScheme.primary;
|
|
||||||
final textStyle = timeLabelTextStyle ?? theme.textTheme.bodyLarge;
|
|
||||||
return _RenderProgressBar(
|
return _RenderProgressBar(
|
||||||
progress: progress,
|
progress: progress,
|
||||||
total: total,
|
total: total,
|
||||||
@@ -269,30 +190,20 @@ class ProgressBar extends LeafRenderObjectWidget {
|
|||||||
onDragUpdate: onDragUpdate,
|
onDragUpdate: onDragUpdate,
|
||||||
onDragEnd: onDragEnd,
|
onDragEnd: onDragEnd,
|
||||||
barHeight: barHeight,
|
barHeight: barHeight,
|
||||||
baseBarColor: baseBarColor ?? primaryColor.withValues(alpha: 0.24),
|
baseBarColor: baseBarColor,
|
||||||
progressBarColor: progressBarColor ?? primaryColor,
|
progressBarColor: progressBarColor,
|
||||||
bufferedBarColor:
|
bufferedBarColor: bufferedBarColor,
|
||||||
bufferedBarColor ?? primaryColor.withValues(alpha: 0.24),
|
|
||||||
barCapShape: barCapShape,
|
barCapShape: barCapShape,
|
||||||
thumbRadius: thumbRadius,
|
thumbRadius: thumbRadius,
|
||||||
thumbColor: thumbColor ?? primaryColor,
|
thumbColor: thumbColor,
|
||||||
thumbGlowColor:
|
thumbGlowColor: thumbGlowColor ?? thumbColor,
|
||||||
thumbGlowColor ?? (thumbColor ?? primaryColor).withAlpha(80),
|
|
||||||
thumbGlowRadius: thumbGlowRadius,
|
thumbGlowRadius: thumbGlowRadius,
|
||||||
thumbCanPaintOutsideBar: thumbCanPaintOutsideBar,
|
thumbCanPaintOutsideBar: thumbCanPaintOutsideBar,
|
||||||
timeLabelLocation: timeLabelLocation ?? TimeLabelLocation.below,
|
|
||||||
timeLabelType: timeLabelType ?? TimeLabelType.totalTime,
|
|
||||||
timeLabelTextStyle: textStyle,
|
|
||||||
timeLabelPadding: timeLabelPadding,
|
|
||||||
textScaleFactor: textScaleFactor,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void updateRenderObject(BuildContext context, RenderObject renderObject) {
|
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)
|
(renderObject as _RenderProgressBar)
|
||||||
..total = total
|
..total = total
|
||||||
..progress = progress
|
..progress = progress
|
||||||
@@ -302,22 +213,15 @@ class ProgressBar extends LeafRenderObjectWidget {
|
|||||||
..onDragUpdate = onDragUpdate
|
..onDragUpdate = onDragUpdate
|
||||||
..onDragEnd = onDragEnd
|
..onDragEnd = onDragEnd
|
||||||
..barHeight = barHeight
|
..barHeight = barHeight
|
||||||
..baseBarColor = baseBarColor ?? primaryColor.withValues(alpha: 0.24)
|
..baseBarColor = baseBarColor
|
||||||
..progressBarColor = progressBarColor ?? primaryColor
|
..progressBarColor = progressBarColor
|
||||||
..bufferedBarColor =
|
..bufferedBarColor = bufferedBarColor
|
||||||
bufferedBarColor ?? primaryColor.withValues(alpha: 0.24)
|
|
||||||
..barCapShape = barCapShape
|
..barCapShape = barCapShape
|
||||||
..thumbRadius = thumbRadius
|
..thumbRadius = thumbRadius
|
||||||
..thumbColor = thumbColor ?? primaryColor
|
..thumbColor = thumbColor
|
||||||
..thumbGlowColor =
|
..thumbGlowColor = thumbGlowColor ?? thumbColor
|
||||||
thumbGlowColor ?? (thumbColor ?? primaryColor).withAlpha(80)
|
|
||||||
..thumbGlowRadius = thumbGlowRadius
|
..thumbGlowRadius = thumbGlowRadius
|
||||||
..thumbCanPaintOutsideBar = thumbCanPaintOutsideBar
|
..thumbCanPaintOutsideBar = thumbCanPaintOutsideBar;
|
||||||
..timeLabelLocation = timeLabelLocation ?? TimeLabelLocation.below
|
|
||||||
..timeLabelType = timeLabelType ?? TimeLabelType.totalTime
|
|
||||||
..timeLabelTextStyle = textStyle
|
|
||||||
..timeLabelPadding = timeLabelPadding
|
|
||||||
..textScaleFactor = textScaleFactor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -372,11 +276,7 @@ class ProgressBar extends LeafRenderObjectWidget {
|
|||||||
ifFalse: 'false',
|
ifFalse: 'false',
|
||||||
showName: true,
|
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,
|
required Color thumbGlowColor,
|
||||||
double thumbGlowRadius = 30.0,
|
double thumbGlowRadius = 30.0,
|
||||||
bool thumbCanPaintOutsideBar = true,
|
bool thumbCanPaintOutsideBar = true,
|
||||||
required TimeLabelLocation timeLabelLocation,
|
|
||||||
required TimeLabelType timeLabelType,
|
|
||||||
TextStyle? timeLabelTextStyle,
|
|
||||||
double timeLabelPadding = 0.0,
|
|
||||||
double textScaleFactor = 1.0,
|
|
||||||
}) : _total = total,
|
}) : _total = total,
|
||||||
_buffered = buffered,
|
_buffered = buffered,
|
||||||
_onSeek = onSeek,
|
_onSeek = onSeek,
|
||||||
@@ -466,12 +361,7 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
_thumbColor = thumbColor,
|
_thumbColor = thumbColor,
|
||||||
_thumbGlowColor = thumbGlowColor,
|
_thumbGlowColor = thumbGlowColor,
|
||||||
_thumbGlowRadius = thumbGlowRadius,
|
_thumbGlowRadius = thumbGlowRadius,
|
||||||
_thumbCanPaintOutsideBar = thumbCanPaintOutsideBar,
|
_thumbCanPaintOutsideBar = thumbCanPaintOutsideBar {
|
||||||
_timeLabelLocation = timeLabelLocation,
|
|
||||||
_timeLabelType = timeLabelType,
|
|
||||||
_timeLabelTextStyle = timeLabelTextStyle,
|
|
||||||
_timeLabelPadding = timeLabelPadding,
|
|
||||||
_textScaleFactor = textScaleFactor {
|
|
||||||
_drag = _EagerHorizontalDragGestureRecognizer()
|
_drag = _EagerHorizontalDragGestureRecognizer()
|
||||||
..onStart = _onDragStart
|
..onStart = _onDragStart
|
||||||
..onUpdate = _onDragUpdate
|
..onUpdate = _onDragUpdate
|
||||||
@@ -486,7 +376,6 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_drag?.dispose();
|
_drag?.dispose();
|
||||||
_clearLabelCache();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,14 +392,6 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
// time as a [progress] update there won't be a conflict.
|
// time as a [progress] update there won't be a conflict.
|
||||||
bool _userIsDraggingThumb = false;
|
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) {
|
void _onDragStart(DragStartDetails details) {
|
||||||
if (onDragStart == null) {
|
if (onDragStart == null) {
|
||||||
return;
|
return;
|
||||||
@@ -565,20 +446,12 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
// only one place to make changes.
|
// only one place to make changes.
|
||||||
void _updateThumbPosition(Offset localPosition) {
|
void _updateThumbPosition(Offset localPosition) {
|
||||||
final dx = localPosition.dx;
|
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
|
// 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
|
// 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.
|
// equal to half of the line width, which in this case is the bar height.
|
||||||
final barCapRadius = _barHeight / 2;
|
final barCapRadius = _barHeight / 2;
|
||||||
double barStart = lengthBefore + barCapRadius;
|
double barStart = barCapRadius;
|
||||||
double barEnd = size.width - lengthAfter - barCapRadius;
|
double barEnd = size.width - barCapRadius;
|
||||||
final barWidth = barEnd - barStart;
|
final barWidth = barEnd - barStart;
|
||||||
final position = (dx - barStart).clamp(0.0, barWidth);
|
final position = (dx - barStart).clamp(0.0, barWidth);
|
||||||
_thumbValue = (position / barWidth);
|
_thumbValue = (position / barWidth);
|
||||||
@@ -596,9 +469,6 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
if (_progress == clamp) {
|
if (_progress == clamp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_labelLengthDifferent(_progress, clamp)) {
|
|
||||||
_clearLabelCache();
|
|
||||||
}
|
|
||||||
if (!_userIsDraggingThumb) {
|
if (!_userIsDraggingThumb) {
|
||||||
_progress = clamp;
|
_progress = clamp;
|
||||||
_thumbValue = _proportionOfTotal(clamp);
|
_thumbValue = _proportionOfTotal(clamp);
|
||||||
@@ -606,60 +476,6 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
markNeedsPaint();
|
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.
|
/// The total time length of the media.
|
||||||
Duration get total => _total;
|
Duration get total => _total;
|
||||||
Duration _total;
|
Duration _total;
|
||||||
@@ -668,9 +484,6 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
if (_total == clamp) {
|
if (_total == clamp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_labelLengthDifferent(_total, clamp)) {
|
|
||||||
_clearLabelCache();
|
|
||||||
}
|
|
||||||
_total = clamp;
|
_total = clamp;
|
||||||
if (!_userIsDraggingThumb) {
|
if (!_userIsDraggingThumb) {
|
||||||
_thumbValue = _proportionOfTotal(progress);
|
_thumbValue = _proportionOfTotal(progress);
|
||||||
@@ -825,59 +638,6 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
markNeedsPaint();
|
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.
|
// The smallest that this widget would ever want to be.
|
||||||
static const _minDesiredWidth = 100.0;
|
static const _minDesiredWidth = 100.0;
|
||||||
|
|
||||||
@@ -888,10 +648,10 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
double computeMaxIntrinsicWidth(double height) => _minDesiredWidth;
|
double computeMaxIntrinsicWidth(double height) => _minDesiredWidth;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMinIntrinsicHeight(double width) => _calculateDesiredHeight();
|
double computeMinIntrinsicHeight(double width) => _heightWhenNoLabels();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMaxIntrinsicHeight(double width) => _calculateDesiredHeight();
|
double computeMaxIntrinsicHeight(double width) => _heightWhenNoLabels();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool hitTestSelf(Offset position) => true;
|
bool hitTestSelf(Offset position) => true;
|
||||||
@@ -912,41 +672,15 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
@override
|
@override
|
||||||
Size computeDryLayout(BoxConstraints constraints) {
|
Size computeDryLayout(BoxConstraints constraints) {
|
||||||
final desiredWidth = constraints.maxWidth;
|
final desiredWidth = constraints.maxWidth;
|
||||||
final desiredHeight = _calculateDesiredHeight();
|
final desiredHeight = _heightWhenNoLabels();
|
||||||
final desiredSize = Size(desiredWidth, desiredHeight);
|
final desiredSize = Size(desiredWidth, desiredHeight);
|
||||||
return constraints.constrain(desiredSize);
|
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() {
|
double _heightWhenNoLabels() {
|
||||||
return max(2 * _thumbRadius, _barHeight);
|
return max(2 * _thumbRadius, _barHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
double _textHeight() {
|
|
||||||
return _leftLabelSize.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isRepaintBoundary => true;
|
bool get isRepaintBoundary => true;
|
||||||
|
|
||||||
@@ -956,87 +690,11 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
..save()
|
..save()
|
||||||
..translate(offset.dx, offset.dy);
|
..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();
|
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:
|
/// Draw the progress bar without labels like this:
|
||||||
///
|
///
|
||||||
/// | -------O---------------- |
|
/// | -------O---------------- |
|
||||||
@@ -1129,19 +787,6 @@ class _RenderProgressBar extends RenderBox {
|
|||||||
return (duration.inMilliseconds / total.inMilliseconds).clamp(0.0, 1.0);
|
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
|
@override
|
||||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
super.describeSemanticsConfiguration(config);
|
super.describeSemanticsConfiguration(config);
|
||||||
|
|||||||
@@ -128,9 +128,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
//播放器放缩
|
//播放器放缩
|
||||||
bool interacting = false;
|
bool interacting = false;
|
||||||
|
|
||||||
// 是否在调整固定进度条
|
|
||||||
RxBool draggingFixedProgressBar = false.obs;
|
|
||||||
|
|
||||||
// 阅读器限制
|
// 阅读器限制
|
||||||
// Timer? _accessibilityDebounce;
|
// Timer? _accessibilityDebounce;
|
||||||
// double _lastAnnouncedValue = -1;
|
// double _lastAnnouncedValue = -1;
|
||||||
@@ -1086,6 +1083,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
maxWidth = widget.maxWidth;
|
maxWidth = widget.maxWidth;
|
||||||
maxHeight = widget.maxHeight;
|
maxHeight = widget.maxHeight;
|
||||||
final Color primary = theme.colorScheme.primary;
|
final Color primary = theme.colorScheme.primary;
|
||||||
|
late final bufferedBarColor = primary.withValues(alpha: 0.4);
|
||||||
const TextStyle textStyle = TextStyle(
|
const TextStyle textStyle = TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@@ -1507,13 +1505,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
total: Duration(seconds: max),
|
total: Duration(seconds: max),
|
||||||
progressBarColor: primary,
|
progressBarColor: primary,
|
||||||
baseBarColor: const Color(0x33FFFFFF),
|
baseBarColor: const Color(0x33FFFFFF),
|
||||||
bufferedBarColor: primary.withValues(alpha: 0.4),
|
bufferedBarColor: bufferedBarColor,
|
||||||
timeLabelLocation: TimeLabelLocation.none,
|
|
||||||
thumbColor: primary,
|
thumbColor: primary,
|
||||||
barHeight: 3.5,
|
barHeight: 3.5,
|
||||||
thumbRadius: draggingFixedProgressBar.value
|
thumbRadius: 2.5,
|
||||||
? 7
|
|
||||||
: 2.5,
|
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
0,
|
0,
|
||||||
|
|||||||
@@ -30,10 +30,58 @@ class BottomControl extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(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;
|
Timer? accessibilityDebounce;
|
||||||
double lastAnnouncedValue = -1;
|
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(
|
return Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(10, 0, 10, 12),
|
padding: const EdgeInsets.fromLTRB(10, 0, 10, 12),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -57,57 +105,15 @@ class BottomControl extends StatelessWidget {
|
|||||||
progress: Duration(seconds: value),
|
progress: Duration(seconds: value),
|
||||||
buffered: Duration(seconds: buffer),
|
buffered: Duration(seconds: buffer),
|
||||||
total: Duration(seconds: max),
|
total: Duration(seconds: max),
|
||||||
progressBarColor: colorTheme,
|
progressBarColor: primary,
|
||||||
baseBarColor: Colors.white.withValues(alpha: 0.2),
|
baseBarColor: const Color(0x33FFFFFF),
|
||||||
bufferedBarColor: colorTheme.withValues(alpha: 0.4),
|
bufferedBarColor: bufferedBarColor,
|
||||||
timeLabelLocation: TimeLabelLocation.none,
|
thumbColor: primary,
|
||||||
thumbColor: colorTheme,
|
|
||||||
barHeight: 3.5,
|
barHeight: 3.5,
|
||||||
thumbRadius: 7,
|
thumbRadius: 7,
|
||||||
onDragStart: (duration) {
|
onDragStart: onDragStart,
|
||||||
feedBack();
|
onDragUpdate: (e) => onDragUpdate(e, max),
|
||||||
controller.onChangedSliderStart(duration.timeStamp);
|
onSeek: (e) => onSeek(e, max),
|
||||||
},
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
if (Utils.isDesktop) {
|
if (Utils.isDesktop) {
|
||||||
return MouseRegion(
|
return MouseRegion(
|
||||||
|
|||||||
Reference in New Issue
Block a user