diff --git a/lib/pages/video/introduction/ugc/widgets/action_item.dart b/lib/pages/video/introduction/ugc/widgets/action_item.dart index 14e3e2dd..bc7cfe8c 100644 --- a/lib/pages/video/introduction/ugc/widgets/action_item.dart +++ b/lib/pages/video/introduction/ugc/widgets/action_item.dart @@ -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, + ), ), ), ), diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 830c2c8b..1f86807a 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -247,7 +247,7 @@ class _PLVideoPlayerState extends State } // 动态构建底部控制条 - 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 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 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 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 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 && diff --git a/lib/plugin/pl_player/widgets/bottom_control.dart b/lib/plugin/pl_player/widgets/bottom_control.dart index aef3996a..4dd7e15b 100644 --- a/lib/plugin/pl_player/widgets/bottom_control.dart +++ b/lib/plugin/pl_player/widgets/bottom_control.dart @@ -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), + ], + ); + }, ), ); }