mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-11 05:11:34 +08:00
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/extra_settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -17,8 +18,7 @@ class _ExtraSettingState extends State<ExtraSetting> {
|
||||
Widget build(BuildContext context) {
|
||||
final showAppBar = widget.showAppBar;
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: showAppBar ? AppBar(title: const Text('其它设置')) : null,
|
||||
body: ListView.builder(
|
||||
padding: EdgeInsets.only(
|
||||
|
||||
@@ -1,36 +1,21 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math' show max;
|
||||
|
||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||
import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/common/widgets/gesture/horizontal_drag_gesture_recognizer.dart'
|
||||
show touchSlopH;
|
||||
import 'package:PiliPlus/common/widgets/image_grid/image_grid_view.dart'
|
||||
show ImageGridView, ImageModel;
|
||||
import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
|
||||
import 'package:PiliPlus/grpc/reply.dart';
|
||||
show ImageGridView;
|
||||
import 'package:PiliPlus/http/fav.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
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/sponsor_block/skip_type.dart';
|
||||
import 'package:PiliPlus/models/common/super_resolution_type.dart';
|
||||
import 'package:PiliPlus/models/dynamics/result.dart'
|
||||
show DynamicsDataModel, ItemModulesModel;
|
||||
import 'package:PiliPlus/models/dynamics/result.dart' show DynamicsDataModel;
|
||||
import 'package:PiliPlus/pages/common/slide/common_slide_page.dart';
|
||||
import 'package:PiliPlus/pages/main/controller.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/model.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/slider_dialog.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
||||
import 'package:PiliPlus/services/download/download_service.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/cache_manager.dart';
|
||||
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
import 'package:PiliPlus/utils/global_data.dart';
|
||||
import 'package:PiliPlus/utils/image_utils.dart';
|
||||
import 'package:PiliPlus/utils/path_utils.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
@@ -38,34 +23,20 @@ import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart' hide RefreshIndicator;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
List<SettingsModel> get extraSettings => [
|
||||
if (PlatformUtils.isDesktop) ...[
|
||||
SwitchModel(
|
||||
title: '退出时最小化',
|
||||
leading: const Icon(Icons.exit_to_app),
|
||||
setKey: SettingBoxKey.minimizeOnExit,
|
||||
defaultVal: true,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
Get.find<MainController>().minimizeOnExit = value;
|
||||
} catch (_) {}
|
||||
},
|
||||
),
|
||||
if (PlatformUtils.isDesktop)
|
||||
NormalModel(
|
||||
title: '缓存路径',
|
||||
getSubtitle: () => downloadPath,
|
||||
leading: const Icon(Icons.storage),
|
||||
onTap: _showDownPathDialog,
|
||||
),
|
||||
],
|
||||
SplitModel(
|
||||
normalModel: const NormalModel.split(
|
||||
title: '空降助手',
|
||||
@@ -87,55 +58,6 @@ List<SettingsModel> get extraSettings => [
|
||||
.put(SettingBoxKey.pgcSkipType, value.index)
|
||||
.whenComplete(setState),
|
||||
),
|
||||
SplitModel(
|
||||
normalModel: const NormalModel.split(
|
||||
title: '检查未读动态',
|
||||
subtitle: '点击设置检查周期(min)',
|
||||
leading: Icon(Icons.notifications_none),
|
||||
),
|
||||
switchModel: SwitchModel.split(
|
||||
defaultVal: true,
|
||||
setKey: SettingBoxKey.checkDynamic,
|
||||
onChanged: (value) => Get.find<MainController>().checkDynamic = value,
|
||||
onTap: _showDynDialog,
|
||||
),
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示视频分段信息',
|
||||
leading: Icon(CustomIcons.view_headline_rotate_90),
|
||||
setKey: SettingBoxKey.showViewPoints,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '视频页显示相关视频',
|
||||
leading: Icon(MdiIcons.motionPlayOutline),
|
||||
setKey: SettingBoxKey.showRelatedVideo,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示视频评论',
|
||||
leading: Icon(MdiIcons.commentTextOutline),
|
||||
setKey: SettingBoxKey.showVideoReply,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示番剧评论',
|
||||
leading: Icon(MdiIcons.commentTextOutline),
|
||||
setKey: SettingBoxKey.showBangumiReply,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '默认展开视频简介',
|
||||
leading: Icon(Icons.expand_more),
|
||||
setKey: SettingBoxKey.alwaysExpandIntroPanel,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '横屏自动展开视频简介',
|
||||
leading: Icon(Icons.expand_more),
|
||||
setKey: SettingBoxKey.expandIntroPanelH,
|
||||
defaultVal: false,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '横屏分P/合集列表显示在Tab栏',
|
||||
leading: const Icon(Icons.format_list_numbered_rtl_sharp),
|
||||
@@ -155,36 +77,6 @@ List<SettingsModel> get extraSettings => [
|
||||
defaultVal: false,
|
||||
onChanged: (value) => ImageGridView.horizontalPreview = value,
|
||||
),
|
||||
NormalModel(
|
||||
title: '弹幕行高',
|
||||
subtitle: '默认1.6',
|
||||
leading: const Icon(CustomIcons.dm_settings),
|
||||
getTrailing: (theme) => Text(
|
||||
Pref.danmakuLineHeight.toString(),
|
||||
style: theme.textTheme.titleSmall,
|
||||
),
|
||||
onTap: _showDmHeightDialog,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示视频警告/争议信息',
|
||||
leading: Icon(Icons.warning_amber_rounded),
|
||||
setKey: SettingBoxKey.showArgueMsg,
|
||||
defaultVal: true,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '显示动态警告/争议信息',
|
||||
leading: const Icon(Icons.warning_amber_rounded),
|
||||
setKey: SettingBoxKey.showDynDispute,
|
||||
defaultVal: false,
|
||||
onChanged: (val) => ItemModulesModel.showDynDispute = val,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '分P/合集:倒序播放从首集开始播放',
|
||||
subtitle: '开启则自动切换为倒序首集,否则保持当前集',
|
||||
leading: Icon(MdiIcons.sort),
|
||||
setKey: SettingBoxKey.reverseFromFirst,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '禁用 SSL 证书验证',
|
||||
subtitle: '谨慎开启,禁用容易受到中间人攻击',
|
||||
@@ -192,20 +84,6 @@ List<SettingsModel> get extraSettings => [
|
||||
needReboot: true,
|
||||
setKey: SettingBoxKey.badCertificateCallback,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示继续播放分P提示',
|
||||
leading: Icon(Icons.local_parking),
|
||||
setKey: SettingBoxKey.continuePlayingPart,
|
||||
defaultVal: true,
|
||||
),
|
||||
getBanWordModel(
|
||||
title: '评论关键词过滤',
|
||||
key: SettingBoxKey.banWordForReply,
|
||||
onChanged: (value) {
|
||||
ReplyGrpc.replyRegExp = value;
|
||||
ReplyGrpc.enableFilter = value.pattern.isNotEmpty;
|
||||
},
|
||||
),
|
||||
getBanWordModel(
|
||||
title: '动态关键词过滤',
|
||||
key: SettingBoxKey.banWordForDyn,
|
||||
@@ -214,12 +92,6 @@ List<SettingsModel> get extraSettings => [
|
||||
DynamicsDataModel.enableFilter = value.pattern.isNotEmpty;
|
||||
},
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '使用外部浏览器打开链接',
|
||||
leading: Icon(Icons.open_in_browser),
|
||||
setKey: SettingBoxKey.openInBrowser,
|
||||
defaultVal: false,
|
||||
),
|
||||
NormalModel(
|
||||
title: '横向滑动阈值',
|
||||
getSubtitle: () => '当前:「${Pref.touchSlopH}」',
|
||||
@@ -238,152 +110,6 @@ List<SettingsModel> get extraSettings => [
|
||||
getSubtitle: () => '当前指示器高度: ${Pref.refreshDisplacement}',
|
||||
onTap: _showRefreshDialog,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示会员彩色弹幕',
|
||||
leading: Icon(MdiIcons.gradientHorizontal),
|
||||
setKey: SettingBoxKey.showVipDanmaku,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '合并弹幕',
|
||||
subtitle: '合并一段时间内获取到的相同弹幕',
|
||||
leading: Icon(Icons.merge),
|
||||
setKey: SettingBoxKey.mergeDanmaku,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示热门推荐',
|
||||
subtitle: '热门页面显示每周必看等推荐内容入口',
|
||||
leading: Icon(Icons.local_fire_department_outlined),
|
||||
setKey: SettingBoxKey.showHotRcmd,
|
||||
defaultVal: false,
|
||||
needReboot: true,
|
||||
),
|
||||
if (kDebugMode || Platform.isAndroid)
|
||||
NormalModel(
|
||||
title: '音量均衡',
|
||||
leading: const Icon(Icons.multitrack_audio),
|
||||
getSubtitle: () {
|
||||
final audioNormalization = AudioNormalization.getTitleFromConfig(
|
||||
Pref.audioNormalization,
|
||||
);
|
||||
String fallback = Pref.fallbackNormalization;
|
||||
if (fallback == '0') {
|
||||
fallback = '';
|
||||
} else {
|
||||
fallback =
|
||||
',无参数时:「${AudioNormalization.getTitleFromConfig(fallback)}」';
|
||||
}
|
||||
return '当前:「$audioNormalization」$fallback';
|
||||
},
|
||||
onTap: audioNormalization,
|
||||
),
|
||||
NormalModel(
|
||||
title: '超分辨率',
|
||||
leading: const Icon(Icons.stay_current_landscape_outlined),
|
||||
getSubtitle: () =>
|
||||
'当前:「${Pref.superResolutionType.label}」\n默认设置对番剧生效, 其他视频默认关闭\n超分辨率需要启用硬件解码, 若启用硬件解码后仍然不生效, 尝试切换硬件解码器为 auto-copy',
|
||||
onTap: _showSuperResolutionDialog,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '提前初始化播放器',
|
||||
subtitle: '相对减少手动播放加载时间',
|
||||
leading: Icon(Icons.play_circle_outlined),
|
||||
setKey: SettingBoxKey.preInitPlayer,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '搜索建议',
|
||||
leading: Icon(Icons.search),
|
||||
setKey: SettingBoxKey.searchSuggestion,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '记录搜索历史',
|
||||
leading: Icon(Icons.history),
|
||||
setKey: SettingBoxKey.recordSearchHistory,
|
||||
defaultVal: true,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '展示头像/评论/动态装饰',
|
||||
leading: const Icon(MdiIcons.stickerCircleOutline),
|
||||
setKey: SettingBoxKey.showDecorate,
|
||||
defaultVal: true,
|
||||
onChanged: (value) => PendantAvatar.showDecorate = value,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '显示粉丝勋章',
|
||||
leading: const Icon(MdiIcons.medalOutline),
|
||||
setKey: SettingBoxKey.showMedal,
|
||||
defaultVal: true,
|
||||
onChanged: (value) => GlobalData().showMedal = value,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '预览 Live Photo',
|
||||
subtitle: '开启则以视频形式预览 Live Photo,否则预览静态图片',
|
||||
leading: const Icon(Icons.image_outlined),
|
||||
setKey: SettingBoxKey.enableLivePhoto,
|
||||
defaultVal: true,
|
||||
onChanged: (value) => ImageModel.enableLivePhoto = value,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '滑动跳转预览视频缩略图',
|
||||
leading: Icon(Icons.preview_outlined),
|
||||
setKey: SettingBoxKey.showSeekPreview,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示高能进度条',
|
||||
subtitle: '高能进度条反应了在时域上,单位时间内弹幕发送量的变化趋势',
|
||||
leading: Icon(Icons.show_chart),
|
||||
setKey: SettingBoxKey.showDmChart,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '记录评论',
|
||||
leading: Icon(Icons.message_outlined),
|
||||
setKey: SettingBoxKey.saveReply,
|
||||
defaultVal: true,
|
||||
needReboot: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '发评反诈',
|
||||
subtitle: '发送评论后检查评论是否可见',
|
||||
leading: Icon(CustomIcons.shield_reply),
|
||||
setKey: SettingBoxKey.enableCommAntifraud,
|
||||
defaultVal: false,
|
||||
),
|
||||
if (Platform.isAndroid)
|
||||
const SwitchModel(
|
||||
title: '使用「哔哩发评反诈」检查评论',
|
||||
leading: Icon(
|
||||
FontAwesomeIcons.b,
|
||||
size: 22,
|
||||
),
|
||||
setKey: SettingBoxKey.biliSendCommAntifraud,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '发布/转发动态反诈',
|
||||
subtitle: '发布/转发动态后检查动态是否可见',
|
||||
leading: Icon(CustomIcons.shield_published),
|
||||
setKey: SettingBoxKey.enableCreateDynAntifraud,
|
||||
defaultVal: false,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '屏蔽带货动态',
|
||||
leading: const Icon(CustomIcons.shopping_bag_not_interested),
|
||||
setKey: SettingBoxKey.antiGoodsDyn,
|
||||
defaultVal: false,
|
||||
onChanged: (value) => DynamicsDataModel.antiGoodsDyn = value,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '屏蔽带货评论',
|
||||
leading: const Icon(CustomIcons.shopping_bag_not_interested),
|
||||
setKey: SettingBoxKey.antiGoodsReply,
|
||||
defaultVal: false,
|
||||
onChanged: (value) => ReplyGrpc.antiGoodsReply = value,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '侧滑关闭二级页面',
|
||||
leading: const Icon(CustomIcons.touch_app_rotate_270),
|
||||
@@ -391,18 +117,6 @@ List<SettingsModel> get extraSettings => [
|
||||
defaultVal: Platform.isIOS,
|
||||
onChanged: (value) => CommonSlideMixin.slideDismissReplyPage = value,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '动态/专栏详情页展示底部操作栏',
|
||||
leading: Icon(Icons.more_horiz),
|
||||
setKey: SettingBoxKey.showDynActionBar,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '启用拖拽字幕调整底部边距',
|
||||
leading: Icon(MdiIcons.dragVariant),
|
||||
setKey: SettingBoxKey.enableDragSubtitle,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '展示追番时间表',
|
||||
leading: Icon(MdiIcons.chartTimelineVariantShimmer),
|
||||
@@ -410,14 +124,6 @@ List<SettingsModel> get extraSettings => [
|
||||
defaultVal: true,
|
||||
needReboot: true,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '静默下载图片',
|
||||
subtitle: '不显示下载 Loading 弹窗',
|
||||
leading: const Icon(Icons.download_for_offline_outlined),
|
||||
setKey: SettingBoxKey.silentDownImg,
|
||||
defaultVal: false,
|
||||
onChanged: (value) => ImageUtils.silentDownImg = value,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '长按/右键显示图片菜单',
|
||||
leading: const Icon(Icons.menu),
|
||||
@@ -425,20 +131,6 @@ List<SettingsModel> get extraSettings => [
|
||||
defaultVal: false,
|
||||
onChanged: (value) => ImageGridView.enableImgMenu = value,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '大家都在搜',
|
||||
subtitle: '是否展示「大家都在搜」',
|
||||
leading: Icon(Icons.data_thresholding_outlined),
|
||||
setKey: SettingBoxKey.enableHotKey,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '搜索发现',
|
||||
subtitle: '是否展示「搜索发现」',
|
||||
leading: Icon(Icons.search_outlined),
|
||||
setKey: SettingBoxKey.enableSearchRcmd,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '快速收藏',
|
||||
subtitle: '点击设置默认收藏夹\n点按收藏至默认,长按选择文件夹',
|
||||
@@ -447,20 +139,6 @@ List<SettingsModel> get extraSettings => [
|
||||
onTap: _showFavDialog,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '启用AI总结',
|
||||
subtitle: '视频详情页开启AI总结',
|
||||
leading: Icon(Icons.engineering_outlined),
|
||||
setKey: SettingBoxKey.enableAi,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '默认展示评论区',
|
||||
subtitle: '在视频详情页默认切换至评论区页(仅Tab型布局)',
|
||||
leading: Icon(Icons.mode_comment_outlined),
|
||||
setKey: SettingBoxKey.defaultShowComment,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '启用HTTP/2',
|
||||
leading: Icon(Icons.swap_horizontal_circle_outlined),
|
||||
@@ -480,58 +158,6 @@ List<SettingsModel> get extraSettings => [
|
||||
leading: Icon(Icons.more_time_outlined),
|
||||
onTap: _showReplyDelayDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '评论展示',
|
||||
leading: const Icon(Icons.whatshot_outlined),
|
||||
getSubtitle: () => '当前优先展示「${Pref.replySortType.title}」',
|
||||
onTap: _showReplySortDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '动态展示',
|
||||
leading: const Icon(Icons.dynamic_feed_rounded),
|
||||
getSubtitle: () => '当前优先展示「${Pref.defaultDynamicType.label}」',
|
||||
onTap: _showDefDynDialog,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '显示动态互动内容',
|
||||
subtitle: '开启后则在动态卡片底部显示互动内容(如关注的人点赞、热评等)',
|
||||
leading: const Icon(Icons.quickreply_outlined),
|
||||
setKey: SettingBoxKey.showDynInteraction,
|
||||
defaultVal: true,
|
||||
onChanged: (val) => ItemModulesModel.showDynInteraction = val,
|
||||
),
|
||||
NormalModel(
|
||||
title: '用户页默认展示TAB',
|
||||
leading: const Icon(Icons.tab),
|
||||
getSubtitle: () => '当前优先展示「${Pref.memberTab.title}」',
|
||||
onTap: _showMemberTabDialog,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '显示UP主页小店TAB',
|
||||
leading: const Icon(Icons.shop_outlined),
|
||||
setKey: SettingBoxKey.showMemberShop,
|
||||
defaultVal: false,
|
||||
onChanged: (value) => MemberTabType.showMemberShop = value,
|
||||
),
|
||||
const SplitModel(
|
||||
normalModel: NormalModel.split(
|
||||
title: '设置代理',
|
||||
subtitle: '设置代理 host:port',
|
||||
leading: Icon(Icons.airplane_ticket_outlined),
|
||||
),
|
||||
switchModel: SwitchModel.split(
|
||||
defaultVal: false,
|
||||
setKey: SettingBoxKey.enableSystemProxy,
|
||||
onTap: _showProxyDialog,
|
||||
),
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '自动清除缓存',
|
||||
subtitle: '每次启动时清除缓存',
|
||||
leading: Icon(Icons.auto_delete_outlined),
|
||||
setKey: SettingBoxKey.autoClearCache,
|
||||
defaultVal: false,
|
||||
),
|
||||
NormalModel(
|
||||
title: '最大缓存大小',
|
||||
getSubtitle: () {
|
||||
@@ -543,99 +169,6 @@ List<SettingsModel> get extraSettings => [
|
||||
),
|
||||
];
|
||||
|
||||
Future<void> audioNormalization(
|
||||
BuildContext context,
|
||||
VoidCallback setState, {
|
||||
bool fallback = false,
|
||||
}) async {
|
||||
final key = fallback
|
||||
? SettingBoxKey.fallbackNormalization
|
||||
: SettingBoxKey.audioNormalization;
|
||||
final res = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
String audioNormalization = fallback
|
||||
? Pref.fallbackNormalization
|
||||
: Pref.audioNormalization;
|
||||
Set<String> values = {
|
||||
'0',
|
||||
'1',
|
||||
if (!fallback) '2',
|
||||
audioNormalization,
|
||||
'3',
|
||||
};
|
||||
return SelectDialog<String>(
|
||||
title: fallback ? '服务器无loudnorm配置时使用' : '音量均衡',
|
||||
toggleable: true,
|
||||
value: audioNormalization,
|
||||
values: values
|
||||
.map(
|
||||
(e) => (
|
||||
e,
|
||||
switch (e) {
|
||||
'0' => AudioNormalization.disable.title,
|
||||
'1' => AudioNormalization.dynaudnorm.title,
|
||||
'2' => AudioNormalization.loudnorm.title,
|
||||
'3' => AudioNormalization.custom.title,
|
||||
_ => e,
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (res != null && context.mounted) {
|
||||
if (res == '3') {
|
||||
String param = '';
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('自定义参数'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 16,
|
||||
children: [
|
||||
const Text('等同于 --lavfi-complex="[aid1] 参数 [ao]"'),
|
||||
TextField(
|
||||
autofocus: true,
|
||||
onChanged: (value) => param = value,
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: ColorScheme.of(context).outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
GStorage.setting.put(key, param);
|
||||
if (!fallback &&
|
||||
PlPlayerController.loudnormRegExp.hasMatch(param)) {
|
||||
audioNormalization(context, setState, fallback: true);
|
||||
}
|
||||
setState();
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
GStorage.setting.put(key, res);
|
||||
if (res == '2') {
|
||||
audioNormalization(context, setState, fallback: true);
|
||||
}
|
||||
setState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _showDownPathDialog(BuildContext context, VoidCallback setState) {
|
||||
showDialog(
|
||||
context: context,
|
||||
@@ -685,90 +218,6 @@ void _showDownPathDialog(BuildContext context, VoidCallback setState) {
|
||||
);
|
||||
}
|
||||
|
||||
void _showDynDialog(BuildContext context) {
|
||||
String dynamicPeriod = Pref.dynamicPeriod.toString();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('检查周期'),
|
||||
content: TextFormField(
|
||||
autofocus: true,
|
||||
initialValue: dynamicPeriod,
|
||||
keyboardType: TextInputType.number,
|
||||
onChanged: (value) => dynamicPeriod = value,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
decoration: const InputDecoration(suffixText: 'min'),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: ColorScheme.of(context).outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
try {
|
||||
final val = int.parse(dynamicPeriod);
|
||||
Get.back();
|
||||
GStorage.setting.put(SettingBoxKey.dynamicPeriod, val);
|
||||
Get.find<MainController>().dynamicPeriod = val * 60 * 1000;
|
||||
} catch (e) {
|
||||
SmartDialog.showToast(e.toString());
|
||||
}
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showDmHeightDialog(BuildContext context, VoidCallback setState) {
|
||||
String danmakuLineHeight = Pref.danmakuLineHeight.toString();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('弹幕行高'),
|
||||
content: TextFormField(
|
||||
autofocus: true,
|
||||
initialValue: danmakuLineHeight,
|
||||
keyboardType: const .numberWithOptions(decimal: true),
|
||||
onChanged: (value) => danmakuLineHeight = value,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[\d\.]+')),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: ColorScheme.of(context).outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
final val = max(
|
||||
1.0,
|
||||
double.parse(danmakuLineHeight).toPrecision(1),
|
||||
);
|
||||
Get.back();
|
||||
await GStorage.setting.put(SettingBoxKey.danmakuLineHeight, val);
|
||||
setState();
|
||||
} catch (e) {
|
||||
SmartDialog.showToast(e.toString());
|
||||
}
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showTouchSlopDialog(BuildContext context, VoidCallback setState) {
|
||||
String initialValue = Pref.touchSlopH.toString();
|
||||
showDialog(
|
||||
@@ -867,27 +316,6 @@ void _visitor(Element context) {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showSuperResolutionDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<SuperResolutionType>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<SuperResolutionType>(
|
||||
title: '超分辨率',
|
||||
value: Pref.superResolutionType,
|
||||
values: SuperResolutionType.values.map((e) => (e, e.label)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(
|
||||
SettingBoxKey.superResolutionType,
|
||||
res.index,
|
||||
);
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showFavDialog(BuildContext context) async {
|
||||
if (Accounts.main.isLogin) {
|
||||
final res = await FavHttp.allFavFolders(Accounts.main.mid);
|
||||
@@ -979,129 +407,6 @@ Future<void> _showReplyDelayDialog(
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showReplySortDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<ReplySortType>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<ReplySortType>(
|
||||
title: '评论展示',
|
||||
value: Pref.replySortType,
|
||||
values: ReplySortType.values.take(2).map((e) => (e, e.title)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(SettingBoxKey.replySortType, res.index);
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showDefDynDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<DynamicsTabType>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<DynamicsTabType>(
|
||||
title: '动态展示',
|
||||
value: Pref.defaultDynamicType,
|
||||
values: DynamicsTabType.values.take(4).map((e) => (e, e.label)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(
|
||||
SettingBoxKey.defaultDynamicType,
|
||||
res.index,
|
||||
);
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showMemberTabDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<MemberTabType>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<MemberTabType>(
|
||||
title: '用户页默认展示TAB',
|
||||
value: Pref.memberTab,
|
||||
values: MemberTabType.values.map((e) => (e, e.title)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(SettingBoxKey.memberTab, res.index);
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
void _showProxyDialog(BuildContext context) {
|
||||
String systemProxyHost = Pref.systemProxyHost;
|
||||
String systemProxyPort = Pref.systemProxyPort;
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('设置代理'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 6),
|
||||
TextFormField(
|
||||
initialValue: systemProxyHost,
|
||||
decoration: const InputDecoration(
|
||||
isDense: true,
|
||||
labelText: '请输入Host,使用 . 分割',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
),
|
||||
onChanged: (e) => systemProxyHost = e,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TextFormField(
|
||||
initialValue: systemProxyPort,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
isDense: true,
|
||||
labelText: '请输入Port',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
),
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onChanged: (e) => systemProxyPort = e,
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: ColorScheme.of(context).outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
GStorage.setting.put(
|
||||
SettingBoxKey.systemProxyHost,
|
||||
systemProxyHost,
|
||||
);
|
||||
GStorage.setting.put(
|
||||
SettingBoxKey.systemProxyPort,
|
||||
systemProxyPort,
|
||||
);
|
||||
},
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showCacheDialog(BuildContext context, VoidCallback setState) {
|
||||
String valueStr = '';
|
||||
showDialog(
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||
import 'package:PiliPlus/models/common/super_chat_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';
|
||||
import 'package:PiliPlus/pages/setting/pages/fullscreen_sc_size.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/bottom_progress_behavior.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/fullscreen_mode.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart';
|
||||
import 'package:PiliPlus/services/service_locator.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.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';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
List<SettingsModel> get playSettings => [
|
||||
const SwitchModel(
|
||||
@@ -28,71 +16,18 @@ List<SettingsModel> get playSettings => [
|
||||
setKey: SettingBoxKey.enableShowDanmaku,
|
||||
defaultVal: true,
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
const SwitchModel(
|
||||
title: '启用点击弹幕',
|
||||
subtitle: '点击弹幕悬停,支持点赞、复制、举报操作',
|
||||
leading: Icon(Icons.touch_app_outlined),
|
||||
setKey: SettingBoxKey.enableTapDm,
|
||||
defaultVal: true,
|
||||
),
|
||||
NormalModel(
|
||||
onTap: (context, setState) => Get.toNamed('/playSpeedSet'),
|
||||
leading: const Icon(Icons.speed_outlined),
|
||||
title: '倍速设置',
|
||||
subtitle: '设置视频播放速度',
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '自动播放',
|
||||
subtitle: '进入详情页自动播放',
|
||||
leading: Icon(Icons.motion_photos_auto_outlined),
|
||||
setKey: SettingBoxKey.autoPlayEnable,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '全屏显示锁定按钮',
|
||||
leading: Icon(Icons.lock_outline),
|
||||
setKey: SettingBoxKey.showFsLockBtn,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '全屏显示截图按钮',
|
||||
leading: Icon(Icons.photo_camera_outlined),
|
||||
setKey: SettingBoxKey.showFsScreenshotBtn,
|
||||
defaultVal: true,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '全屏显示电池电量',
|
||||
leading: const Icon(Icons.battery_3_bar),
|
||||
setKey: SettingBoxKey.showBatteryLevel,
|
||||
defaultVal: PlatformUtils.isMobile,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '双击快退/快进',
|
||||
subtitle: '左侧双击快退/右侧双击快进,关闭则双击均为暂停/播放',
|
||||
leading: Icon(Icons.touch_app_outlined),
|
||||
setKey: SettingBoxKey.enableQuickDouble,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '左右侧滑动调节亮度/音量',
|
||||
leading: Icon(MdiIcons.tuneVerticalVariant),
|
||||
setKey: SettingBoxKey.enableSlideVolumeBrightness,
|
||||
defaultVal: true,
|
||||
),
|
||||
if (Platform.isAndroid)
|
||||
const SwitchModel(
|
||||
title: '调节系统亮度',
|
||||
leading: Icon(Icons.brightness_6_outlined),
|
||||
setKey: SettingBoxKey.setSystemBrightness,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '中间滑动进入/退出全屏',
|
||||
leading: Icon(MdiIcons.panVertical),
|
||||
setKey: SettingBoxKey.enableSlideFS,
|
||||
defaultVal: true,
|
||||
),
|
||||
getVideoFilterSelectModel(
|
||||
title: '双击快进/快退时长',
|
||||
suffix: 's',
|
||||
@@ -101,78 +36,21 @@ List<SettingsModel> get playSettings => [
|
||||
defaultValue: 10,
|
||||
isFilter: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '滑动快进/快退使用相对时长',
|
||||
leading: Icon(Icons.swap_horiz_outlined),
|
||||
setKey: SettingBoxKey.useRelativeSlide,
|
||||
defaultVal: false,
|
||||
),
|
||||
getVideoFilterSelectModel(
|
||||
title: '滑动快进/快退时长',
|
||||
subtitle: '从播放器一端滑到另一端的快进/快退时长',
|
||||
suffix: Pref.useRelativeSlide ? '%' : 's',
|
||||
suffix: 's',
|
||||
key: SettingBoxKey.sliderDuration,
|
||||
values: [25, 50, 90, 100],
|
||||
defaultValue: 90,
|
||||
isFilter: false,
|
||||
),
|
||||
NormalModel(
|
||||
title: '自动启用字幕',
|
||||
leading: const Icon(Icons.closed_caption_outlined),
|
||||
getSubtitle: () => '当前选择偏好:${Pref.subtitlePreferenceV2.desc}',
|
||||
onTap: _showSubtitleDialog,
|
||||
),
|
||||
if (PlatformUtils.isDesktop)
|
||||
SwitchModel(
|
||||
title: '最小化时暂停/还原时播放',
|
||||
leading: const Icon(Icons.pause_circle_outline),
|
||||
setKey: SettingBoxKey.pauseOnMinimize,
|
||||
defaultVal: false,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
Get.find<MainController>().pauseOnMinimize = value;
|
||||
} catch (_) {}
|
||||
},
|
||||
),
|
||||
SwitchModel(
|
||||
title: '启用键盘控制',
|
||||
leading: const Icon(Icons.keyboard_alt_outlined),
|
||||
setKey: SettingBoxKey.keyboardControl,
|
||||
defaultVal: PlatformUtils.isDesktop,
|
||||
),
|
||||
NormalModel(
|
||||
title: 'SuperChat (醒目留言) 显示类型',
|
||||
leading: const Icon(Icons.live_tv),
|
||||
getSubtitle: () => '当前:「${Pref.superChatType.title}」',
|
||||
onTap: _showSuperChatDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '全屏 SC 大小',
|
||||
subtitle: 'SuperChat (醒目留言) 大小设置',
|
||||
leading: const Icon(Icons.open_in_full),
|
||||
onTap: (_, _) => Get.to(const FullScreenScSize()),
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '竖屏扩大展示',
|
||||
subtitle: '小屏竖屏视频宽高比由16:9扩大至1:1(不支持收起);横屏适配时,扩大至9:16',
|
||||
leading: Icon(Icons.expand_outlined),
|
||||
setKey: SettingBoxKey.enableVerticalExpand,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '自动全屏',
|
||||
subtitle: '视频开始播放时进入全屏',
|
||||
leading: Icon(Icons.fullscreen_outlined),
|
||||
setKey: SettingBoxKey.enableAutoEnter,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '自动退出全屏',
|
||||
subtitle: '视频结束播放时退出全屏',
|
||||
leading: Icon(Icons.fullscreen_exit_outlined),
|
||||
setKey: SettingBoxKey.enableAutoExit,
|
||||
defaultVal: true,
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
const SwitchModel(
|
||||
title: '后台播放',
|
||||
@@ -181,40 +59,6 @@ List<SettingsModel> get playSettings => [
|
||||
setKey: SettingBoxKey.continuePlayInBackground,
|
||||
defaultVal: false,
|
||||
),
|
||||
if (Platform.isAndroid) ...[
|
||||
SwitchModel(
|
||||
title: '后台画中画',
|
||||
subtitle: '进入后台时以小窗形式(PiP)播放',
|
||||
leading: const Icon(Icons.picture_in_picture_outlined),
|
||||
setKey: SettingBoxKey.autoPiP,
|
||||
defaultVal: false,
|
||||
onChanged: (val) {
|
||||
if (val && !videoPlayerServiceHandler!.enableBackgroundPlay) {
|
||||
SmartDialog.showToast('建议开启后台音频服务');
|
||||
}
|
||||
},
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '画中画不加载弹幕',
|
||||
subtitle: '当弹幕开关开启时,小窗屏蔽弹幕以获得较好的体验',
|
||||
leading: Icon(CustomIcons.dm_off),
|
||||
setKey: SettingBoxKey.pipNoDanmaku,
|
||||
defaultVal: false,
|
||||
),
|
||||
],
|
||||
const SwitchModel(
|
||||
title: '全屏手势反向',
|
||||
subtitle: '默认播放器中部向上滑动进入全屏,向下退出\n开启后向下全屏,向上退出',
|
||||
leading: Icon(Icons.swap_vert),
|
||||
setKey: SettingBoxKey.fullScreenGestureReverse,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '全屏展示点赞/投币/收藏等操作按钮',
|
||||
leading: Icon(MdiIcons.dotsHorizontalCircleOutline),
|
||||
setKey: SettingBoxKey.showFSActionItem,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '观看人数',
|
||||
subtitle: '展示同时在看人数',
|
||||
@@ -222,28 +66,6 @@ List<SettingsModel> get playSettings => [
|
||||
setKey: SettingBoxKey.enableOnlineTotal,
|
||||
defaultVal: false,
|
||||
),
|
||||
NormalModel(
|
||||
title: '默认全屏方向',
|
||||
leading: const Icon(Icons.open_with_outlined),
|
||||
getSubtitle: () => '当前全屏方向:${Pref.fullScreenMode.desc}',
|
||||
onTap: _showFullScreenModeDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '底部进度条展示',
|
||||
leading: const Icon(Icons.border_bottom_outlined),
|
||||
getSubtitle: () => '当前展示方式:${Pref.btmProgressBehavior.desc}',
|
||||
onTap: _showProgressBehaviorDialog,
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
SwitchModel(
|
||||
title: '后台音频服务',
|
||||
subtitle: '避免画中画没有播放暂停功能',
|
||||
leading: const Icon(Icons.volume_up_outlined),
|
||||
setKey: SettingBoxKey.enableBackgroundPlay,
|
||||
defaultVal: true,
|
||||
onChanged: (value) =>
|
||||
videoPlayerServiceHandler!.enableBackgroundPlay = value,
|
||||
),
|
||||
PopupModel(
|
||||
title: '播放顺序',
|
||||
leading: const Icon(Icons.repeat),
|
||||
@@ -253,89 +75,4 @@ List<SettingsModel> get playSettings => [
|
||||
.put(VideoBoxKey.playRepeat, value.index)
|
||||
.whenComplete(setState),
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '播放器设置仅对当前生效',
|
||||
subtitle: '弹幕、字幕及部分设置中没有的设置除外',
|
||||
leading: Icon(Icons.video_settings_outlined),
|
||||
setKey: SettingBoxKey.tempPlayerConf,
|
||||
defaultVal: false,
|
||||
),
|
||||
];
|
||||
|
||||
Future<void> _showSubtitleDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<SubtitlePrefType>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<SubtitlePrefType>(
|
||||
title: '字幕选择偏好',
|
||||
value: Pref.subtitlePreferenceV2,
|
||||
values: SubtitlePrefType.values.map((e) => (e, e.desc)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(
|
||||
SettingBoxKey.subtitlePreferenceV2,
|
||||
res.index,
|
||||
);
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showSuperChatDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<SuperChatType>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<SuperChatType>(
|
||||
title: 'SuperChat (醒目留言) 显示类型',
|
||||
value: Pref.superChatType,
|
||||
values: SuperChatType.values.map((e) => (e, e.title)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(SettingBoxKey.superChatType, res.index);
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showFullScreenModeDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<FullScreenMode>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<FullScreenMode>(
|
||||
title: '默认全屏方向',
|
||||
value: Pref.fullScreenMode,
|
||||
values: FullScreenMode.values.map((e) => (e, e.desc)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(SettingBoxKey.fullScreenMode, res.index);
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showProgressBehaviorDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<BtmProgressBehavior>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<BtmProgressBehavior>(
|
||||
title: '底部进度条展示',
|
||||
value: Pref.btmProgressBehavior,
|
||||
values: BtmProgressBehavior.values.map((e) => (e, e.desc)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(
|
||||
SettingBoxKey.btmProgressBehavior,
|
||||
res.index,
|
||||
);
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import 'package:PiliPlus/http/video.dart';
|
||||
import 'package:PiliPlus/pages/rcmd/controller.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/model.dart';
|
||||
import 'package:PiliPlus/utils/recommend_filter.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
List<SettingsModel> get recommendSettings => [
|
||||
const SwitchModel(
|
||||
title: '首页使用app端推荐',
|
||||
subtitle: '若web端推荐不太符合预期,可尝试切换至app端推荐',
|
||||
leading: Icon(Icons.model_training_outlined),
|
||||
setKey: SettingBoxKey.appRcmd,
|
||||
defaultVal: true,
|
||||
needReboot: true,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '保留首页推荐刷新',
|
||||
subtitle: '下拉刷新时保留上次内容',
|
||||
leading: const Icon(Icons.refresh),
|
||||
setKey: SettingBoxKey.enableSaveLastData,
|
||||
defaultVal: true,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
Get.find<RcmdController>()
|
||||
..enableSaveLastData = value
|
||||
..lastRefreshAt = null;
|
||||
} catch (e) {
|
||||
if (kDebugMode) debugPrint('$e');
|
||||
}
|
||||
},
|
||||
),
|
||||
SwitchModel(
|
||||
title: '显示上次看到位置提示',
|
||||
subtitle: '保留上次推荐时,在上次刷新位置显示提示',
|
||||
leading: const Icon(Icons.tips_and_updates_outlined),
|
||||
setKey: SettingBoxKey.savedRcmdTip,
|
||||
defaultVal: true,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
Get.find<RcmdController>()
|
||||
..savedRcmdTip = value
|
||||
..lastRefreshAt = null;
|
||||
} catch (e) {
|
||||
if (kDebugMode) debugPrint('$e');
|
||||
}
|
||||
},
|
||||
),
|
||||
getVideoFilterSelectModel(
|
||||
title: '点赞率',
|
||||
suffix: '%',
|
||||
key: SettingBoxKey.minLikeRatioForRecommend,
|
||||
values: [0, 1, 2, 3, 4],
|
||||
onChanged: (value) => RecommendFilter.minLikeRatioForRecommend = value,
|
||||
),
|
||||
getBanWordModel(
|
||||
title: '标题关键词过滤',
|
||||
key: SettingBoxKey.banWordForRecommend,
|
||||
onChanged: (value) {
|
||||
RecommendFilter.rcmdRegExp = value;
|
||||
RecommendFilter.enableFilter = value.pattern.isNotEmpty;
|
||||
},
|
||||
),
|
||||
getBanWordModel(
|
||||
title: 'App推荐/热门/排行榜: 视频分区关键词过滤',
|
||||
key: SettingBoxKey.banWordForZone,
|
||||
onChanged: (value) {
|
||||
VideoHttp.zoneRegExp = value;
|
||||
VideoHttp.enableFilter = value.pattern.isNotEmpty;
|
||||
},
|
||||
),
|
||||
getVideoFilterSelectModel(
|
||||
title: '视频时长',
|
||||
suffix: 's',
|
||||
key: SettingBoxKey.minDurationForRcmd,
|
||||
values: [0, 30, 60, 90, 120],
|
||||
onChanged: (value) => RecommendFilter.minDurationForRcmd = value,
|
||||
),
|
||||
getVideoFilterSelectModel(
|
||||
title: '播放量',
|
||||
key: SettingBoxKey.minPlayForRcmd,
|
||||
values: [0, 50, 100, 500, 1000],
|
||||
onChanged: (value) => RecommendFilter.minPlayForRcmd = value,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '已关注UP豁免推荐过滤',
|
||||
subtitle: '推荐中已关注用户发布的内容不会被过滤',
|
||||
leading: const Icon(Icons.favorite_border_outlined),
|
||||
setKey: SettingBoxKey.exemptFilterForFollowed,
|
||||
defaultVal: true,
|
||||
onChanged: (value) => RecommendFilter.exemptFilterForFollowed = value,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '过滤器也应用于相关视频',
|
||||
subtitle: '视频详情页的相关视频也进行过滤¹',
|
||||
leading: const Icon(Icons.explore_outlined),
|
||||
setKey: SettingBoxKey.applyFilterToRelatedVideos,
|
||||
defaultVal: true,
|
||||
onChanged: (value) => RecommendFilter.applyFilterToRelatedVideos = value,
|
||||
),
|
||||
];
|
||||
@@ -1,15 +1,9 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:PiliPlus/common/widgets/color_palette.dart';
|
||||
import 'package:PiliPlus/common/widgets/scale_app.dart';
|
||||
import 'package:PiliPlus/common/widgets/stateful_builder.dart';
|
||||
import 'package:PiliPlus/models/common/bar_hide_type.dart';
|
||||
import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart';
|
||||
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/theme/theme_color_type.dart';
|
||||
import 'package:PiliPlus/models/common/theme/theme_type.dart';
|
||||
import 'package:PiliPlus/pages/main/controller.dart';
|
||||
@@ -20,13 +14,9 @@ import 'package:PiliPlus/pages/setting/widgets/multi_select_dialog.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/slider_dialog.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart';
|
||||
import 'package:PiliPlus/utils/extension/file_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/get_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/theme_ext.dart';
|
||||
import 'package:PiliPlus/utils/global_data.dart';
|
||||
import 'package:PiliPlus/utils/path_utils.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
@@ -36,26 +26,8 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
List<SettingsModel> get styleSettings => [
|
||||
if (PlatformUtils.isDesktop) ...[
|
||||
const SwitchModel(
|
||||
title: '显示窗口标题栏',
|
||||
leading: Icon(Icons.window),
|
||||
setKey: SettingBoxKey.showWindowTitleBar,
|
||||
defaultVal: true,
|
||||
needReboot: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '显示托盘图标',
|
||||
leading: Icon(Icons.donut_large_rounded),
|
||||
setKey: SettingBoxKey.showTrayIcon,
|
||||
defaultVal: true,
|
||||
needReboot: true,
|
||||
),
|
||||
],
|
||||
if (Platform.isLinux) _useSSDModel(),
|
||||
SwitchModel(
|
||||
title: '横屏适配',
|
||||
subtitle: '启用横屏布局与逻辑,平板、折叠屏等可开启;建议全屏方向设为【不改变当前方向】',
|
||||
@@ -70,12 +42,6 @@ List<SettingsModel> get styleSettings => [
|
||||
}
|
||||
},
|
||||
),
|
||||
NormalModel(
|
||||
title: '界面缩放',
|
||||
getSubtitle: () => '当前缩放比例:${Pref.uiScale.toStringAsFixed(2)}',
|
||||
leading: const Icon(Icons.zoom_in_outlined),
|
||||
onTap: _showUiScaleDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '页面过渡动画',
|
||||
leading: const Icon(Icons.animation),
|
||||
@@ -96,18 +62,6 @@ List<SettingsModel> get styleSettings => [
|
||||
'当前: 主页${Pref.recommendCardWidth.toInt()}dp 其他${Pref.smallCardWidth.toInt()}dp,屏幕宽度:${MediaQuery.widthOf(Get.context!).toPrecision(2)}dp。宽度越小列数越多。',
|
||||
onTap: _showCardWidthDialog,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '播放页移除安全边距',
|
||||
leading: Icon(Icons.fit_screen_outlined),
|
||||
setKey: SettingBoxKey.removeSafeArea,
|
||||
defaultVal: false,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '视频播放页使用深色主题',
|
||||
leading: Icon(Icons.dark_mode_outlined),
|
||||
setKey: SettingBoxKey.darkVideoPage,
|
||||
defaultVal: false,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '动态页启用瀑布流',
|
||||
subtitle: '关闭会显示为单列',
|
||||
@@ -122,20 +76,6 @@ List<SettingsModel> get styleSettings => [
|
||||
getSubtitle: () => '当前:${Pref.upPanelPosition.label}',
|
||||
onTap: _showUpPosDialog,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '动态页显示所有已关注UP主',
|
||||
leading: Icon(Icons.people_alt_outlined),
|
||||
setKey: SettingBoxKey.dynamicsShowAllFollowedUp,
|
||||
defaultVal: false,
|
||||
needReboot: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '动态页展开正在直播UP列表',
|
||||
leading: Icon(Icons.live_tv),
|
||||
setKey: SettingBoxKey.expandDynLivePanel,
|
||||
defaultVal: false,
|
||||
needReboot: true,
|
||||
),
|
||||
NormalModel(
|
||||
title: '动态未读标记',
|
||||
leading: const Icon(Icons.motion_photos_on_outlined),
|
||||
@@ -155,28 +95,6 @@ List<SettingsModel> get styleSettings => [
|
||||
getSubtitle: () =>
|
||||
'当前消息类型:${Pref.msgUnReadTypeV2.map((item) => item.title).join('、')}',
|
||||
),
|
||||
NormalModel(
|
||||
onTap: _showBarHideTypeDialog,
|
||||
title: '顶/底栏收起类型',
|
||||
leading: const Icon(MdiIcons.arrowExpandVertical),
|
||||
getSubtitle: () => '当前:${Pref.barHideType.label}',
|
||||
),
|
||||
SwitchModel(
|
||||
title: '首页顶栏收起',
|
||||
subtitle: '首页列表滑动时,收起顶栏',
|
||||
leading: const Icon(Icons.vertical_align_top_outlined),
|
||||
setKey: SettingBoxKey.hideTopBar,
|
||||
defaultVal: PlatformUtils.isMobile,
|
||||
needReboot: true,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '首页底栏收起',
|
||||
subtitle: '首页列表滑动时,收起底栏',
|
||||
leading: const Icon(Icons.vertical_align_bottom_outlined),
|
||||
setKey: SettingBoxKey.hideBottomBar,
|
||||
defaultVal: PlatformUtils.isMobile,
|
||||
needReboot: true,
|
||||
),
|
||||
NormalModel(
|
||||
onTap: (context, setState) => _showQualityDialog(
|
||||
context: context,
|
||||
@@ -220,17 +138,6 @@ List<SettingsModel> get styleSettings => [
|
||||
title: '主题模式',
|
||||
getSubtitle: () => '当前模式:${Pref.themeType.desc}',
|
||||
),
|
||||
SwitchModel(
|
||||
leading: const Icon(Icons.invert_colors),
|
||||
title: '纯黑主题',
|
||||
setKey: SettingBoxKey.isPureBlackTheme,
|
||||
defaultVal: false,
|
||||
onChanged: (value) {
|
||||
if (ThemeUtils.isDarkMode || Pref.darkVideoPage) {
|
||||
Get.updateMyAppTheme();
|
||||
}
|
||||
},
|
||||
),
|
||||
NormalModel(
|
||||
onTap: (context, setState) => Get.toNamed('/colorSetting'),
|
||||
leading: const Icon(Icons.color_lens_outlined),
|
||||
@@ -248,65 +155,11 @@ List<SettingsModel> get styleSettings => [
|
||||
),
|
||||
),
|
||||
),
|
||||
NormalModel(
|
||||
leading: const Icon(Icons.home_outlined),
|
||||
title: '默认启动页',
|
||||
getSubtitle: () => '当前启动页:${Pref.defaultHomePage.label}',
|
||||
onTap: _showDefHomeDialog,
|
||||
),
|
||||
const NormalModel(
|
||||
title: '滑动动画弹簧参数',
|
||||
leading: Icon(Icons.chrome_reader_mode_outlined),
|
||||
onTap: _showSpringDialog,
|
||||
),
|
||||
NormalModel(
|
||||
onTap: (context, setState) async {
|
||||
final res = await Get.toNamed('/fontSizeSetting');
|
||||
if (res != null) {
|
||||
setState();
|
||||
}
|
||||
},
|
||||
title: '字体大小',
|
||||
leading: const Icon(Icons.format_size_outlined),
|
||||
getSubtitle: () {
|
||||
final scale = Pref.defaultTextScale;
|
||||
return scale == 1.0 ? '默认' : scale.toString();
|
||||
},
|
||||
),
|
||||
NormalModel(
|
||||
onTap: (context, setState) => Get.toNamed(
|
||||
'/barSetting',
|
||||
arguments: {
|
||||
'key': SettingBoxKey.tabBarSort,
|
||||
'defaultBars': HomeTabType.values,
|
||||
'title': '首页标签页',
|
||||
},
|
||||
),
|
||||
title: '首页标签页',
|
||||
subtitle: '删除或调换首页标签页',
|
||||
leading: const Icon(Icons.toc_outlined),
|
||||
),
|
||||
NormalModel(
|
||||
onTap: (context, setState) => Get.toNamed(
|
||||
'/barSetting',
|
||||
arguments: {
|
||||
'key': SettingBoxKey.navBarSort,
|
||||
'defaultBars': NavigationBarType.values,
|
||||
'title': 'Navbar',
|
||||
},
|
||||
),
|
||||
title: 'Navbar编辑',
|
||||
subtitle: '删除或调换Navbar',
|
||||
leading: const Icon(Icons.toc_outlined),
|
||||
),
|
||||
SwitchModel(
|
||||
title: '返回时直接退出',
|
||||
subtitle: '开启后在主页任意tab按返回键都直接退出,关闭则先回到Navbar的第一个tab',
|
||||
leading: const Icon(Icons.exit_to_app_outlined),
|
||||
setKey: SettingBoxKey.directExitOnBack,
|
||||
defaultVal: false,
|
||||
onChanged: (value) => Get.find<MainController>().directExitOnBack = value,
|
||||
),
|
||||
];
|
||||
|
||||
void _showQualityDialog({
|
||||
@@ -334,107 +187,6 @@ void _showQualityDialog({
|
||||
});
|
||||
}
|
||||
|
||||
void _showUiScaleDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) {
|
||||
const minUiScale = 0.5;
|
||||
const maxUiScale = 2.0;
|
||||
|
||||
double uiScale = Pref.uiScale;
|
||||
final textController = TextEditingController(
|
||||
text: uiScale.toStringAsFixed(2),
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('界面缩放'),
|
||||
contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 12),
|
||||
content: StatefulBuilder(
|
||||
onDispose: textController.dispose,
|
||||
builder: (context, setDialogState) => Column(
|
||||
spacing: 20,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Slider(
|
||||
padding: .zero,
|
||||
value: uiScale,
|
||||
min: minUiScale,
|
||||
max: maxUiScale,
|
||||
secondaryTrackValue: 1.0,
|
||||
divisions: ((maxUiScale - minUiScale) * 20).toInt(),
|
||||
label: textController.text,
|
||||
onChanged: (value) => setDialogState(() {
|
||||
uiScale = value.toPrecision(2);
|
||||
textController.text = uiScale.toStringAsFixed(2);
|
||||
}),
|
||||
),
|
||||
TextFormField(
|
||||
controller: textController,
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true,
|
||||
),
|
||||
inputFormatters: [
|
||||
LengthLimitingTextInputFormatter(4),
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[\d.]+')),
|
||||
],
|
||||
decoration: const InputDecoration(
|
||||
labelText: '缩放比例',
|
||||
hintText: '0.50 - 2.00',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
onChanged: (value) {
|
||||
final parsed = double.tryParse(value);
|
||||
if (parsed != null &&
|
||||
parsed >= minUiScale &&
|
||||
parsed <= maxUiScale) {
|
||||
setDialogState(() {
|
||||
uiScale = parsed;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
GStorage.setting.delete(SettingBoxKey.uiScale).whenComplete(() {
|
||||
setState();
|
||||
Get.appUpdate();
|
||||
ScaledWidgetsFlutterBinding.instance.scaleFactor = 1.0;
|
||||
});
|
||||
},
|
||||
child: const Text('重置'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: ColorScheme.of(context).outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
GStorage.setting.put(SettingBoxKey.uiScale, uiScale).whenComplete(
|
||||
() {
|
||||
setState();
|
||||
Get.appUpdate();
|
||||
ScaledWidgetsFlutterBinding.instance.scaleFactor = uiScale;
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showSpringDialog(BuildContext context, _) {
|
||||
final List<String> springDescription = Pref.springDescription
|
||||
.map((i) => i.toString())
|
||||
@@ -729,69 +481,3 @@ Future<void> _showThemeTypeDialog(
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showDefHomeDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<NavigationBarType>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<NavigationBarType>(
|
||||
title: '首页启动页',
|
||||
value: Pref.defaultHomePage,
|
||||
values: NavigationBarType.values.map((e) => (e, e.label)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(SettingBoxKey.defaultHomePage, res.index);
|
||||
SmartDialog.showToast('设置成功,重启生效');
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showBarHideTypeDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) async {
|
||||
final res = await showDialog<BarHideType>(
|
||||
context: context,
|
||||
builder: (context) => SelectDialog<BarHideType>(
|
||||
title: '顶/底栏收起类型',
|
||||
value: Pref.barHideType,
|
||||
values: BarHideType.values.map((e) => (e, e.label)).toList(),
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
await GStorage.setting.put(SettingBoxKey.barHideType, res.index);
|
||||
SmartDialog.showToast('重启生效');
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
NormalModel _useSSDModel() {
|
||||
final file = File(path.join(appSupportDirPath, 'use_ssd'));
|
||||
void onChanged(BuildContext context, VoidCallback setState) {
|
||||
(file.existsSync() ? file.tryDel() : file.create()).whenComplete(() {
|
||||
if (context.mounted) {
|
||||
setState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return NormalModel(
|
||||
title: '使用SSD(Server-Side Decoration)',
|
||||
leading: const Icon(Icons.web_asset),
|
||||
onTap: onChanged,
|
||||
getTrailing: (theme) => Builder(
|
||||
builder: (context) => Transform.scale(
|
||||
scale: 0.8,
|
||||
alignment: .centerRight,
|
||||
child: Switch(
|
||||
value: file.existsSync(),
|
||||
onChanged: (_) =>
|
||||
onChanged(context, (context as Element).markNeedsBuild),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,44 +16,10 @@ import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/video_utils.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show FilteringTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
List<SettingsModel> get videoSettings => [
|
||||
const SwitchModel(
|
||||
title: '开启硬解',
|
||||
subtitle: '以较低功耗播放视频,若异常卡死请关闭',
|
||||
leading: Icon(Icons.flash_on_outlined),
|
||||
setKey: SettingBoxKey.enableHA,
|
||||
defaultVal: true,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '免登录1080P',
|
||||
subtitle: '免登录查看1080P视频',
|
||||
leading: Icon(Icons.hd_outlined),
|
||||
setKey: SettingBoxKey.p1080,
|
||||
defaultVal: true,
|
||||
),
|
||||
NormalModel(
|
||||
title: 'B站定向流量支持',
|
||||
subtitle: '若套餐含B站定向流量,则会自动使用。可查阅运营商的流量记录确认。',
|
||||
leading: const Icon(Icons.perm_data_setting_outlined),
|
||||
getTrailing: (theme) => IgnorePointer(
|
||||
child: Transform.scale(
|
||||
scale: 0.8,
|
||||
alignment: Alignment.centerRight,
|
||||
child: Switch(
|
||||
value: true,
|
||||
onChanged: (_) {},
|
||||
thumbIcon: WidgetStateProperty.all(
|
||||
const Icon(Icons.lock_outline_rounded),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
NormalModel(
|
||||
title: 'CDN 设置',
|
||||
leading: const Icon(MdiIcons.cloudPlusOutline),
|
||||
@@ -74,14 +40,6 @@ List<SettingsModel> get videoSettings => [
|
||||
setKey: SettingBoxKey.cdnSpeedTest,
|
||||
defaultVal: true,
|
||||
),
|
||||
SwitchModel(
|
||||
title: '音频不跟随 CDN 设置',
|
||||
subtitle: '直接采用备用 URL,可解决部分视频无声',
|
||||
leading: const Icon(MdiIcons.musicNotePlus),
|
||||
setKey: SettingBoxKey.disableAudioCDN,
|
||||
defaultVal: false,
|
||||
onChanged: (value) => VideoUtils.disableAudioCDN = value,
|
||||
),
|
||||
NormalModel(
|
||||
title: '默认画质',
|
||||
leading: const Icon(Icons.video_settings_outlined),
|
||||
@@ -144,19 +102,6 @@ List<SettingsModel> get videoSettings => [
|
||||
getSubtitle: () => '当前:${Pref.audioOutput}',
|
||||
onTap: _showAudioOutputDialog,
|
||||
),
|
||||
const SwitchModel(
|
||||
title: '扩大缓冲区',
|
||||
leading: Icon(Icons.storage_outlined),
|
||||
subtitle: '默认缓冲区为视频4MB/直播16MB,开启后为32MB/64MB,加载时间变长',
|
||||
setKey: SettingBoxKey.expandBuffer,
|
||||
defaultVal: false,
|
||||
),
|
||||
NormalModel(
|
||||
title: '自动同步',
|
||||
leading: const Icon(Icons.sync_rounded),
|
||||
getSubtitle: () => '当前:${Pref.autosync}(此项即mpv的--autosync)',
|
||||
onTap: _showAutoSyncDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '视频同步',
|
||||
leading: const Icon(Icons.view_timeline_outlined),
|
||||
@@ -454,43 +399,3 @@ Future<void> _showHwDecDialog(
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
void _showAutoSyncDialog(BuildContext context, VoidCallback setState) {
|
||||
String autosync = Pref.autosync.toString();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('自动同步'),
|
||||
content: TextFormField(
|
||||
autofocus: true,
|
||||
initialValue: autosync,
|
||||
keyboardType: TextInputType.number,
|
||||
onChanged: (value) => autosync = value,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: ColorScheme.of(context).outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
// validate
|
||||
int.parse(autosync);
|
||||
Get.back();
|
||||
await GStorage.setting.put(SettingBoxKey.autosync, autosync);
|
||||
setState();
|
||||
} catch (e) {
|
||||
SmartDialog.showToast(e.toString());
|
||||
}
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/widgets/pair.dart';
|
||||
import 'package:PiliPlus/common/widgets/reorder_mixin.dart';
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/models/common/enum_with_label.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -60,8 +61,7 @@ class _BarSetPageState extends State<BarSetPage> with ReorderMixin {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('$title编辑'),
|
||||
actions: [
|
||||
@@ -76,7 +76,7 @@ class _BarSetPageState extends State<BarSetPage> with ReorderMixin {
|
||||
footer: Padding(
|
||||
padding:
|
||||
MediaQuery.viewPaddingOf(context).copyWith(top: 0, left: 0) +
|
||||
const EdgeInsets.only(right: 34, top: 10),
|
||||
const .only(right: 34, top: 10),
|
||||
child: const Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text('*长按拖动排序'),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:PiliPlus/common/widgets/color_palette.dart';
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/main.dart' show MyApp;
|
||||
import 'package:PiliPlus/models/common/nav_bar_config.dart';
|
||||
import 'package:PiliPlus/models/common/theme/theme_color_type.dart';
|
||||
@@ -65,10 +66,10 @@ class _ColorSelectPageState extends State<ColorSelectPage> {
|
||||
final padding = MediaQuery.viewPaddingOf(
|
||||
context,
|
||||
).copyWith(top: 0, bottom: 0);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: AppBar(title: const Text('选择应用主题')),
|
||||
body: ListView(
|
||||
padding: .only(bottom: MediaQuery.viewPaddingOf(context).bottom),
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
import 'package:PiliPlus/utils/extension/num_ext.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';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class FontSizeSelectPage extends StatefulWidget {
|
||||
const FontSizeSelectPage({super.key});
|
||||
|
||||
@override
|
||||
State<FontSizeSelectPage> createState() => _FontSizeSelectPageState();
|
||||
}
|
||||
|
||||
class _FontSizeSelectPageState extends State<FontSizeSelectPage> {
|
||||
List<double> list = List.generate(16, (index) => 0.85 + index * 0.05);
|
||||
late double minSize = list.first;
|
||||
late double maxSize = list.last;
|
||||
double currentSize = Pref.defaultTextScale;
|
||||
|
||||
void setFontSize() {
|
||||
GStorage.setting.put(SettingBoxKey.defaultTextScale, currentSize);
|
||||
Get
|
||||
..back(result: currentSize)
|
||||
..appUpdate();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
currentSize = 1.0;
|
||||
setFontSize();
|
||||
},
|
||||
child: const Text('重置'),
|
||||
),
|
||||
TextButton(onPressed: setFontSize, child: const Text('确定')),
|
||||
const SizedBox(width: 12),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Text(
|
||||
'当前字体大小:${currentSize == 1.0 ? '默认' : currentSize}',
|
||||
style: TextStyle(fontSize: 14 * currentSize),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: theme.colorScheme.primary.withValues(alpha: 0.3),
|
||||
),
|
||||
),
|
||||
color: theme.colorScheme.surface,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Text('小'),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
min: minSize,
|
||||
value: currentSize,
|
||||
max: maxSize,
|
||||
divisions: list.length - 1,
|
||||
secondaryTrackValue: 1,
|
||||
onChanged: (double val) {
|
||||
currentSize = val.toPrecision(2);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
const Text(
|
||||
'大',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
import 'dart:io' show Platform;
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||
import 'package:PiliPlus/common/widgets/extra_hittest_stack.dart';
|
||||
import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
|
||||
import 'package:PiliPlus/pages/live_room/superchat/superchat_card.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.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';
|
||||
|
||||
const kFullScreenSCWidth = 255.0;
|
||||
|
||||
class FullScreenScSize extends StatefulWidget {
|
||||
const FullScreenScSize({super.key});
|
||||
|
||||
@override
|
||||
State<FullScreenScSize> createState() => _FullScreenScSizeState();
|
||||
}
|
||||
|
||||
class _FullScreenScSizeState extends State<FullScreenScSize> {
|
||||
double _width = Pref.fullScreenSCWidth;
|
||||
final _randomSC = SuperChatItem.random;
|
||||
late EdgeInsets _padding;
|
||||
late ColorScheme _colorScheme;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (Platform.isAndroid) {
|
||||
landscapeLeftMode();
|
||||
} else if (Platform.isIOS) {
|
||||
landscapeRightMode();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (PlatformUtils.isMobile) {
|
||||
if (Pref.horizontalScreen) {
|
||||
fullMode();
|
||||
} else {
|
||||
portraitUpMode();
|
||||
}
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
_padding = .only(
|
||||
right: padding.right + 17,
|
||||
left: padding.left + 25,
|
||||
bottom: padding.bottom + 25,
|
||||
);
|
||||
_colorScheme = ColorScheme.of(context);
|
||||
}
|
||||
|
||||
void _onReset() {
|
||||
_width = kFullScreenSCWidth;
|
||||
GStorage.setting.delete(SettingBoxKey.fullScreenSCWidth);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: const Text('全屏 SC 大小设置'),
|
||||
actions: [
|
||||
TextButton(onPressed: _onReset, child: const Text('重置')),
|
||||
],
|
||||
),
|
||||
body: Padding(padding: _padding, child: _buildBody),
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _buildBody {
|
||||
return Align(
|
||||
alignment: .bottomLeft,
|
||||
child: ExtraHitTestStack(
|
||||
clipBehavior: .none,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: _width,
|
||||
child: IgnorePointer(
|
||||
child: SuperChatCard(
|
||||
item: _randomSC,
|
||||
persistentSC: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: -17,
|
||||
width: 34,
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.resizeRight,
|
||||
child: GestureDetector(
|
||||
behavior: .opaque,
|
||||
onHorizontalDragUpdate: _onHorizontalDragUpdate,
|
||||
onHorizontalDragEnd: _onHorizontalDragEnd,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
shape: .circle,
|
||||
color: _colorScheme.secondaryContainer.withValues(
|
||||
alpha: .8,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
size: 18,
|
||||
CustomIcons.open_in_full_rotate_45,
|
||||
color: _colorScheme.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onHorizontalDragUpdate(DragUpdateDetails details) {
|
||||
_width = math.max(25.0, _width + details.delta.dx);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
void _onHorizontalDragEnd(DragEndDetails details) {
|
||||
GStorage.setting.put(SettingBoxKey.fullScreenSCWidth, _width);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/services/logger.dart';
|
||||
import 'package:PiliPlus/utils/date_utils.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
@@ -17,8 +16,6 @@ import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
|
||||
const _snackBarDisplayDuration = Duration(seconds: 1);
|
||||
|
||||
class LogsPage extends StatefulWidget {
|
||||
const LogsPage({super.key});
|
||||
|
||||
@@ -75,29 +72,13 @@ class _LogsPageState extends State<LogsPage> {
|
||||
}
|
||||
|
||||
void copyLogs() {
|
||||
Utils.copyText(
|
||||
'```\n${logsContent.join('\n\n')}```',
|
||||
needToast: false,
|
||||
);
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('复制成功'),
|
||||
duration: _snackBarDisplayDuration,
|
||||
),
|
||||
);
|
||||
}
|
||||
Utils.copyText('```\n${logsContent.join('\n\n')}```');
|
||||
}
|
||||
|
||||
Future<void> clearLogs() async {
|
||||
if (await LoggerUtils.clearLogs()) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('已清空'),
|
||||
duration: _snackBarDisplayDuration,
|
||||
),
|
||||
);
|
||||
SmartDialog.showToast('已清空');
|
||||
logsContent.clear();
|
||||
setState(() {});
|
||||
}
|
||||
@@ -107,8 +88,7 @@ class _LogsPageState extends State<LogsPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('日志'),
|
||||
actions: [
|
||||
@@ -140,11 +120,6 @@ class _LogsPageState extends State<LogsPage> {
|
||||
onTap: copyLogs,
|
||||
child: const Text('复制日志'),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () =>
|
||||
PageUtils.launchURL('${Constants.sourceCodeUrl}/issues'),
|
||||
child: const Text('错误反馈'),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
latestLog = null;
|
||||
@@ -334,15 +309,7 @@ class ReportCard extends StatelessWidget {
|
||||
iconButton(
|
||||
size: 34,
|
||||
iconSize: 22,
|
||||
onPressed: () {
|
||||
Utils.copyText('```\n$report```', needToast: false);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('已将 $dateTime 复制至剪贴板'),
|
||||
duration: _snackBarDisplayDuration,
|
||||
),
|
||||
);
|
||||
},
|
||||
onPressed: () => Utils.copyText('```\n$report```'),
|
||||
icon: const Icon(
|
||||
Icons.copy_outlined,
|
||||
size: 16,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:PiliPlus/common/widgets/flutter/list_tile.dart';
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/common/widgets/view_safe_area.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/switch_item.dart';
|
||||
import 'package:PiliPlus/utils/extension/context_ext.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
@@ -24,7 +24,6 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
||||
late double playSpeedDefault = Pref.playSpeedDefault;
|
||||
late double longPressSpeedDefault = Pref.longPressSpeedDefault;
|
||||
late List<double> speedList = Pref.speedList;
|
||||
late bool enableAutoLongPressSpeed = Pref.enableAutoLongPressSpeed;
|
||||
List<({int id, String title, Icon icon})> sheetMenu = [
|
||||
(
|
||||
id: 1,
|
||||
@@ -130,9 +129,6 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
||||
const SizedBox(height: 10),
|
||||
...sheetMenu.map(
|
||||
(item) => ListTile(
|
||||
enabled: enableAutoLongPressSpeed && item.id == 2
|
||||
? false
|
||||
: true,
|
||||
onTap: () {
|
||||
Get.back();
|
||||
menuAction(index, item.id);
|
||||
@@ -183,8 +179,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('倍速设置'),
|
||||
actions: [
|
||||
@@ -201,6 +196,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
||||
),
|
||||
body: ViewSafeArea(
|
||||
child: ListView(
|
||||
padding: .zero,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
@@ -218,19 +214,10 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
||||
title: const Text('默认倍速'),
|
||||
subtitle: Text(playSpeedDefault.toString()),
|
||||
),
|
||||
SetSwitchItem(
|
||||
title: '动态长按倍速',
|
||||
subtitle: '根据默认倍速长按时自动双倍',
|
||||
setKey: SettingBoxKey.enableAutoLongPressSpeed,
|
||||
defaultVal: enableAutoLongPressSpeed,
|
||||
onChanged: (val) =>
|
||||
setState(() => enableAutoLongPressSpeed = val),
|
||||
ListTile(
|
||||
title: const Text('默认长按倍速'),
|
||||
subtitle: Text(longPressSpeedDefault.toString()),
|
||||
),
|
||||
if (!enableAutoLongPressSpeed)
|
||||
ListTile(
|
||||
title: const Text('默认长按倍速'),
|
||||
subtitle: Text(longPressSpeedDefault.toString()),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 14,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/play_settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -17,8 +18,7 @@ class _PlaySettingState extends State<PlaySetting> {
|
||||
Widget build(BuildContext context) {
|
||||
final showAppBar = widget.showAppBar;
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: showAppBar ? AppBar(title: const Text('播放器设置')) : null,
|
||||
body: ListView.builder(
|
||||
padding: EdgeInsets.only(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/privacy_settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -17,11 +18,10 @@ class _PrivacySettingState extends State<PrivacySetting> {
|
||||
Widget build(BuildContext context) {
|
||||
final showAppBar = widget.showAppBar;
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: showAppBar ? AppBar(title: const Text('隐私设置')) : null,
|
||||
body: ListView(
|
||||
padding: EdgeInsets.only(
|
||||
padding: .only(
|
||||
left: showAppBar ? padding.left : 0,
|
||||
right: showAppBar ? padding.right : 0,
|
||||
bottom: padding.bottom + 100,
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import 'package:PiliPlus/common/widgets/flutter/list_tile.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/recommend_settings.dart';
|
||||
import 'package:flutter/material.dart' hide ListTile;
|
||||
|
||||
class RecommendSetting extends StatefulWidget {
|
||||
const RecommendSetting({super.key, this.showAppBar = true});
|
||||
|
||||
final bool showAppBar;
|
||||
|
||||
@override
|
||||
State<RecommendSetting> createState() => _RecommendSettingState();
|
||||
}
|
||||
|
||||
class _RecommendSettingState extends State<RecommendSetting> {
|
||||
final list = recommendSettings;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final showAppBar = widget.showAppBar;
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
final theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: widget.showAppBar ? AppBar(title: const Text('推荐流设置')) : null,
|
||||
body: ListView(
|
||||
padding: EdgeInsets.only(
|
||||
left: showAppBar ? padding.left : 0,
|
||||
right: showAppBar ? padding.right : 0,
|
||||
bottom: padding.bottom + 100,
|
||||
),
|
||||
children: [
|
||||
...list.take(4).map((item) => item.widget),
|
||||
const Divider(height: 1),
|
||||
...list.skip(4).map((item) => item.widget),
|
||||
ListTile(
|
||||
dense: true,
|
||||
subtitle: Text(
|
||||
'¹ 由于接口未提供关注信息,无法豁免相关视频中的已关注Up。\n\n'
|
||||
'* 其它(如热门视频、手动搜索、链接跳转等)均不受过滤器影响。\n'
|
||||
'* 设定较严苛的条件可导致推荐项数锐减或多次请求,请酌情选择。\n'
|
||||
'* 后续可能会增加更多过滤条件,敬请期待。',
|
||||
style: theme.textTheme.labelSmall!.copyWith(
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/style_settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -17,8 +18,7 @@ class _StyleSettingState extends State<StyleSetting> {
|
||||
Widget build(BuildContext context) {
|
||||
final showAppBar = widget.showAppBar;
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: showAppBar ? AppBar(title: const Text('外观设置')) : null,
|
||||
body: ListView.builder(
|
||||
padding: EdgeInsets.only(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/video_settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -17,8 +18,7 @@ class _VideoSettingState extends State<VideoSetting> {
|
||||
Widget build(BuildContext context) {
|
||||
final showAppBar = widget.showAppBar;
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
return scaffold(
|
||||
appBar: showAppBar ? AppBar(title: const Text('音视频设置')) : null,
|
||||
body: ListView.builder(
|
||||
padding: EdgeInsets.only(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:PiliPlus/common/widgets/flutter/list_tile.dart';
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/common/widgets/view_safe_area.dart';
|
||||
import 'package:PiliPlus/http/login.dart';
|
||||
import 'package:PiliPlus/models/common/setting_type.dart';
|
||||
@@ -7,18 +8,15 @@ import 'package:PiliPlus/pages/login/controller.dart';
|
||||
import 'package:PiliPlus/pages/setting/extra_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/play_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/privacy_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/recommend_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/style_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/video_setting.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/multi_select_dialog.dart';
|
||||
import 'package:PiliPlus/pages/webdav/view.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/accounts/account.dart';
|
||||
import 'package:PiliPlus/utils/extension/size_ext.dart';
|
||||
import 'package:flutter/material.dart' hide ListTile;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
class _SettingsModel {
|
||||
final SettingType type;
|
||||
@@ -50,11 +48,6 @@ class _SettingPageState extends State<SettingPage> {
|
||||
subtitle: '黑名单、无痕模式',
|
||||
icon: Icon(Icons.privacy_tip_outlined),
|
||||
),
|
||||
_SettingsModel(
|
||||
type: SettingType.recommendSetting,
|
||||
subtitle: '推荐来源(web/app)、刷新保留内容、过滤器',
|
||||
icon: Icon(Icons.explore_outlined),
|
||||
),
|
||||
_SettingsModel(
|
||||
type: SettingType.videoSetting,
|
||||
subtitle: '画质、音质、解码、缓冲、音频输出等',
|
||||
@@ -75,10 +68,6 @@ class _SettingPageState extends State<SettingPage> {
|
||||
subtitle: '震动、搜索、收藏、ai、评论、动态、代理、更新检查等',
|
||||
icon: Icon(Icons.extension_outlined),
|
||||
),
|
||||
_SettingsModel(
|
||||
type: SettingType.webdavSetting,
|
||||
icon: Icon(MdiIcons.databaseCogOutline),
|
||||
),
|
||||
_SettingsModel(
|
||||
type: SettingType.about,
|
||||
icon: Icon(Icons.info_outline),
|
||||
@@ -89,11 +78,8 @@ class _SettingPageState extends State<SettingPage> {
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
_isPortrait = MediaQuery.sizeOf(context).isPortrait;
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: _isPortrait ? const Text('设置') : Text(_type.title),
|
||||
),
|
||||
return scaffold(
|
||||
appBar: AppBar(title: _isPortrait ? const Text('设置') : Text(_type.title)),
|
||||
body: ViewSafeArea(
|
||||
child: _isPortrait
|
||||
? _buildList(theme)
|
||||
@@ -114,9 +100,6 @@ class _SettingPageState extends State<SettingPage> {
|
||||
SettingType.privacySetting => const PrivacySetting(
|
||||
showAppBar: false,
|
||||
),
|
||||
SettingType.recommendSetting => const RecommendSetting(
|
||||
showAppBar: false,
|
||||
),
|
||||
SettingType.videoSetting => const VideoSetting(
|
||||
showAppBar: false,
|
||||
),
|
||||
@@ -129,9 +112,6 @@ class _SettingPageState extends State<SettingPage> {
|
||||
SettingType.extraSetting => const ExtraSetting(
|
||||
showAppBar: false,
|
||||
),
|
||||
SettingType.webdavSetting => const WebDavSettingPage(
|
||||
showAppBar: false,
|
||||
),
|
||||
SettingType.about => const AboutPage(showAppBar: false),
|
||||
},
|
||||
),
|
||||
@@ -171,7 +151,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
color: theme.colorScheme.outline,
|
||||
);
|
||||
return ListView(
|
||||
padding: EdgeInsets.only(bottom: padding.bottom + 100),
|
||||
padding: .only(bottom: padding.bottom + 100),
|
||||
children: [
|
||||
_buildSearchItem(theme),
|
||||
..._items
|
||||
|
||||
Reference in New Issue
Block a user