From 8c8c8620952af22b6ac4c464bba187169eefc528 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 18 Nov 2024 19:32:15 +0800 Subject: [PATCH 1/6] feat: pure dark mode --- lib/main.dart | 25 +++++++++++++++++++++++-- lib/pages/setting/style_setting.dart | 9 +++++++++ lib/utils/storage.dart | 3 ++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 1ec86c8e..30464b0c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -214,6 +214,27 @@ class BuildMainApp extends StatelessWidget { @override Widget build(BuildContext context) { + Box setting = GStorage.setting; + + /// 纯黑模式主题配置 + ColorScheme? pureDarkColorScheme; + final bool enablePureBlack = + setting.get(SettingBoxKey.enablePureBlack, defaultValue: false); + if (enablePureBlack) { + pureDarkColorScheme = darkColorScheme.copyWith( + background: Colors.black, + surface: Colors.black, + primary: Colors.white, + secondary: Colors.white, + error: Colors.red, + onPrimary: Colors.black, + onSecondary: Colors.black, + onSurface: Colors.white, + onBackground: Colors.white, + onError: Colors.white, + ); + } + final SnackBarThemeData snackBarTheme = SnackBarThemeData( actionTextColor: lightColorScheme.primary, backgroundColor: lightColorScheme.secondaryContainer, @@ -253,13 +274,13 @@ class BuildMainApp extends StatelessWidget { title: 'PiliPala', theme: buildThemeData( currentThemeValue == ThemeType.dark - ? darkColorScheme + ? pureDarkColorScheme ?? darkColorScheme : lightColorScheme, ), darkTheme: buildThemeData( currentThemeValue == ThemeType.light ? lightColorScheme - : darkColorScheme, + : pureDarkColorScheme ?? darkColorScheme, ), localizationsDelegates: const [ GlobalCupertinoLocalizations.delegate, diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart index 5b59397e..12f52414 100644 --- a/lib/pages/setting/style_setting.dart +++ b/lib/pages/setting/style_setting.dart @@ -249,6 +249,15 @@ class _StyleSettingState extends State { '当前模式:${settingController.themeType.value.description}', style: subTitleStyle)), ), + SetSwitchItem( + title: '纯黑模式', + subTitle: '深色模式时使用纯黑色背景,适用于OLED屏幕', + setKey: SettingBoxKey.enablePureBlack, + defaultVal: false, + callFn: (bool val) => { + if (val && Get.isDarkMode) {Get.appUpdate()} + }, + ), ListTile( dense: false, onTap: () => settingController.setDynamicBadgeMode(context), diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index a5b36768..ac02592e 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -133,7 +133,8 @@ class SettingBoxKey { enableGradientBg = 'enableGradientBg', enableDynamicSwitch = 'enableDynamicSwitch', navBarSort = 'navBarSort', - actionTypeSort = 'actionTypeSort'; + actionTypeSort = 'actionTypeSort', + enablePureBlack = 'enablePureBlack'; } class LocalCacheKey { From 417c225b27a6df680c044ab7027b6ff80821dd9b Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 4 Dec 2024 23:35:59 +0800 Subject: [PATCH 2/6] mod: pureBlack theme config --- lib/main.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 8dc243ab..6c43a139 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -226,14 +226,8 @@ class BuildMainApp extends StatelessWidget { pureDarkColorScheme = darkColorScheme.copyWith( background: Colors.black, surface: Colors.black, - primary: Colors.white, - secondary: Colors.white, - error: Colors.red, onPrimary: Colors.black, onSecondary: Colors.black, - onSurface: Colors.white, - onBackground: Colors.white, - onError: Colors.white, ); } From 30c1a5037da503222e9c624722b5c7c5f7722c5e Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 7 Dec 2024 20:45:05 +0800 Subject: [PATCH 3/6] opt: control bar height --- .../video/detail/widgets/header_control.dart | 11 +- lib/plugin/pl_player/view.dart | 858 +++++++++--------- .../pl_player/widgets/bottom_control.dart | 9 +- 3 files changed, 437 insertions(+), 441 deletions(-) diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 28448f51..718cdac6 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -1068,13 +1068,10 @@ class _HeaderControlState extends State { ); final bool isLandscape = MediaQuery.of(context).orientation == Orientation.landscape; - return AppBar( - backgroundColor: Colors.transparent, - foregroundColor: Colors.white, - primary: false, - automaticallyImplyLeading: false, - titleSpacing: 14, - title: Column( + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 14), + child: Column( + mainAxisSize: MainAxisSize.min, children: [ if (isFullScreen.value && isLandscape) ...[ Row( diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index b47d38de..0790d10a 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -443,334 +443,336 @@ class _PLVideoPlayerState extends State color: Colors.white, fontSize: 12, ); - return Stack( - fit: StackFit.passthrough, - children: [ - Obx( - () => Video( - key: ValueKey(_.videoFit.value), - controller: videoController, - controls: NoVideoControls, - alignment: widget.alignment!, - pauseUponEnteringBackgroundMode: !enableBackgroundPlay, - resumeUponEnteringForegroundMode: true, - subtitleViewConfiguration: const SubtitleViewConfiguration( - style: subTitleStyle, - padding: EdgeInsets.all(24.0), + return ClipRect( + child: Stack( + fit: StackFit.passthrough, + children: [ + Obx( + () => Video( + key: ValueKey(_.videoFit.value), + controller: videoController, + controls: NoVideoControls, + alignment: widget.alignment!, + pauseUponEnteringBackgroundMode: !enableBackgroundPlay, + resumeUponEnteringForegroundMode: true, + subtitleViewConfiguration: const SubtitleViewConfiguration( + style: subTitleStyle, + padding: EdgeInsets.all(24.0), + ), + fit: _.videoFit.value, ), - fit: _.videoFit.value, ), - ), - /// 长按倍速 toast - Obx( - () => Align( - alignment: Alignment.topCenter, - child: FractionalTranslation( - translation: const Offset(0.0, 0.3), // 上下偏移量(负数向上偏移) - child: AnimatedOpacity( - curve: Curves.easeInOut, - opacity: _.doubleSpeedStatus.value ? 1.0 : 0.0, - duration: const Duration(milliseconds: 150), - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color(0x88000000), - borderRadius: BorderRadius.circular(16.0), - ), - height: 32.0, - width: 70.0, - child: const Center( - child: Text( - '倍速中', - style: TextStyle(color: Colors.white, fontSize: 13), + /// 长按倍速 toast + Obx( + () => Align( + alignment: Alignment.topCenter, + child: FractionalTranslation( + translation: const Offset(0.0, 0.3), // 上下偏移量(负数向上偏移) + child: AnimatedOpacity( + curve: Curves.easeInOut, + opacity: _.doubleSpeedStatus.value ? 1.0 : 0.0, + duration: const Duration(milliseconds: 150), + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color(0x88000000), + borderRadius: BorderRadius.circular(16.0), ), - )), + height: 32.0, + width: 70.0, + child: const Center( + child: Text( + '倍速中', + style: TextStyle(color: Colors.white, fontSize: 13), + ), + )), + ), ), ), ), - ), - /// 时间进度 toast - Obx( - () => Align( - alignment: Alignment.topCenter, - child: FractionalTranslation( - translation: const Offset(0.0, 1.0), // 上下偏移量(负数向上偏移) - child: AnimatedOpacity( - curve: Curves.easeInOut, - opacity: _.isSliderMoving.value ? 1.0 : 0.0, - duration: const Duration(milliseconds: 150), - child: IntrinsicWidth( - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color(0x88000000), - borderRadius: BorderRadius.circular(64.0), - ), - height: 34.0, - padding: const EdgeInsets.only(left: 10, right: 10), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Obx(() { - return Text( - _.sliderTempPosition.value.inMinutes >= 60 - ? printDurationWithHours( - _.sliderTempPosition.value) - : printDuration(_.sliderTempPosition.value), - style: textStyle, - ); - }), - const SizedBox(width: 2), - const Text('/', style: textStyle), - const SizedBox(width: 2), - Obx( - () => Text( - _.duration.value.inMinutes >= 60 - ? printDurationWithHours(_.duration.value) - : printDuration(_.duration.value), - style: textStyle, + /// 时间进度 toast + Obx( + () => Align( + alignment: Alignment.topCenter, + child: FractionalTranslation( + translation: const Offset(0.0, 1.0), // 上下偏移量(负数向上偏移) + child: AnimatedOpacity( + curve: Curves.easeInOut, + opacity: _.isSliderMoving.value ? 1.0 : 0.0, + duration: const Duration(milliseconds: 150), + child: IntrinsicWidth( + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color(0x88000000), + borderRadius: BorderRadius.circular(64.0), + ), + height: 34.0, + padding: const EdgeInsets.only(left: 10, right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Obx(() { + return Text( + _.sliderTempPosition.value.inMinutes >= 60 + ? printDurationWithHours( + _.sliderTempPosition.value) + : printDuration(_.sliderTempPosition.value), + style: textStyle, + ); + }), + const SizedBox(width: 2), + const Text('/', style: textStyle), + const SizedBox(width: 2), + Obx( + () => Text( + _.duration.value.inMinutes >= 60 + ? printDurationWithHours(_.duration.value) + : printDuration(_.duration.value), + style: textStyle, + ), ), - ), - ], + ], + ), ), ), ), ), ), ), - ), - /// 音量🔊 控制条展示 - Obx( - () => ControlBar( - visible: _volumeIndicator.value, - icon: _volumeValue.value < 1.0 / 3.0 - ? Icons.volume_mute - : _volumeValue.value < 2.0 / 3.0 - ? Icons.volume_down - : Icons.volume_up, - value: _volumeValue.value, + /// 音量🔊 控制条展示 + Obx( + () => ControlBar( + visible: _volumeIndicator.value, + icon: _volumeValue.value < 1.0 / 3.0 + ? Icons.volume_mute + : _volumeValue.value < 2.0 / 3.0 + ? Icons.volume_down + : Icons.volume_up, + value: _volumeValue.value, + ), ), - ), - /// 亮度🌞 控制条展示 - Obx( - () => ControlBar( - visible: _brightnessIndicator.value, - icon: _brightnessValue.value < 1.0 / 3.0 - ? Icons.brightness_low - : _brightnessValue.value < 2.0 / 3.0 - ? Icons.brightness_medium - : Icons.brightness_high, - value: _brightnessValue.value, + /// 亮度🌞 控制条展示 + Obx( + () => ControlBar( + visible: _brightnessIndicator.value, + icon: _brightnessValue.value < 1.0 / 3.0 + ? Icons.brightness_low + : _brightnessValue.value < 2.0 / 3.0 + ? Icons.brightness_medium + : Icons.brightness_high, + value: _brightnessValue.value, + ), ), - ), - // Obx(() { - // if (_.buffered.value == Duration.zero) { - // return Positioned.fill( - // child: Container( - // color: Colors.black, - // child: Center( - // child: Image.asset( - // 'assets/images/loading.gif', - // height: 25, - // ), - // ), - // ), - // ); - // } else { - // return Container(); - // } - // }), + // Obx(() { + // if (_.buffered.value == Duration.zero) { + // return Positioned.fill( + // child: Container( + // color: Colors.black, + // child: Center( + // child: Image.asset( + // 'assets/images/loading.gif', + // height: 25, + // ), + // ), + // ), + // ); + // } else { + // return Container(); + // } + // }), - /// 弹幕面板 - if (widget.danmuWidget != null) - Positioned.fill(top: 4, child: widget.danmuWidget!), + /// 弹幕面板 + if (widget.danmuWidget != null) + Positioned.fill(top: 4, child: widget.danmuWidget!), - /// 开启且有字幕时展示 - Stack( - children: [ - Positioned( - left: 0, - right: 0, - bottom: 30, - child: Align( - alignment: Alignment.center, - child: Obx( - () => Visibility( - visible: widget.controller.subTitleCode.value != -1, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: widget.controller.subtitleContent.value != '' - ? Colors.black.withOpacity(0.6) - : Colors.transparent, - ), - padding: widget.controller.subTitleCode.value != -1 - ? const EdgeInsets.symmetric( - horizontal: 10, - vertical: 4, - ) - : EdgeInsets.zero, - child: Text( - widget.controller.subtitleContent.value, - style: const TextStyle( - color: Colors.white, - fontSize: 12, + /// 开启且有字幕时展示 + Stack( + children: [ + Positioned( + left: 0, + right: 0, + bottom: 30, + child: Align( + alignment: Alignment.center, + child: Obx( + () => Visibility( + visible: widget.controller.subTitleCode.value != -1, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: widget.controller.subtitleContent.value != '' + ? Colors.black.withOpacity(0.6) + : Colors.transparent, ), - ), - )), + padding: widget.controller.subTitleCode.value != -1 + ? const EdgeInsets.symmetric( + horizontal: 10, + vertical: 4, + ) + : EdgeInsets.zero, + child: Text( + widget.controller.subtitleContent.value, + style: const TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + )), + ), ), ), - ), - ], - ), - - /// 手势 - Positioned.fill( - left: 16, - top: 25, - right: 15, - bottom: 15, - child: GestureDetector( - onTap: () { - _.controls = !_.showControls.value; - }, - onDoubleTapDown: (TapDownDetails details) { - // live模式下禁用 锁定时🔒禁用 - if (_.videoType == 'live' || _.controlsLock.value) { - return; - } - final double totalWidth = MediaQuery.sizeOf(context).width; - final double tapPosition = details.localPosition.dx; - final double sectionWidth = totalWidth / 3; - String type = 'left'; - if (tapPosition < sectionWidth) { - type = 'left'; - } else if (tapPosition < sectionWidth * 2) { - type = 'center'; - } else { - type = 'right'; - } - doubleTapFuc(type); - }, - onLongPressStart: (LongPressStartDetails detail) { - feedBack(); - _.setDoubleSpeedStatus(true); - }, - onLongPressEnd: (LongPressEndDetails details) { - _.setDoubleSpeedStatus(false); - }, - - /// 水平位置 快进 live模式下禁用 - onHorizontalDragUpdate: (DragUpdateDetails details) { - // live模式下禁用 锁定时🔒禁用 - if (_.videoType == 'live' || _.controlsLock.value) { - return; - } - // final double tapPosition = details.localPosition.dx; - final int curSliderPosition = - _.sliderPosition.value.inMilliseconds; - final double scale = 90000 / MediaQuery.sizeOf(context).width; - final Duration pos = Duration( - milliseconds: - curSliderPosition + (details.delta.dx * scale).round()); - final Duration result = - pos.clamp(Duration.zero, _.duration.value); - _.onUpdatedSliderProgress(result); - _.onChangedSliderStart(); - }, - onHorizontalDragEnd: (DragEndDetails details) { - if (_.videoType == 'live' || _.controlsLock.value) { - return; - } - _.onChangedSliderEnd(); - _.seekTo(_.sliderPosition.value, type: 'slider'); - }, - // 垂直方向 音量/亮度调节 - onVerticalDragUpdate: (DragUpdateDetails details) async { - final double totalWidth = MediaQuery.sizeOf(context).width; - final double tapPosition = details.localPosition.dx; - final double sectionWidth = - fullScreenGestureMode == FullScreenGestureMode.none - ? totalWidth / 2 - : totalWidth / 3; - final double delta = details.delta.dy; - - /// 锁定时禁用 - if (_.controlsLock.value) { - return; - } - if (lastFullScreenToggleTime != null && - DateTime.now().difference(lastFullScreenToggleTime!) < - const Duration(milliseconds: 500)) { - return; - } - if (tapPosition < sectionWidth) { - // 左边区域 👈 - final double level = (_.isFullScreen.value - ? Get.size.height - : screenWidth * 9 / 16) * - 3; - final double brightness = - _brightnessValue.value - delta / level; - final double result = brightness.clamp(0.0, 1.0); - setBrightness(result); - } else if (isUsingFullScreenGestures(tapPosition, sectionWidth)) { - // 全屏 - final double dy = details.delta.dy; - const double threshold = 7.0; // 滑动阈值 - final bool flag = fullScreenGestureMode != - FullScreenGestureMode.fromBottomtoTop; - if (dy > _distance.value && - dy > threshold && - !_.controlsLock.value) { - if (_.isFullScreen.value ^ flag) { - lastFullScreenToggleTime = DateTime.now(); - // 下滑退出全屏 - await widget.controller.triggerFullScreen(status: flag); - } - _distance.value = 0.0; - } else if (dy < _distance.value && - dy < -threshold && - !_.controlsLock.value) { - if (!_.isFullScreen.value ^ flag) { - lastFullScreenToggleTime = DateTime.now(); - // 上滑进入全屏 - await widget.controller.triggerFullScreen(status: !flag); - } - _distance.value = 0.0; - } - _distance.value = dy; - } else { - // 右边区域 👈 - EasyThrottle.throttle( - 'setVolume', const Duration(milliseconds: 20), () { - final double level = (_.isFullScreen.value - ? Get.size.height - : screenWidth * 9 / 16); - final double volume = _volumeValue.value - - double.parse(delta.toStringAsFixed(1)) / level; - final double result = volume.clamp(0.0, 1.0); - setVolume(result); - }); - } - }, - onVerticalDragEnd: (DragEndDetails details) {}, + ], ), - ), - // 头部、底部控制条 - Obx( - () => Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (widget.headerControl != null || _.headerControl != null) ...[ - Flexible( - child: ClipRect( + /// 手势 + Positioned.fill( + left: 16, + top: 25, + right: 15, + bottom: 15, + child: GestureDetector( + onTap: () { + _.controls = !_.showControls.value; + }, + onDoubleTapDown: (TapDownDetails details) { + // live模式下禁用 锁定时🔒禁用 + if (_.videoType == 'live' || _.controlsLock.value) { + return; + } + final double totalWidth = MediaQuery.sizeOf(context).width; + final double tapPosition = details.localPosition.dx; + final double sectionWidth = totalWidth / 3; + String type = 'left'; + if (tapPosition < sectionWidth) { + type = 'left'; + } else if (tapPosition < sectionWidth * 2) { + type = 'center'; + } else { + type = 'right'; + } + doubleTapFuc(type); + }, + onLongPressStart: (LongPressStartDetails detail) { + feedBack(); + _.setDoubleSpeedStatus(true); + }, + onLongPressEnd: (LongPressEndDetails details) { + _.setDoubleSpeedStatus(false); + }, + + /// 水平位置 快进 live模式下禁用 + onHorizontalDragUpdate: (DragUpdateDetails details) { + // live模式下禁用 锁定时🔒禁用 + if (_.videoType == 'live' || _.controlsLock.value) { + return; + } + // final double tapPosition = details.localPosition.dx; + final int curSliderPosition = + _.sliderPosition.value.inMilliseconds; + final double scale = 90000 / MediaQuery.sizeOf(context).width; + final Duration pos = Duration( + milliseconds: + curSliderPosition + (details.delta.dx * scale).round()); + final Duration result = + pos.clamp(Duration.zero, _.duration.value); + _.onUpdatedSliderProgress(result); + _.onChangedSliderStart(); + }, + onHorizontalDragEnd: (DragEndDetails details) { + if (_.videoType == 'live' || _.controlsLock.value) { + return; + } + _.onChangedSliderEnd(); + _.seekTo(_.sliderPosition.value, type: 'slider'); + }, + // 垂直方向 音量/亮度调节 + onVerticalDragUpdate: (DragUpdateDetails details) async { + final double totalWidth = MediaQuery.sizeOf(context).width; + final double tapPosition = details.localPosition.dx; + final double sectionWidth = + fullScreenGestureMode == FullScreenGestureMode.none + ? totalWidth / 2 + : totalWidth / 3; + final double delta = details.delta.dy; + + /// 锁定时禁用 + if (_.controlsLock.value) { + return; + } + if (lastFullScreenToggleTime != null && + DateTime.now().difference(lastFullScreenToggleTime!) < + const Duration(milliseconds: 500)) { + return; + } + if (tapPosition < sectionWidth) { + // 左边区域 👈 + final double level = (_.isFullScreen.value + ? Get.size.height + : screenWidth * 9 / 16) * + 3; + final double brightness = + _brightnessValue.value - delta / level; + final double result = brightness.clamp(0.0, 1.0); + setBrightness(result); + } else if (isUsingFullScreenGestures( + tapPosition, sectionWidth)) { + // 全屏 + final double dy = details.delta.dy; + const double threshold = 7.0; // 滑动阈值 + final bool flag = fullScreenGestureMode != + FullScreenGestureMode.fromBottomtoTop; + if (dy > _distance.value && + dy > threshold && + !_.controlsLock.value) { + if (_.isFullScreen.value ^ flag) { + lastFullScreenToggleTime = DateTime.now(); + // 下滑退出全屏 + await widget.controller.triggerFullScreen(status: flag); + } + _distance.value = 0.0; + } else if (dy < _distance.value && + dy < -threshold && + !_.controlsLock.value) { + if (!_.isFullScreen.value ^ flag) { + lastFullScreenToggleTime = DateTime.now(); + // 上滑进入全屏 + await widget.controller.triggerFullScreen(status: !flag); + } + _distance.value = 0.0; + } + _distance.value = dy; + } else { + // 右边区域 👈 + EasyThrottle.throttle( + 'setVolume', const Duration(milliseconds: 20), () { + final double level = (_.isFullScreen.value + ? Get.size.height + : screenWidth * 9 / 16); + final double volume = _volumeValue.value - + double.parse(delta.toStringAsFixed(1)) / level; + final double result = volume.clamp(0.0, 1.0); + setVolume(result); + }); + } + }, + onVerticalDragEnd: (DragEndDetails details) {}, + ), + ), + + // 头部、底部控制条 + Obx( + () => Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (widget.headerControl != null || + _.headerControl != null) ...[ + Flexible( child: AppBarAni( controller: animationController, visible: !_.controlsLock.value && _.showControls.value, @@ -778,13 +780,11 @@ class _PLVideoPlayerState extends State child: widget.headerControl ?? _.headerControl!, ), ), - ), - ] else ...[ - const SizedBox.shrink() - ], - Flexible( - flex: _.videoType == 'live' ? 0 : 1, - child: ClipRect( + ] else ...[ + const SizedBox.shrink() + ], + Flexible( + flex: _.videoType == 'live' ? 0 : 1, child: AppBarAni( controller: animationController, visible: !_.controlsLock.value && _.showControls.value, @@ -797,141 +797,141 @@ class _PLVideoPlayerState extends State ), ), ), - ), - ], + ], + ), ), - ), - /// 进度条 live模式下禁用 + /// 进度条 live模式下禁用 - Obx( - () { - final int value = _.sliderPositionSeconds.value; - final int max = _.durationSeconds.value; - final int buffer = _.bufferedSeconds.value; - if (_.showControls.value) { - return Container(); - } - if (defaultBtmProgressBehavior == - BtmProgresBehavior.alwaysHide.code) { - return const SizedBox(); - } - if (defaultBtmProgressBehavior == - BtmProgresBehavior.onlyShowFullScreen.code && - !_.isFullScreen.value) { - return const SizedBox(); - } else if (defaultBtmProgressBehavior == - BtmProgresBehavior.onlyHideFullScreen.code && - _.isFullScreen.value) { - return const SizedBox(); - } + Obx( + () { + final int value = _.sliderPositionSeconds.value; + final int max = _.durationSeconds.value; + final int buffer = _.bufferedSeconds.value; + if (_.showControls.value) { + return Container(); + } + if (defaultBtmProgressBehavior == + BtmProgresBehavior.alwaysHide.code) { + return const SizedBox(); + } + if (defaultBtmProgressBehavior == + BtmProgresBehavior.onlyShowFullScreen.code && + !_.isFullScreen.value) { + return const SizedBox(); + } else if (defaultBtmProgressBehavior == + BtmProgresBehavior.onlyHideFullScreen.code && + _.isFullScreen.value) { + return const SizedBox(); + } - if (_.videoType == 'live') { - return const SizedBox(); - } - if (value > max || max <= 0) { - return const SizedBox(); - } - return Positioned( - bottom: -1.5, - left: 0, - right: 0, - child: ProgressBar( - progress: Duration(seconds: value), - buffered: Duration(seconds: buffer), - total: Duration(seconds: max), - progressBarColor: colorTheme, - baseBarColor: Colors.white.withOpacity(0.2), - bufferedBarColor: Colors.white.withOpacity(0.6), - timeLabelLocation: TimeLabelLocation.none, - thumbColor: colorTheme, - barHeight: 3, - 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: ), - ); - }, - ), + if (_.videoType == 'live') { + return const SizedBox(); + } + if (value > max || max <= 0) { + return const SizedBox(); + } + return Positioned( + bottom: -1.5, + left: 0, + right: 0, + child: ProgressBar( + progress: Duration(seconds: value), + buffered: Duration(seconds: buffer), + total: Duration(seconds: max), + progressBarColor: colorTheme, + baseBarColor: Colors.white.withOpacity(0.2), + bufferedBarColor: Colors.white.withOpacity(0.6), + timeLabelLocation: TimeLabelLocation.none, + thumbColor: colorTheme, + barHeight: 3, + 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: ), + ); + }, + ), - // 锁 - Obx( - () => Visibility( - visible: _.videoType != 'live' && _.isFullScreen.value, - child: Align( - alignment: Alignment.centerLeft, - child: FractionalTranslation( - translation: const Offset(1, 0.0), - child: Visibility( - visible: _.showControls.value, - child: ComBtn( - icon: Icon( - _.controlsLock.value - ? FontAwesomeIcons.lock - : FontAwesomeIcons.lockOpen, - size: 15, - color: Colors.white, + // 锁 + Obx( + () => Visibility( + visible: _.videoType != 'live' && _.isFullScreen.value, + child: Align( + alignment: Alignment.centerLeft, + child: FractionalTranslation( + translation: const Offset(1, 0.0), + child: Visibility( + visible: _.showControls.value, + child: ComBtn( + icon: Icon( + _.controlsLock.value + ? FontAwesomeIcons.lock + : FontAwesomeIcons.lockOpen, + size: 15, + color: Colors.white, + ), + fuc: () => _.onLockControl(!_.controlsLock.value), ), - fuc: () => _.onLockControl(!_.controlsLock.value), ), ), ), ), ), - ), - // - Obx(() { - if (_.dataStatus.loading || _.isBuffering.value) { - return Center( - child: Container( - padding: const EdgeInsets.all(30), - decoration: const BoxDecoration( - shape: BoxShape.circle, - gradient: RadialGradient( - colors: [Colors.black26, Colors.transparent], + // + Obx(() { + if (_.dataStatus.loading || _.isBuffering.value) { + return Center( + child: Container( + padding: const EdgeInsets.all(30), + decoration: const BoxDecoration( + shape: BoxShape.circle, + gradient: RadialGradient( + colors: [Colors.black26, Colors.transparent], + ), + ), + child: Lottie.asset( + 'assets/loading.json', + width: 200, ), ), - child: Lottie.asset( - 'assets/loading.json', - width: 200, - ), - ), - ); - } else { - return const SizedBox(); - } - }), + ); + } else { + return const SizedBox(); + } + }), - /// 快进/快退面板 - SeekPanel( - mountSeekBackwardButton: _mountSeekBackwardButton, - mountSeekForwardButton: _mountSeekForwardButton, - hideSeekBackwardButton: _hideSeekBackwardButton, - hideSeekForwardButton: _hideSeekForwardButton, - onSubmittedcb: _handleSubmittedCallback, - ), - ], + /// 快进/快退面板 + SeekPanel( + mountSeekBackwardButton: _mountSeekBackwardButton, + mountSeekForwardButton: _mountSeekForwardButton, + hideSeekBackwardButton: _hideSeekBackwardButton, + hideSeekForwardButton: _hideSeekForwardButton, + onSubmittedcb: _handleSubmittedCallback, + ), + ], + ), ); } } diff --git a/lib/plugin/pl_player/widgets/bottom_control.dart b/lib/plugin/pl_player/widgets/bottom_control.dart index 3c21c2af..67652fff 100644 --- a/lib/plugin/pl_player/widgets/bottom_control.dart +++ b/lib/plugin/pl_player/widgets/bottom_control.dart @@ -18,19 +18,18 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { - return Container( - color: Colors.transparent, - height: 90, + return Padding( padding: const EdgeInsets.symmetric(horizontal: 18), child: Column( mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, children: [ Padding( - padding: const EdgeInsets.fromLTRB(7, 0, 7, 6), + padding: const EdgeInsets.fromLTRB(7, 0, 7, 4), child: ProgressBarWidget(controller: controller!), ), Row(children: buildBottomControl!), - const SizedBox(height: 10), + const SizedBox(height: 6), ], ), ); From d91d4ab62e1a78e33eba987ae773f5b4262d9cbd Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 8 Dec 2024 20:48:11 +0800 Subject: [PATCH 4/6] fix: forward dynamics reply --- lib/http/api.dart | 3 +++ lib/http/dynamics.dart | 21 +++++++++++++++++++++ lib/pages/dynamics/detail/controller.dart | 18 +++++++++++------- lib/pages/dynamics/detail/view.dart | 3 +-- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/http/api.dart b/lib/http/api.dart index 379540a5..04847cab 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -626,4 +626,7 @@ class Api { /// 修复标题和海报 // /api/view?id=${aid} /all/video/av${aid} /video/av${aid}/ static const String fixTitleAndPic = '${HttpString.biliplusBaseUrl}/api/view'; + + /// 专栏详情 + static const String opusDetail = '/x/polymer/web-dynamic/v1/opus/detail'; } diff --git a/lib/http/dynamics.dart b/lib/http/dynamics.dart index 53ba6fc1..74b9b566 100644 --- a/lib/http/dynamics.dart +++ b/lib/http/dynamics.dart @@ -215,4 +215,25 @@ class DynamicsHttp { }; } } + + static Future opusDetail({ + required int opusId, + }) async { + var res = await Request().get( + Api.opusDetail, + data: {'id': opusId}, + ); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': res.data['data'], + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } } diff --git a/lib/pages/dynamics/detail/controller.dart b/lib/pages/dynamics/detail/controller.dart index a5f04bbe..ac68565d 100644 --- a/lib/pages/dynamics/detail/controller.dart +++ b/lib/pages/dynamics/detail/controller.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; -import 'package:pilipala/http/html.dart'; +import 'package:pilipala/http/dynamics.dart'; import 'package:pilipala/http/reply.dart'; import 'package:pilipala/models/common/reply_sort_type.dart'; import 'package:pilipala/models/video/reply/item.dart'; @@ -12,6 +12,7 @@ class DynamicDetailController extends GetxController { DynamicDetailController(this.oid, this.type); int? oid; int? type; + int? opusId; dynamic item; int? floor; String nextOffset = ""; @@ -56,6 +57,12 @@ class DynamicDetailController extends GetxController { if (reqType == 'init') { nextOffset = ''; noMore.value = ''; + if (opusId != null && oid == 0) { + var res = await DynamicsHttp.opusDetail(opusId: opusId!); + if (res['status']) { + oid = int.parse(res['data']['item']['basic']['comment_id_str']); + } + } } var res = await ReplyHttp.replyList( oid: oid!, @@ -110,15 +117,12 @@ class DynamicDetailController extends GetxController { sortTypeTitle.value = _sortType.titles; sortTypeLabel.value = _sortType.labels; replyList.clear(); + noMore.value = ''; + isLoadingMore = false; + isEnd = false; queryReplyList(reqType: 'init'); } - // 根据jumpUrl获取动态html - reqHtmlByOpusId(int id) async { - var res = await HtmlHttp.reqHtml(id, 'opus'); - oid = res['commentId']; - } - // 上拉加载 Future onLoad() async { queryReplyList(reqType: 'onLoad'); diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index 5c8f85e3..cd180fbe 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -89,9 +89,8 @@ class _DynamicDetailPageState extends State _dynamicDetailController = Get.put( DynamicDetailController(oid, replyType), tag: opusId.toString()); + _dynamicDetailController.opusId = opusId; _futureBuilderFuture = _dynamicDetailController.queryReplyList(); - await _dynamicDetailController.reqHtmlByOpusId(opusId!); - setState(() {}); } } else { oid = moduleDynamic.major!.draw!.id!; From ef7d84409d5c23007e53f1eef1ec7ec0c2101a77 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 8 Dec 2024 21:03:18 +0800 Subject: [PATCH 5/6] fix: repeated reply logic --- lib/pages/video/detail/reply/controller.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index 38d59617..9c4855c5 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -73,7 +73,7 @@ class VideoReplyController extends GetxController { /// 临时修复 final bool flag = replyList .any((ReplyItemModel reply) => reply.rpid == replies.first.rpid); - if (replies.length == 1 && flag) { + if (replies.length == 1 && flag && type == 'onLoad') { replies.clear(); isEnd = true; } From e24ac4fbfb1017d886d30e639009573cc573ac0b Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 9 Dec 2024 00:32:53 +0800 Subject: [PATCH 6/6] fix: live fullScreen pip error --- lib/pages/live_room/view.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index ced55e37..801f1440 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -110,7 +110,8 @@ class _LiveRoomPageState extends State Widget build(BuildContext context) { final mediaQuery = MediaQuery.of(context); final isPortrait = mediaQuery.orientation == Orientation.portrait; - final isLandscape = mediaQuery.orientation == Orientation.landscape; + final RxBool isLandscape = + (mediaQuery.orientation == Orientation.landscape).obs; final padding = mediaQuery.padding; @@ -194,7 +195,7 @@ class _LiveRoomPageState extends State Obx( () => SizedBox( height: padding.top + - (_liveRoomController.isPortrait.value || isLandscape + (_liveRoomController.isPortrait.value || isLandscape.value ? 0 : kToolbarHeight), ), @@ -205,14 +206,14 @@ class _LiveRoomPageState extends State if (plPlayerController.isFullScreen.value == true) { plPlayerController.triggerFullScreen(status: false); } - if (isLandscape) { + if (isLandscape.value) { verticalScreen(); } }, child: Obx( () => Container( width: Get.size.width, - height: isLandscape + height: isLandscape.value ? Get.size.height : !_liveRoomController.isPortrait.value ? Get.size.width * 9 / 16 @@ -313,7 +314,7 @@ class _LiveRoomPageState extends State ), // 消息列表 Visibility( - visible: !isLandscape, + visible: !isLandscape.value, child: Obx( () => Align( alignment: Alignment.bottomCenter,