diff --git a/lib/pages/common/common_intro_controller.dart b/lib/pages/common/common_intro_controller.dart index d9a82c054..f9c011276 100644 --- a/lib/pages/common/common_intro_controller.dart +++ b/lib/pages/common/common_intro_controller.dart @@ -9,6 +9,7 @@ import 'package:PiliPlus/models_new/fav/fav_folder/data.dart'; import 'package:PiliPlus/models_new/video/video_detail/data.dart'; import 'package:PiliPlus/models_new/video/video_detail/stat_detail.dart'; import 'package:PiliPlus/models_new/video/video_tag/data.dart'; +import 'package:PiliPlus/pages/video/introduction/ugc/widgets/triple_mixin.dart'; import 'package:PiliPlus/services/account_service.dart'; import 'package:PiliPlus/utils/global_data.dart'; import 'package:PiliPlus/utils/id_utils.dart'; @@ -21,25 +22,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -abstract class CommonIntroController extends GetxController { +abstract class CommonIntroController extends GetxController + with GetSingleTickerProviderStateMixin, TripleMixin { late final String heroTag; late String bvid; - // 是否点赞 - final RxBool hasLike = false.obs; - // 投币数量 - final RxNum coinNum = RxNum(0); - // 是否投币 - bool get hasCoin => coinNum.value != 0; - // 是否收藏 - final RxBool hasFav = false.obs; // 是否稍后再看 final RxBool hasLater = false.obs; final Rx?> videoTags = Rx?>(null); - bool get hasTriple => hasLike.value && hasCoin && hasFav.value; - bool isProcessing = false; Future handleAction(FutureOr Function() action) async { if (!isProcessing) { @@ -65,9 +57,7 @@ abstract class CommonIntroController extends GetxController { bool prevPlay(); bool nextPlay(); - Future actionLikeVideo(); void actionCoinVideo(); - void actionTriple(); void actionShareVideo(BuildContext context); // 同时观看 diff --git a/lib/pages/video/introduction/pgc/view.dart b/lib/pages/video/introduction/pgc/view.dart index 5d7cba4e0..8787e58e5 100644 --- a/lib/pages/video/introduction/pgc/view.dart +++ b/lib/pages/video/introduction/pgc/view.dart @@ -14,7 +14,6 @@ import 'package:PiliPlus/pages/video/controller.dart'; import 'package:PiliPlus/pages/video/introduction/pgc/controller.dart'; import 'package:PiliPlus/pages/video/introduction/pgc/widgets/pgc_panel.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart'; -import 'package:PiliPlus/pages/video/introduction/ugc/widgets/triple_state.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/num_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; @@ -44,8 +43,7 @@ class PgcIntroPage extends StatefulWidget { State createState() => _PgcIntroPageState(); } -class _PgcIntroPageState extends TripleState { - @override +class _PgcIntroPageState extends State { late final PgcIntroController introController; late final VideoDetailController videoDetailCtr; @@ -412,19 +410,19 @@ class _PgcIntroPageState extends TripleState { children: [ Obx( () => ActionItem( - animation: tripleAnimation, + animation: introController.tripleAnimation, icon: const Icon(FontAwesomeIcons.thumbsUp), selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), selectStatus: introController.hasLike.value, semanticsLabel: '点赞', text: NumUtils.numFormat(item.stat!.like), - onStartTriple: onStartTriple, - onCancelTriple: onCancelTriple, + onStartTriple: introController.onStartTriple, + onCancelTriple: introController.onCancelTriple, ), ), Obx( () => ActionItem( - animation: tripleAnimation, + animation: introController.tripleAnimation, icon: const Icon(FontAwesomeIcons.b), selectIcon: const Icon(FontAwesomeIcons.b), onTap: introController.actionCoinVideo, @@ -435,7 +433,7 @@ class _PgcIntroPageState extends TripleState { ), Obx( () => ActionItem( - animation: tripleAnimation, + animation: introController.tripleAnimation, icon: const Icon(FontAwesomeIcons.star), selectIcon: const Icon(FontAwesomeIcons.solidStar), onTap: () => introController.showFavBottomSheet(context), diff --git a/lib/pages/video/introduction/ugc/view.dart b/lib/pages/video/introduction/ugc/view.dart index e080731cb..777b438f9 100644 --- a/lib/pages/video/introduction/ugc/view.dart +++ b/lib/pages/video/introduction/ugc/view.dart @@ -16,7 +16,6 @@ import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/widgets/page.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/widgets/season.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/widgets/selectable_text.dart'; -import 'package:PiliPlus/pages/video/introduction/ugc/widgets/triple_state.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/date_utils.dart'; import 'package:PiliPlus/utils/extension.dart'; @@ -55,8 +54,7 @@ class UgcIntroPanel extends StatefulWidget { State createState() => _UgcIntroPanelState(); } -class _UgcIntroPanelState extends TripleState { - @override +class _UgcIntroPanelState extends State { late final UgcIntroController introController; late final VideoDetailController videoDetailCtr = Get.find(tag: widget.heroTag); @@ -514,7 +512,7 @@ class _UgcIntroPanelState extends TripleState { children: [ Obx( () => ActionItem( - animation: tripleAnimation, + animation: introController.tripleAnimation, icon: const Icon(FontAwesomeIcons.thumbsUp), selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), selectStatus: introController.hasLike.value, @@ -522,8 +520,8 @@ class _UgcIntroPanelState extends TripleState { text: !isLoading ? NumUtils.numFormat(videoDetail.stat!.like) : null, - onStartTriple: onStartTriple, - onCancelTriple: onCancelTriple, + onStartTriple: introController.onStartTriple, + onCancelTriple: introController.onCancelTriple, ), ), Obx( @@ -540,7 +538,7 @@ class _UgcIntroPanelState extends TripleState { ), Obx( () => ActionItem( - animation: tripleAnimation, + animation: introController.tripleAnimation, icon: const Icon(FontAwesomeIcons.b), selectIcon: const Icon(FontAwesomeIcons.b), onTap: introController.actionCoinVideo, @@ -553,7 +551,7 @@ class _UgcIntroPanelState extends TripleState { ), Obx( () => ActionItem( - animation: tripleAnimation, + animation: introController.tripleAnimation, icon: const Icon(FontAwesomeIcons.star), selectIcon: const Icon(FontAwesomeIcons.solidStar), onTap: () => introController.showFavBottomSheet(context), diff --git a/lib/pages/video/introduction/ugc/widgets/triple_state.dart b/lib/pages/video/introduction/ugc/widgets/triple_mixin.dart similarity index 74% rename from lib/pages/video/introduction/ugc/widgets/triple_state.dart rename to lib/pages/video/introduction/ugc/widgets/triple_mixin.dart index 0f7725b6f..67fcc07aa 100644 --- a/lib/pages/video/introduction/ugc/widgets/triple_state.dart +++ b/lib/pages/video/introduction/ugc/widgets/triple_mixin.dart @@ -1,15 +1,26 @@ import 'dart:async'; import 'dart:math' show pi; -import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; -abstract class TripleState extends State - with SingleTickerProviderStateMixin { - CommonIntroController get introController; +mixin TripleMixin on GetxController, TickerProvider { + // 是否点赞 + final RxBool hasLike = false.obs; + // 投币数量 + final RxNum coinNum = RxNum(0); + // 是否投币 + bool get hasCoin => coinNum.value != 0; + // 是否收藏 + final RxBool hasFav = false.obs; + + bool get hasTriple => hasLike.value && hasCoin && hasFav.value; + + void actionTriple(); + Future actionLikeVideo(); // no need for pugv AnimationController? _tripleAnimCtr; @@ -34,13 +45,6 @@ abstract class TripleState extends State _timer = null; } - @override - void dispose() { - _cancelTimer(); - _tripleAnimCtr?.dispose(); - super.dispose(); - } - static final _duration = Utils.isMobile ? const Duration(milliseconds: 200) : const Duration(milliseconds: 230); @@ -48,12 +52,12 @@ abstract class TripleState extends State void onStartTriple() { _timer ??= Timer(_duration, () { HapticFeedback.lightImpact(); - if (introController.hasTriple) { + if (hasTriple) { SmartDialog.showToast('已完成三连'); } else { tripleAnimCtr.forward().whenComplete(() { tripleAnimCtr.reset(); - introController.actionTriple(); + actionTriple(); }); } _cancelTimer(); @@ -66,8 +70,15 @@ abstract class TripleState extends State } else if (_timer != null && _timer!.tick == 0) { _cancelTimer(); if (isTapUp) { - introController.actionLikeVideo(); + actionLikeVideo(); } } } + + @override + void onClose() { + _cancelTimer(); + _tripleAnimCtr?.dispose(); + super.onClose(); + } } diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index 5fabf7385..9bcd6a165 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -20,7 +20,6 @@ import 'package:PiliPlus/pages/video/introduction/pgc/controller.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/widgets/menu_row.dart'; -import 'package:PiliPlus/pages/video/introduction/ugc/widgets/triple_state.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart'; import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart'; import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart'; @@ -64,7 +63,7 @@ class HeaderControl extends StatefulWidget { State createState() => HeaderControlState(); } -class HeaderControlState extends TripleState { +class HeaderControlState extends State { late final PlPlayerController plPlayerController = widget.controller; late final VideoDetailController videoDetailCtr = widget.videoDetailCtr; late final PlayUrlModel videoInfo = videoDetailCtr.data; @@ -74,7 +73,6 @@ class HeaderControlState extends TripleState { String get heroTag => widget.heroTag; late final UgcIntroController ugcIntroController; late final PgcIntroController pgcIntroController; - @override late CommonIntroController introController = videoDetailCtr.isUgc ? ugcIntroController : pgcIntroController; @@ -2289,16 +2287,16 @@ class HeaderControlState extends TripleState { ), selectStatus: introController.hasLike.value, semanticsLabel: '点赞', - animation: tripleAnimation, + animation: introController.tripleAnimation, onStartTriple: () { plPlayerController.tripling = true; - onStartTriple(); + introController.onStartTriple(); }, - onCancelTriple: ([bool isTap = false]) { + onCancelTriple: ([bool isTapUp = false]) { plPlayerController ..tripling = false ..hideTaskControls(); - onCancelTriple(isTap); + introController.onCancelTriple(isTapUp); }, ), ), @@ -2329,7 +2327,7 @@ class HeaderControlState extends TripleState { child: Obx( () => ActionItem( expand: false, - animation: tripleAnimation, + animation: introController.tripleAnimation, icon: const Icon( FontAwesomeIcons.b, color: Colors.white, @@ -2347,7 +2345,7 @@ class HeaderControlState extends TripleState { child: Obx( () => ActionItem( expand: false, - animation: tripleAnimation, + animation: introController.tripleAnimation, icon: const Icon( FontAwesomeIcons.star, color: Colors.white, diff --git a/lib/pages/video/widgets/player_focus.dart b/lib/pages/video/widgets/player_focus.dart index accc4e4d9..7c4fa8434 100644 --- a/lib/pages/video/widgets/player_focus.dart +++ b/lib/pages/video/widgets/player_focus.dart @@ -55,8 +55,81 @@ class PlayerFocus extends StatelessWidget { bool get isFullScreen => plPlayerController.isFullScreen.value; bool get hasPlayer => plPlayerController.videoPlayerController != null; + void _setVolume({required bool isIncrease}) { + final volume = isIncrease + ? math.min(1.0, plPlayerController.volume.value + 0.1) + : math.max(0.0, plPlayerController.volume.value - 0.1); + plPlayerController.setVolume(volume); + } + + void _updateVolume(KeyEvent event, {required bool isIncrease}) { + if (event is KeyDownEvent) { + if (hasPlayer) { + plPlayerController + ..cancelLongPressTimer() + ..longPressTimer ??= Timer.periodic( + const Duration(milliseconds: 200), + (_) => _setVolume(isIncrease: isIncrease), + ); + } + } else if (event is KeyUpEvent) { + if (plPlayerController.longPressTimer?.tick == 0 && hasPlayer) { + _setVolume(isIncrease: isIncrease); + } + plPlayerController.cancelLongPressTimer(); + } + } + bool _handleKey(KeyEvent event) { final key = event.logicalKey; + + final isKeyQ = key == LogicalKeyboardKey.keyQ; + if (isKeyQ || key == LogicalKeyboardKey.keyR) { + if (!plPlayerController.isLive) { + if (event is KeyDownEvent) { + introController!.onStartTriple(); + } else if (event is KeyUpEvent) { + introController!.onCancelTriple(isKeyQ); + } + } + return true; + } + + final isArrowUp = key == LogicalKeyboardKey.arrowUp; + if (isArrowUp || key == LogicalKeyboardKey.arrowDown) { + _updateVolume(event, isIncrease: isArrowUp); + return true; + } + + if (key == LogicalKeyboardKey.arrowRight) { + if (!plPlayerController.isLive) { + if (event is KeyDownEvent) { + if (hasPlayer && !plPlayerController.longPressStatus.value) { + plPlayerController + ..cancelLongPressTimer() + ..longPressTimer ??= Timer( + const Duration(milliseconds: 200), + () => plPlayerController + ..cancelLongPressTimer() + ..setLongPressStatus(true), + ); + } + } else if (event is KeyUpEvent) { + plPlayerController.cancelLongPressTimer(); + if (hasPlayer) { + if (plPlayerController.longPressStatus.value) { + plPlayerController.setLongPressStatus(false); + } else { + plPlayerController.onForward( + plPlayerController.fastForBackwardDuration, + ); + } + } + } + } + return true; + } + if (event is KeyDownEvent) { switch (key) { case LogicalKeyboardKey.space: @@ -101,20 +174,6 @@ class PlayerFocus extends StatelessWidget { plPlayerController.toggleDesktopPip(); return true; - case LogicalKeyboardKey.arrowUp: - if (hasPlayer) { - final volume = math.min(1.0, plPlayerController.volume.value + 0.1); - plPlayerController.setVolume(volume); - } - return true; - - case LogicalKeyboardKey.arrowDown: - if (hasPlayer) { - final volume = math.max(0.0, plPlayerController.volume.value - 0.1); - plPlayerController.setVolume(volume); - } - return true; - case LogicalKeyboardKey.keyM: if (hasPlayer) { final isMuted = !plPlayerController.isMuted; @@ -141,10 +200,6 @@ class PlayerFocus extends StatelessWidget { } return true; - case LogicalKeyboardKey.keyQ: - introController?.actionLikeVideo(); - return true; - case LogicalKeyboardKey.keyW: introController?.actionCoinVideo(); return true; @@ -153,7 +208,7 @@ class PlayerFocus extends StatelessWidget { introController?.actionFavVideo(isQuick: true); return true; - case LogicalKeyboardKey.keyR: + case LogicalKeyboardKey.keyT || LogicalKeyboardKey.keyV: introController?.viewLater(); return true; @@ -182,29 +237,6 @@ class PlayerFocus extends StatelessWidget { } } - if (key == LogicalKeyboardKey.arrowRight) { - if (!plPlayerController.isLive && hasPlayer) { - if (event is KeyDownEvent) { - if (!plPlayerController.longPressStatus.value) { - plPlayerController.longPressTimer ??= Timer( - const Duration(milliseconds: 200), - () => plPlayerController.setLongPressStatus(true), - ); - } - } else if (event is KeyUpEvent) { - plPlayerController.cancelLongPressTimer(); - if (plPlayerController.longPressStatus.value) { - plPlayerController.setLongPressStatus(false); - } else { - plPlayerController.onForward( - plPlayerController.fastForBackwardDuration, - ); - } - } - } - return true; - } - return false; } } diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index ff18ab915..e1a4edcee 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -283,7 +283,7 @@ class PlPlayerController { final width = state.width ?? this.width ?? 16; final height = state.height ?? this.height ?? 9; if (height > width) { - size = Size(400.0, 400.0 * height / width); + size = Size(280.0, 280.0 * height / width); } else { size = Size(280.0 * width / height, 280.0); } diff --git a/lib/services/audio_session.dart b/lib/services/audio_session.dart index 4d4234429..6952d94fe 100644 --- a/lib/services/audio_session.dart +++ b/lib/services/audio_session.dart @@ -16,12 +16,7 @@ class AudioSessionHandler { Future initSession() async { session = await AudioSession.instance; - session.configure( - const AudioSessionConfiguration.music().copyWith( - avAudioSessionSetActiveOptions: - AVAudioSessionSetActiveOptions.notifyOthersOnDeactivation, - ), - ); + session.configure(const AudioSessionConfiguration.music()); session.interruptionEventStream.listen((event) { final playerStatus = PlPlayerController.getPlayerStatusIfExists();