diff --git a/assets/images/live.png b/assets/images/live.png new file mode 100644 index 000000000..2547e137f Binary files /dev/null and b/assets/images/live.png differ diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart index bb27a38ae..e9b777f14 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -236,7 +236,7 @@ class _BangumiPanelState extends State { children: [ if (i == currentIndex) ...[ Image.asset( - 'assets/images/live.gif', + 'assets/images/live.png', color: Theme.of(context).colorScheme.primary, height: 12, diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 706209e1b..ff3857baf 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -46,13 +46,18 @@ class PlPlayerController { // bool controlsEnabled = false; /// 响应数据 + /// 带有Seconds的变量只在秒数更新时更新,以避免频繁触发重绘 // 播放位置 final Rx _position = Rx(Duration.zero); + final RxInt positionSeconds = 0.obs; final Rx _sliderPosition = Rx(Duration.zero); + final RxInt sliderPositionSeconds = 0.obs; // 展示使用 final Rx _sliderTempPosition = Rx(Duration.zero); final Rx _duration = Rx(Duration.zero); + final RxInt durationSeconds = 0.obs; final Rx _buffered = Rx(Duration.zero); + final RxInt bufferedSeconds = 0.obs; final Rx _playerCount = Rx(0); @@ -225,6 +230,30 @@ class PlPlayerController { // 播放顺序相关 PlayRepeat playRepeat = PlayRepeat.pause; + void updateSliderPositionSecond() { + int newSecond = _sliderPosition.value.inSeconds; + if (sliderPositionSeconds.value != newSecond) { + sliderPositionSeconds.value = newSecond; + } + } + void updatePositionSecond() { + int newSecond = _position.value.inSeconds; + if (positionSeconds.value != newSecond) { + positionSeconds.value = newSecond; + } + } + void updateDurationSecond() { + int newSecond = _duration.value.inSeconds; + if (durationSeconds.value != newSecond) { + durationSeconds.value = newSecond; + } + } + void updateBufferedSecond() { + int newSecond = _buffered.value.inSeconds; + if (bufferedSeconds.value != newSecond) { + bufferedSeconds.value = newSecond; + } + } // 添加一个私有构造函数 PlPlayerController._() { _videoType = videoType; @@ -335,6 +364,7 @@ class PlPlayerController { dataSource, _looping, enableHA, width, height); // 获取视频时长 00:00 _duration.value = duration ?? _videoPlayerController!.state.duration; + updateDurationSecond(); // 数据加载完成 dataStatus.status.value = DataStatus.loaded; @@ -506,7 +536,7 @@ class PlPlayerController { element(event ? PlayerStatus.playing : PlayerStatus.paused); } if (videoPlayerController!.state.position.inSeconds != 0) { - makeHeartBeat(_position.value.inSeconds, type: 'status'); + makeHeartBeat(positionSeconds.value, type: 'status'); } }), videoPlayerController!.stream.completed.listen((event) { @@ -520,12 +550,14 @@ class PlPlayerController { } else { // playerStatus.status.value = PlayerStatus.playing; } - makeHeartBeat(_position.value.inSeconds, type: 'status'); + makeHeartBeat(positionSeconds.value, type: 'status'); }), videoPlayerController!.stream.position.listen((event) { _position.value = event; + updatePositionSecond(); if (!isSliderMoving.value) { _sliderPosition.value = event; + updateSliderPositionSecond(); } /// 触发回调事件 @@ -539,6 +571,7 @@ class PlPlayerController { }), videoPlayerController!.stream.buffer.listen((event) { _buffered.value = event; + updateBufferedSecond(); }), videoPlayerController!.stream.buffering.listen((event) { isBuffering.value = event; @@ -580,6 +613,7 @@ class PlPlayerController { position = Duration.zero; } _position.value = position; + updatePositionSecond(); _heartDuration = position.inSeconds; if (duration.value.inSeconds != 0) { if (type != 'slider') { @@ -667,6 +701,7 @@ class PlPlayerController { /// 临时fix _duration.value丢失 if (duration != null) { _duration.value = duration; + updateDurationSecond(); } audioSessionHandler.setActive(true); } @@ -705,15 +740,17 @@ class PlPlayerController { /// 调整播放时间 onChangedSlider(double v) { _sliderPosition.value = Duration(seconds: v.floor()); + updateSliderPositionSecond(); } void onChangedSliderStart() { _isSliderMoving.value = true; } - void onUodatedSliderProgress(Duration value) { + void onUpdatedSliderProgress(Duration value) { _sliderTempPosition.value = value; _sliderPosition.value = value; + updateSliderPositionSecond(); } void onChangedSliderEnd() { diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 8b8b5780a..66051d2bc 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -486,7 +486,7 @@ class _PLVideoPlayerState extends State milliseconds: curSliderPosition + (details.delta.dx * scale).round()); Duration result = pos.clamp(Duration.zero, _.duration.value); - _.onUodatedSliderProgress(result); + _.onUpdatedSliderProgress(result); _.onChangedSliderStart(); _initTapPositoin = tapPosition; }, @@ -589,9 +589,9 @@ class _PLVideoPlayerState extends State /// 进度条 live模式下禁用 Obx( () { - final int value = _.sliderPosition.value.inSeconds; - final int max = _.duration.value.inSeconds; - final int buffer = _.buffered.value.inSeconds; + final int value = _.sliderPositionSeconds.value; + final int max = _.durationSeconds.value; + final int buffer = _.bufferedSeconds.value; if (defaultBtmProgressBehavior == BtmProgresBehavior.alwaysHide.code) { return Container(); @@ -612,41 +612,42 @@ class _PLVideoPlayerState extends State bottom: -3.5, left: 0, right: 0, - child: SlideTransition( - position: Tween( - begin: Offset.zero, - end: const Offset(0, -1), - ).animate(CurvedAnimation( - parent: animationController, - curve: Curves.easeInOut, - )), - child: ProgressBar( - progress: Duration(seconds: value), - buffered: Duration(seconds: buffer), - total: Duration(seconds: max), - progressBarColor: colorTheme, - baseBarColor: Colors.white.withOpacity(0.2), - bufferedBarColor: - Theme.of(context).colorScheme.primary.withOpacity(0.4), - timeLabelLocation: TimeLabelLocation.none, - thumbColor: colorTheme, - barHeight: 2, - thumbRadius: 0.0, - // onDragStart: (duration) { - // _.onChangedSliderStart(); - // }, - // onDragEnd: () { - // _.onChangedSliderEnd(); - // }, - // onDragUpdate: (details) { - // print(details); - // }, - // onSeek: (duration) { - // feedBack(); - // _.onChangedSlider(duration.inSeconds.toDouble()); - // _.seekTo(duration); - // }, - )), + child: ProgressBar( + progress: Duration(seconds: value), + buffered: Duration(seconds: buffer), + total: Duration(seconds: max), + progressBarColor: colorTheme, + baseBarColor: Colors.white.withOpacity(0.2), + bufferedBarColor: + Theme.of(context).colorScheme.primary.withOpacity(0.4), + timeLabelLocation: TimeLabelLocation.none, + thumbColor: colorTheme, + barHeight: 2, + thumbRadius: 0.0, + // onDragStart: (duration) { + // _.onChangedSliderStart(); + // }, + // onDragEnd: () { + // _.onChangedSliderEnd(); + // }, + // onDragUpdate: (details) { + // print(details); + // }, + // onSeek: (duration) { + // feedBack(); + // _.onChangedSlider(duration.inSeconds.toDouble()); + // _.seekTo(duration); + // }, + ), + // SlideTransition( + // position: Tween( + // begin: Offset.zero, + // end: const Offset(0, -1), + // ).animate(CurvedAnimation( + // parent: animationController, + // curve: Curves.easeInOut, + // )), + // child: ), ); }, ), diff --git a/lib/plugin/pl_player/widgets/bottom_control.dart b/lib/plugin/pl_player/widgets/bottom_control.dart index de8263e50..dfb2c6a0f 100644 --- a/lib/plugin/pl_player/widgets/bottom_control.dart +++ b/lib/plugin/pl_player/widgets/bottom_control.dart @@ -33,9 +33,9 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget { children: [ Obx( () { - final int value = _.sliderPosition.value.inSeconds; - final int max = _.duration.value.inSeconds; - final int buffer = _.buffered.value.inSeconds; + final int value = _.sliderPositionSeconds.value; + final int max = _.durationSeconds.value; + final int buffer = _.bufferedSeconds.value; if (value > max || max <= 0) { return Container(); } @@ -57,7 +57,7 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget { _.onChangedSliderStart(); }, onDragUpdate: (duration) { - _.onUodatedSliderProgress(duration.timeStamp); + _.onUpdatedSliderProgress(duration.timeStamp); }, onSeek: (duration) { _.onChangedSliderEnd(); @@ -78,9 +78,9 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget { // 播放时间 Obx(() { return Text( - _.duration.value.inMinutes >= 60 - ? printDurationWithHours(_.position.value) - : printDuration(_.position.value), + _.durationSeconds.value >= 3600 + ? printDurationWithHours(Duration(seconds: _.positionSeconds.value)) + : printDuration(Duration(seconds: _.positionSeconds.value)), style: textStyle, ); }), @@ -89,9 +89,9 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget { const SizedBox(width: 2), Obx( () => Text( - _.duration.value.inMinutes >= 60 - ? printDurationWithHours(_.duration.value) - : printDuration(_.duration.value), + _.durationSeconds.value >= 3600 + ? printDurationWithHours(Duration(seconds: _.durationSeconds.value)) + : printDuration(Duration(seconds: _.durationSeconds.value)), style: textStyle, ), ),