diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 2b14b621..d6795c52 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -317,13 +317,15 @@ class VideoDetailController extends GetxController closestNumber = 30280; } firstAudio = audiosList.firstWhere((e) => e.id == closestNumber); + } else { + firstAudio = AudioItem(); } } catch (err) { - firstAudio = audiosList.first; + firstAudio = audiosList.isNotEmpty ? audiosList.first : AudioItem(); SmartDialog.showToast('firstAudio error: $err'); } - audioUrl = firstAudio!.baseUrl ?? ''; + audioUrl = firstAudio.baseUrl ?? ''; // if (firstAudio.id != null) { currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!; diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 6a2ffaa2..4478e8d0 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -820,6 +820,9 @@ class PlPlayerController { builder: (context) => Dialog.fullscreen( backgroundColor: Colors.black, child: SafeArea( + // 忽略手机安全区域 + left: false, + right: false, bottom: direction.value == 'vertical' || mode == FullScreenMode.vertical ? true diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 81e82e74..b3905b24 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -48,25 +48,26 @@ class _PLVideoPlayerState extends State with TickerProviderStateMixin { late AnimationController animationController; late VideoController videoController; + final PLVideoPlayerController _ctr = Get.put(PLVideoPlayerController()); - bool _mountSeekBackwardButton = false; - bool _mountSeekForwardButton = false; - bool _hideSeekBackwardButton = false; - bool _hideSeekForwardButton = false; + // bool _mountSeekBackwardButton = false; + // bool _mountSeekForwardButton = false; + // bool _hideSeekBackwardButton = false; + // bool _hideSeekForwardButton = false; - double _brightnessValue = 0.0; - bool _brightnessIndicator = false; + // double _brightnessValue = 0.0; + // bool _brightnessIndicator = false; Timer? _brightnessTimer; - double _volumeValue = 0.0; - bool _volumeIndicator = false; + // double _volumeValue = 0.0; + // bool _volumeIndicator = false; Timer? _volumeTimer; double _distance = 0.0; // 初始手指落下位置 double _initTapPositoin = 0.0; - bool _volumeInterceptEventStream = false; + // bool _volumeInterceptEventStream = false; Box setting = GStrorage.setting; late FullScreenMode mode; @@ -75,15 +76,11 @@ class _PLVideoPlayerState extends State late bool enableBackgroundPlay; void onDoubleTapSeekBackward() { - setState(() { - _mountSeekBackwardButton = true; - }); + _ctr.onDoubleTapSeekBackward(); } void onDoubleTapSeekForward() { - setState(() { - _mountSeekForwardButton = true; - }); + _ctr.onDoubleTapSeekForward(); } // 双击播放、暂停 @@ -135,12 +132,10 @@ class _PLVideoPlayerState extends State Future.microtask(() async { try { FlutterVolumeController.showSystemUI = true; - _volumeValue = (await FlutterVolumeController.getVolume())!; + _ctr.volumeValue.value = (await FlutterVolumeController.getVolume())!; FlutterVolumeController.addListener((value) { - if (mounted && !_volumeInterceptEventStream) { - setState(() { - _volumeValue = value; - }); + if (mounted && !_ctr.volumeInterceptEventStream.value) { + _ctr.volumeValue.value = value; } }); } catch (_) {} @@ -148,12 +143,10 @@ class _PLVideoPlayerState extends State Future.microtask(() async { try { - _brightnessValue = await ScreenBrightness().current; + _ctr.brightnessValue.value = await ScreenBrightness().current; ScreenBrightness().onCurrentBrightnessChanged.listen((value) { if (mounted) { - setState(() { - _brightnessValue = value; - }); + _ctr.brightnessValue.value = value; } }); } catch (_) {} @@ -165,18 +158,14 @@ class _PLVideoPlayerState extends State FlutterVolumeController.showSystemUI = false; await FlutterVolumeController.setVolume(value); } catch (_) {} - setState(() { - _volumeValue = value; - _volumeIndicator = true; - _volumeInterceptEventStream = true; - }); + _ctr.volumeValue.value = value; + _ctr.volumeIndicator.value = true; + _ctr.volumeInterceptEventStream.value = true; _volumeTimer?.cancel(); _volumeTimer = Timer(const Duration(milliseconds: 200), () { if (mounted) { - setState(() { - _volumeIndicator = false; - _volumeInterceptEventStream = false; - }); + _ctr.volumeIndicator.value = false; + _ctr.volumeInterceptEventStream.value = false; } }); } @@ -185,15 +174,11 @@ class _PLVideoPlayerState extends State try { await ScreenBrightness().setScreenBrightness(value); } catch (_) {} - setState(() { - _brightnessIndicator = true; - }); + _ctr.brightnessIndicator.value = true; _brightnessTimer?.cancel(); _brightnessTimer = Timer(const Duration(milliseconds: 200), () { if (mounted) { - setState(() { - _brightnessIndicator = false; - }); + _ctr.brightnessIndicator.value = false; } }); widget.controller.brightness.value = value; @@ -322,103 +307,107 @@ class _PLVideoPlayerState extends State ), /// 音量🔊 控制条展示 - Align( - alignment: Alignment.center, - child: AnimatedOpacity( - curve: Curves.easeInOut, - opacity: _volumeIndicator ? 1.0 : 0.0, - duration: const Duration(milliseconds: 150), - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color(0x88000000), - borderRadius: BorderRadius.circular(64.0), - ), - height: 34.0, - width: 70.0, - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - height: 34.0, - width: 28.0, - alignment: Alignment.centerRight, - child: Icon( - _volumeValue == 0.0 - ? Icons.volume_off - : _volumeValue < 0.5 - ? Icons.volume_down - : Icons.volume_up, - color: const Color(0xFFFFFFFF), - size: 20.0, - ), - ), - Expanded( - child: Text( - '${(_volumeValue * 100.0).round()}%', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 13.0, - color: Color(0xFFFFFFFF), + Obx( + () => Align( + alignment: Alignment.center, + child: AnimatedOpacity( + curve: Curves.easeInOut, + opacity: _ctr.volumeIndicator.value ? 1.0 : 0.0, + duration: const Duration(milliseconds: 150), + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color(0x88000000), + borderRadius: BorderRadius.circular(64.0), + ), + height: 34.0, + width: 70.0, + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + height: 34.0, + width: 28.0, + alignment: Alignment.centerRight, + child: Icon( + _ctr.volumeValue.value == 0.0 + ? Icons.volume_off + : _ctr.volumeValue.value < 0.5 + ? Icons.volume_down + : Icons.volume_up, + color: const Color(0xFFFFFFFF), + size: 20.0, ), ), - ), - const SizedBox(width: 6.0), - ], + Expanded( + child: Text( + '${(_ctr.volumeValue.value * 100.0).round()}%', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 13.0, + color: Color(0xFFFFFFFF), + ), + ), + ), + const SizedBox(width: 6.0), + ], + ), ), ), ), ), /// 亮度🌞 控制条展示 - Align( - alignment: Alignment.center, - child: AnimatedOpacity( - curve: Curves.easeInOut, - opacity: _brightnessIndicator ? 1.0 : 0.0, - duration: const Duration(milliseconds: 150), - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color(0x88000000), - borderRadius: BorderRadius.circular(64.0), - ), - height: 34.0, - width: 70.0, - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - height: 30.0, - width: 28.0, - alignment: Alignment.centerRight, - child: Icon( - _brightnessValue < 1.0 / 3.0 - ? Icons.brightness_low - : _brightnessValue < 2.0 / 3.0 - ? Icons.brightness_medium - : Icons.brightness_high, - color: const Color(0xFFFFFFFF), - size: 18.0, - ), - ), - const SizedBox(width: 2.0), - Expanded( - child: Text( - '${(_brightnessValue * 100.0).round()}%', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 13.0, - color: Color(0xFFFFFFFF), + Obx( + () => Align( + alignment: Alignment.center, + child: AnimatedOpacity( + curve: Curves.easeInOut, + opacity: _ctr.brightnessIndicator.value ? 1.0 : 0.0, + duration: const Duration(milliseconds: 150), + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color(0x88000000), + borderRadius: BorderRadius.circular(64.0), + ), + height: 34.0, + width: 70.0, + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + height: 30.0, + width: 28.0, + alignment: Alignment.centerRight, + child: Icon( + _ctr.brightnessValue.value < 1.0 / 3.0 + ? Icons.brightness_low + : _ctr.brightnessValue.value < 2.0 / 3.0 + ? Icons.brightness_medium + : Icons.brightness_high, + color: const Color(0xFFFFFFFF), + size: 18.0, ), ), - ), - const SizedBox(width: 6.0), - ], + const SizedBox(width: 2.0), + Expanded( + child: Text( + '${(_ctr.brightnessValue.value * 100.0).round()}%', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 13.0, + color: Color(0xFFFFFFFF), + ), + ), + ), + const SizedBox(width: 6.0), + ], + ), ), ), ), @@ -525,7 +514,7 @@ class _PLVideoPlayerState extends State } if (tapPosition < sectionWidth) { // 左边区域 👈 - final brightness = _brightnessValue - delta / 100.0; + final brightness = _ctr.brightnessValue.value - delta / 100.0; final result = brightness.clamp(0.0, 1.0); setBrightness(result); } else if (tapPosition < sectionWidth * 2) { @@ -548,7 +537,7 @@ class _PLVideoPlayerState extends State _distance = dy; } else { // 右边区域 👈 - final volume = _volumeValue - delta / 100.0; + final volume = _ctr.volumeValue.value - delta / 100.0; final result = volume.clamp(0.0, 1.0); setVolume(result); } @@ -704,103 +693,129 @@ class _PLVideoPlayerState extends State }), /// 点击 快进/快退 - if (_mountSeekBackwardButton || _mountSeekForwardButton) - Positioned.fill( - child: Row( - children: [ - Expanded( - child: _mountSeekBackwardButton - ? TweenAnimationBuilder( - tween: Tween( - begin: 0.0, - end: _hideSeekBackwardButton ? 0.0 : 1.0, - ), - duration: const Duration(milliseconds: 500), - builder: (context, value, child) => Opacity( - opacity: value, - child: child, - ), - onEnd: () { - if (_hideSeekBackwardButton) { - setState(() { - _hideSeekBackwardButton = false; - _mountSeekBackwardButton = false; - }); - } - }, - child: BackwardSeekIndicator( - onChanged: (value) { - // _seekBarDeltaValueNotifier.value = -value; + Obx( + () => Visibility( + visible: _ctr.mountSeekBackwardButton.value || + _ctr.mountSeekForwardButton.value, + child: Positioned.fill( + child: Row( + children: [ + Expanded( + child: _ctr.mountSeekBackwardButton.value + ? TweenAnimationBuilder( + tween: Tween( + begin: 0.0, + end: + _ctr.hideSeekBackwardButton.value ? 0.0 : 1.0, + ), + duration: const Duration(milliseconds: 500), + builder: (context, value, child) => Opacity( + opacity: value, + child: child, + ), + onEnd: () { + if (_ctr.hideSeekBackwardButton.value) { + _ctr.hideSeekBackwardButton.value = false; + _ctr.mountSeekBackwardButton.value = false; + } }, - onSubmitted: (value) { - setState(() { - _hideSeekBackwardButton = true; - }); - Player player = - widget.controller.videoPlayerController!; - var result = player.state.position - value; - result = result.clamp( - Duration.zero, - player.state.duration, - ); - player.seek(result); - widget.controller.play(); - }, - ), - ) - : const SizedBox(), - ), - Expanded( - child: SizedBox( - width: MediaQuery.of(context).size.width / 4, + child: BackwardSeekIndicator( + onChanged: (value) { + // _seekBarDeltaValueNotifier.value = -value; + }, + onSubmitted: (value) { + _ctr.hideSeekBackwardButton.value = true; + Player player = + widget.controller.videoPlayerController!; + var result = player.state.position - value; + result = result.clamp( + Duration.zero, + player.state.duration, + ); + player.seek(result); + widget.controller.play(); + }, + ), + ) + : const SizedBox(), ), - ), - Expanded( - child: _mountSeekForwardButton - ? TweenAnimationBuilder( - tween: Tween( - begin: 0.0, - end: _hideSeekForwardButton ? 0.0 : 1.0, - ), - duration: const Duration(milliseconds: 500), - builder: (context, value, child) => Opacity( - opacity: value, - child: child, - ), - onEnd: () { - if (_hideSeekForwardButton) { - setState(() { - _hideSeekForwardButton = false; - _mountSeekForwardButton = false; - }); - } - }, - child: ForwardSeekIndicator( - onChanged: (value) { - // _seekBarDeltaValueNotifier.value = value; + Expanded( + child: SizedBox( + width: MediaQuery.of(context).size.width / 4, + ), + ), + Expanded( + child: _ctr.mountSeekForwardButton.value + ? TweenAnimationBuilder( + tween: Tween( + begin: 0.0, + end: _ctr.hideSeekForwardButton.value ? 0.0 : 1.0, + ), + duration: const Duration(milliseconds: 500), + builder: (context, value, child) => Opacity( + opacity: value, + child: child, + ), + onEnd: () { + if (_ctr.hideSeekForwardButton.value) { + _ctr.hideSeekForwardButton.value = false; + _ctr.mountSeekForwardButton.value = false; + } }, - onSubmitted: (value) { - setState(() { - _hideSeekForwardButton = true; - }); - Player player = - widget.controller.videoPlayerController!; - var result = player.state.position + value; - result = result.clamp( - Duration.zero, - player.state.duration, - ); - player.seek(result); - widget.controller.play(); - }, - ), - ) - : const SizedBox(), - ), - ], + child: ForwardSeekIndicator( + onChanged: (value) { + // _seekBarDeltaValueNotifier.value = value; + }, + onSubmitted: (value) { + _ctr.hideSeekForwardButton.value = true; + Player player = + widget.controller.videoPlayerController!; + var result = player.state.position + value; + result = result.clamp( + Duration.zero, + player.state.duration, + ); + player.seek(result); + widget.controller.play(); + }, + ), + ) + : const SizedBox(), + ), + ], + ), ), ), + ), ], ); } } + +class PLVideoPlayerController extends GetxController { + RxBool mountSeekBackwardButton = false.obs; + RxBool mountSeekForwardButton = false.obs; + RxBool hideSeekBackwardButton = false.obs; + RxBool hideSeekForwardButton = false.obs; + + RxDouble brightnessValue = 0.0.obs; + RxBool brightnessIndicator = false.obs; + + RxDouble volumeValue = 0.0.obs; + RxBool volumeIndicator = false.obs; + + RxDouble distance = 0.0.obs; + // 初始手指落下位置 + RxDouble initTapPositoin = 0.0.obs; + + RxBool volumeInterceptEventStream = false.obs; + + // 双击快进 展示样式 + void onDoubleTapSeekForward() { + mountSeekForwardButton.value = true; + } + + void onDoubleTapSeekBackward() { + mountSeekBackwardButton.value = true; + } +}