diff --git a/lib/common/widgets/image/custom_grid_view.dart b/lib/common/widgets/image/custom_grid_view.dart index a7e9bc519..edc0aa3b2 100644 --- a/lib/common/widgets/image/custom_grid_view.dart +++ b/lib/common/widgets/image/custom_grid_view.dart @@ -15,6 +15,7 @@ * along with PiliPlus. If not, see . */ +import 'dart:io' show Platform; import 'dart:math' show min; import 'package:PiliPlus/common/constants.dart'; @@ -26,10 +27,13 @@ import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/utils/extension/context_ext.dart'; import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/extension/size_ext.dart'; +import 'package:PiliPlus/utils/image_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:flutter/material.dart' hide CustomMultiChildLayout, MultiChildLayoutDelegate; +import 'package:flutter/services.dart' show HapticFeedback; import 'package:get/get_core/src/get_main.dart'; import 'package:get/get_navigation/get_navigation.dart'; @@ -138,6 +142,56 @@ class CustomGridView extends StatelessWidget { ); } + static bool enableImgMenu = Pref.enableImgMenu; + + void _showMenu(BuildContext context, Offset offset, ImageModel item) { + HapticFeedback.mediumImpact(); + showMenu( + context: context, + position: .fromLTRB(offset.dx, offset.dy, offset.dx, 0), + items: [ + if (PlatformUtils.isMobile) + PopupMenuItem( + height: 42, + onTap: () => ImageUtils.onShareImg(item.url), + child: const Text('分享', style: TextStyle(fontSize: 14)), + ), + PopupMenuItem( + height: 42, + onTap: () => ImageUtils.downloadImg([item.url]), + child: const Text('保存图片', style: TextStyle(fontSize: 14)), + ), + if (PlatformUtils.isDesktop) + PopupMenuItem( + height: 42, + onTap: () => PageUtils.launchURL(item.url), + child: const Text('网页打开', style: TextStyle(fontSize: 14)), + ) + else if (picArr.length > 1) + PopupMenuItem( + height: 42, + onTap: () => + ImageUtils.downloadImg(picArr.map((item) => item.url).toList()), + child: const Text('保存全部', style: TextStyle(fontSize: 14)), + ), + if (item.isLivePhoto) + PopupMenuItem( + height: 42, + onTap: () => ImageUtils.downloadLivePhoto( + url: item.url, + liveUrl: item.liveUrl!, + width: item.width.toInt(), + height: item.height.toInt(), + ), + child: Text( + '保存${Platform.isIOS ? '实况' : '视频'}', + style: const TextStyle(fontSize: 14), + ), + ), + ], + ); + } + @override Widget build(BuildContext context) { double imageWidth; @@ -205,6 +259,14 @@ class CustomGridView extends StatelessWidget { id: index, child: GestureDetector( onTap: () => onTap(context, index), + onSecondaryTapUp: enableImgMenu && PlatformUtils.isDesktop + ? (details) => + _showMenu(context, details.globalPosition, item) + : null, + onLongPressStart: enableImgMenu && PlatformUtils.isMobile + ? (details) => + _showMenu(context, details.globalPosition, item) + : null, child: Hero( tag: item.url, child: Stack( diff --git a/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart b/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart index 66518bd87..f7b476427 100644 --- a/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart +++ b/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart @@ -11,6 +11,7 @@ import 'package:PiliPlus/utils/utils.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart' show HapticFeedback; import 'package:get/get.dart'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; @@ -336,6 +337,9 @@ class _InteractiveviewerGalleryState extends State imageUrl: _getActualUrl(item.url), placeholderFadeInDuration: Duration.zero, placeholder: (context, url) { + if (widget.quality == _quality) { + return const SizedBox.expand(); + } return CachedNetworkImage( fadeInDuration: Duration.zero, fadeOutDuration: Duration.zero, @@ -408,6 +412,7 @@ class _InteractiveviewerGalleryState extends State } void onLongPress(SourceModel item) { + HapticFeedback.mediumImpact(); showDialog( context: context, builder: (context) { diff --git a/lib/http/validate.dart b/lib/http/validate.dart index bbc5f30c9..9f03a80c7 100644 --- a/lib/http/validate.dart +++ b/lib/http/validate.dart @@ -25,10 +25,10 @@ abstract final class ValidateHttp { } static Future gaiaVgateValidate({ - required challenge, - required seccode, - required token, - required validate, + required dynamic challenge, + required dynamic seccode, + required dynamic token, + required dynamic validate, }) async { final res = await Request().post( Api.gaiaVgateValidate, diff --git a/lib/main.dart b/lib/main.dart index 85a0acdc8..2a397584a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,7 +29,6 @@ import 'package:PiliPlus/utils/theme_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:catcher_2/catcher_2.dart'; import 'package:dynamic_color/dynamic_color.dart'; -import 'package:flex_seed_scheme/flex_seed_scheme.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart' show PointerDeviceKind; import 'package:flutter/material.dart'; @@ -263,7 +262,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { final dynamicColor = Pref.dynamicColor && _light != null && _dark != null; late final brandColor = colorThemeTypes[Pref.customColor].color; - late final variant = FlexSchemeVariant.values[Pref.schemeVariant]; + late final variant = Pref.schemeVariant; return GetMaterialApp( title: Constants.appName, theme: ThemeUtils.getThemeData( @@ -395,7 +394,7 @@ class MyApp extends StatelessWidget { if (kDebugMode) { debugPrint('dynamic_color: Accent color detected.'); } - final variant = FlexSchemeVariant.values[Pref.schemeVariant]; + final variant = Pref.schemeVariant; _light = accentColor.asColorSchemeSeed(variant, .light); _dark = accentColor.asColorSchemeSeed(variant, .dark); return true; diff --git a/lib/models/dynamics/result.dart b/lib/models/dynamics/result.dart index 1e8ed47f2..05a69529e 100644 --- a/lib/models/dynamics/result.dart +++ b/lib/models/dynamics/result.dart @@ -170,7 +170,7 @@ class ItemModulesModel { ModuleBlocked? moduleBlocked; ModuleFold? moduleFold; - static bool showArgueMsg = Pref.showArgueMsg; + static bool showDynDispute = Pref.showDynDispute; static bool showDynInteraction = Pref.showDynInteraction; ItemModulesModel.fromJson(Map json) { @@ -194,7 +194,7 @@ class ItemModulesModel { ? ModuleInteraction.fromJson(json['module_interaction']) : null; } - if (showArgueMsg) { + if (showDynDispute) { moduleDispute = json['module_dispute'] != null ? ModuleDispute.fromJson(json['module_dispute']) : null; diff --git a/lib/models_new/live/live_danmaku/danmaku_msg.dart b/lib/models_new/live/live_danmaku/danmaku_msg.dart index 4e7a8d764..b0fe0ae17 100644 --- a/lib/models_new/live/live_danmaku/danmaku_msg.dart +++ b/lib/models_new/live/live_danmaku/danmaku_msg.dart @@ -57,4 +57,14 @@ class DanmakuMsg { reply: reply, ); } + + Map toJson() => { + 'name': name, + 'uid': uid, + 'text': text, + 'emots': emots, + 'uemote': uemote?.toJson(), + 'extra': extra.toJson(), + 'reply': reply?.toJson(), + }; } diff --git a/lib/models_new/live/live_danmaku/live_emote.dart b/lib/models_new/live/live_danmaku/live_emote.dart index 583268437..3c80dad17 100644 --- a/lib/models_new/live/live_danmaku/live_emote.dart +++ b/lib/models_new/live/live_danmaku/live_emote.dart @@ -11,6 +11,13 @@ class BaseEmote { width = (json['width'] as num).toDouble(); height = (json['height'] as num?)?.toDouble(); } + + Map toJson() => { + 'url': url, + 'emoticon_unique': emoticonUnique, + 'width': width, + 'height': height, + }; } // class Emote extends BaseEmote { diff --git a/lib/models_new/live/live_superchat/item.dart b/lib/models_new/live/live_superchat/item.dart index 8ce5895e2..c0b72d613 100644 --- a/lib/models_new/live/live_superchat/item.dart +++ b/lib/models_new/live/live_superchat/item.dart @@ -91,4 +91,19 @@ class SuperChatItem { userInfo: userInfo ?? this.userInfo, ); } + + Map toJson() => { + 'id': id, + 'uid': uid, + 'price': price, + 'background_color': backgroundColor, + 'background_bottom_color': backgroundBottomColor, + 'background_price_color': backgroundPriceColor, + 'message_font_color': messageFontColor, + 'end_time': endTime, + 'message': message, + 'token': token, + 'ts': ts, + 'user_info': userInfo.toJson(), + }; } diff --git a/lib/models_new/live/live_superchat/user_info.dart b/lib/models_new/live/live_superchat/user_info.dart index 19089f6e4..13ce96f17 100644 --- a/lib/models_new/live/live_superchat/user_info.dart +++ b/lib/models_new/live/live_superchat/user_info.dart @@ -14,4 +14,10 @@ class UserInfo { uname: json['uname'], nameColor: json['name_color'] ?? '#666666', ); + + Map toJson() => { + 'face': face, + 'uname': uname, + 'name_color': nameColor, + }; } diff --git a/lib/pages/common/publish/common_rich_text_pub_page.dart b/lib/pages/common/publish/common_rich_text_pub_page.dart index adc4c4245..2e0176785 100644 --- a/lib/pages/common/publish/common_rich_text_pub_page.dart +++ b/lib/pages/common/publish/common_rich_text_pub_page.dart @@ -110,7 +110,10 @@ abstract class CommonRichTextPubPageState ); controller.restoreChatPanel(); }, - onLongPress: onClear, + onLongPress: () { + Feedback.forLongPress(context); + onClear(); + }, onSecondaryTap: PlatformUtils.isMobile ? null : onClear, child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(4)), diff --git a/lib/pages/common/reply_controller.dart b/lib/pages/common/reply_controller.dart index d99e953d6..3875c906b 100644 --- a/lib/pages/common/reply_controller.dart +++ b/lib/pages/common/reply_controller.dart @@ -45,9 +45,10 @@ abstract class ReplyController extends CommonListController { @override void onInit() { super.onInit(); - int replySortType = Pref.replySortType; - sortType = ReplySortType.values[replySortType].obs; - mode = (replySortType == 0 ? Mode.MAIN_LIST_TIME : Mode.MAIN_LIST_HOT).obs; + final cacheSortType = Pref.replySortType; + sortType = cacheSortType.obs; + mode = + (cacheSortType == .time ? Mode.MAIN_LIST_TIME : Mode.MAIN_LIST_HOT).obs; } @override diff --git a/lib/pages/danmaku/danmaku_model.dart b/lib/pages/danmaku/danmaku_model.dart index 72009e234..0177bbc1c 100644 --- a/lib/pages/danmaku/danmaku_model.dart +++ b/lib/pages/danmaku/danmaku_model.dart @@ -41,4 +41,12 @@ class LiveDanmaku extends DanmakuExtra { required this.ts, required this.ct, }); + + Map toJson() => { + 'id': id, + 'mid': mid, + 'dm_type': dmType, + 'ts': ts, + 'ct': ct, + }; } diff --git a/lib/pages/dynamics/controller.dart b/lib/pages/dynamics/controller.dart index 7eef83034..4301e8cab 100644 --- a/lib/pages/dynamics/controller.dart +++ b/lib/pages/dynamics/controller.dart @@ -58,7 +58,7 @@ class DynamicsController extends GetxController tabController = TabController( length: DynamicsTabType.values.length, vsync: this, - initialIndex: Pref.defaultDynamicType, + initialIndex: Pref.defaultDynamicTypeIndex, ); queryFollowUp(); } diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index eab217f96..ee1189b37 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -249,7 +249,7 @@ class DynamicPanel extends StatelessWidget { Widget _buildDispute(ThemeData theme, ModuleDispute moduleDispute) { final child = Container( width: .infinity, - margin: const .fromLTRB(12, 0, 12, 6), + margin: const .fromLTRB(12, 2, 12, 6), padding: const .symmetric(horizontal: 8, vertical: 6), decoration: BoxDecoration( color: theme.colorScheme.secondaryContainer.withValues( diff --git a/lib/pages/live_room/superchat/superchat_card.dart b/lib/pages/live_room/superchat/superchat_card.dart index 70a83433c..feec5e892 100644 --- a/lib/pages/live_room/superchat/superchat_card.dart +++ b/lib/pages/live_room/superchat/superchat_card.dart @@ -103,6 +103,14 @@ class _SuperChatCardState extends State { style: const TextStyle(fontSize: 13), ), ), + PopupMenuItem( + height: 38, + onTap: () => Utils.copyText(Utils.jsonEncoder.convert(item.toJson())), + child: const Text( + '复制 SC 信息', + style: TextStyle(fontSize: 13), + ), + ), PopupMenuItem( height: 38, onTap: widget.onReport, diff --git a/lib/pages/live_room/widgets/chat_panel.dart b/lib/pages/live_room/widgets/chat_panel.dart index 497007606..179270e70 100644 --- a/lib/pages/live_room/widgets/chat_panel.dart +++ b/lib/pages/live_room/widgets/chat_panel.dart @@ -9,6 +9,7 @@ import 'package:PiliPlus/pages/live_room/superchat/superchat_card.dart'; import 'package:PiliPlus/pages/video/widgets/header_control.dart'; import 'package:PiliPlus/utils/accounts.dart'; import 'package:PiliPlus/utils/extension/theme_ext.dart'; +import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/foundation.dart' show kDebugMode; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -314,6 +315,14 @@ class LiveRoomChatPanel extends StatelessWidget { ), ), const CustomPopupMenuDivider(height: 1), + PopupMenuItem( + height: 38, + onTap: () => Utils.copyText(Utils.jsonEncoder.convert(item.toJson())), + child: const Text( + '复制弹幕信息', + style: TextStyle(fontSize: 13), + ), + ), PopupMenuItem( height: 38, onTap: () => Get.toNamed('/member?mid=${item.uid}'), diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart index 52b2b0802..e39c7ccec 100644 --- a/lib/pages/main/controller.dart +++ b/lib/pages/main/controller.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:math' show max; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/grpc/dyn.dart'; @@ -85,7 +84,7 @@ class MainController extends GetxController if (navigationBars.length > 1 && Pref.hideTabBar) { bottomBar = true.obs; } - dynamicBadgeMode = DynamicBadgeMode.values[Pref.dynamicBadgeMode]; + dynamicBadgeMode = Pref.dynamicBadgeMode; hasDyn = navigationBars.contains(NavigationBarType.dynamics); if (dynamicBadgeMode != DynamicBadgeMode.hidden) { @@ -211,7 +210,6 @@ class MainController extends GetxController void setNavBarConfig() { List? navBarSort = (GStorage.setting.get(SettingBoxKey.navBarSort) as List?)?.fromCast(); - int defaultHomePage = Pref.defaultHomePage; late final List navigationBars; if (navBarSort == null || navBarSort.isEmpty) { navigationBars = NavigationBarType.values; @@ -221,10 +219,7 @@ class MainController extends GetxController .toList(); } this.navigationBars = navigationBars; - selectedIndex.value = max( - 0, - navigationBars.indexWhere((e) => e.index == defaultHomePage), - ); + selectedIndex.value = Pref.defaultHomePageIndex; } void checkDefaultSearch([bool shouldCheck = false]) { diff --git a/lib/pages/setting/models/extra_settings.dart b/lib/pages/setting/models/extra_settings.dart index 2b33a24f4..a91f32632 100644 --- a/lib/pages/setting/models/extra_settings.dart +++ b/lib/pages/setting/models/extra_settings.dart @@ -405,12 +405,18 @@ List get extraSettings => [ ); }, ), - SwitchModel( + const SwitchModel( title: '显示视频警告/争议信息', - leading: const Icon(Icons.warning_amber_rounded), + leading: Icon(Icons.warning_amber_rounded), setKey: SettingBoxKey.showArgueMsg, defaultVal: true, - onChanged: (val) => ItemModulesModel.showArgueMsg = val, + ), + SwitchModel( + title: '显示动态警告/争议信息', + leading: const Icon(Icons.warning_amber_rounded), + setKey: SettingBoxKey.showDynDispute, + defaultVal: false, + onChanged: (val) => ItemModulesModel.showDynDispute = val, ), const SwitchModel( title: '分P/合集:倒序播放从首集开始播放', @@ -746,6 +752,13 @@ List get extraSettings => [ defaultVal: false, onChanged: (value) => ImageUtils.silentDownImg = value, ), + SwitchModel( + title: '长按/右键显示图片菜单', + leading: const Icon(Icons.menu), + setKey: SettingBoxKey.enableImgMenu, + defaultVal: false, + onChanged: (value) => CustomGridView.enableImgMenu = value, + ), SwitchModel( setKey: SettingBoxKey.feedBackEnable, onChanged: (value) { @@ -929,23 +942,20 @@ List get extraSettings => [ NormalModel( title: '评论展示', leading: const Icon(Icons.whatshot_outlined), - getSubtitle: () => - '当前优先展示「${ReplySortType.values[Pref.replySortType].title}」', + getSubtitle: () => '当前优先展示「${Pref.replySortType.title}」', onTap: (context, setState) async { - final result = await showDialog( + final result = await showDialog( context: context, builder: (context) { - return SelectDialog( + return SelectDialog( title: '评论展示', value: Pref.replySortType, - values: ReplySortType.values - .map((e) => (e.index, e.title)) - .toList(), + values: ReplySortType.values.map((e) => (e, e.title)).toList(), ); }, ); if (result != null) { - await GStorage.setting.put(SettingBoxKey.replySortType, result); + await GStorage.setting.put(SettingBoxKey.replySortType, result.index); setState(); } }, @@ -953,24 +963,26 @@ List get extraSettings => [ NormalModel( title: '动态展示', leading: const Icon(Icons.dynamic_feed_rounded), - getSubtitle: () => - '当前优先展示「${DynamicsTabType.values[Pref.defaultDynamicType].label}」', + getSubtitle: () => '当前优先展示「${Pref.defaultDynamicType.label}」', onTap: (context, setState) async { - final result = await showDialog( + final result = await showDialog( context: context, builder: (context) { - return SelectDialog( + return SelectDialog( title: '动态展示', value: Pref.defaultDynamicType, values: DynamicsTabType.values .take(4) - .map((e) => (e.index, e.label)) + .map((e) => (e, e.label)) .toList(), ); }, ); if (result != null) { - await GStorage.setting.put(SettingBoxKey.defaultDynamicType, result); + await GStorage.setting.put( + SettingBoxKey.defaultDynamicType, + result.index, + ); setState(); } }, diff --git a/lib/pages/setting/models/play_settings.dart b/lib/pages/setting/models/play_settings.dart index 57d427acc..18a28999e 100644 --- a/lib/pages/setting/models/play_settings.dart +++ b/lib/pages/setting/models/play_settings.dart @@ -119,23 +119,23 @@ List get playSettings => [ NormalModel( title: '自动启用字幕', leading: const Icon(Icons.closed_caption_outlined), - getSubtitle: () => - '当前选择偏好:${SubtitlePrefType.values[Pref.subtitlePreferenceV2].desc}', + getSubtitle: () => '当前选择偏好:${Pref.subtitlePreferenceV2.desc}', onTap: (context, setState) async { - final result = await showDialog( + final result = await showDialog( context: context, builder: (context) { - return SelectDialog( + return SelectDialog( title: '字幕选择偏好', value: Pref.subtitlePreferenceV2, - values: SubtitlePrefType.values - .map((e) => (e.index, e.desc)) - .toList(), + values: SubtitlePrefType.values.map((e) => (e, e.desc)).toList(), ); }, ); if (result != null) { - await GStorage.setting.put(SettingBoxKey.subtitlePreferenceV2, result); + await GStorage.setting.put( + SettingBoxKey.subtitlePreferenceV2, + result.index, + ); setState(); } }, @@ -266,23 +266,20 @@ List get playSettings => [ NormalModel( title: '默认全屏方向', leading: const Icon(Icons.open_with_outlined), - getSubtitle: () => - '当前全屏方向:${FullScreenMode.values[Pref.fullScreenMode].desc}', + getSubtitle: () => '当前全屏方向:${Pref.fullScreenMode.desc}', onTap: (context, setState) async { - final result = await showDialog( + final result = await showDialog( context: context, builder: (context) { - return SelectDialog( + return SelectDialog( title: '默认全屏方向', value: Pref.fullScreenMode, - values: FullScreenMode.values - .map((e) => (e.index, e.desc)) - .toList(), + values: FullScreenMode.values.map((e) => (e, e.desc)).toList(), ); }, ); if (result != null) { - await GStorage.setting.put(SettingBoxKey.fullScreenMode, result); + await GStorage.setting.put(SettingBoxKey.fullScreenMode, result.index); setState(); } }, @@ -290,23 +287,23 @@ List get playSettings => [ NormalModel( title: '底部进度条展示', leading: const Icon(Icons.border_bottom_outlined), - getSubtitle: () => - '当前展示方式:${BtmProgressBehavior.values[Pref.btmProgressBehavior].desc}', + getSubtitle: () => '当前展示方式:${Pref.btmProgressBehavior.desc}', onTap: (context, setState) async { - final result = await showDialog( + final result = await showDialog( context: context, builder: (context) { - return SelectDialog( + return SelectDialog( title: '底部进度条展示', value: Pref.btmProgressBehavior, - values: BtmProgressBehavior.values - .map((e) => (e.index, e.desc)) - .toList(), + values: BtmProgressBehavior.values.map((e) => (e, e.desc)).toList(), ); }, ); if (result != null) { - await GStorage.setting.put(SettingBoxKey.btmProgressBehavior, result); + await GStorage.setting.put( + SettingBoxKey.btmProgressBehavior, + result.index, + ); setState(); } }, diff --git a/lib/pages/setting/models/recommend_settings.dart b/lib/pages/setting/models/recommend_settings.dart index d60dd7089..db70d0220 100644 --- a/lib/pages/setting/models/recommend_settings.dart +++ b/lib/pages/setting/models/recommend_settings.dart @@ -21,7 +21,7 @@ List get recommendSettings => [ subtitle: '下拉刷新时保留上次内容', leading: const Icon(Icons.refresh), setKey: SettingBoxKey.enableSaveLastData, - defaultVal: false, + defaultVal: true, onChanged: (value) { try { Get.find() diff --git a/lib/pages/setting/models/style_settings.dart b/lib/pages/setting/models/style_settings.dart index 1c4b27e7b..1245f96fa 100644 --- a/lib/pages/setting/models/style_settings.dart +++ b/lib/pages/setting/models/style_settings.dart @@ -33,7 +33,6 @@ import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:auto_orientation/auto_orientation.dart'; -import 'package:flex_seed_scheme/flex_seed_scheme.dart'; import 'package:flutter/material.dart' hide StatefulBuilder; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -593,10 +592,7 @@ List get styleSettings => [ dimension: 32, child: ColorPalette( colorScheme: colorThemeTypes[Pref.customColor].color - .asColorSchemeSeed( - FlexSchemeVariant.values[Pref.schemeVariant], - Get.theme.brightness, - ), + .asColorSchemeSeed(Pref.schemeVariant, Get.theme.brightness), selected: false, showBgColor: false, ), @@ -604,28 +600,25 @@ List get styleSettings => [ ), NormalModel( onTap: (context, setState) async { - final result = await showDialog( + final result = await showDialog( context: context, builder: (context) { - return SelectDialog( + return SelectDialog( title: '首页启动页', value: Pref.defaultHomePage, - values: NavigationBarType.values - .map((e) => (e.index, e.label)) - .toList(), + values: NavigationBarType.values.map((e) => (e, e.label)).toList(), ); }, ); if (result != null) { - await GStorage.setting.put(SettingBoxKey.defaultHomePage, result); + await GStorage.setting.put(SettingBoxKey.defaultHomePage, result.index); SmartDialog.showToast('设置成功,重启生效'); setState(); } }, leading: const Icon(Icons.home_outlined), title: '默认启动页', - getSubtitle: () => - '当前启动页:${NavigationBarType.values.firstWhere((e) => e.index == Pref.defaultHomePage).label}', + getSubtitle: () => '当前启动页:${Pref.defaultHomePage.label}', ), NormalModel( title: '滑动动画弹簧参数', diff --git a/lib/pages/setting/pages/color_select.dart b/lib/pages/setting/pages/color_select.dart index 31e43f085..5ef1f07ab 100644 --- a/lib/pages/setting/pages/color_select.dart +++ b/lib/pages/setting/pages/color_select.dart @@ -39,8 +39,7 @@ class Item { class _ColorSelectPageState extends State { final ctr = Get.put(ColorSelectController()); - FlexSchemeVariant _dynamicSchemeVariant = - FlexSchemeVariant.values[Pref.schemeVariant]; + FlexSchemeVariant _dynamicSchemeVariant = Pref.schemeVariant; @override Widget build(BuildContext context) { diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index 0b35370ff..69dd355f9 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -1592,8 +1592,7 @@ class VideoDetailController extends GetxController if (response.subtitle?.subtitles?.isNotEmpty == true) { subtitles.value = response.subtitle!.subtitles!; - final idx = switch (SubtitlePrefType.values[Pref - .subtitlePreferenceV2]) { + final idx = switch (Pref.subtitlePreferenceV2) { SubtitlePrefType.off => 0, SubtitlePrefType.on => 1, SubtitlePrefType.withoutAi => diff --git a/lib/pages/video/introduction/ugc/view.dart b/lib/pages/video/introduction/ugc/view.dart index 19a3fb513..773756c3b 100644 --- a/lib/pages/video/introduction/ugc/view.dart +++ b/lib/pages/video/introduction/ugc/view.dart @@ -773,6 +773,9 @@ class _UgcIntroPanelState extends State { int? ownerMid, Staff item, ) { + void onTap() => Get.toNamed( + '/member?mid=${item.mid}&from_view_aid=${videoDetailCtr.aid}', + ); return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { @@ -781,11 +784,13 @@ class _UgcIntroPanelState extends State { introController.horizontalMemberPage) { widget.onShowMemberPage(ownerMid); } else { - Get.toNamed( - '/member?mid=${item.mid}&from_view_aid=${videoDetailCtr.aid}', - ); + onTap(); } }, + onSecondaryTap: + PlatformUtils.isDesktop && introController.horizontalMemberPage + ? onTap + : null, child: Row( children: [ Stack( @@ -893,6 +898,12 @@ class _UgcIntroPanelState extends State { ) => GestureDetector( onTap: onPushMember, behavior: HitTestBehavior.opaque, + onSecondaryTap: + PlatformUtils.isDesktop && introController.horizontalMemberPage + ? () => Get.toNamed( + '/member?mid=${introController.userStat.value.card?.mid}&from_view_aid=${videoDetailCtr.aid}', + ) + : null, child: Obx( () { final userStat = introController.userStat.value; diff --git a/lib/pages/video/reply/widgets/reply_item_grpc.dart b/lib/pages/video/reply/widgets/reply_item_grpc.dart index bd5eb6e27..8cdd098ec 100644 --- a/lib/pages/video/reply/widgets/reply_item_grpc.dart +++ b/lib/pages/video/reply/widgets/reply_item_grpc.dart @@ -99,14 +99,8 @@ class ReplyItemGrpc extends StatelessWidget { return Material( type: MaterialType.transparency, child: InkWell( - onTap: () { - feedBack(); - replyReply?.call(replyItem, null); - }, - onLongPress: () { - feedBack(); - showMore(); - }, + onTap: () => replyReply?.call(replyItem, null), + onLongPress: showMore, onSecondaryTap: isMobile ? null : showMore, child: _buildContent(context, theme), ), @@ -468,10 +462,7 @@ class ReplyItemGrpc extends StatelessWidget { return InkWell( onTap: () => replyReply?.call(replyItem, childReply.id.toInt()), - onLongPress: () { - feedBack(); - showMore(); - }, + onLongPress: showMore, onSecondaryTap: PlatformUtils.isMobile ? null : showMore, child: Padding( padding: padding, diff --git a/lib/pages/whisper_detail/widget/chat_item.dart b/lib/pages/whisper_detail/widget/chat_item.dart index dc5012bdd..f8c72957f 100644 --- a/lib/pages/whisper_detail/widget/chat_item.dart +++ b/lib/pages/whisper_detail/widget/chat_item.dart @@ -587,7 +587,7 @@ class ChatItem extends StatelessWidget { ); } - Widget msgTypePic_2(content) { + Widget msgTypePic_2(Map content) { final url = content['url']; return GestureDetector( onTap: () => PageUtils.imageView(imgList: [SourceModel(url: url)]), diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index ddfdc66cc..263167f4d 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -19,7 +19,6 @@ import 'package:PiliPlus/models/video/play/url.dart'; import 'package:PiliPlus/models_new/video/video_shot/data.dart'; import 'package:PiliPlus/pages/danmaku/danmaku_model.dart'; import 'package:PiliPlus/pages/mine/controller.dart'; -import 'package:PiliPlus/plugin/pl_player/models/bottom_progress_behavior.dart'; import 'package:PiliPlus/plugin/pl_player/models/data_source.dart'; import 'package:PiliPlus/plugin/pl_player/models/data_status.dart'; import 'package:PiliPlus/plugin/pl_player/models/double_tap_type.dart'; @@ -402,8 +401,7 @@ class PlPlayerController { late final bool enableHA = Pref.enableHA; late final String hwdec = Pref.hardwareDecoding; - late final progressType = - BtmProgressBehavior.values[Pref.btmProgressBehavior]; + late final progressType = Pref.btmProgressBehavior; late final enableQuickDouble = Pref.enableQuickDouble; late final fullScreenGestureReverse = Pref.fullScreenGestureReverse; @@ -416,7 +414,7 @@ class PlPlayerController { isRelative ? duration.value.inMilliseconds * offset : offset; // 播放顺序相关 - late PlayRepeat playRepeat = PlayRepeat.values[Pref.playRepeat]; + late PlayRepeat playRepeat = Pref.playRepeat; TextStyle get subTitleStyle => TextStyle( height: 1.5, @@ -1519,7 +1517,7 @@ class PlPlayerController { } late bool isManualFS = true; - late final FullScreenMode mode = FullScreenMode.values[Pref.fullScreenMode]; + late final FullScreenMode mode = Pref.fullScreenMode; late final horizontalScreen = Pref.horizontalScreen; // 全屏 diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 59f597252..c3b8214f5 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -1146,11 +1146,7 @@ class _PLVideoPlayerState extends State } void onDoubleTapDownMobile(TapDownDetails details) { - if (plPlayerController.controlsLock.value) { - return; - } - if (plPlayerController.isLive) { - plPlayerController.doubleTapFuc(DoubleTapType.center); + if (plPlayerController.isLive || plPlayerController.controlsLock.value) { return; } final double tapPosition = details.localPosition.dx; @@ -1167,7 +1163,7 @@ class _PLVideoPlayerState extends State } void onTapDesktop() { - if (plPlayerController.controlsLock.value) { + if (plPlayerController.isLive || plPlayerController.controlsLock.value) { return; } plPlayerController.onDoubleTapCenter(); diff --git a/lib/utils/storage_key.dart b/lib/utils/storage_key.dart index 07580d003..b42f2577b 100644 --- a/lib/utils/storage_key.dart +++ b/lib/utils/storage_key.dart @@ -144,7 +144,9 @@ abstract final class SettingBoxKey { enableTapDm = 'enableTapDm', setSystemBrightness = 'setSystemBrightness', downloadPath = 'downloadPath', - followOrderType = 'followOrderType'; + followOrderType = 'followOrderType', + enableImgMenu = 'enableImgMenu', + showDynDispute = 'showDynDispute'; static const String minimizeOnExit = 'minimizeOnExit', windowSize = 'windowSize', diff --git a/lib/utils/storage_pref.dart b/lib/utils/storage_pref.dart index 21c0882a1..e02c3c8e8 100644 --- a/lib/utils/storage_pref.dart +++ b/lib/utils/storage_pref.dart @@ -4,10 +4,13 @@ import 'dart:math' show pow, sqrt; import 'package:PiliPlus/common/widgets/pair.dart'; import 'package:PiliPlus/http/constants.dart'; import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart'; +import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart'; import 'package:PiliPlus/models/common/dynamic/up_panel_position.dart'; import 'package:PiliPlus/models/common/follow_order_type.dart'; import 'package:PiliPlus/models/common/member/tab_type.dart'; import 'package:PiliPlus/models/common/msg/msg_unread_type.dart'; +import 'package:PiliPlus/models/common/nav_bar_config.dart'; +import 'package:PiliPlus/models/common/reply/reply_sort_type.dart'; import 'package:PiliPlus/models/common/sponsor_block/segment_type.dart'; import 'package:PiliPlus/models/common/sponsor_block/skip_type.dart'; import 'package:PiliPlus/models/common/super_chat_type.dart'; @@ -32,6 +35,7 @@ import 'package:PiliPlus/utils/login_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; +import 'package:flex_seed_scheme/flex_seed_scheme.dart' show FlexSchemeVariant; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; @@ -55,25 +59,23 @@ abstract final class Pref { static Set get blackMids => _localCache.get(LocalCacheKey.blackMids, defaultValue: {}); - static set blackMids(Set blackMidsSet) { - _localCache.put(LocalCacheKey.blackMids, blackMidsSet); - } + static set blackMids(Set blackMidsSet) => + _localCache.put(LocalCacheKey.blackMids, blackMidsSet); static RuleFilter get danmakuFilterRule => _localCache.get( LocalCacheKey.danmakuFilterRules, defaultValue: RuleFilter.empty(), ); - static void setBlackMid(int mid) { - _localCache.put(LocalCacheKey.blackMids, GlobalData().blackMids..add(mid)); - } + static void setBlackMid(int mid) => _localCache.put( + LocalCacheKey.blackMids, + GlobalData().blackMids..add(mid), + ); - static void removeBlackMid(int mid) { - _localCache.put( - LocalCacheKey.blackMids, - GlobalData().blackMids..remove(mid), - ); - } + static void removeBlackMid(int mid) => _localCache.put( + LocalCacheKey.blackMids, + GlobalData().blackMids..remove(mid), + ); static MemberTabType get memberTab => MemberTabType.values[_setting.get( @@ -86,13 +88,13 @@ abstract final class Pref { defaultValue: ThemeType.system.index, ); - static ThemeMode get themeMode { - return switch (_themeTypeInt) { - 0 => ThemeMode.light, - 1 => ThemeMode.dark, - _ => ThemeMode.system, - }; - } + static ThemeType get themeType => ThemeType.values[_themeTypeInt]; + + static ThemeMode get themeMode => switch (_themeTypeInt) { + 0 => ThemeMode.light, + 1 => ThemeMode.dark, + _ => ThemeMode.system, + }; static List get springDescription => List.from( _setting.get(SettingBoxKey.springDescription) ?? @@ -143,8 +145,6 @@ abstract final class Pref { static int get picQuality => _setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10); - static ThemeType get themeType => ThemeType.values[_themeTypeInt]; - static DynamicBadgeMode get dynamicBadgeType => DynamicBadgeMode.values[_setting.get( SettingBoxKey.dynamicBadgeMode, @@ -163,8 +163,13 @@ abstract final class Pref { .toSet() ?? MsgUnReadType.values.toSet(); - static int get defaultHomePage => - _setting.get(SettingBoxKey.defaultHomePage, defaultValue: 0); + static NavigationBarType get defaultHomePage => + NavigationBarType.values[defaultHomePageIndex]; + + static int get defaultHomePageIndex => _setting.get( + SettingBoxKey.defaultHomePage, + defaultValue: NavigationBarType.home.index, + ); static int get previewQ => _setting.get(SettingBoxKey.previewQuality, defaultValue: 100); @@ -181,20 +186,23 @@ abstract final class Pref { defaultValue: UpPanelPosition.leftFixed.index, )]; - static int get fullScreenMode => _setting.get( - SettingBoxKey.fullScreenMode, - defaultValue: FullScreenMode.auto.index, - ); + static FullScreenMode get fullScreenMode => + FullScreenMode.values[_setting.get( + SettingBoxKey.fullScreenMode, + defaultValue: FullScreenMode.auto.index, + )]; - static int get btmProgressBehavior => _setting.get( - SettingBoxKey.btmProgressBehavior, - defaultValue: BtmProgressBehavior.alwaysShow.index, - ); + static BtmProgressBehavior get btmProgressBehavior => + BtmProgressBehavior.values[_setting.get( + SettingBoxKey.btmProgressBehavior, + defaultValue: BtmProgressBehavior.alwaysShow.index, + )]; - static int get subtitlePreferenceV2 => _setting.get( - SettingBoxKey.subtitlePreferenceV2, - defaultValue: SubtitlePrefType.off.index, - ); + static SubtitlePrefType get subtitlePreferenceV2 => + SubtitlePrefType.values[_setting.get( + SettingBoxKey.subtitlePreferenceV2, + defaultValue: SubtitlePrefType.off.index, + )]; static bool get useRelativeSlide => _setting.get(SettingBoxKey.useRelativeSlide, defaultValue: false); @@ -267,8 +275,13 @@ abstract final class Pref { static String get systemProxyPort => _setting.get(SettingBoxKey.systemProxyPort, defaultValue: ''); - static int get defaultDynamicType => - _setting.get(SettingBoxKey.defaultDynamicType, defaultValue: 0); + static DynamicsTabType get defaultDynamicType => + DynamicsTabType.values[defaultDynamicTypeIndex]; + + static int get defaultDynamicTypeIndex => _setting.get( + SettingBoxKey.defaultDynamicType, + defaultValue: DynamicsTabType.all.index, + ); static bool get showDynInteraction => _setting.get(SettingBoxKey.showDynInteraction, defaultValue: true); @@ -285,11 +298,8 @@ abstract final class Pref { ); static String get blockUserID { - String blockUserID = _setting.get( - SettingBoxKey.blockUserID, - defaultValue: '', - ); - if (blockUserID.isEmpty) { + String? blockUserID = _setting.get(SettingBoxKey.blockUserID); + if (blockUserID == null || blockUserID.isEmpty) { blockUserID = const Uuid().v4().replaceAll('-', ''); _setting.put(SettingBoxKey.blockUserID, blockUserID); } @@ -313,11 +323,16 @@ abstract final class Pref { static int get dynamicPeriod => _setting.get(SettingBoxKey.dynamicPeriod, defaultValue: 5); - static int get schemeVariant => - _setting.get(SettingBoxKey.schemeVariant, defaultValue: 10); + static FlexSchemeVariant get schemeVariant => + FlexSchemeVariant.values[_setting.get( + SettingBoxKey.schemeVariant, + defaultValue: FlexSchemeVariant.material3Legacy.index, + )]; - static double get danmakuFontScaleFS => - _setting.get(SettingBoxKey.danmakuFontScaleFS, defaultValue: 1.2); + static double get danmakuFontScaleFS => _setting.get( + SettingBoxKey.danmakuFontScaleFS, + defaultValue: PlatformUtils.isMobile ? 1.2 : 1.7, + ); static bool get danmakuMassiveMode => _setting.get(SettingBoxKey.danmakuMassiveMode, defaultValue: false); @@ -352,11 +367,15 @@ abstract final class Pref { static bool get expandIntroPanelH => _setting.get(SettingBoxKey.expandIntroPanelH, defaultValue: false); - static bool get horizontalSeasonPanel => - _setting.get(SettingBoxKey.horizontalSeasonPanel, defaultValue: false); + static bool get horizontalSeasonPanel => _setting.get( + SettingBoxKey.horizontalSeasonPanel, + defaultValue: PlatformUtils.isDesktop, + ); - static bool get horizontalMemberPage => - _setting.get(SettingBoxKey.horizontalMemberPage, defaultValue: false); + static bool get horizontalMemberPage => _setting.get( + SettingBoxKey.horizontalMemberPage, + defaultValue: PlatformUtils.isDesktop, + ); static int? get replyLengthLimit { int length = _setting.get(SettingBoxKey.replyLengthLimit, defaultValue: 6); @@ -435,8 +454,7 @@ abstract final class Pref { if (index != null) { superResolutionType = SuperResolutionType.values.getOrNull(index); } - superResolutionType ??= SuperResolutionType.disable; - return superResolutionType; + return superResolutionType ?? SuperResolutionType.disable; } static bool get preInitPlayer => @@ -682,16 +700,20 @@ abstract final class Pref { static bool get enableHttp2 => _setting.get(SettingBoxKey.enableHttp2, defaultValue: false); - static int get replySortType => - _setting.get(SettingBoxKey.replySortType, defaultValue: 1); + static ReplySortType get replySortType => + ReplySortType.values[_setting.get( + SettingBoxKey.replySortType, + defaultValue: ReplySortType.hot.index, + )]; static bool get hideTabBar => _setting.get(SettingBoxKey.hideTabBar, defaultValue: true); - static int get dynamicBadgeMode => _setting.get( - SettingBoxKey.dynamicBadgeMode, - defaultValue: DynamicBadgeMode.number.index, - ); + static DynamicBadgeMode get dynamicBadgeMode => + DynamicBadgeMode.values[_setting.get( + SettingBoxKey.dynamicBadgeMode, + defaultValue: DynamicBadgeMode.number.index, + )]; static bool get enableMYBar => _setting.get(SettingBoxKey.enableMYBar, defaultValue: true); @@ -730,8 +752,10 @@ abstract final class Pref { static double get danmakuOpacity => _setting.get(SettingBoxKey.danmakuOpacity, defaultValue: 1.0); - static double get danmakuFontScale => - _setting.get(SettingBoxKey.danmakuFontScale, defaultValue: 1.0); + static double get danmakuFontScale => _setting.get( + SettingBoxKey.danmakuFontScale, + defaultValue: PlatformUtils.isMobile ? 1.0 : 1.4, + ); static double get danmakuDuration => _setting.get(SettingBoxKey.danmakuDuration, defaultValue: 7.0); @@ -739,11 +763,15 @@ abstract final class Pref { static double get danmakuStaticDuration => _setting.get(SettingBoxKey.danmakuStaticDuration, defaultValue: 4.0); - static double get danmakuStrokeWidth => - _setting.get(SettingBoxKey.danmakuStrokeWidth, defaultValue: 1.5); + static double get danmakuStrokeWidth => _setting.get( + SettingBoxKey.danmakuStrokeWidth, + defaultValue: PlatformUtils.isMobile ? 1.5 : 2.5, + ); - static int get danmakuFontWeight => - _setting.get(SettingBoxKey.danmakuFontWeight, defaultValue: 5); + static int get danmakuFontWeight => _setting.get( + SettingBoxKey.danmakuFontWeight, + defaultValue: PlatformUtils.isMobile ? 5 : 6, + ); static bool get enableLongShowControl => _setting.get(SettingBoxKey.enableLongShowControl, defaultValue: false); @@ -782,14 +810,16 @@ abstract final class Pref { _setting.get(SettingBoxKey.enableSearchRcmd, defaultValue: true); static bool get enableSaveLastData => - _setting.get(SettingBoxKey.enableSaveLastData, defaultValue: false); + _setting.get(SettingBoxKey.enableSaveLastData, defaultValue: true); static double get defaultToastOp => _setting.get(SettingBoxKey.defaultToastOp, defaultValue: 1.0); - static int get playRepeat => - (_video.get(VideoBoxKey.playRepeat) as num?)?.toInt() ?? - PlayRepeat.pause.index; + static PlayRepeat get playRepeat => + PlayRepeat.values[_video.get( + VideoBoxKey.playRepeat, + defaultValue: PlayRepeat.pause.index, + )]; static int get cacheVideoFit => _video.get(VideoBoxKey.cacheVideoFit, defaultValue: 1); @@ -904,4 +934,10 @@ abstract final class Pref { SettingBoxKey.followOrderType, defaultValue: FollowOrderType.def.index, )]; + + static bool get enableImgMenu => + _setting.get(SettingBoxKey.enableImgMenu, defaultValue: false); + + static bool get showDynDispute => + _setting.get(SettingBoxKey.showDynDispute, defaultValue: false); } diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 3fb15d4c5..70f20a2af 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -145,7 +145,7 @@ abstract final class Utils { return Clipboard.setData(ClipboardData(text: text)); } - static String makeHeroTag(v) { + static String makeHeroTag(dynamic v) { return v.toString() + random.nextInt(9999).toString(); }