mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-19 16:46:22 +08:00
opt video bar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -49,13 +49,15 @@ class ActionItem extends StatelessWidget {
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
AnimatedBuilder(
|
||||
animation: animation!,
|
||||
builder: (context, child) => CustomPaint(
|
||||
size: const Size.square(28),
|
||||
painter: _ArcPainter(
|
||||
color: primary,
|
||||
sweepAngle: animation!.value,
|
||||
RepaintBoundary(
|
||||
child: AnimatedBuilder(
|
||||
animation: animation!,
|
||||
builder: (context, child) => CustomPaint(
|
||||
size: const Size.square(28),
|
||||
painter: _ArcPainter(
|
||||
color: primary,
|
||||
sweepAngle: animation!.value,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -247,7 +247,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
}
|
||||
|
||||
// 动态构建底部控制条
|
||||
Widget buildBottomControl(bool isLandscape) {
|
||||
Widget buildBottomControl(bool isLandscape, double maxWidth) {
|
||||
final videoDetail = introController.videoDetail.value;
|
||||
final isSeason = videoDetail.ugcSeason != null;
|
||||
final isPart = videoDetail.pages != null && videoDetail.pages!.length > 1;
|
||||
@@ -659,14 +659,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
children: [
|
||||
...userSpecifyItemLeft.map(progressWidget),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => FittedBox(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: constraints.maxWidth),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: userSpecifyItemRight.map(progressWidget).toList(),
|
||||
),
|
||||
child: FittedBox(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: maxWidth),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: userSpecifyItemRight.map(progressWidget).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1292,9 +1290,11 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
widget.bottomControl ??
|
||||
BottomControl(
|
||||
controller: plPlayerController,
|
||||
buildBottomControl: () =>
|
||||
buildBottomControl(maxWidth > maxHeight),
|
||||
maxWidth: maxWidth,
|
||||
buildBottomControl: (bottomMaxWidth) =>
|
||||
buildBottomControl(
|
||||
maxWidth > maxHeight,
|
||||
bottomMaxWidth,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1472,10 +1472,13 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
right: 0,
|
||||
bottom: 0.75,
|
||||
child: IgnorePointer(
|
||||
child: CustomPaint(
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors: plPlayerController.segmentList,
|
||||
child: RepaintBoundary(
|
||||
child: CustomPaint(
|
||||
key: const Key('segmentList'),
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors: plPlayerController.segmentList,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1487,10 +1490,13 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
right: 0,
|
||||
bottom: 0.75,
|
||||
child: IgnorePointer(
|
||||
child: CustomPaint(
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors: plPlayerController.viewPointList,
|
||||
child: RepaintBoundary(
|
||||
child: CustomPaint(
|
||||
key: const Key('viewPointList'),
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors: plPlayerController.viewPointList,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1851,6 +1857,10 @@ Widget buildSeekPreviewWidget(
|
||||
|
||||
VideoShotData data = plPlayerController.videoShot!['data'];
|
||||
|
||||
if (data.index.isNullOrEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
try {
|
||||
double scale =
|
||||
plPlayerController.isFullScreen.value &&
|
||||
|
||||
@@ -13,13 +13,11 @@ class BottomControl extends StatelessWidget {
|
||||
const BottomControl({
|
||||
required this.controller,
|
||||
required this.buildBottomControl,
|
||||
required this.maxWidth,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final PlPlayerController controller;
|
||||
final Widget Function() buildBottomControl;
|
||||
final double maxWidth;
|
||||
final Widget Function(double maxWidth) buildBottomControl;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -30,136 +28,161 @@ class BottomControl extends StatelessWidget {
|
||||
double lastAnnouncedValue = -1;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Obx(
|
||||
() {
|
||||
final int value = controller.sliderPositionSeconds.value;
|
||||
final int max = controller.durationSeconds.value.inSeconds;
|
||||
final int buffer = controller.bufferedSeconds.value;
|
||||
if (value > max || max <= 0) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 7),
|
||||
child: Semantics(
|
||||
value: '${(value / max * 100).round()}%',
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: [
|
||||
if (controller.dmTrend.isNotEmpty &&
|
||||
controller.showDmTreandChart.value)
|
||||
buildDmChart(theme, controller, 4.5),
|
||||
if (controller.viewPointList.isNotEmpty &&
|
||||
controller.showVP.value)
|
||||
buildViewPointWidget(controller, 8.75, maxWidth),
|
||||
ProgressBar(
|
||||
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,
|
||||
barHeight: 3.5,
|
||||
thumbRadius: 7,
|
||||
onDragStart: (duration) {
|
||||
feedBack();
|
||||
controller.onChangedSliderStart(duration.timeStamp);
|
||||
},
|
||||
onDragUpdate: (duration) {
|
||||
double newProgress =
|
||||
duration.timeStamp.inSeconds / max;
|
||||
if (controller.showSeekPreview) {
|
||||
if (!controller.showPreview.value) {
|
||||
controller.showPreview.value = true;
|
||||
}
|
||||
controller.previewDx.value =
|
||||
duration.localPosition.dx;
|
||||
}
|
||||
if ((newProgress - lastAnnouncedValue).abs() > 0.02) {
|
||||
accessibilityDebounce?.cancel();
|
||||
accessibilityDebounce = Timer(
|
||||
const Duration(milliseconds: 200),
|
||||
() {
|
||||
SemanticsService.announce(
|
||||
"${(newProgress * 100).round()}%",
|
||||
TextDirection.ltr,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final maxWidth = constraints.maxWidth;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Obx(
|
||||
() {
|
||||
final int value = controller.sliderPositionSeconds.value;
|
||||
final int max = controller.durationSeconds.value.inSeconds;
|
||||
final int buffer = controller.bufferedSeconds.value;
|
||||
if (value > max || max <= 0) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 7,
|
||||
),
|
||||
child: Semantics(
|
||||
value: '${(value / max * 100).round()}%',
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: [
|
||||
if (controller.dmTrend.isNotEmpty &&
|
||||
controller.showDmTreandChart.value)
|
||||
buildDmChart(theme, controller, 4.5),
|
||||
if (controller.viewPointList.isNotEmpty &&
|
||||
controller.showVP.value)
|
||||
buildViewPointWidget(
|
||||
controller,
|
||||
8.75,
|
||||
maxWidth - 20,
|
||||
),
|
||||
ProgressBar(
|
||||
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,
|
||||
barHeight: 3.5,
|
||||
thumbRadius: 7,
|
||||
onDragStart: (duration) {
|
||||
feedBack();
|
||||
controller.onChangedSliderStart(
|
||||
duration.timeStamp,
|
||||
);
|
||||
},
|
||||
onDragUpdate: (duration) {
|
||||
double newProgress =
|
||||
duration.timeStamp.inSeconds / max;
|
||||
if (controller.showSeekPreview) {
|
||||
if (!controller.showPreview.value) {
|
||||
controller.showPreview.value = true;
|
||||
}
|
||||
controller.previewDx.value =
|
||||
duration.localPosition.dx;
|
||||
}
|
||||
if ((newProgress - lastAnnouncedValue).abs() >
|
||||
0.02) {
|
||||
accessibilityDebounce?.cancel();
|
||||
accessibilityDebounce = Timer(
|
||||
const Duration(milliseconds: 200),
|
||||
() {
|
||||
SemanticsService.announce(
|
||||
"${(newProgress * 100).round()}%",
|
||||
TextDirection.ltr,
|
||||
);
|
||||
lastAnnouncedValue = newProgress;
|
||||
},
|
||||
);
|
||||
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,
|
||||
);
|
||||
},
|
||||
}
|
||||
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 (controller.segmentList.isNotEmpty)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 5.25,
|
||||
child: IgnorePointer(
|
||||
child: RepaintBoundary(
|
||||
child: CustomPaint(
|
||||
key: const Key('segmentList'),
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors: controller.segmentList,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (controller.viewPointList.isNotEmpty &&
|
||||
controller.showVP.value)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 5.25,
|
||||
child: IgnorePointer(
|
||||
child: RepaintBoundary(
|
||||
child: CustomPaint(
|
||||
key: const Key('viewPointList'),
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors: controller.viewPointList,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (controller.showSeekPreview &&
|
||||
controller.showControls.value)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 18,
|
||||
child: buildSeekPreviewWidget(
|
||||
controller,
|
||||
maxWidth - 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (controller.segmentList.isNotEmpty)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 5.25,
|
||||
child: IgnorePointer(
|
||||
child: CustomPaint(
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors: controller.segmentList,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (controller.viewPointList.isNotEmpty &&
|
||||
controller.showVP.value)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 5.25,
|
||||
child: IgnorePointer(
|
||||
child: CustomPaint(
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors: controller.viewPointList,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (controller.showSeekPreview &&
|
||||
controller.showControls.value)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 18,
|
||||
child: buildSeekPreviewWidget(controller, maxWidth),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
buildBottomControl(),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
buildBottomControl(maxWidth),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user