diff --git a/lib/common/widgets/image/image_save.dart b/lib/common/widgets/image/image_save.dart index b6088ada0..9fecfc772 100644 --- a/lib/common/widgets/image/image_save.dart +++ b/lib/common/widgets/image/image_save.dart @@ -14,7 +14,7 @@ void imageSaveDialog({ dynamic aid, String? bvid, }) { - final double imgWidth = Get.mediaQuery.size.shortestSide - 8 * 2; + final double imgWidth = MediaQuery.sizeOf(Get.context!).shortestSide - 8 * 2; SmartDialog.show( animationType: SmartAnimationType.centerScale_otherSlide, builder: (context) { diff --git a/lib/models/common/settings_type.dart b/lib/models/common/settings_type.dart deleted file mode 100644 index 5cd6a19e6..000000000 --- a/lib/models/common/settings_type.dart +++ /dev/null @@ -1 +0,0 @@ -enum SettingsType { normal, sw1tch } diff --git a/lib/pages/setting/models/extra_settings.dart b/lib/pages/setting/models/extra_settings.dart index 9616f16d3..30bac8de7 100644 --- a/lib/pages/setting/models/extra_settings.dart +++ b/lib/pages/setting/models/extra_settings.dart @@ -12,7 +12,6 @@ import 'package:PiliPlus/models/common/audio_normalization.dart'; import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart'; import 'package:PiliPlus/models/common/member/tab_type.dart'; import 'package:PiliPlus/models/common/reply/reply_sort_type.dart'; -import 'package:PiliPlus/models/common/settings_type.dart'; import 'package:PiliPlus/models/common/sponsor_block/skip_type.dart'; import 'package:PiliPlus/models/common/super_resolution_type.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; @@ -47,8 +46,7 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart List get extraSettings => [ if (Utils.isDesktop) ...[ - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '退出时最小化', leading: const Icon(Icons.exit_to_app), setKey: SettingBoxKey.minimizeOnExit, @@ -59,14 +57,13 @@ List get extraSettings => [ } catch (_) {} }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '缓存路径', getSubtitle: () => downloadPath, leading: const Icon(Icons.storage), - onTap: (setState) { + onTap: (context, setState) { showDialog( - context: Get.context!, + context: context, builder: (context) { return AlertDialog( clipBehavior: Clip.hardEdge, @@ -116,13 +113,12 @@ List get extraSettings => [ }, ), ], - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '空降助手', subtitle: '点击配置', setKey: SettingBoxKey.enableSponsorBlock, defaultVal: false, - onTap: () => Get.toNamed('/sponsorBlock'), + onTap: (context) => Get.toNamed('/sponsorBlock'), leading: const Stack( clipBehavior: Clip.none, alignment: Alignment.center, @@ -132,8 +128,7 @@ List get extraSettings => [ ], ), ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( leading: const Icon(MdiIcons.debugStepOver), title: '番剧片头/片尾跳过类型', getTrailing: () => Builder( @@ -180,8 +175,7 @@ List get extraSettings => [ }, ), ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '检查未读动态', subtitle: '点击设置检查周期(min)', leading: const Icon(Icons.notifications_none), @@ -190,10 +184,10 @@ List get extraSettings => [ onChanged: (value) { Get.find().checkDynamic = value; }, - onTap: () { + onTap: (context) { int dynamicPeriod = Pref.dynamicPeriod; showDialog( - context: Get.context!, + context: context, builder: (context) { return AlertDialog( title: const Text('检查周期'), @@ -235,8 +229,7 @@ List get extraSettings => [ ); }, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '显示视频分段信息', leading: Transform.rotate( angle: pi / 2, @@ -245,77 +238,67 @@ List get extraSettings => [ setKey: SettingBoxKey.showViewPoints, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '视频页显示相关视频', leading: Icon(MdiIcons.motionPlayOutline), setKey: SettingBoxKey.showRelatedVideo, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示视频评论', leading: Icon(MdiIcons.commentTextOutline), setKey: SettingBoxKey.showVideoReply, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示番剧评论', leading: Icon(MdiIcons.commentTextOutline), setKey: SettingBoxKey.showBangumiReply, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '默认展开视频简介', leading: Icon(Icons.expand_more), setKey: SettingBoxKey.alwaysExpandIntroPanel, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '横屏自动展开视频简介', leading: Icon(Icons.expand_more), setKey: SettingBoxKey.expandIntroPanelH, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '横屏分P/合集列表显示在Tab栏', leading: Icon(Icons.format_list_numbered_rtl_sharp), setKey: SettingBoxKey.horizontalSeasonPanel, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '横屏播放页在侧栏打开UP主页', leading: Icon(Icons.account_circle_outlined), setKey: SettingBoxKey.horizontalMemberPage, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '横屏在侧栏打开图片预览', leading: const Icon(Icons.photo_outlined), setKey: SettingBoxKey.horizontalPreview, defaultVal: false, onChanged: (value) => CustomGridView.horizontalPreview = value, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '评论折叠行数', subtitle: '0行为不折叠', leading: const Icon(Icons.compress), - setKey: SettingBoxKey.replyLengthLimit, getTrailing: () => Text( '${ReplyItemGrpc.replyLengthLimit}行', style: Get.theme.textTheme.titleSmall, ), - onTap: (setState) { + onTap: (context, setState) { String replyLengthLimit = ReplyItemGrpc.replyLengthLimit.toString(); showDialog( - context: Get.context!, + context: context, builder: (context) { return AlertDialog( title: const Text('评论折叠行数'), @@ -358,20 +341,18 @@ List get extraSettings => [ ); }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '弹幕行高', subtitle: '默认1.6', - setKey: SettingBoxKey.danmakuLineHeight, leading: const Icon(CustomIcons.dm_settings), getTrailing: () => Text( Pref.danmakuLineHeight.toString(), style: Get.theme.textTheme.titleSmall, ), - onTap: (setState) { + onTap: (context, setState) { String danmakuLineHeight = Pref.danmakuLineHeight.toString(); showDialog( - context: Get.context!, + context: context, builder: (context) { return AlertDialog( title: const Text('弹幕行高'), @@ -418,38 +399,33 @@ List get extraSettings => [ ); }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示视频警告/争议信息', leading: Icon(Icons.warning_amber_rounded), setKey: SettingBoxKey.showArgueMsg, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '分P/合集:倒序播放从首集开始播放', subtitle: '开启则自动切换为倒序首集,否则保持当前集', leading: Icon(MdiIcons.sort), setKey: SettingBoxKey.reverseFromFirst, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '禁用 SSL 证书验证', subtitle: '谨慎开启,禁用容易受到中间人攻击', leading: Icon(Icons.security), needReboot: true, setKey: SettingBoxKey.badCertificateCallback, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示继续播放分P提示', leading: Icon(Icons.local_parking), setKey: SettingBoxKey.continuePlayingPart, defaultVal: true, ), getBanwordModel( - context: Get.context!, title: '评论关键词过滤', key: SettingBoxKey.banWordForReply, onChanged: (value) { @@ -458,7 +434,6 @@ List get extraSettings => [ }, ), getBanwordModel( - context: Get.context!, title: '动态关键词过滤', key: SettingBoxKey.banWordForDyn, onChanged: (value) { @@ -466,22 +441,19 @@ List get extraSettings => [ DynamicsDataModel.enableFilter = value.pattern.isNotEmpty; }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '使用外部浏览器打开链接', leading: Icon(Icons.open_in_browser), setKey: SettingBoxKey.openInBrowser, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '刷新滑动距离', leading: const Icon(Icons.refresh), - setKey: SettingBoxKey.refreshDragPercentage, getSubtitle: () => '当前滑动距离: ${Pref.refreshDragPercentage}x', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SlideDialog( title: '刷新滑动距离', @@ -502,15 +474,13 @@ List get extraSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '刷新指示器高度', leading: const Icon(Icons.height), - setKey: SettingBoxKey.refreshDisplacement, getSubtitle: () => '当前指示器高度: ${Pref.refreshDisplacement}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SlideDialog( title: '刷新指示器高度', @@ -529,23 +499,20 @@ List get extraSettings => [ } }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示会员彩色弹幕', leading: Icon(MdiIcons.gradientHorizontal), setKey: SettingBoxKey.showVipDanmaku, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '合并弹幕', subtitle: '合并一段时间内获取到的相同弹幕', leading: Icon(Icons.merge), setKey: SettingBoxKey.mergeDanmaku, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '显示热门推荐', subtitle: '热门页面显示每周必看等推荐内容入口', leading: const Icon(Icons.local_fire_department_outlined), @@ -558,10 +525,8 @@ List get extraSettings => [ }, ), if (kDebugMode || Platform.isAndroid) - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '音量均衡', - setKey: SettingBoxKey.audioNormalization, leading: const Icon(Icons.multitrack_audio), getSubtitle: () { final audioNormalization = AudioNormalization.getTitleFromConfig( @@ -578,15 +543,14 @@ List get extraSettings => [ }, onTap: audioNormalization, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '超分辨率', leading: const Icon(Icons.stay_current_landscape_outlined), getSubtitle: () => '当前:「${Pref.superResolutionType.title}」\n默认设置对番剧生效, 其他视频默认关闭\n超分辨率需要启用硬件解码, 若启用硬件解码后仍然不生效, 尝试切换硬件解码器为 auto-copy', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '超分辨率', @@ -606,46 +570,40 @@ List get extraSettings => [ } }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '提前初始化播放器', subtitle: '相对减少手动播放加载时间', leading: Icon(Icons.play_circle_outlined), setKey: SettingBoxKey.preInitPlayer, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '首页切换页面动画', leading: Icon(Icons.home_outlined), setKey: SettingBoxKey.mainTabBarView, defaultVal: false, needReboot: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '搜索建议', leading: Icon(Icons.search), setKey: SettingBoxKey.searchSuggestion, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '记录搜索历史', leading: Icon(Icons.history), setKey: SettingBoxKey.recordSearchHistory, defaultVal: true, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '展示头像/评论/动态装饰', leading: const Icon(MdiIcons.stickerCircleOutline), setKey: SettingBoxKey.showDynDecorate, defaultVal: true, onChanged: (value) => PendantAvatar.showDynDecorate = value, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '预览 Live Photo', subtitle: '开启则以视频形式预览 Live Photo,否则预览静态图片', leading: const Icon(Icons.image_outlined), @@ -653,23 +611,20 @@ List get extraSettings => [ defaultVal: true, onChanged: (value) => ImageModel.enableLivePhoto = value, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '滑动跳转预览视频缩略图', leading: Icon(Icons.preview_outlined), setKey: SettingBoxKey.showSeekPreview, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示高能进度条', subtitle: '高能进度条反应了在时域上,单位时间内弹幕发送量的变化趋势', leading: Icon(Icons.show_chart), setKey: SettingBoxKey.showDmChart, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '发评反诈', subtitle: '发送评论后检查评论是否可见', leading: Stack( @@ -683,8 +638,7 @@ List get extraSettings => [ setKey: SettingBoxKey.enableCommAntifraud, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '使用「哔哩发评反诈」检查评论', subtitle: '仅对Android生效', leading: Icon( @@ -694,8 +648,7 @@ List get extraSettings => [ setKey: SettingBoxKey.biliSendCommAntifraud, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '发布/转发动态反诈', subtitle: '发布/转发动态后检查动态是否可见', leading: Stack( @@ -709,8 +662,7 @@ List get extraSettings => [ setKey: SettingBoxKey.enableCreateDynAntifraud, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '屏蔽带货动态', leading: const Stack( clipBehavior: Clip.none, @@ -726,8 +678,7 @@ List get extraSettings => [ DynamicsDataModel.antiGoodsDyn = value; }, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '屏蔽带货评论', leading: const Stack( clipBehavior: Clip.none, @@ -743,8 +694,7 @@ List get extraSettings => [ ReplyGrpc.antiGoodsReply = value; }, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '侧滑关闭二级页面', leading: Transform.rotate( angle: pi * 1.5, @@ -756,37 +706,32 @@ List get extraSettings => [ CommonSlideMixin.slideDismissReplyPage = value; }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '启用双指缩小视频', leading: Icon(Icons.pinch), setKey: SettingBoxKey.enableShrinkVideoSize, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '动态/专栏详情页展示底部操作栏', leading: Icon(Icons.more_horiz), setKey: SettingBoxKey.showDynActionBar, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '启用拖拽字幕调整底部边距', leading: Icon(MdiIcons.dragVariant), setKey: SettingBoxKey.enableDragSubtitle, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '展示追番时间表', leading: Icon(MdiIcons.chartTimelineVariantShimmer), setKey: SettingBoxKey.showPgcTimeline, defaultVal: true, needReboot: true, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '静默下载图片', subtitle: '不显示下载 Loading 弹窗', leading: const Icon(Icons.download_for_offline_outlined), @@ -794,8 +739,7 @@ List get extraSettings => [ defaultVal: false, onChanged: (value) => ImageUtils.silentDownImg = value, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( setKey: SettingBoxKey.feedBackEnable, onChanged: (value) { enableFeedback = value; @@ -805,24 +749,21 @@ List get extraSettings => [ title: '震动反馈', subtitle: '请确定手机设置中已开启震动反馈', ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '大家都在搜', subtitle: '是否展示「大家都在搜」', leading: Icon(Icons.data_thresholding_outlined), setKey: SettingBoxKey.enableHotKey, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '搜索发现', subtitle: '是否展示「搜索发现」', leading: Icon(Icons.search_outlined), setKey: SettingBoxKey.enableSearchRcmd, defaultVal: true, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '搜索默认词', subtitle: '是否展示搜索框默认词', leading: const Icon(Icons.whatshot_outlined), @@ -839,13 +780,12 @@ List get extraSettings => [ } catch (_) {} }, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '快速收藏', subtitle: '点击设置默认收藏夹\n点按收藏至默认,长按选择文件夹', leading: const Icon(Icons.bookmark_add_outlined), setKey: SettingBoxKey.enableQuickFav, - onTap: () async { + onTap: (context) async { if (Accounts.main.isLogin) { final res = await FavHttp.allFavFolders(Accounts.main.mid); if (res.isSuccess) { @@ -888,8 +828,7 @@ List get extraSettings => [ }, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '评论区搜索关键词', subtitle: '展示评论区搜索关键词', leading: const Icon(Icons.search_outlined), @@ -899,46 +838,42 @@ List get extraSettings => [ ReplyItemGrpc.enableWordRe = value; }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '启用AI总结', subtitle: '视频详情页开启AI总结', leading: Icon(Icons.engineering_outlined), setKey: SettingBoxKey.enableAi, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '消息页禁用"收到的赞"功能', subtitle: '禁止打开入口,降低网络社交依赖', leading: Icon(Icons.beach_access_outlined), setKey: SettingBoxKey.disableLikeMsg, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '默认展示评论区', subtitle: '在视频详情页默认切换至评论区页(仅Tab型布局)', leading: Icon(Icons.mode_comment_outlined), setKey: SettingBoxKey.defaultShowComment, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '启用HTTP/2', leading: Icon(Icons.swap_horizontal_circle_outlined), setKey: SettingBoxKey.enableHttp2, defaultVal: false, needReboot: true, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '连接重试次数', subtitle: '为0时禁用', leading: const Icon(Icons.repeat), - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, + builder: (context) { return SlideDialog( title: '连接重试次数', @@ -957,14 +892,14 @@ List get extraSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '连接重试间隔', subtitle: '实际间隔 = 间隔 * 第x次重试', leading: const Icon(Icons.more_time_outlined), - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, + builder: (context) { return SlideDialog( title: '连接重试间隔', @@ -984,16 +919,15 @@ List get extraSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '评论展示', - setKey: SettingBoxKey.replySortType, leading: const Icon(Icons.whatshot_outlined), getSubtitle: () => '当前优先展示「${ReplySortType.values[Pref.replySortType].title}」', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, + builder: (context) { return SelectDialog( title: '评论展示', @@ -1010,16 +944,15 @@ List get extraSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '动态展示', - setKey: SettingBoxKey.defaultDynamicType, leading: const Icon(Icons.dynamic_feed_rounded), getSubtitle: () => '当前优先展示「${DynamicsTabType.values[Pref.defaultDynamicType].label}」', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, + builder: (context) { return SelectDialog( title: '动态展示', @@ -1037,15 +970,14 @@ List get extraSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '用户页默认展示TAB', - setKey: SettingBoxKey.memberTab, leading: const Icon(Icons.tab), getSubtitle: () => '当前优先展示「${Pref.memberTab.title}」', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, + builder: (context) { return SelectDialog( title: '用户页默认展示TAB', @@ -1060,22 +992,20 @@ List get extraSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '显示UP主页小店TAB', leading: const Icon(Icons.shop_outlined), setKey: SettingBoxKey.showMemberShop, defaultVal: false, onChanged: (value) => MemberTabType.showMemberShop = value, ), - SettingsModel( - settingsType: SettingsType.sw1tch, - onTap: () { + SwitchModel( + onTap: (context) { String systemProxyHost = Pref.systemProxyHost; String systemProxyPort = Pref.systemProxyPort; showDialog( - context: Get.context!, + context: context, builder: (context) { return AlertDialog( title: const Text('设置代理'), @@ -1144,24 +1074,22 @@ List get extraSettings => [ subtitle: '设置代理 host:port', setKey: SettingBoxKey.enableSystemProxy, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '自动清除缓存', subtitle: '每次启动时清除缓存', leading: Icon(Icons.auto_delete_outlined), setKey: SettingBoxKey.autoClearCache, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '最大缓存大小', getSubtitle: () { final num = Pref.maxCacheSize; return '当前最大缓存大小: 「${num == 0 ? '无限' : CacheManager.formatSize(Pref.maxCacheSize)}」'; }, - onTap: (setState) { + onTap: (context, setState) { showDialog( - context: Get.context!, + context: context, builder: (context) { String valueStr = ''; return AlertDialog( @@ -1204,8 +1132,7 @@ List get extraSettings => [ }, leading: const Icon(Icons.delete_outlined), ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '检查更新', subtitle: '每次启动时检查是否需要更新', leading: const Icon(Icons.system_update_alt), @@ -1220,6 +1147,7 @@ List get extraSettings => [ ]; Future audioNormalization( + BuildContext context, VoidCallback setState, { bool fallback = false, }) async { @@ -1227,7 +1155,7 @@ Future audioNormalization( ? SettingBoxKey.fallbackNormalization : SettingBoxKey.audioNormalization; final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { String audioNormalization = fallback ? Pref.fallbackNormalization @@ -1260,11 +1188,12 @@ Future audioNormalization( ); }, ); - if (result != null) { + if (result != null && context.mounted) { if (result == '3') { String param = ''; await showDialog( - context: Get.context!, + context: context, + builder: (context) { return AlertDialog( title: const Text('自定义参数'), @@ -1290,12 +1219,12 @@ Future audioNormalization( ), ), TextButton( - onPressed: () async { + onPressed: () { Get.back(); - await GStorage.setting.put(key, param); + GStorage.setting.put(key, param); if (!fallback && PlPlayerController.loudnormRegExp.hasMatch(param)) { - audioNormalization(setState, fallback: true); + audioNormalization(context, setState, fallback: true); } setState(); }, @@ -1306,9 +1235,9 @@ Future audioNormalization( }, ); } else { - await GStorage.setting.put(key, result); + GStorage.setting.put(key, result); if (result == '2') { - audioNormalization(setState, fallback: true); + audioNormalization(context, setState, fallback: true); } setState(); } diff --git a/lib/pages/setting/models/model.dart b/lib/pages/setting/models/model.dart index f29c89271..9e24eceaa 100644 --- a/lib/pages/setting/models/model.dart +++ b/lib/pages/setting/models/model.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/models/common/settings_type.dart'; import 'package:PiliPlus/pages/setting/widgets/normal_item.dart'; import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart'; import 'package:PiliPlus/pages/setting/widgets/switch_item.dart'; @@ -9,80 +8,117 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @immutable -class SettingsModel { - final SettingsType settingsType; - final String? title; - final StringGetter? getTitle; +sealed class SettingsModel { final String? subtitle; - final StringGetter? getSubtitle; - final String? setKey; - final bool defaultVal; - final ValueChanged? onChanged; - final bool needReboot; final Widget? leading; - final Widget Function()? getTrailing; - final Function? onTap; final EdgeInsetsGeometry? contentPadding; final TextStyle? titleStyle; + String? get title; + Widget get widget; + String get effectiveTitle; + String? get effectiveSubtitle; + const SettingsModel({ - required this.settingsType, + this.subtitle, + this.leading, + this.contentPadding, + this.titleStyle, + }); +} + +class NormalModel extends SettingsModel { + @override + final String? title; + final StringGetter? getTitle; + final StringGetter? getSubtitle; + final Widget Function()? getTrailing; + final void Function(BuildContext context, void Function() setState)? onTap; + + const NormalModel({ + super.subtitle, + super.leading, + super.contentPadding, + super.titleStyle, this.title, this.getTitle, - this.subtitle, this.getSubtitle, - this.setKey, + this.getTrailing, + this.onTap, + }) : assert(title != null || getTitle != null); + + @override + String get effectiveTitle => title ?? getTitle!(); + @override + String? get effectiveSubtitle => subtitle ?? getSubtitle?.call(); + + @override + Widget get widget => NormalItem( + title: title, + getTitle: getTitle, + subtitle: subtitle, + getSubtitle: getSubtitle, + leading: leading, + getTrailing: getTrailing, + onTap: onTap, + contentPadding: contentPadding, + titleStyle: titleStyle, + ); +} + +class SwitchModel extends SettingsModel { + @override + final String title; + final String setKey; + final bool defaultVal; + final ValueChanged? onChanged; + final bool needReboot; + final void Function(BuildContext context)? onTap; + + const SwitchModel({ + super.subtitle, + super.leading, + super.contentPadding, + super.titleStyle, + required this.title, + required this.setKey, this.defaultVal = false, this.onChanged, this.needReboot = false, - this.leading, - this.getTrailing, this.onTap, - this.contentPadding, - this.titleStyle, - }) : assert(title != null || getTitle != null); + }); - Widget get widget => switch (settingsType) { - SettingsType.normal => NormalItem( - title: title, - getTitle: getTitle, - subtitle: subtitle, - getSubtitle: getSubtitle, - setKey: setKey, - leading: leading, - getTrailing: getTrailing, - onTap: onTap, - contentPadding: contentPadding, - titleStyle: titleStyle, - ), - SettingsType.sw1tch => SetSwitchItem( - title: title, - subtitle: subtitle, - setKey: setKey!, - defaultVal: defaultVal, - onChanged: onChanged, - needReboot: needReboot, - leading: leading, - onTap: onTap, - contentPadding: contentPadding, - titleStyle: titleStyle, - ), - }; + @override + String get effectiveTitle => title; + @override + String? get effectiveSubtitle => subtitle; + + @override + Widget get widget => SetSwitchItem( + title: title, + subtitle: subtitle, + setKey: setKey, + defaultVal: defaultVal, + onChanged: onChanged, + needReboot: needReboot, + leading: leading, + onTap: onTap, + contentPadding: contentPadding, + titleStyle: titleStyle, + ); } SettingsModel getBanwordModel({ - required BuildContext context, required String title, required String key, required ValueChanged onChanged, }) { String banWord = GStorage.setting.get(key, defaultValue: ''); - return SettingsModel( - settingsType: SettingsType.normal, + return NormalModel( leading: const Icon(Icons.filter_alt_outlined), title: title, getSubtitle: () => banWord.isEmpty ? "点击添加" : banWord, - onTap: (setState) { + onTap: (context, setState) { showDialog( context: context, builder: (context) { @@ -132,7 +168,6 @@ SettingsModel getBanwordModel({ } SettingsModel getVideoFilterSelectModel({ - required BuildContext context, required String title, String? subtitle, String? suffix, @@ -144,8 +179,7 @@ SettingsModel getVideoFilterSelectModel({ }) { assert(!isFilter || onChanged != null); int value = GStorage.setting.get(key, defaultValue: defaultValue); - return SettingsModel( - settingsType: SettingsType.normal, + return NormalModel( title: '$title${isFilter ? '过滤' : ''}', leading: const Icon(Icons.timelapse_outlined), subtitle: subtitle, @@ -154,7 +188,7 @@ SettingsModel getVideoFilterSelectModel({ ? '过滤掉$title小于「$value${suffix ?? ""}」的视频' : '当前$title:「$value${suffix ?? ""}」' : null, - onTap: (setState) async { + onTap: (context, setState) async { var result = await showDialog( context: context, builder: (context) { diff --git a/lib/pages/setting/models/play_settings.dart b/lib/pages/setting/models/play_settings.dart index eacc823a4..da415a2b0 100644 --- a/lib/pages/setting/models/play_settings.dart +++ b/lib/pages/setting/models/play_settings.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; -import 'package:PiliPlus/models/common/settings_type.dart'; import 'package:PiliPlus/models/common/video/subtitle_pref_type.dart'; import 'package:PiliPlus/pages/main/controller.dart'; import 'package:PiliPlus/pages/setting/models/model.dart'; @@ -21,8 +20,7 @@ import 'package:get/get.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; List get playSettings => [ - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '弹幕开关', subtitle: '是否展示弹幕', leading: Icon(CustomIcons.dm_settings), @@ -30,82 +28,71 @@ List get playSettings => [ defaultVal: true, ), if (Utils.isMobile) - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '启用点击弹幕', subtitle: '点击弹幕悬停,支持点赞、复制、举报操作', leading: Icon(Icons.touch_app_outlined), setKey: SettingBoxKey.enableTapDm, defaultVal: true, ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) => Get.toNamed('/playSpeedSet'), + NormalModel( + onTap: (context, setState) => Get.toNamed('/playSpeedSet'), leading: const Icon(Icons.speed_outlined), title: '倍速设置', subtitle: '设置视频播放速度', ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '自动播放', subtitle: '进入详情页自动播放', leading: Icon(Icons.motion_photos_auto_outlined), setKey: SettingBoxKey.autoPlayEnable, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '全屏显示锁定按钮', leading: Icon(Icons.lock_outline), setKey: SettingBoxKey.showFsLockBtn, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '全屏显示截图按钮', leading: Icon(Icons.photo_camera_outlined), setKey: SettingBoxKey.showFsScreenshotBtn, defaultVal: true, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '全屏显示电池电量', leading: const Icon(Icons.battery_3_bar), setKey: SettingBoxKey.showBatteryLevel, defaultVal: Utils.isMobile, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '双击快退/快进', subtitle: '左侧双击快退/右侧双击快进,关闭则双击均为暂停/播放', leading: Icon(Icons.touch_app_outlined), setKey: SettingBoxKey.enableQuickDouble, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '左右侧滑动调节亮度/音量', leading: Icon(MdiIcons.tuneVerticalVariant), setKey: SettingBoxKey.enableSlideVolumeBrightness, defaultVal: true, ), if (Platform.isAndroid) - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '调节系统亮度', leading: Icon(Icons.brightness_6_outlined), setKey: SettingBoxKey.setSystemBrightness, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '中间滑动进入/退出全屏', leading: Icon(MdiIcons.panVertical), setKey: SettingBoxKey.enableSlideFS, defaultVal: true, ), getVideoFilterSelectModel( - context: Get.context!, title: '双击快进/快退时长', suffix: 's', key: SettingBoxKey.fastForBackwardDuration, @@ -113,15 +100,13 @@ List get playSettings => [ defaultValue: 10, isFilter: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '滑动快进/快退使用相对时长', leading: Icon(Icons.swap_horiz_outlined), setKey: SettingBoxKey.useRelativeSlide, defaultVal: false, ), getVideoFilterSelectModel( - context: Get.context!, title: '滑动快进/快退时长', subtitle: '从播放器一端滑到另一端的快进/快退时长', suffix: Pref.useRelativeSlide ? '%' : 's', @@ -130,15 +115,14 @@ List get playSettings => [ defaultValue: 90, isFilter: false, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '自动启用字幕', leading: const Icon(Icons.closed_caption_outlined), getSubtitle: () => '当前选择偏好:${SubtitlePrefType.values[Pref.subtitlePreferenceV2].desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '字幕选择偏好', @@ -156,8 +140,7 @@ List get playSettings => [ }, ), if (Utils.isDesktop) - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '最小化时暂停/还原时播放', leading: const Icon(Icons.pause_circle_outline), setKey: SettingBoxKey.pauseOnMinimize, @@ -168,54 +151,47 @@ List get playSettings => [ } catch (_) {} }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '启用键盘控制', leading: Icon(Icons.keyboard_alt_outlined), setKey: SettingBoxKey.keyboardControl, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示 SuperChat (醒目留言)', leading: Icon(Icons.live_tv), setKey: SettingBoxKey.showSuperChat, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '竖屏扩大展示', subtitle: '小屏竖屏视频宽高比由16:9扩大至1:1(不支持收起);横屏适配时,扩大至9:16', leading: Icon(Icons.expand_outlined), setKey: SettingBoxKey.enableVerticalExpand, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '自动全屏', subtitle: '视频开始播放时进入全屏', leading: Icon(Icons.fullscreen_outlined), setKey: SettingBoxKey.enableAutoEnter, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '自动退出全屏', subtitle: '视频结束播放时退出全屏', leading: Icon(Icons.fullscreen_exit_outlined), setKey: SettingBoxKey.enableAutoExit, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '延长播放控件显示时间', subtitle: '开启后延长至30秒,便于屏幕阅读器滑动切换控件焦点', leading: Icon(Icons.timer_outlined), setKey: SettingBoxKey.enableLongShowControl, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '全向旋转', subtitle: '小屏可受重力转为临时全屏,若系统锁定旋转仍触发请关闭,关闭会影响横屏适配', leading: const Icon(Icons.screen_rotation_alt_outlined), @@ -223,8 +199,7 @@ List get playSettings => [ defaultVal: true, onChanged: (value) => allowRotateScreen = value, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '后台播放', subtitle: '进入后台时继续播放', leading: Icon(Icons.motion_photos_pause_outlined), @@ -232,8 +207,7 @@ List get playSettings => [ defaultVal: false, ), if (Platform.isAndroid) ...[ - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '后台画中画', subtitle: '进入后台时以小窗形式(PiP)播放', leading: const Icon(Icons.picture_in_picture_outlined), @@ -245,8 +219,7 @@ List get playSettings => [ } }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '画中画不加载弹幕', subtitle: '当弹幕开关开启时,小窗屏蔽弹幕以获得较好的体验', leading: Icon(CustomIcons.dm_off), @@ -254,38 +227,34 @@ List get playSettings => [ defaultVal: false, ), ], - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '全屏手势反向', subtitle: '默认播放器中部向上滑动进入全屏,向下退出\n开启后向下全屏,向上退出', leading: Icon(Icons.swap_vert), setKey: SettingBoxKey.fullScreenGestureReverse, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '全屏展示点赞/投币/收藏等操作按钮', leading: Icon(MdiIcons.dotsHorizontalCircleOutline), setKey: SettingBoxKey.showFSActionItem, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '观看人数', subtitle: '展示同时在看人数', leading: Icon(Icons.people_outlined), setKey: SettingBoxKey.enableOnlineTotal, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '默认全屏方向', leading: const Icon(Icons.open_with_outlined), getSubtitle: () => '当前全屏方向:${FullScreenMode.values[Pref.fullScreenMode].desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '默认全屏方向', @@ -302,15 +271,14 @@ List get playSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '底部进度条展示', leading: const Icon(Icons.border_bottom_outlined), getSubtitle: () => '当前展示方式:${BtmProgressBehavior.values[Pref.btmProgressBehavior].desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '底部进度条展示', @@ -328,8 +296,7 @@ List get playSettings => [ }, ), if (Utils.isMobile) - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '后台音频服务', subtitle: '避免画中画没有播放暂停功能', leading: const Icon(Icons.volume_up_outlined), @@ -339,8 +306,7 @@ List get playSettings => [ videoPlayerServiceHandler!.enableBackgroundPlay = value; }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '播放器设置仅对当前生效', subtitle: '弹幕、字幕及部分设置中没有的设置除外', leading: Icon(Icons.video_settings_outlined), diff --git a/lib/pages/setting/models/privacy_settings.dart b/lib/pages/setting/models/privacy_settings.dart index 6702aac2e..387904bbd 100644 --- a/lib/pages/setting/models/privacy_settings.dart +++ b/lib/pages/setting/models/privacy_settings.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/models/common/account_type.dart'; -import 'package:PiliPlus/models/common/settings_type.dart'; import 'package:PiliPlus/pages/mine/controller.dart'; import 'package:PiliPlus/pages/setting/models/model.dart'; import 'package:PiliPlus/utils/accounts.dart'; @@ -9,9 +8,8 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; List get privacySettings => [ - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) { + NormalModel( + onTap: (context, setState) { if (!Accounts.main.isLogin) { SmartDialog.showToast('登录后查看'); return; @@ -22,9 +20,8 @@ List get privacySettings => [ subtitle: '已拉黑用户', leading: const Icon(Icons.block), ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) { + NormalModel( + onTap: (context, setState) { MineController.onChangeAnonymity(); setState(); }, @@ -34,11 +31,10 @@ List get privacySettings => [ ? '已进入无痕模式,搜索、观看视频/直播不携带Cookie与CSRF,其余操作不受影响' : '未开启无痕模式,将使用账户信息提供完整服务', ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) { + NormalModel( + onTap: (context, setState) { showDialog( - context: Get.context!, + context: context, builder: (context) { return AlertDialog( title: const Text('账号模式详情'), diff --git a/lib/pages/setting/models/recommend_settings.dart b/lib/pages/setting/models/recommend_settings.dart index 16ed51bdd..4a86e6510 100644 --- a/lib/pages/setting/models/recommend_settings.dart +++ b/lib/pages/setting/models/recommend_settings.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/http/video.dart'; -import 'package:PiliPlus/models/common/settings_type.dart'; import 'package:PiliPlus/pages/rcmd/controller.dart'; import 'package:PiliPlus/pages/setting/models/model.dart'; import 'package:PiliPlus/utils/recommend_filter.dart'; @@ -9,8 +8,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; List get recommendSettings => [ - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '首页使用app端推荐', subtitle: '若web端推荐不太符合预期,可尝试切换至app端推荐', leading: Icon(Icons.model_training_outlined), @@ -18,8 +16,7 @@ List get recommendSettings => [ defaultVal: true, needReboot: true, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '保留首页推荐刷新', subtitle: '下拉刷新时保留上次内容', leading: const Icon(Icons.refresh), @@ -35,8 +32,7 @@ List get recommendSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '显示上次看到位置提示', subtitle: '保留上次推荐时,在上次刷新位置显示提示', leading: const Icon(Icons.tips_and_updates_outlined), @@ -53,7 +49,6 @@ List get recommendSettings => [ }, ), getVideoFilterSelectModel( - context: Get.context!, title: '点赞率', suffix: '%', key: SettingBoxKey.minLikeRatioForRecommend, @@ -61,7 +56,6 @@ List get recommendSettings => [ onChanged: (value) => RecommendFilter.minLikeRatioForRecommend = value, ), getBanwordModel( - context: Get.context!, title: '标题关键词过滤', key: SettingBoxKey.banWordForRecommend, onChanged: (value) { @@ -70,7 +64,6 @@ List get recommendSettings => [ }, ), getBanwordModel( - context: Get.context!, title: 'App推荐/热门/排行榜: 视频分区关键词过滤', key: SettingBoxKey.banWordForZone, onChanged: (value) { @@ -79,7 +72,6 @@ List get recommendSettings => [ }, ), getVideoFilterSelectModel( - context: Get.context!, title: '视频时长', suffix: 's', key: SettingBoxKey.minDurationForRcmd, @@ -87,14 +79,12 @@ List get recommendSettings => [ onChanged: (value) => RecommendFilter.minDurationForRcmd = value, ), getVideoFilterSelectModel( - context: Get.context!, title: '播放量', key: SettingBoxKey.minPlayForRcmd, values: [0, 50, 100, 500, 1000], onChanged: (value) => RecommendFilter.minPlayForRcmd = value, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '已关注UP豁免推荐过滤', subtitle: '推荐中已关注用户发布的内容不会被过滤', leading: const Icon(Icons.favorite_border_outlined), @@ -104,8 +94,7 @@ List get recommendSettings => [ RecommendFilter.exemptFilterForFollowed = value; }, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '过滤器也应用于相关视频', subtitle: '视频详情页的相关视频也进行过滤¹', leading: const Icon(Icons.explore_outlined), diff --git a/lib/pages/setting/models/style_settings.dart b/lib/pages/setting/models/style_settings.dart index b892505fa..a2758a2a9 100644 --- a/lib/pages/setting/models/style_settings.dart +++ b/lib/pages/setting/models/style_settings.dart @@ -11,7 +11,6 @@ import 'package:PiliPlus/models/common/dynamic/up_panel_position.dart'; import 'package:PiliPlus/models/common/home_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/settings_type.dart'; import 'package:PiliPlus/models/common/theme/theme_type.dart'; import 'package:PiliPlus/pages/main/controller.dart'; import 'package:PiliPlus/pages/mine/controller.dart'; @@ -37,16 +36,14 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart List get styleSettings => [ if (Utils.isDesktop) ...[ - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示窗口标题栏', leading: Icon(Icons.window), setKey: SettingBoxKey.showWindowTitleBar, defaultVal: true, needReboot: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '显示托盘图标', leading: Icon(Icons.donut_large_rounded), setKey: SettingBoxKey.showTrayIcon, @@ -54,8 +51,7 @@ List get styleSettings => [ needReboot: true, ), ], - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '横屏适配', subtitle: '启用横屏布局与逻辑,平板、折叠屏等可开启;建议全屏方向设为【不改变当前方向】', leading: const Icon(Icons.phonelink_outlined), @@ -69,8 +65,7 @@ List get styleSettings => [ } }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '改用侧边栏', subtitle: '开启后底栏与顶栏被替换,且相关设置失效', leading: Icon(Icons.chrome_reader_mode_outlined), @@ -78,15 +73,14 @@ List get styleSettings => [ defaultVal: false, needReboot: true, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: 'App字体字重', subtitle: '点击设置', setKey: SettingBoxKey.appFontWeight, defaultVal: false, - onTap: () { + onTap: (context) { showDialog( - context: Get.context!, + context: context, builder: (context) { return SlideDialog( title: 'App字体字重', @@ -111,14 +105,13 @@ List get styleSettings => [ Get.forceAppUpdate(); }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '页面过渡动画', leading: const Icon(Icons.animation), getSubtitle: () => '当前:${Pref.pageTransition.name}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '页面过渡动画', @@ -134,16 +127,14 @@ List get styleSettings => [ } }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '优化平板导航栏', leading: Icon(MdiIcons.soundbar), setKey: SettingBoxKey.optTabletNav, defaultVal: true, needReboot: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: 'MD3样式底栏', subtitle: 'Material You设计规范底栏,关闭可变窄', leading: Icon(Icons.design_services_outlined), @@ -151,11 +142,10 @@ List get styleSettings => [ defaultVal: true, needReboot: true, ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) async { + NormalModel( + onTap: (context, setState) async { final result = await showDialog<(double, double)>( - context: Get.context!, + context: context, builder: (context) { return DualSlideDialog( title: '列表最大列宽度(默认240dp)', @@ -182,10 +172,9 @@ List get styleSettings => [ leading: const Icon(Icons.calendar_view_week_outlined), title: '列表宽度(dp)限制', getSubtitle: () => - '当前: 主页${Pref.recommendCardWidth.toInt()}dp 其他${Pref.smallCardWidth.toInt()}dp,屏幕宽度:${Get.mediaQuery.size.width.toPrecision(2)}dp。宽度越小列数越多。', + '当前: 主页${Pref.recommendCardWidth.toInt()}dp 其他${Pref.smallCardWidth.toInt()}dp,屏幕宽度:${MediaQuery.widthOf(Get.context!).toPrecision(2)}dp。宽度越小列数越多。', ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '视频播放页使用深色主题', leading: const Icon(Icons.dark_mode_outlined), setKey: SettingBoxKey.darkVideoPage, @@ -196,8 +185,7 @@ List get styleSettings => [ } }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '动态页启用瀑布流', subtitle: '关闭会显示为单列', leading: Icon(Icons.view_array_outlined), @@ -205,14 +193,13 @@ List get styleSettings => [ defaultVal: true, needReboot: true, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '动态页UP主显示位置', leading: const Icon(Icons.person_outlined), getSubtitle: () => '当前:${Pref.upPanelPosition.label}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '动态页UP主显示位置', @@ -228,25 +215,22 @@ List get styleSettings => [ } }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '动态页显示所有已关注UP主', leading: Icon(Icons.people_alt_outlined), setKey: SettingBoxKey.dynamicsShowAllFollowedUp, defaultVal: false, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '动态页展开正在直播UP列表', leading: Icon(Icons.live_tv), setKey: SettingBoxKey.expandDynLivePanel, defaultVal: false, ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) async { + NormalModel( + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '动态未读标记', @@ -273,11 +257,10 @@ List get styleSettings => [ leading: const Icon(Icons.motion_photos_on_outlined), getSubtitle: () => '当前标记样式:${Pref.dynamicBadgeType.desc}', ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) async { + NormalModel( + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '消息未读标记', @@ -303,11 +286,10 @@ List get styleSettings => [ leading: const Icon(MdiIcons.bellBadgeOutline), getSubtitle: () => '当前标记样式:${Pref.msgBadgeMode.desc}', ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) async { + NormalModel( + onTap: (context, setState) async { final result = await showDialog>( - context: Get.context!, + context: context, builder: (context) { return MultiSelectDialog( title: '消息未读类型', @@ -335,8 +317,7 @@ List get styleSettings => [ getSubtitle: () => '当前消息类型:${Pref.msgUnReadTypeV2.map((item) => item.title).join('、')}', ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '首页顶栏收起', subtitle: '首页列表滑动时,收起顶栏', leading: Icon(Icons.vertical_align_top_outlined), @@ -344,8 +325,7 @@ List get styleSettings => [ defaultVal: true, needReboot: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '首页底栏收起', subtitle: '首页列表滑动时,收起底栏', leading: Icon(Icons.vertical_align_bottom_outlined), @@ -353,18 +333,17 @@ List get styleSettings => [ defaultVal: true, needReboot: true, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '顶/底栏滚动阈值', subtitle: '滚动多少像素后收起/展开顶底栏,默认50像素', leading: const Icon(Icons.swipe_vertical), defaultVal: false, setKey: SettingBoxKey.enableScrollThreshold, needReboot: true, - onTap: () { + onTap: (context) { String scrollThreshold = Pref.scrollThreshold.toString(); showDialog( - context: Get.context!, + context: context, builder: (context) { return AlertDialog( title: const Text('滚动阈值'), @@ -412,11 +391,10 @@ List get styleSettings => [ ); }, ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) { + NormalModel( + onTap: (context, setState) { _showQualityDialog( - context: Get.context!, + context: context, title: '图片质量', initValue: Pref.picQuality, callback: (picQuality) async { @@ -438,11 +416,10 @@ List get styleSettings => [ ), ), // preview quality - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) { + NormalModel( + onTap: (context, setState) { _showQualityDialog( - context: Get.context!, + context: context, title: '查看大图质量', initValue: Pref.previewQ, callback: (picQuality) async { @@ -462,12 +439,11 @@ List get styleSettings => [ ), ), ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) { + NormalModel( + onTap: (context, setState) { final reduceLuxColor = Pref.reduceLuxColor; showDialog( - context: Get.context!, + context: context, builder: (context) => AlertDialog( clipBehavior: Clip.hardEdge, contentPadding: const EdgeInsets.symmetric(vertical: 16), @@ -523,11 +499,10 @@ List get styleSettings => [ ), ), ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) async { + NormalModel( + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SlideDialog( title: 'Toast不透明度', @@ -556,11 +531,10 @@ List get styleSettings => [ ), ), ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) async { + NormalModel( + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '主题模式', @@ -583,8 +557,7 @@ List get styleSettings => [ title: '主题模式', getSubtitle: () => '当前模式:${Pref.themeType.desc}', ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( leading: const Icon(Icons.invert_colors), title: '纯黑主题', setKey: SettingBoxKey.isPureBlackTheme, @@ -595,19 +568,17 @@ List get styleSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) => Get.toNamed('/colorSetting'), + NormalModel( + onTap: (context, setState) => Get.toNamed('/colorSetting'), leading: const Icon(Icons.color_lens_outlined), title: '应用主题', getSubtitle: () => '当前主题:${Get.put(ColorSelectController()).dynamicColor.value ? '动态取色' : '指定颜色'}', ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) async { + NormalModel( + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '首页启动页', @@ -629,16 +600,15 @@ List get styleSettings => [ getSubtitle: () => '当前启动页:${NavigationBarType.values.firstWhere((e) => e.index == Pref.defaultHomePage).label}', ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '滑动动画弹簧参数', leading: const Icon(Icons.chrome_reader_mode_outlined), - onTap: (setState) { + onTap: (context, setState) { List springDescription = CustomSpringDescription.springDescription .map((i) => i.toString()) .toList(); showDialog( - context: Get.context!, + context: context, builder: (context) { return AlertDialog( title: const Text('弹簧参数'), @@ -697,9 +667,8 @@ List get styleSettings => [ ); }, ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) async { + NormalModel( + onTap: (context, setState) async { var result = await Get.toNamed('/fontSizeSetting'); if (result != null) { Get.put(ColorSelectController()).currentTextScale.value = result; @@ -712,9 +681,8 @@ List get styleSettings => [ ? '默认' : Get.put(ColorSelectController()).currentTextScale.value.toString(), ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) => Get.toNamed( + NormalModel( + onTap: (context, setState) => Get.toNamed( '/barSetting', arguments: { 'key': SettingBoxKey.tabBarSort, @@ -726,9 +694,8 @@ List get styleSettings => [ subtitle: '删除或调换首页标签页', leading: const Icon(Icons.toc_outlined), ), - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) => Get.toNamed( + NormalModel( + onTap: (context, setState) => Get.toNamed( '/barSetting', arguments: { 'key': SettingBoxKey.navBarSort, @@ -740,8 +707,7 @@ List get styleSettings => [ subtitle: '删除或调换Navbar', leading: const Icon(Icons.toc_outlined), ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '返回时直接退出', subtitle: '开启后在主页任意tab按返回键都直接退出,关闭则先回到Navbar的第一个tab', leading: const Icon(Icons.exit_to_app_outlined), @@ -752,9 +718,8 @@ List get styleSettings => [ }, ), if (Platform.isAndroid) - SettingsModel( - settingsType: SettingsType.normal, - onTap: (setState) => Get.toNamed('/displayModeSetting'), + NormalModel( + onTap: (context, setState) => Get.toNamed('/displayModeSetting'), title: '屏幕帧率', leading: const Icon(Icons.autofps_select_outlined), ), diff --git a/lib/pages/setting/models/video_settings.dart b/lib/pages/setting/models/video_settings.dart index 5b60c9855..8c228b55d 100644 --- a/lib/pages/setting/models/video_settings.dart +++ b/lib/pages/setting/models/video_settings.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:PiliPlus/models/common/settings_type.dart'; import 'package:PiliPlus/models/common/video/audio_quality.dart'; import 'package:PiliPlus/models/common/video/cdn_type.dart'; import 'package:PiliPlus/models/common/video/live_quality.dart'; @@ -19,45 +18,43 @@ import 'package:get/get.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; List get videoSettings => [ - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '开启硬解', subtitle: '以较低功耗播放视频,若异常卡死请关闭', leading: Icon(Icons.flash_on_outlined), setKey: SettingBoxKey.enableHA, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '免登录1080P', subtitle: '免登录查看1080P视频', leading: Icon(Icons.hd_outlined), setKey: SettingBoxKey.p1080, defaultVal: true, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: 'B站定向流量支持', subtitle: '若套餐含B站定向流量,则会自动使用。可查阅运营商的流量记录确认。', leading: const Icon(Icons.perm_data_setting_outlined), - getTrailing: () => Transform.scale( - alignment: Alignment.centerRight, - scale: 0.8, - child: Switch( - value: true, - onChanged: (_) {}, + getTrailing: () => IgnorePointer( + child: Transform.scale( + alignment: Alignment.centerRight, + scale: 0.8, + child: Switch( + value: true, + onChanged: (_) {}, + ), ), ), ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: 'CDN 设置', leading: const Icon(MdiIcons.cloudPlusOutline), getSubtitle: () => '当前使用:${VideoUtils.cdnService.desc},部分 CDN 可能失效,如无法播放请尝试切换', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return const CdnSelectDialog(); }, @@ -69,14 +66,13 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '直播 CDN 设置', leading: const Icon(MdiIcons.cloudPlusOutline), getSubtitle: () => '当前使用:${Pref.liveCdnUrl ?? "默认"}', - onTap: (setState) async { + onTap: (context, setState) async { String? result = await showDialog( - context: Get.context!, + context: context, builder: (context) { String host = Pref.liveCdnUrl ?? ''; return AlertDialog( @@ -119,16 +115,14 @@ List get videoSettings => [ } }, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: 'CDN 测速', leading: Icon(Icons.speed), subtitle: '测速通过模拟加载视频实现,注意流量消耗,结果仅供参考', setKey: SettingBoxKey.cdnSpeedTest, defaultVal: true, ), - SettingsModel( - settingsType: SettingsType.sw1tch, + SwitchModel( title: '音频不跟随 CDN 设置', subtitle: '直接采用备用 URL,可解决部分视频无声', leading: const Icon(MdiIcons.musicNotePlus), @@ -138,15 +132,14 @@ List get videoSettings => [ VideoUtils.disableAudioCDN = value; }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '默认画质', leading: const Icon(Icons.video_settings_outlined), getSubtitle: () => '当前画质:${VideoQuality.fromCode(Pref.defaultVideoQa).desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '默认画质', @@ -161,15 +154,14 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '蜂窝网络画质', leading: const Icon(Icons.video_settings_outlined), getSubtitle: () => '当前画质:${VideoQuality.fromCode(Pref.defaultVideoQaCellular).desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '蜂窝网络画质', @@ -187,15 +179,14 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '默认音质', leading: const Icon(Icons.music_video_outlined), getSubtitle: () => '当前音质:${AudioQuality.fromCode(Pref.defaultAudioQa).desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '默认音质', @@ -210,15 +201,14 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '蜂窝网络音质', leading: const Icon(Icons.music_video_outlined), getSubtitle: () => '当前音质:${AudioQuality.fromCode(Pref.defaultAudioQaCellular).desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '蜂窝网络音质', @@ -236,14 +226,13 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '直播默认画质', leading: const Icon(Icons.video_settings_outlined), getSubtitle: () => '当前画质:${LiveQuality.fromCode(Pref.liveQuality)?.desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '直播默认画质', @@ -258,15 +247,14 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '蜂窝网络直播默认画质', leading: const Icon(Icons.video_settings_outlined), getSubtitle: () => '当前画质:${LiveQuality.fromCode(Pref.liveQualityCellular)?.desc}', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '蜂窝网络直播默认画质', @@ -281,15 +269,14 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '首选解码格式', leading: const Icon(Icons.movie_creation_outlined), getSubtitle: () => '首选解码格式:${VideoDecodeFormatType.fromCode(Pref.defaultDecode).description},请根据设备支持情况与需求调整', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '默认解码格式', @@ -306,15 +293,14 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '次选解码格式', getSubtitle: () => '非杜比视频次选:${VideoDecodeFormatType.fromCode(Pref.secondDecode).description},仍无则选择首个提供的解码格式', leading: const Icon(Icons.swap_horizontal_circle_outlined), - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '次选解码格式', @@ -332,16 +318,14 @@ List get videoSettings => [ }, ), if (Platform.isAndroid) - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '优先使用 OpenSL ES 输出音频', leading: Icon(Icons.speaker_outlined), subtitle: '关闭则优先使用AudioTrack输出音频(此项即mpv的--ao),若遇系统音效丢失、无声、音画不同步等问题请尝试关闭。', setKey: SettingBoxKey.useOpenSLES, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, + const SwitchModel( title: '扩大缓冲区', leading: Icon(Icons.storage_outlined), subtitle: '默认缓冲区为视频4MB/直播16MB,开启后为32MB/64MB,加载时间变长', @@ -349,14 +333,13 @@ List get videoSettings => [ defaultVal: false, ), //video-sync - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '视频同步', leading: const Icon(Icons.view_timeline_outlined), getSubtitle: () => '当前:${Pref.videoSync}(此项即mpv的--video-sync)', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog( - context: Get.context!, + context: context, builder: (context) { return SelectDialog( title: '视频同步', @@ -381,14 +364,13 @@ List get videoSettings => [ } }, ), - SettingsModel( - settingsType: SettingsType.normal, + NormalModel( title: '硬解模式', leading: const Icon(Icons.memory_outlined), getSubtitle: () => '当前:${Pref.hardwareDecoding}(此项即mpv的--hwdec)', - onTap: (setState) async { + onTap: (context, setState) async { final result = await showDialog>( - context: Get.context!, + context: context, builder: (context) { return OrderedMultiSelectDialog( title: '硬解模式', diff --git a/lib/pages/setting/widgets/normal_item.dart b/lib/pages/setting/widgets/normal_item.dart index 9c5c4e973..809853929 100644 --- a/lib/pages/setting/widgets/normal_item.dart +++ b/lib/pages/setting/widgets/normal_item.dart @@ -8,10 +8,9 @@ class NormalItem extends StatefulWidget { final StringGetter? getTitle; final String? subtitle; final StringGetter? getSubtitle; - final String? setKey; final Widget? leading; final Widget Function()? getTrailing; - final Function? onTap; + final void Function(BuildContext context, void Function() setState)? onTap; final EdgeInsetsGeometry? contentPadding; final TextStyle? titleStyle; @@ -20,7 +19,6 @@ class NormalItem extends StatefulWidget { this.getTitle, this.subtitle, this.getSubtitle, - this.setKey, this.leading, this.getTrailing, this.onTap, @@ -36,22 +34,21 @@ class NormalItem extends StatefulWidget { class _NormalItemState extends State { @override Widget build(BuildContext context) { + late final theme = Theme.of(context); return ListTile( contentPadding: widget.contentPadding, - onTap: () => widget.onTap?.call(() { - if (mounted) { - setState(() {}); - } - }), + onTap: widget.onTap == null + ? null + : () => widget.onTap!(context, refresh), title: Text( widget.title ?? widget.getTitle!(), - style: widget.titleStyle ?? Theme.of(context).textTheme.titleMedium!, + style: widget.titleStyle ?? theme.textTheme.titleMedium!, ), subtitle: widget.subtitle != null || widget.getSubtitle != null ? Text( widget.subtitle ?? widget.getSubtitle!(), - style: Theme.of(context).textTheme.labelMedium!.copyWith( - color: Theme.of(context).colorScheme.outline, + style: theme.textTheme.labelMedium!.copyWith( + color: theme.colorScheme.outline, ), ) : null, @@ -59,4 +56,10 @@ class _NormalItemState extends State { trailing: widget.getTrailing?.call(), ); } + + void refresh() { + if (mounted) { + setState(() {}); + } + } } diff --git a/lib/pages/setting/widgets/switch_item.dart b/lib/pages/setting/widgets/switch_item.dart index 8063f2b95..6e31660ce 100644 --- a/lib/pages/setting/widgets/switch_item.dart +++ b/lib/pages/setting/widgets/switch_item.dart @@ -1,25 +1,25 @@ +import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:flutter/material.dart' hide ListTile; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:get/get.dart'; class SetSwitchItem extends StatefulWidget { - final String? title; + final String title; final String? subtitle; final String setKey; final bool defaultVal; final ValueChanged? onChanged; final bool needReboot; final Widget? leading; - final Function? onTap; + final void Function(BuildContext context)? onTap; final EdgeInsetsGeometry? contentPadding; final TextStyle? titleStyle; const SetSwitchItem({ - this.title, + required this.title, this.subtitle, required this.setKey, this.defaultVal = false, @@ -64,47 +64,17 @@ class _SetSwitchItemState extends State { setVal(); } - Future switchChange(ThemeData theme, value) async { - if (widget.setKey == SettingBoxKey.badCertificateCallback && - (value ?? !val)) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('确定禁用 SSL 证书验证?'), - content: const Text('禁用容易受到中间人攻击'), - actions: [ - TextButton( - onPressed: Get.back, - child: Text( - '取消', - style: TextStyle( - color: theme.colorScheme.outline, - ), - ), - ), - TextButton( - onPressed: () async { - Get.back(); - await GStorage.setting.put( - SettingBoxKey.badCertificateCallback, - true, - ); - val = true; - SmartDialog.showToast('重启生效'); - if (mounted) { - setState(() {}); - } - }, - child: const Text('确认'), - ), - ], - ), - ); - return; - } - + Future switchChange([bool? value]) async { val = value ?? !val; + if (widget.setKey == SettingBoxKey.badCertificateCallback && val) { + val = await showConfirmDialog( + context: context, + title: '确定禁用 SSL 证书验证?', + content: '禁用容易受到中间人攻击', + ); + } + if (widget.setKey == SettingBoxKey.appFontWeight) { await GStorage.setting.put(SettingBoxKey.appFontWeight, val ? 4 : -1); } else { @@ -135,10 +105,9 @@ class _SetSwitchItemState extends State { ); return ListTile( contentPadding: widget.contentPadding, - enabled: widget.onTap != null ? val : true, - onTap: () => - widget.onTap != null ? widget.onTap!() : switchChange(theme, null), - title: Text(widget.title!, style: titleStyle), + enabled: widget.onTap == null ? true : val, + onTap: widget.onTap == null ? switchChange : () => widget.onTap!(context), + title: Text(widget.title, style: titleStyle), subtitle: widget.subtitle != null ? Text(widget.subtitle!, style: subTitleStyle) : null, @@ -148,7 +117,7 @@ class _SetSwitchItemState extends State { scale: 0.8, child: Switch( value: val, - onChanged: (value) => switchChange(theme, value), + onChanged: switchChange, ), ), ); diff --git a/lib/pages/settings_search/view.dart b/lib/pages/settings_search/view.dart index c36853b30..487b8fb35 100644 --- a/lib/pages/settings_search/view.dart +++ b/lib/pages/settings_search/view.dart @@ -44,13 +44,8 @@ class _SettingsSearchPageState _list.value = _settings .where( (item) => - (item.title ?? item.getTitle!()).toLowerCase().contains( - value, - ) || - (item.subtitle ?? item.getSubtitle?.call()) - ?.toLowerCase() - .contains(value) == - true, + item.effectiveTitle.toLowerCase().contains(value) || + item.effectiveSubtitle?.toLowerCase().contains(value) == true, ) .toList(); } diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 22d9dad5e..756e82273 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -1561,7 +1561,7 @@ class PlPlayerController { await fullAutoModeForceSensor(); return; } - late final size = Get.mediaQuery.size; + late final size = MediaQuery.sizeOf(Get.context!); if ((mode == FullScreenMode.vertical || (mode == FullScreenMode.auto && isVertical) || (mode == FullScreenMode.ratio &&