diff --git a/lib/models/common/gesture_mode.dart b/lib/models/common/gesture_mode.dart new file mode 100644 index 00000000..1149ae12 --- /dev/null +++ b/lib/models/common/gesture_mode.dart @@ -0,0 +1,12 @@ +enum FullScreenGestureMode { + /// 从上滑到下 + fromToptoBottom, + + /// 从下滑到上 + fromBottomtoTop, +} + +extension FullScreenGestureModeExtension on FullScreenGestureMode { + String get values => ['fromToptoBottom', 'fromBottomtoTop'][index]; + String get labels => ['从上往下滑进入全屏', '从下往上滑进入全屏'][index]; +} diff --git a/lib/models/common/index.dart b/lib/models/common/index.dart new file mode 100644 index 00000000..89a05076 --- /dev/null +++ b/lib/models/common/index.dart @@ -0,0 +1,4 @@ +library commonn_model; + +export './business_type.dart'; +export './gesture_mode.dart'; diff --git a/lib/models/user/fav_folder.dart b/lib/models/user/fav_folder.dart index 6d3f9975..c45e2de9 100644 --- a/lib/models/user/fav_folder.dart +++ b/lib/models/user/fav_folder.dart @@ -15,7 +15,7 @@ class FavFolderData { ? json['list'] .map((e) => FavFolderItemData.fromJson(e)) .toList() - : [FavFolderItemData()]; + : []; hasMore = json['has_more']; } } diff --git a/lib/pages/bangumi/controller.dart b/lib/pages/bangumi/controller.dart index 09afc43a..e5748d6c 100644 --- a/lib/pages/bangumi/controller.dart +++ b/lib/pages/bangumi/controller.dart @@ -7,8 +7,8 @@ import 'package:pilipala/utils/storage.dart'; class BangumiController extends GetxController { final ScrollController scrollController = ScrollController(); - RxList bangumiList = [BangumiListItemModel()].obs; - RxList bangumiFollowList = [BangumiListItemModel()].obs; + RxList bangumiList = [].obs; + RxList bangumiFollowList = [].obs; int _currentPage = 1; bool isLoadingMore = true; Box userInfoCache = GStrorage.userInfo; diff --git a/lib/pages/blacklist/index.dart b/lib/pages/blacklist/index.dart index 3bf64146..402790f5 100644 --- a/lib/pages/blacklist/index.dart +++ b/lib/pages/blacklist/index.dart @@ -139,7 +139,7 @@ class BlackListController extends GetxController { int currentPage = 1; int pageSize = 50; RxInt total = 0.obs; - RxList blackList = [BlackListItem()].obs; + RxList blackList = [].obs; Future queryBlacklist({type = 'init'}) async { if (type == 'init') { diff --git a/lib/pages/dynamics/controller.dart b/lib/pages/dynamics/controller.dart index 26ba2b22..1e9f2da4 100644 --- a/lib/pages/dynamics/controller.dart +++ b/lib/pages/dynamics/controller.dart @@ -20,7 +20,7 @@ import 'package:pilipala/utils/utils.dart'; class DynamicsController extends GetxController { int page = 1; String? offset = ''; - RxList dynamicsList = [DynamicItemModel()].obs; + RxList dynamicsList = [].obs; Rx dynamicsType = DynamicsType.values[0].obs; RxString dynamicsTypeLabel = '全部'.obs; final ScrollController scrollController = ScrollController(); @@ -105,7 +105,7 @@ class DynamicsController extends GetxController { onSelectType(value) async { dynamicsType.value = filterTypeList[value]['value']; - dynamicsList.value = [DynamicItemModel()]; + dynamicsList.value = []; page = 1; initialValue.value = value; await queryFollowDynamic(); @@ -264,7 +264,7 @@ class DynamicsController extends GetxController { onSelectUp(mid) async { dynamicsType.value = DynamicsType.values[0]; - dynamicsList.value = [DynamicItemModel()]; + dynamicsList.value = []; page = 1; queryFollowDynamic(); } @@ -293,7 +293,7 @@ class DynamicsController extends GetxController { dynamicsType.value = DynamicsType.values[0]; initialValue.value = 0; SmartDialog.showToast('还原默认加载'); - dynamicsList.value = [DynamicItemModel()]; + dynamicsList.value = []; queryFollowDynamic(); } } diff --git a/lib/pages/dynamics/detail/controller.dart b/lib/pages/dynamics/detail/controller.dart index 4c5f35d6..8e117383 100644 --- a/lib/pages/dynamics/detail/controller.dart +++ b/lib/pages/dynamics/detail/controller.dart @@ -17,7 +17,7 @@ class DynamicDetailController extends GetxController { int currentPage = 0; bool isLoadingMore = false; RxString noMore = ''.obs; - RxList replyList = [ReplyItemModel()].obs; + RxList replyList = [].obs; RxInt acount = 0.obs; final ScrollController scrollController = ScrollController(); diff --git a/lib/pages/fan/controller.dart b/lib/pages/fan/controller.dart index 8675ada7..c1c2a427 100644 --- a/lib/pages/fan/controller.dart +++ b/lib/pages/fan/controller.dart @@ -10,7 +10,7 @@ class FansController extends GetxController { int pn = 1; int ps = 20; int total = 0; - RxList fansList = [FansItemModel()].obs; + RxList fansList = [].obs; late int mid; late String name; var userInfo; diff --git a/lib/pages/hot/controller.dart b/lib/pages/hot/controller.dart index 65706c32..85072475 100644 --- a/lib/pages/hot/controller.dart +++ b/lib/pages/hot/controller.dart @@ -7,7 +7,7 @@ class HotController extends GetxController { final ScrollController scrollController = ScrollController(); final int _count = 20; int _currentPage = 1; - RxList videoList = [HotVideoItemModel()].obs; + RxList videoList = [].obs; bool isLoadingMore = false; bool flag = false; OverlayEntry? popupDialog; diff --git a/lib/pages/member/controller.dart b/lib/pages/member/controller.dart index 70169e3d..0aa7166f 100644 --- a/lib/pages/member/controller.dart +++ b/lib/pages/member/controller.dart @@ -20,7 +20,7 @@ class MemberController extends GetxController { Box userInfoCache = GStrorage.userInfo; late int ownerMid; // 投稿列表 - RxList? archiveList = [VListItemModel()].obs; + RxList? archiveList = [].obs; dynamic userInfo; RxInt attribute = (-1).obs; RxString attributeText = '关注'.obs; diff --git a/lib/pages/search/controller.dart b/lib/pages/search/controller.dart index 5ec1710a..cbb86405 100644 --- a/lib/pages/search/controller.dart +++ b/lib/pages/search/controller.dart @@ -15,7 +15,7 @@ class SSearchController extends GetxController { Box histiryWord = GStrorage.historyword; List historyCacheList = []; RxList historyList = [].obs; - RxList searchSuggestList = [SearchSuggestItem()].obs; + RxList searchSuggestList = [].obs; final _debouncer = Debouncer(delay: const Duration(milliseconds: 200)); // 设置延迟时间 String hintText = '搜索'; diff --git a/lib/pages/setting/pages/play_gesture_set.dart b/lib/pages/setting/pages/play_gesture_set.dart new file mode 100644 index 00000000..f688c43c --- /dev/null +++ b/lib/pages/setting/pages/play_gesture_set.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:hive/hive.dart'; +import 'package:pilipala/utils/global_data.dart'; + +import '../../../models/common/gesture_mode.dart'; +import '../../../utils/storage.dart'; +import '../widgets/select_dialog.dart'; +import '../widgets/switch_item.dart'; + +class PlayGesturePage extends StatefulWidget { + const PlayGesturePage({super.key}); + + @override + State createState() => _PlayGesturePageState(); +} + +class _PlayGesturePageState extends State { + Box setting = GStrorage.setting; + late int fullScreenGestureMode; + + @override + void initState() { + super.initState(); + fullScreenGestureMode = setting.get(SettingBoxKey.fullScreenGestureMode, + defaultValue: FullScreenGestureMode.values.last.index); + } + + @override + Widget build(BuildContext context) { + TextStyle titleStyle = Theme.of(context).textTheme.titleMedium!; + TextStyle subTitleStyle = Theme.of(context) + .textTheme + .labelMedium! + .copyWith(color: Theme.of(context).colorScheme.outline); + return Scaffold( + appBar: AppBar( + centerTitle: false, + titleSpacing: 0, + title: Text( + '手势设置', + style: Theme.of(context).textTheme.titleMedium, + ), + ), + body: ListView( + children: [ + ListTile( + dense: false, + title: Text('全屏手势', style: titleStyle), + subtitle: Text( + '通过手势快速进入全屏', + style: subTitleStyle, + ), + onTap: () async { + String? result = await showDialog( + context: context, + builder: (context) { + return SelectDialog( + title: '全屏手势', + value: FullScreenGestureMode + .values[fullScreenGestureMode].values, + values: FullScreenGestureMode.values.map((e) { + return {'title': e.labels, 'value': e.values}; + }).toList()); + }, + ); + if (result != null) { + GlobalData().fullScreenGestureMode = FullScreenGestureMode + .values + .firstWhere((element) => element.values == result); + fullScreenGestureMode = + GlobalData().fullScreenGestureMode.index; + setting.put( + SettingBoxKey.fullScreenGestureMode, fullScreenGestureMode); + setState(() {}); + } + }, + ), + const SetSwitchItem( + title: '双击快退/快进', + subTitle: '左侧双击快退,右侧双击快进', + setKey: SettingBoxKey.enableQuickDouble, + defaultVal: true, + ), + ], + ), + ); + } +} diff --git a/lib/pages/setting/play_setting.dart b/lib/pages/setting/play_setting.dart index bfd5db5f..469bf975 100644 --- a/lib/pages/setting/play_setting.dart +++ b/lib/pages/setting/play_setting.dart @@ -7,6 +7,7 @@ import 'package:pilipala/models/video/play/quality.dart'; import 'package:pilipala/pages/setting/widgets/select_dialog.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/services/service_locator.dart'; +import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/storage.dart'; import 'widgets/switch_item.dart'; @@ -73,6 +74,12 @@ class _PlaySettingState extends State { title: Text('倍速设置', style: titleStyle), subtitle: Text('设置视频播放速度', style: subTitleStyle), ), + ListTile( + dense: false, + onTap: () => Get.toNamed('/playerGestureSet'), + title: Text('手势设置', style: titleStyle), + subtitle: Text('设置播放器手势', style: subTitleStyle), + ), const SetSwitchItem( title: '开启1080P', subTitle: '免登录查看1080P视频', @@ -134,18 +141,20 @@ class _PlaySettingState extends State { setKey: SettingBoxKey.enableAutoBrightness, defaultVal: false, ), - const SetSwitchItem( - title: '双击快退/快进', - subTitle: '左侧双击快退,右侧双击快进', - setKey: SettingBoxKey.enableQuickDouble, - defaultVal: true, - ), const SetSwitchItem( title: '弹幕开关', subTitle: '展示弹幕', setKey: SettingBoxKey.enableShowDanmaku, defaultVal: false, ), + SetSwitchItem( + title: '控制栏动画', + subTitle: '播放器控制栏显示动画效果', + setKey: SettingBoxKey.enablePlayerControlAnimation, + defaultVal: true, + callFn: (bool val) { + GlobalData().enablePlayerControlAnimation = val; + }), ListTile( dense: false, title: Text('默认画质', style: titleStyle), diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index e564ef02..91344fc1 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -22,7 +22,7 @@ class VideoReplyController extends GetxController { String? replyLevel; // rpid 请求楼中楼回复 String? rpid; - RxList replyList = [ReplyItemModel()].obs; + RxList replyList = [].obs; // 当前页 int currentPage = 0; bool isLoadingMore = false; diff --git a/lib/pages/video/detail/reply_reply/controller.dart b/lib/pages/video/detail/reply_reply/controller.dart index 0d5b4488..6daa0b8a 100644 --- a/lib/pages/video/detail/reply_reply/controller.dart +++ b/lib/pages/video/detail/reply_reply/controller.dart @@ -12,7 +12,7 @@ class VideoReplyReplyController extends GetxController { // rpid 请求楼中楼回复 String? rpid; ReplyType replyType = ReplyType.video; - RxList replyList = [ReplyItemModel()].obs; + RxList replyList = [].obs; // 当前页 int currentPage = 0; bool isLoadingMore = false; diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index d073945b..988ec26d 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -9,6 +9,7 @@ import 'package:hive/hive.dart'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:nil/nil.dart'; +import 'package:pilipala/models/common/gesture_mode.dart'; import 'package:pilipala/plugin/pl_player/controller.dart'; import 'package:pilipala/plugin/pl_player/models/duration.dart'; import 'package:pilipala/plugin/pl_player/models/fullscreen_mode.dart'; @@ -17,6 +18,7 @@ import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:screen_brightness/screen_brightness.dart'; +import '../../utils/global_data.dart'; import 'models/bottom_progress_behavior.dart'; import 'widgets/app_bar_ani.dart'; import 'widgets/backward_seek.dart'; @@ -73,6 +75,8 @@ class _PLVideoPlayerState extends State late bool enableQuickDouble; late bool enableBackgroundPlay; late double screenWidth; + final FullScreenGestureMode fullScreenGestureMode = + GlobalData().fullScreenGestureMode; // 用于记录上一次全屏切换手势触发时间,避免误触 DateTime? lastFullScreenToggleTime; @@ -116,7 +120,11 @@ class _PLVideoPlayerState extends State super.initState(); screenWidth = Get.size.width; animationController = AnimationController( - vsync: this, duration: const Duration(milliseconds: 300)); + vsync: this, + duration: GlobalData().enablePlayerControlAnimation + ? const Duration(milliseconds: 150) + : const Duration(milliseconds: 10), + ); videoController = widget.controller.videoController!; widget.controller.headerControl = widget.headerControl; widget.controller.bottomControl = widget.bottomControl; @@ -520,18 +528,20 @@ class _PLVideoPlayerState extends State // 全屏 final double dy = details.delta.dy; const double threshold = 7.0; // 滑动阈值 + final bool flag = + fullScreenGestureMode != FullScreenGestureMode.values.last; if (dy > _distance && dy > threshold) { - if (_.isFullScreen.value) { + if (_.isFullScreen.value ^ flag) { lastFullScreenToggleTime = DateTime.now(); // 下滑退出全屏 - await widget.controller.triggerFullScreen(status: false); + await widget.controller.triggerFullScreen(status: flag); } _distance = 0.0; } else if (dy < _distance && dy < -threshold) { - if (!_.isFullScreen.value) { + if (!_.isFullScreen.value ^ flag) { lastFullScreenToggleTime = DateTime.now(); // 上滑进入全屏 - await widget.controller.triggerFullScreen(); + await widget.controller.triggerFullScreen(status: !flag); } _distance = 0.0; } diff --git a/lib/plugin/pl_player/widgets/app_bar_ani.dart b/lib/plugin/pl_player/widgets/app_bar_ani.dart index 9a3af267..53eaad16 100644 --- a/lib/plugin/pl_player/widgets/app_bar_ani.dart +++ b/lib/plugin/pl_player/widgets/app_bar_ani.dart @@ -19,11 +19,11 @@ class AppBarAni extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { - visible ? controller.reverse() : controller.forward(); + visible ? controller.forward() : controller.reverse(); return SlideTransition( position: Tween( - begin: Offset.zero, - end: Offset(0, position! == 'top' ? -1 : 1), + begin: Offset(0, position! == 'top' ? -1 : 1), + end: Offset.zero, ).animate(CurvedAnimation( parent: controller, curve: Curves.linear, diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index 6ebaa638..1f1ea31e 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -39,6 +39,7 @@ import '../pages/setting/pages/color_select.dart'; import '../pages/setting/pages/display_mode.dart'; import '../pages/setting/pages/font_size_select.dart'; import '../pages/setting/pages/home_tabbar_set.dart'; +import '../pages/setting/pages/play_gesture_set.dart'; import '../pages/setting/pages/play_speed_set.dart'; import '../pages/setting/recommend_setting.dart'; import '../pages/setting/play_setting.dart'; @@ -166,6 +167,9 @@ class Routes { CustomGetPage(name: '/subscription', page: () => const SubPage()), // 订阅详情 CustomGetPage(name: '/subDetail', page: () => const SubDetailPage()), + // 播放器手势 + CustomGetPage( + name: '/playerGestureSet', page: () => const PlayGesturePage()), ]; } diff --git a/lib/utils/global_data.dart b/lib/utils/global_data.dart index a8a04eba..ef3daf21 100644 --- a/lib/utils/global_data.dart +++ b/lib/utils/global_data.dart @@ -1,5 +1,10 @@ +import '../models/common/index.dart'; + class GlobalData { int imgQuality = 10; + FullScreenGestureMode fullScreenGestureMode = + FullScreenGestureMode.values.last; + bool enablePlayerControlAnimation = true; // 私有构造函数 GlobalData._(); diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 09e362fd..44beb4e7 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -4,6 +4,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:pilipala/models/model_owner.dart'; import 'package:pilipala/models/search/hot.dart'; import 'package:pilipala/models/user/info.dart'; +import '../models/common/gesture_mode.dart'; import 'global_data.dart'; class GStrorage { @@ -45,6 +46,11 @@ class GStrorage { video = await Hive.openBox('video'); GlobalData().imgQuality = setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10); // 设置全局变量 + GlobalData().fullScreenGestureMode = FullScreenGestureMode.values[ + setting.get(SettingBoxKey.fullScreenGestureMode, + defaultValue: FullScreenGestureMode.values.last.index) as int]; + GlobalData().enablePlayerControlAnimation = setting + .get(SettingBoxKey.enablePlayerControlAnimation, defaultValue: true); } static void regAdapter() { @@ -94,11 +100,13 @@ class SettingBoxKey { enableCDN = 'enableCDN', autoPiP = 'autoPiP', enableAutoLongPressSpeed = 'enableAutoLongPressSpeed', + enablePlayerControlAnimation = 'enablePlayerControlAnimation', // youtube 双击快进快退 enableQuickDouble = 'enableQuickDouble', enableShowDanmaku = 'enableShowDanmaku', enableBackgroundPlay = 'enableBackgroundPlay', + fullScreenGestureMode = 'fullScreenGestureMode', /// 隐私 blackMidsList = 'blackMidsList',