diff --git a/lib/common/widgets/image_save.dart b/lib/common/widgets/image_save.dart index 6d0fa14d..aa5cee4f 100644 --- a/lib/common/widgets/image_save.dart +++ b/lib/common/widgets/image_save.dart @@ -84,7 +84,11 @@ void imageSaveDialog({ SmartDialog.dismiss(); } }, - icon: const Icon(Icons.download, size: 20), + icon: Icon( + Icons.download, + size: 20, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), ) ], ), diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 948757d2..3235a811 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -7,6 +7,7 @@ import 'package:PiliPlus/common/widgets/segment_progress_bar.dart'; import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/user.dart'; +import 'package:PiliPlus/main.dart'; import 'package:PiliPlus/models/common/sponsor_block/action_type.dart'; import 'package:PiliPlus/models/common/sponsor_block/post_segment_model.dart'; import 'package:PiliPlus/models/common/sponsor_block/segment_model.dart'; @@ -1331,11 +1332,21 @@ class VideoDetailController extends GetxController } if (plPlayerController.isFullScreen.value) { Utils.showFSSheet( - child: PostPanel( - enableSlide: false, - videoDetailController: this, - plPlayerController: plPlayerController, - ), + context, + child: plPlayerController.darkVideoPage && MyApp.darkThemeData != null + ? Theme( + data: MyApp.darkThemeData!, + child: PostPanel( + enableSlide: false, + videoDetailController: this, + plPlayerController: plPlayerController, + ), + ) + : PostPanel( + enableSlide: false, + videoDetailController: this, + plPlayerController: plPlayerController, + ), isFullScreen: () => plPlayerController.isFullScreen.value, ); } else { @@ -1597,10 +1608,19 @@ class VideoDetailController extends GetxController void showNoteList(BuildContext context) async { if (plPlayerController.isFullScreen.value) { Utils.showFSSheet( - child: NoteListPage( - oid: oid.value, - enableSlide: false, - ), + context, + child: plPlayerController.darkVideoPage && MyApp.darkThemeData != null + ? Theme( + data: MyApp.darkThemeData!, + child: NoteListPage( + oid: oid.value, + enableSlide: false, + ), + ) + : NoteListPage( + oid: oid.value, + enableSlide: false, + ), isFullScreen: () => plPlayerController.isFullScreen.value, ); } else { diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 3bdadd7d..cbc113b0 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -1813,7 +1813,11 @@ class _VideoDetailPageState extends State ); if (isFullScreen) { Utils.showFSSheet( - child: listSheetContent(false), + context, + child: Theme( + data: themeData, + child: listSheetContent(false), + ), isFullScreen: () => isFullScreen, ); } else { @@ -1897,10 +1901,14 @@ class _VideoDetailPageState extends State void showViewPoints() { if (isFullScreen) { Utils.showFSSheet( - child: ViewPointsPage( - enableSlide: false, - videoDetailController: videoDetailController, - plPlayerController: plPlayerController, + context, + child: Theme( + data: themeData, + child: ViewPointsPage( + enableSlide: false, + videoDetailController: videoDetailController, + plPlayerController: plPlayerController, + ), ), isFullScreen: () => isFullScreen, ); diff --git a/lib/pages/video/detail/view_v.dart b/lib/pages/video/detail/view_v.dart index 0438df45..6d3f026c 100644 --- a/lib/pages/video/detail/view_v.dart +++ b/lib/pages/video/detail/view_v.dart @@ -2217,7 +2217,11 @@ class _VideoDetailPageVState extends State ); if (isFullScreen) { Utils.showFSSheet( - child: listSheetContent(false), + context, + child: Theme( + data: themeData, + child: listSheetContent(false), + ), isFullScreen: () => isFullScreen, ); } else { @@ -2301,10 +2305,14 @@ class _VideoDetailPageVState extends State void showViewPoints() { if (isFullScreen) { Utils.showFSSheet( - child: ViewPointsPage( - enableSlide: false, - videoDetailController: videoDetailController, - plPlayerController: plPlayerController, + context, + child: Theme( + data: themeData, + child: ViewPointsPage( + enableSlide: false, + videoDetailController: videoDetailController, + plPlayerController: plPlayerController, + ), ), isFullScreen: () => isFullScreen, ); diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 3597fd9a..74b67e9f 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -97,24 +97,21 @@ class _HeaderControlState extends State { /// 设置面板 void showSettingSheet() { Utils.showFSSheet( + context, isFullScreen: () => isFullScreen, - child: Builder( - builder: (context) => Container( + child: Theme( + data: Theme.of(context), + child: Container( clipBehavior: Clip.hardEdge, decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: const BorderRadius.all(Radius.circular(12)), ), - margin: EdgeInsets.only( - left: 12, - top: 12, - right: 12, - bottom: 12 + MediaQuery.paddingOf(context).bottom, - ), + margin: const EdgeInsets.all(12), child: Material( color: Colors.transparent, child: ListView( - padding: EdgeInsets.only(bottom: 0), + padding: EdgeInsets.zero, children: [ const SizedBox(height: 14), // ListTile( @@ -564,171 +561,179 @@ class _HeaderControlState extends State { void scheduleExit() async { const List scheduleTimeChoices = [0, 15, 30, 45, 60]; Utils.showFSSheet( + context, isFullScreen: () => isFullScreen, child: StatefulBuilder( - builder: (context, setState) { - return Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.all(Radius.circular(12)), - ), - margin: EdgeInsets.only( - left: 12, - top: 12, - right: 12, - bottom: 12 + MediaQuery.paddingOf(context).bottom, - ), - padding: const EdgeInsets.only(left: 14, right: 14), - child: ListView( - padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 20), - children: [ - const SizedBox(height: 10), - const Center(child: Text('定时关闭', style: titleStyle)), - const SizedBox(height: 10), - ...[ - ...[ - ...scheduleTimeChoices, - if (scheduleTimeChoices - .contains(shutdownTimerService.scheduledExitInMinutes) - .not) - shutdownTimerService.scheduledExitInMinutes, - ]..sort(), - -1, - ].map( - (choice) => ListTile( - dense: true, - onTap: () { - if (choice == -1) { - showDialog( - context: context, - builder: (context) { - String duration = ''; - return AlertDialog( - title: const Text('自定义时长'), - content: TextField( - autofocus: true, - onChanged: (value) => duration = value, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'\d+')), - ], - decoration: - const InputDecoration(suffixText: 'min'), - ), - actions: [ - TextButton( - onPressed: Get.back, - child: Text( - '取消', - style: TextStyle( - color: Theme.of(context) - .colorScheme - .outline), + builder: (_, setState) { + return Theme( + data: Theme.of(context), + child: Material( + color: Colors.transparent, + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(12), + padding: const EdgeInsets.only(left: 14, right: 14), + child: ListView( + padding: + const EdgeInsets.symmetric(vertical: 0, horizontal: 20), + children: [ + const SizedBox(height: 10), + const Center(child: Text('定时关闭', style: titleStyle)), + const SizedBox(height: 10), + ...[ + ...[ + ...scheduleTimeChoices, + if (scheduleTimeChoices + .contains( + shutdownTimerService.scheduledExitInMinutes) + .not) + shutdownTimerService.scheduledExitInMinutes, + ]..sort(), + -1, + ].map( + (choice) => ListTile( + dense: true, + onTap: () { + if (choice == -1) { + showDialog( + context: context, + builder: (context) { + String duration = ''; + return AlertDialog( + title: const Text('自定义时长'), + content: TextField( + autofocus: true, + onChanged: (value) => duration = value, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'\d+')), + ], + decoration: const InputDecoration( + suffixText: 'min'), ), - ), - TextButton( - onPressed: () { - Get.back(); - int choice = int.tryParse(duration) ?? 0; - shutdownTimerService - .scheduledExitInMinutes = choice; - shutdownTimerService.startShutdownTimer(); - setState(() {}); - }, - child: Text('确定'), - ), - ], + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: TextStyle( + color: Theme.of(context) + .colorScheme + .outline), + ), + ), + TextButton( + onPressed: () { + Get.back(); + int choice = + int.tryParse(duration) ?? 0; + shutdownTimerService + .scheduledExitInMinutes = choice; + shutdownTimerService + .startShutdownTimer(); + setState(() {}); + }, + child: Text('确定'), + ), + ], + ); + }, ); - }, - ); - } else { - Get.back(); - shutdownTimerService.scheduledExitInMinutes = choice; - shutdownTimerService.startShutdownTimer(); - } - }, - contentPadding: const EdgeInsets.only(), - title: Text(choice == -1 - ? '自定义' - : choice == 0 - ? "禁用" - : "$choice分钟后"), - trailing: - shutdownTimerService.scheduledExitInMinutes == choice + } else { + Get.back(); + shutdownTimerService.scheduledExitInMinutes = + choice; + shutdownTimerService.startShutdownTimer(); + } + }, + contentPadding: const EdgeInsets.only(), + title: Text(choice == -1 + ? '自定义' + : choice == 0 + ? "禁用" + : "$choice分钟后"), + trailing: shutdownTimerService.scheduledExitInMinutes == + choice ? Icon( Icons.done, color: Theme.of(context).colorScheme.primary, ) : null, - ), - ), - const SizedBox(height: 6), - const Center( - child: SizedBox( - width: 125, - child: Divider(height: 1), - ), - ), - const SizedBox(height: 10), - ListTile( - dense: true, - onTap: () { - shutdownTimerService.waitForPlayingCompleted = - !shutdownTimerService.waitForPlayingCompleted; - setState(() {}); - }, - contentPadding: const EdgeInsets.only(), - title: const Text("额外等待视频播放完毕", style: titleStyle), - trailing: Transform.scale( - alignment: - Alignment.centerRight, // 缩放Switch的大小后保持右侧对齐, 避免右侧空隙过大 - scale: 0.8, - child: Switch( - thumbIcon: WidgetStateProperty.resolveWith( - (Set states) { - if (states.isNotEmpty && - states.first == WidgetState.selected) { - return const Icon(Icons.done); - } - return null; - }), - value: shutdownTimerService.waitForPlayingCompleted, - onChanged: (value) => setState(() => - shutdownTimerService.waitForPlayingCompleted = value), + ), ), - ), - ), - const SizedBox(height: 10), - Row( - children: [ - const Text('倒计时结束:', style: titleStyle), - const Spacer(), - ActionRowLineItem( - onTap: () { - shutdownTimerService.exitApp = false; - setState(() {}); - // Get.back(); - }, - text: " 暂停视频 ", - selectStatus: !shutdownTimerService.exitApp, + const SizedBox(height: 6), + const Center( + child: SizedBox( + width: 125, + child: Divider(height: 1), + ), ), - const Spacer(), - // const SizedBox(width: 10), - ActionRowLineItem( + const SizedBox(height: 10), + ListTile( + dense: true, onTap: () { - shutdownTimerService.exitApp = true; + shutdownTimerService.waitForPlayingCompleted = + !shutdownTimerService.waitForPlayingCompleted; setState(() {}); - // Get.back(); }, - text: " 退出APP ", - selectStatus: shutdownTimerService.exitApp, - ) + contentPadding: const EdgeInsets.only(), + title: const Text("额外等待视频播放完毕", style: titleStyle), + trailing: Transform.scale( + alignment: Alignment + .centerRight, // 缩放Switch的大小后保持右侧对齐, 避免右侧空隙过大 + scale: 0.8, + child: Switch( + thumbIcon: WidgetStateProperty.resolveWith( + (Set states) { + if (states.isNotEmpty && + states.first == WidgetState.selected) { + return const Icon(Icons.done); + } + return null; + }), + value: shutdownTimerService.waitForPlayingCompleted, + onChanged: (value) => setState(() => + shutdownTimerService.waitForPlayingCompleted = + value), + ), + ), + ), + const SizedBox(height: 10), + Row( + children: [ + const Text('倒计时结束:', style: titleStyle), + const Spacer(), + ActionRowLineItem( + onTap: () { + shutdownTimerService.exitApp = false; + setState(() {}); + // Get.back(); + }, + text: " 暂停视频 ", + selectStatus: !shutdownTimerService.exitApp, + ), + const Spacer(), + // const SizedBox(width: 10), + ActionRowLineItem( + onTap: () { + shutdownTimerService.exitApp = true; + setState(() {}); + // Get.back(); + }, + text: " 退出APP ", + selectStatus: shutdownTimerService.exitApp, + ) + ], + ), + const SizedBox(height: 10), ], ), - const SizedBox(height: 10), - ], + ), ), ); }, @@ -761,98 +766,98 @@ class _HeaderControlState extends State { } Utils.showFSSheet( + context, isFullScreen: () => isFullScreen, - child: Builder( - builder: (context) => Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.all(Radius.circular(12)), - ), - margin: EdgeInsets.only( - left: 12, - top: 12, - right: 12, - bottom: 12 + MediaQuery.paddingOf(context).bottom, - ), - child: Column( - children: [ - SizedBox( - height: 45, - child: GestureDetector( - onTap: () { - SmartDialog.showToast( - '标灰画质需要bilibili会员(已是会员?请关闭无痕模式);4k和杜比视界播放效果可能不佳'); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('选择画质', style: titleStyle), - SizedBox(width: buttonSpace), - Icon( - Icons.info_outline, - size: 16, - color: Theme.of(context).colorScheme.outline, - ) - ], - ), - ), - ), - Expanded( - child: Material( - color: Colors.transparent, - child: Scrollbar( - child: ListView( - padding: EdgeInsets.only(bottom: 0), + child: Theme( + data: Theme.of(context), + child: Material( + color: Colors.transparent, + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(12), + child: Column( + children: [ + SizedBox( + height: 45, + child: GestureDetector( + onTap: () { + SmartDialog.showToast( + '标灰画质需要bilibili会员(已是会员?请关闭无痕模式);4k和杜比视界播放效果可能不佳'); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - for (int i = 0; i < totalQaSam; i++) ...[ - ListTile( - dense: true, - onTap: () { - if (currentVideoQa.code == - videoFormat[i].quality) { - return; - } - Get.back(); - final int quality = videoFormat[i].quality!; - videoDetailCtr.currentVideoQa = - VideoQualityCode.fromCode(quality)!; - videoDetailCtr.updatePlayer(); - // String oldQualityDesc = - // VideoQualityCode.fromCode(setting.get( - // SettingBoxKey.defaultVideoQa, - // defaultValue: - // VideoQuality.values.last.code))! - // .description; - // setting.put( - // SettingBoxKey.defaultVideoQa, quality); - // SmartDialog.showToast( - // "默认画质由:$oldQualityDesc 变为:${VideoQualityCode.fromCode(quality)!.description}"); - }, - // 可能包含会员解锁画质 - enabled: i >= totalQaSam - userfulQaSam, - contentPadding: - const EdgeInsets.only(left: 20, right: 20), - title: Text(videoFormat[i].newDesc!), - trailing: currentVideoQa.code == - videoFormat[i].quality - ? Icon( - Icons.done, - color: - Theme.of(context).colorScheme.primary, - ) - : Text( - videoFormat[i].format!, - style: subTitleStyle, - ), - ), - ] + const Text('选择画质', style: titleStyle), + SizedBox(width: buttonSpace), + Icon( + Icons.info_outline, + size: 16, + color: Theme.of(context).colorScheme.outline, + ) ], ), ), ), - ), - ], + Expanded( + child: Material( + color: Colors.transparent, + child: Scrollbar( + child: ListView( + padding: EdgeInsets.zero, + children: [ + for (int i = 0; i < totalQaSam; i++) ...[ + ListTile( + dense: true, + onTap: () { + if (currentVideoQa.code == + videoFormat[i].quality) { + return; + } + Get.back(); + final int quality = videoFormat[i].quality!; + videoDetailCtr.currentVideoQa = + VideoQualityCode.fromCode(quality)!; + videoDetailCtr.updatePlayer(); + // String oldQualityDesc = + // VideoQualityCode.fromCode(setting.get( + // SettingBoxKey.defaultVideoQa, + // defaultValue: + // VideoQuality.values.last.code))! + // .description; + // setting.put( + // SettingBoxKey.defaultVideoQa, quality); + // SmartDialog.showToast( + // "默认画质由:$oldQualityDesc 变为:${VideoQualityCode.fromCode(quality)!.description}"); + }, + // 可能包含会员解锁画质 + enabled: i >= totalQaSam - userfulQaSam, + contentPadding: + const EdgeInsets.only(left: 20, right: 20), + title: Text(videoFormat[i].newDesc!), + trailing: currentVideoQa.code == + videoFormat[i].quality + ? Icon( + Icons.done, + color: + Theme.of(context).colorScheme.primary, + ) + : Text( + videoFormat[i].format!, + style: subTitleStyle, + ), + ), + ] + ], + ), + ), + ), + ), + ], + ), ), ), ), @@ -864,73 +869,74 @@ class _HeaderControlState extends State { final AudioQuality currentAudioQa = videoDetailCtr.currentAudioQa!; final List audio = videoInfo.dash!.audio!; Utils.showFSSheet( + context, isFullScreen: () => isFullScreen, - child: Builder( - builder: (context) => Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.all(Radius.circular(12)), - ), - margin: EdgeInsets.only( - left: 12, - top: 12, - right: 12, - bottom: 12 + MediaQuery.paddingOf(context).bottom, - ), - child: Column( - children: [ - const SizedBox( - height: 45, - child: Center(child: Text('选择音质', style: titleStyle))), - Expanded( - child: Material( - color: Colors.transparent, - child: ListView( - padding: EdgeInsets.only(bottom: 0), - children: [ - for (final AudioItem i in audio) ...[ - ListTile( - dense: true, - onTap: () { - if (currentAudioQa.code == i.id) { - return; - } - Get.back(); - final int quality = i.id!; - videoDetailCtr.currentAudioQa = - AudioQualityCode.fromCode(quality)!; - videoDetailCtr.updatePlayer(); - // String oldQualityDesc = AudioQualityCode.fromCode( - // setting.get(SettingBoxKey.defaultAudioQa, - // defaultValue: - // AudioQuality.values.last.code))! - // .description; - // setting.put( - // SettingBoxKey.defaultAudioQa, quality); - // SmartDialog.showToast( - // "默认音质由:$oldQualityDesc 变为:${AudioQualityCode.fromCode(quality)!.description}"); - }, - contentPadding: - const EdgeInsets.only(left: 20, right: 20), - title: Text(i.quality!), - subtitle: Text( - i.codecs!, - style: subTitleStyle, + child: Theme( + data: Theme.of(context), + child: Material( + color: Colors.transparent, + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(12), + child: Column( + children: [ + const SizedBox( + height: 45, + child: Center(child: Text('选择音质', style: titleStyle))), + Expanded( + child: Material( + color: Colors.transparent, + child: ListView( + padding: EdgeInsets.zero, + children: [ + for (final AudioItem i in audio) ...[ + ListTile( + dense: true, + onTap: () { + if (currentAudioQa.code == i.id) { + return; + } + Get.back(); + final int quality = i.id!; + videoDetailCtr.currentAudioQa = + AudioQualityCode.fromCode(quality)!; + videoDetailCtr.updatePlayer(); + // String oldQualityDesc = AudioQualityCode.fromCode( + // setting.get(SettingBoxKey.defaultAudioQa, + // defaultValue: + // AudioQuality.values.last.code))! + // .description; + // setting.put( + // SettingBoxKey.defaultAudioQa, quality); + // SmartDialog.showToast( + // "默认音质由:$oldQualityDesc 变为:${AudioQualityCode.fromCode(quality)!.description}"); + }, + contentPadding: + const EdgeInsets.only(left: 20, right: 20), + title: Text(i.quality!), + subtitle: Text( + i.codecs!, + style: subTitleStyle, + ), + trailing: currentAudioQa.code == i.id + ? Icon( + Icons.done, + color: + Theme.of(context).colorScheme.primary, + ) + : const SizedBox(), ), - trailing: currentAudioQa.code == i.id - ? Icon( - Icons.done, - color: Theme.of(context).colorScheme.primary, - ) - : const SizedBox(), - ), - ] - ], + ] + ], + ), ), ), - ), - ], + ], + ), ), ), ), @@ -954,64 +960,65 @@ class _HeaderControlState extends State { } Utils.showFSSheet( + context, isFullScreen: () => isFullScreen, - child: Builder( - builder: (context) => Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.all(Radius.circular(12)), - ), - margin: EdgeInsets.only( - left: 12, - top: 12, - right: 12, - bottom: 12 + MediaQuery.paddingOf(context).bottom, - ), - child: Column( - children: [ - const SizedBox( - height: 45, - child: Center(child: Text('选择解码格式', style: titleStyle))), - Expanded( - child: Material( - color: Colors.transparent, - child: ListView( - padding: EdgeInsets.only(bottom: 0), - children: [ - for (var i in list) ...[ - ListTile( - dense: true, - onTap: () { - if (i.startsWith(currentDecodeFormats.code)) { - return; - } - videoDetailCtr.currentDecodeFormats = - VideoDecodeFormatsCode.fromString(i)!; - videoDetailCtr.updatePlayer(); - Get.back(); - }, - contentPadding: - const EdgeInsets.only(left: 20, right: 20), - title: Text(VideoDecodeFormatsCode.fromString(i)! - .description!), - subtitle: Text( - i!, - style: subTitleStyle, + child: Theme( + data: Theme.of(context), + child: Material( + color: Colors.transparent, + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(12), + child: Column( + children: [ + const SizedBox( + height: 45, + child: Center(child: Text('选择解码格式', style: titleStyle))), + Expanded( + child: Material( + color: Colors.transparent, + child: ListView( + padding: EdgeInsets.zero, + children: [ + for (var i in list) ...[ + ListTile( + dense: true, + onTap: () { + if (i.startsWith(currentDecodeFormats.code)) { + return; + } + videoDetailCtr.currentDecodeFormats = + VideoDecodeFormatsCode.fromString(i)!; + videoDetailCtr.updatePlayer(); + Get.back(); + }, + contentPadding: + const EdgeInsets.only(left: 20, right: 20), + title: Text(VideoDecodeFormatsCode.fromString(i)! + .description!), + subtitle: Text( + i!, + style: subTitleStyle, + ), + trailing: i.startsWith(currentDecodeFormats.code) + ? Icon( + Icons.done, + color: + Theme.of(context).colorScheme.primary, + ) + : const SizedBox(), ), - trailing: i.startsWith(currentDecodeFormats.code) - ? Icon( - Icons.done, - color: Theme.of(context).colorScheme.primary, - ) - : const SizedBox(), - ), - ] - ], + ] + ], + ), ), ), - ), - ], + ], + ), ), ), ), @@ -1062,670 +1069,695 @@ class _HeaderControlState extends State { final DanmakuController? danmakuController = widget.controller.danmakuController; Utils.showFSSheet( + context, isFullScreen: () => isFullScreen, padding: isFullScreen ? 70 : null, child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.all(Radius.circular(12)), - ), - margin: EdgeInsets.only( - left: 12, - top: 12, - right: 12, - bottom: MediaQuery.paddingOf(context).bottom + 12, - ), - padding: const EdgeInsets.only(left: 14, right: 14), - child: ListView( - padding: EdgeInsets.only(bottom: 0), - children: [ - const SizedBox( - height: 45, - child: Center(child: Text('弹幕/字幕设置', style: titleStyle)), - ), - const SizedBox(height: 10), - Row( - children: [ - Text('智能云屏蔽 $danmakuWeight 级'), - const Spacer(), - TextButton( - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, + builder: (_, setState) { + return Theme( + data: Theme.of(context), + child: Material( + color: Colors.transparent, + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(12), + padding: const EdgeInsets.only(left: 14, right: 14), + child: ListView( + padding: EdgeInsets.zero, + children: [ + SizedBox( + height: 45, + child: Center(child: Text('弹幕/字幕设置', style: titleStyle)), + ), + const SizedBox(height: 10), + Row( + children: [ + Text('智能云屏蔽 $danmakuWeight 级'), + const Spacer(), + TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + minimumSize: Size.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + onPressed: () => { + Get.back(), + Get.toNamed('/danmakuBlock', + arguments: widget.controller) + }, + child: + Text("屏蔽管理(${widget.controller.filterCount})")), + ], + ), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, ), - onPressed: () => { - Get.back(), - Get.toNamed('/danmakuBlock', - arguments: widget.controller) + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0, + max: 10, + value: danmakuWeight.toDouble(), + divisions: 10, + label: '$danmakuWeight', + onChanged: (double val) { + danmakuWeight = val.toInt(); + widget.controller + ..danmakuWeight = danmakuWeight + ..putDanmakuSettings(); + setState(() {}); }, - child: Text("屏蔽管理(${widget.controller.filterCount})")), - ], - ), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0, - max: 10, - value: danmakuWeight.toDouble(), - divisions: 10, - label: '$danmakuWeight', - onChanged: (double val) { - danmakuWeight = val.toInt(); - widget.controller - ..danmakuWeight = danmakuWeight - ..putDanmakuSettings(); - setState(() {}); - }, - ), - ), - ), - const Text('按类型屏蔽'), - Padding( - padding: const EdgeInsets.only(top: 12, bottom: 18), - child: Row( - children: [ - for (final Map i in blockTypesList) ...[ - ActionRowLineItem( - onTap: () async { - final bool isChoose = blockTypes.contains(i['value']); - if (isChoose) { - blockTypes.remove(i['value']); - } else { - blockTypes.add(i['value']); - } - widget.controller - ..blockTypes = blockTypes - ..putDanmakuSettings(); - setState(() {}); - try { - danmakuController?.updateOption( - danmakuController.option.copyWith( - hideTop: blockTypes.contains(5), - hideBottom: blockTypes.contains(4), - hideScroll: blockTypes.contains(2), - // 添加或修改其他需要修改的选项属性 - ), - ); - } catch (_) {} - }, - text: i['label'], - selectStatus: blockTypes.contains(i['value']), + ), ), - const SizedBox(width: 10), - ] + ), + const Text('按类型屏蔽'), + Padding( + padding: const EdgeInsets.only(top: 12, bottom: 18), + child: Row( + children: [ + for (final Map i + in blockTypesList) ...[ + ActionRowLineItem( + onTap: () async { + final bool isChoose = + blockTypes.contains(i['value']); + if (isChoose) { + blockTypes.remove(i['value']); + } else { + blockTypes.add(i['value']); + } + widget.controller + ..blockTypes = blockTypes + ..putDanmakuSettings(); + setState(() {}); + try { + danmakuController?.updateOption( + danmakuController.option.copyWith( + hideTop: blockTypes.contains(5), + hideBottom: blockTypes.contains(4), + hideScroll: blockTypes.contains(2), + // 添加或修改其他需要修改的选项属性 + ), + ); + } catch (_) {} + }, + text: i['label'], + selectStatus: blockTypes.contains(i['value']), + ), + const SizedBox(width: 10), + ] + ], + ), + ), + const Text('显示区域'), + Padding( + padding: const EdgeInsets.only(top: 12), + child: Row( + children: [ + for (final Map i in showAreas) ...[ + ActionRowLineItem( + onTap: () { + showArea = i['value']; + widget.controller + ..showArea = showArea + ..putDanmakuSettings(); + setState(() {}); + try { + danmakuController?.updateOption( + danmakuController.option + .copyWith(area: i['value']), + ); + } catch (_) {} + }, + text: i['label'], + selectStatus: showArea == i['value'], + ), + const SizedBox(width: 10), + ] + ], + ), + ), + SetSwitchItem( + title: '海量弹幕', + contentPadding: EdgeInsets.all(0), + titleStyle: TextStyle(fontSize: 14), + defaultVal: massiveMode, + setKey: SettingBoxKey.danmakuMassiveMode, + onChanged: (value) { + massiveMode = value; + widget.controller.massiveMode = value; + setState(() {}); + try { + danmakuController?.updateOption( + danmakuController.option + .copyWith(massiveMode: value), + ); + } catch (_) {} + }, + ), + Text('不透明度 ${opacityVal * 100}%'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0, + max: 1, + value: opacityVal, + divisions: 10, + label: '${opacityVal * 100}%', + onChanged: (double val) { + opacityVal = val; + widget.controller + ..opacityVal = opacityVal + ..putDanmakuSettings(); + setState(() {}); + try { + danmakuController?.updateOption( + danmakuController.option.copyWith(opacity: val), + ); + } catch (_) {} + }, + ), + ), + ), + Text('字体粗细 ${fontWeight + 1}(可能无法精确调节)'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0, + max: 8, + value: fontWeight.toDouble(), + divisions: 8, + label: '${fontWeight + 1}', + onChanged: (double val) { + fontWeight = val.toInt(); + widget.controller + ..fontWeight = fontWeight + ..putDanmakuSettings(); + setState(() {}); + try { + danmakuController?.updateOption( + danmakuController.option + .copyWith(fontWeight: fontWeight), + ); + } catch (_) {} + }, + ), + ), + ), + Text('描边粗细 $strokeWidth'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0, + max: 3, + value: strokeWidth, + divisions: 6, + label: '$strokeWidth', + onChanged: (double val) { + strokeWidth = val; + widget.controller + ..strokeWidth = val + ..putDanmakuSettings(); + setState(() {}); + try { + danmakuController?.updateOption( + danmakuController.option + .copyWith(strokeWidth: val), + ); + } catch (_) {} + }, + ), + ), + ), + Text('字体大小 ${(fontSizeVal * 100).toStringAsFixed(1)}%'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0.5, + max: 2.5, + value: fontSizeVal, + divisions: 20, + label: '${(fontSizeVal * 100).toStringAsFixed(1)}%', + onChanged: (double val) { + fontSizeVal = val; + widget.controller + ..fontSizeVal = fontSizeVal + ..putDanmakuSettings(); + setState(() {}); + if (widget.controller.isFullScreen.value == false) { + try { + danmakuController?.updateOption( + danmakuController.option.copyWith( + fontSize: (15 * fontSizeVal).toDouble(), + ), + ); + } catch (_) {} + } + }, + ), + ), + ), + Text('全屏字体大小 ${(fontSizeFSVal * 100).toStringAsFixed(1)}%'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0.5, + max: 2.5, + value: fontSizeFSVal, + divisions: 20, + label: '${(fontSizeFSVal * 100).toStringAsFixed(1)}%', + onChanged: (double val) { + fontSizeFSVal = val; + widget.controller + ..fontSizeFSVal = fontSizeFSVal + ..putDanmakuSettings(); + setState(() {}); + if (widget.controller.isFullScreen.value == true) { + try { + danmakuController?.updateOption( + danmakuController.option.copyWith( + fontSize: (15 * fontSizeFSVal).toDouble(), + ), + ); + } catch (_) {} + } + }, + ), + ), + ), + Text('弹幕时长 $danmakuDurationVal 秒'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 1, + max: 4, + value: pow(danmakuDurationVal, 1 / 4) as double, + divisions: 60, + label: danmakuDurationVal.toString(), + onChanged: (double val) { + danmakuDurationVal = + (pow(val, 4) as double).toPrecision(2); + widget.controller + ..danmakuDurationVal = danmakuDurationVal + ..putDanmakuSettings(); + setState(() {}); + try { + danmakuController?.updateOption( + danmakuController.option.copyWith( + duration: danmakuDurationVal ~/ + widget.controller.playbackSpeed), + ); + } catch (_) {} + }, + ), + ), + ), + Text('弹幕行高 $danmakuLineHeight'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 1.0, + max: 3.0, + value: danmakuLineHeight, + // label: '$danmakuLineHeight', + onChanged: (double val) { + danmakuLineHeight = val.toPrecision(1); + widget.controller + ..danmakuLineHeight = danmakuLineHeight + ..putDanmakuSettings(); + setState(() {}); + try { + danmakuController?.updateOption( + danmakuController.option.copyWith( + lineHeight: danmakuLineHeight, + ), + ); + } catch (_) {} + }, + ), + ), + ), + Text( + '字幕字体大小 ${(subtitleFontScale * 100).toStringAsFixed(1)}%'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0.5, + max: 2.5, + value: subtitleFontScale, + divisions: 20, + label: + '${(subtitleFontScale * 100).toStringAsFixed(1)}%', + onChanged: (double val) { + subtitleFontScale = val; + widget.controller + ..subtitleFontScale = subtitleFontScale + ..updateSubtitleStyle() + ..putDanmakuSettings(); + setState(() {}); + }, + ), + ), + ), + Text( + '全屏字幕字体大小 ${(subtitleFontScaleFS * 100).toStringAsFixed(1)}%'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0.5, + max: 2.5, + value: subtitleFontScaleFS, + divisions: 20, + label: + '${(subtitleFontScaleFS * 100).toStringAsFixed(1)}%', + onChanged: (double val) { + subtitleFontScaleFS = val; + widget.controller + ..subtitleFontScaleFS = subtitleFontScaleFS + ..updateSubtitleStyle() + ..putDanmakuSettings(); + setState(() {}); + }, + ), + ), + ), + Text('字幕左右边距 $subtitlePaddingH'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0, + max: 100, + value: subtitlePaddingH.toDouble(), + divisions: 100, + label: '$subtitlePaddingH', + onChanged: (double val) { + subtitlePaddingH = val.round(); + widget.controller + ..subtitlePaddingH = subtitlePaddingH + ..updateSubtitleStyle() + ..putDanmakuSettings(); + setState(() {}); + }, + ), + ), + ), + Text('字幕底部边距 $subtitlePaddingB'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0, + max: 100, + value: subtitlePaddingB.toDouble(), + divisions: 100, + label: '$subtitlePaddingB', + onChanged: (double val) { + subtitlePaddingB = val.round(); + widget.controller + ..subtitlePaddingB = subtitlePaddingB + ..updateSubtitleStyle() + ..putDanmakuSettings(); + setState(() {}); + }, + ), + ), + ), + Text('字幕背景不透明度 ${(subtitleBgOpaticy * 100).toInt()}%'), + Padding( + padding: const EdgeInsets.only( + top: 0, + bottom: 6, + left: 10, + right: 10, + ), + child: SliderTheme( + data: SliderThemeData( + trackShape: MSliderTrackShape(), + thumbColor: Theme.of(context).colorScheme.primary, + activeTrackColor: + Theme.of(context).colorScheme.primary, + trackHeight: 10, + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 6.0), + ), + child: Slider( + min: 0, + max: 1, + value: subtitleBgOpaticy, + // label: '${(subtitleBgOpaticy * 100).toInt()}%', + onChanged: (double val) { + subtitleBgOpaticy = val.toPrecision(2); + widget.controller + ..subtitleBgOpaticy = subtitleBgOpaticy + ..updateSubtitleStyle() + ..putDanmakuSettings(); + setState(() {}); + }, + ), + ), + ), ], ), ), - const Text('显示区域'), - Padding( - padding: const EdgeInsets.only(top: 12), - child: Row( - children: [ - for (final Map i in showAreas) ...[ - ActionRowLineItem( - onTap: () { - showArea = i['value']; - widget.controller - ..showArea = showArea - ..putDanmakuSettings(); - setState(() {}); - try { - danmakuController?.updateOption( - danmakuController.option - .copyWith(area: i['value']), - ); - } catch (_) {} - }, - text: i['label'], - selectStatus: showArea == i['value'], - ), - const SizedBox(width: 10), - ] - ], - ), - ), - SetSwitchItem( - title: '海量弹幕', - contentPadding: EdgeInsets.all(0), - titleStyle: TextStyle(fontSize: 14), - defaultVal: massiveMode, - setKey: SettingBoxKey.danmakuMassiveMode, - onChanged: (value) { - massiveMode = value; - widget.controller.massiveMode = value; - setState(() {}); - try { - danmakuController?.updateOption( - danmakuController.option.copyWith(massiveMode: value), - ); - } catch (_) {} - }, - ), - Text('不透明度 ${opacityVal * 100}%'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0, - max: 1, - value: opacityVal, - divisions: 10, - label: '${opacityVal * 100}%', - onChanged: (double val) { - opacityVal = val; - widget.controller - ..opacityVal = opacityVal - ..putDanmakuSettings(); - setState(() {}); - try { - danmakuController?.updateOption( - danmakuController.option.copyWith(opacity: val), - ); - } catch (_) {} - }, - ), - ), - ), - Text('字体粗细 ${fontWeight + 1}(可能无法精确调节)'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0, - max: 8, - value: fontWeight.toDouble(), - divisions: 8, - label: '${fontWeight + 1}', - onChanged: (double val) { - fontWeight = val.toInt(); - widget.controller - ..fontWeight = fontWeight - ..putDanmakuSettings(); - setState(() {}); - try { - danmakuController?.updateOption( - danmakuController.option - .copyWith(fontWeight: fontWeight), - ); - } catch (_) {} - }, - ), - ), - ), - Text('描边粗细 $strokeWidth'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0, - max: 3, - value: strokeWidth, - divisions: 6, - label: '$strokeWidth', - onChanged: (double val) { - strokeWidth = val; - widget.controller - ..strokeWidth = val - ..putDanmakuSettings(); - setState(() {}); - try { - danmakuController?.updateOption( - danmakuController.option.copyWith(strokeWidth: val), - ); - } catch (_) {} - }, - ), - ), - ), - Text('字体大小 ${(fontSizeVal * 100).toStringAsFixed(1)}%'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0.5, - max: 2.5, - value: fontSizeVal, - divisions: 20, - label: '${(fontSizeVal * 100).toStringAsFixed(1)}%', - onChanged: (double val) { - fontSizeVal = val; - widget.controller - ..fontSizeVal = fontSizeVal - ..putDanmakuSettings(); - setState(() {}); - if (widget.controller.isFullScreen.value == false) { - try { - danmakuController?.updateOption( - danmakuController.option.copyWith( - fontSize: (15 * fontSizeVal).toDouble(), - ), - ); - } catch (_) {} - } - }, - ), - ), - ), - Text('全屏字体大小 ${(fontSizeFSVal * 100).toStringAsFixed(1)}%'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0.5, - max: 2.5, - value: fontSizeFSVal, - divisions: 20, - label: '${(fontSizeFSVal * 100).toStringAsFixed(1)}%', - onChanged: (double val) { - fontSizeFSVal = val; - widget.controller - ..fontSizeFSVal = fontSizeFSVal - ..putDanmakuSettings(); - setState(() {}); - if (widget.controller.isFullScreen.value == true) { - try { - danmakuController?.updateOption( - danmakuController.option.copyWith( - fontSize: (15 * fontSizeFSVal).toDouble(), - ), - ); - } catch (_) {} - } - }, - ), - ), - ), - Text('弹幕时长 $danmakuDurationVal 秒'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 1, - max: 4, - value: pow(danmakuDurationVal, 1 / 4) as double, - divisions: 60, - label: danmakuDurationVal.toString(), - onChanged: (double val) { - danmakuDurationVal = - (pow(val, 4) as double).toPrecision(2); - widget.controller - ..danmakuDurationVal = danmakuDurationVal - ..putDanmakuSettings(); - setState(() {}); - try { - danmakuController?.updateOption( - danmakuController.option.copyWith( - duration: danmakuDurationVal ~/ - widget.controller.playbackSpeed), - ); - } catch (_) {} - }, - ), - ), - ), - Text('弹幕行高 $danmakuLineHeight'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 1.0, - max: 3.0, - value: danmakuLineHeight, - // label: '$danmakuLineHeight', - onChanged: (double val) { - danmakuLineHeight = val.toPrecision(1); - widget.controller - ..danmakuLineHeight = danmakuLineHeight - ..putDanmakuSettings(); - setState(() {}); - try { - danmakuController?.updateOption( - danmakuController.option.copyWith( - lineHeight: danmakuLineHeight, - ), - ); - } catch (_) {} - }, - ), - ), - ), - Text('字幕字体大小 ${(subtitleFontScale * 100).toStringAsFixed(1)}%'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0.5, - max: 2.5, - value: subtitleFontScale, - divisions: 20, - label: '${(subtitleFontScale * 100).toStringAsFixed(1)}%', - onChanged: (double val) { - subtitleFontScale = val; - widget.controller - ..subtitleFontScale = subtitleFontScale - ..updateSubtitleStyle() - ..putDanmakuSettings(); - setState(() {}); - }, - ), - ), - ), - Text( - '全屏字幕字体大小 ${(subtitleFontScaleFS * 100).toStringAsFixed(1)}%'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0.5, - max: 2.5, - value: subtitleFontScaleFS, - divisions: 20, - label: '${(subtitleFontScaleFS * 100).toStringAsFixed(1)}%', - onChanged: (double val) { - subtitleFontScaleFS = val; - widget.controller - ..subtitleFontScaleFS = subtitleFontScaleFS - ..updateSubtitleStyle() - ..putDanmakuSettings(); - setState(() {}); - }, - ), - ), - ), - Text('字幕左右边距 $subtitlePaddingH'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0, - max: 100, - value: subtitlePaddingH.toDouble(), - divisions: 100, - label: '$subtitlePaddingH', - onChanged: (double val) { - subtitlePaddingH = val.round(); - widget.controller - ..subtitlePaddingH = subtitlePaddingH - ..updateSubtitleStyle() - ..putDanmakuSettings(); - setState(() {}); - }, - ), - ), - ), - Text('字幕底部边距 $subtitlePaddingB'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0, - max: 100, - value: subtitlePaddingB.toDouble(), - divisions: 100, - label: '$subtitlePaddingB', - onChanged: (double val) { - subtitlePaddingB = val.round(); - widget.controller - ..subtitlePaddingB = subtitlePaddingB - ..updateSubtitleStyle() - ..putDanmakuSettings(); - setState(() {}); - }, - ), - ), - ), - Text('字幕背景不透明度 ${(subtitleBgOpaticy * 100).toInt()}%'), - Padding( - padding: const EdgeInsets.only( - top: 0, - bottom: 6, - left: 10, - right: 10, - ), - child: SliderTheme( - data: SliderThemeData( - trackShape: MSliderTrackShape(), - thumbColor: Theme.of(context).colorScheme.primary, - activeTrackColor: Theme.of(context).colorScheme.primary, - trackHeight: 10, - thumbShape: - const RoundSliderThumbShape(enabledThumbRadius: 6.0), - ), - child: Slider( - min: 0, - max: 1, - value: subtitleBgOpaticy, - // label: '${(subtitleBgOpaticy * 100).toInt()}%', - onChanged: (double val) { - subtitleBgOpaticy = val.toPrecision(2); - widget.controller - ..subtitleBgOpaticy = subtitleBgOpaticy - ..updateSubtitleStyle() - ..putDanmakuSettings(); - setState(() {}); - }, - ), - ), - ), - ], - ), - ); - }), + ), + ); + }, + ), ); } /// 播放顺序 void showSetRepeat() async { Utils.showFSSheet( + context, isFullScreen: () => isFullScreen, - child: Builder( - builder: (context) => Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.all(Radius.circular(12)), - ), - margin: EdgeInsets.only( - left: 12, - top: 12, - right: 12, - bottom: 12 + MediaQuery.paddingOf(context).bottom, - ), - child: Column( - children: [ - const SizedBox( - height: 45, - child: Center(child: Text('选择播放顺序', style: titleStyle))), - Expanded( - child: Material( - color: Colors.transparent, - child: ListView( - padding: EdgeInsets.only(bottom: 0), - children: [ - for (final PlayRepeat i in PlayRepeat.values) ...[ - ListTile( - dense: true, - onTap: () { - widget.controller.setPlayRepeat(i); - Get.back(); - }, - contentPadding: - const EdgeInsets.only(left: 20, right: 20), - title: Text(i.description), - trailing: widget.controller.playRepeat == i - ? Icon( - Icons.done, - color: Theme.of(context).colorScheme.primary, - ) - : const SizedBox(), - ) + child: Theme( + data: Theme.of(context), + child: Material( + color: Colors.transparent, + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(12), + child: Column( + children: [ + const SizedBox( + height: 45, + child: Center(child: Text('选择播放顺序', style: titleStyle))), + Expanded( + child: Material( + color: Colors.transparent, + child: ListView( + padding: EdgeInsets.zero, + children: [ + for (final PlayRepeat i in PlayRepeat.values) ...[ + ListTile( + dense: true, + onTap: () { + widget.controller.setPlayRepeat(i); + Get.back(); + }, + contentPadding: + const EdgeInsets.only(left: 20, right: 20), + title: Text(i.description), + trailing: widget.controller.playRepeat == i + ? Icon( + Icons.done, + color: + Theme.of(context).colorScheme.primary, + ) + : const SizedBox(), + ) + ], ], - ], + ), ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 3cd9f9b0..17bbbc75 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -270,41 +270,52 @@ class Utils { } } - static void showFSSheet({ + static void showFSSheet( + BuildContext context, { required Widget child, required Function isFullScreen, double? padding, }) { - Navigator.of(Get.context!).push( + Navigator.of(context).push( GetDialogRoute( pageBuilder: (buildContext, animation, secondaryAnimation) { return MediaQuery.orientationOf(Get.context!) == Orientation.portrait - ? Column( - children: [ - const Spacer(flex: 3), - Expanded( - flex: 7, - child: MediaQuery.removePadding( - context: Get.context!, - removeTop: true, - child: child, + ? SafeArea( + child: Column( + children: [ + const Spacer(flex: 3), + Expanded( + flex: 7, + child: MediaQuery.removePadding( + context: context, + removeTop: true, + removeBottom: true, + removeLeft: true, + removeRight: true, + child: child, + ), ), - ), - if (isFullScreen() && padding != null) - SizedBox(height: padding), - ], + if (isFullScreen() && padding != null) + SizedBox(height: padding), + ], + ), ) - : Row( - children: [ - const Spacer(), - Expanded( - child: MediaQuery.removePadding( - context: Get.context!, - removeLeft: true, - child: child, + : SafeArea( + child: Row( + children: [ + const Spacer(), + Expanded( + child: MediaQuery.removePadding( + context: context, + removeTop: true, + removeBottom: true, + removeLeft: true, + removeRight: true, + child: child, + ), ), - ), - ], + ], + ), ); }, transitionDuration: const Duration(milliseconds: 350),