diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 7e2e7d9..a8aa9e9 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 4 -/// Strings: 384 (96 per locale) +/// Strings: 404 (101 per locale) /// -/// Built on 2025-12-01 at 13:41 UTC +/// Built on 2026-05-02 at 02:19 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -226,6 +226,10 @@ class _StringsVideoEn { String playingCollection({required Object title}) => 'Playing: ${title}'; String get changeEpisode => 'Change Episode'; String episodeTotal({required Object total}) => 'total ${total} episodes'; + String seekForward({required Object seconds}) => 'Fast forward ${seconds} s'; + String seekBackward({required Object seconds}) => 'Rewind ${seconds} s'; + String get doubleTapPause => 'Paused'; + String get doubleTapPlay => 'Playing'; } // Path: anime @@ -331,6 +335,7 @@ class _StringsMyPlayerSettingsEn { String get autoPlay => 'Auto Play'; String get autoJump => 'Auto Jump'; String get autoJumpSubtitle => 'Jump to the position where you stopped last time'; + String get doubleTapSeekDuration => 'Double Tap fast forward/rewind seconds'; } // Path: my.danmakuSettings @@ -508,6 +513,10 @@ class _StringsVideoZhCn implements _StringsVideoEn { @override String playingCollection({required Object title}) => '正在播放 ${title}'; @override String get changeEpisode => '切换选集'; @override String episodeTotal({required Object total}) => '全 ${total} 话'; + @override String seekForward({required Object seconds}) => '快进 ${seconds} 秒'; + @override String seekBackward({required Object seconds}) => '快退 ${seconds} 秒'; + @override String get doubleTapPause => '暂停'; + @override String get doubleTapPlay => '播放'; } // Path: anime @@ -612,6 +621,7 @@ class _StringsMyPlayerSettingsZhCn implements _StringsMyPlayerSettingsEn { @override String get hardwareAcceleration => '硬件解码'; @override String get autoPlay => '自动播放'; @override String get autoJump => '自动跳转'; + @override String get doubleTapSeekDuration => '双击跳转时长'; @override String get autoJumpSubtitle => '跳转到上次播放位置'; } @@ -790,6 +800,10 @@ class _StringsVideoZhHk implements _StringsVideoEn { @override String playingCollection({required Object title}) => '正在播放 ${title}'; @override String get changeEpisode => '切換選集'; @override String episodeTotal({required Object total}) => '全 ${total} 話'; + @override String seekForward({required Object seconds}) => '快進 ${seconds} 秒'; + @override String seekBackward({required Object seconds}) => '快退 ${seconds} 秒'; + @override String get doubleTapPause => '暫停'; + @override String get doubleTapPlay => '播放'; } // Path: anime @@ -894,6 +908,7 @@ class _StringsMyPlayerSettingsZhHk implements _StringsMyPlayerSettingsEn { @override String get hardwareAcceleration => '硬件解碼'; @override String get autoPlay => '自動播放'; @override String get autoJump => '自動跳轉'; + @override String get doubleTapSeekDuration => '雙擊跳轉時長'; @override String get autoJumpSubtitle => '跳轉到上次播放位置'; } @@ -1072,6 +1087,10 @@ class _StringsVideoZhTw implements _StringsVideoEn { @override String playingCollection({required Object title}) => '正在播放 ${title}'; @override String get changeEpisode => '切換選集'; @override String episodeTotal({required Object total}) => '全 ${total} 話'; + @override String seekForward({required Object seconds}) => '快進 ${seconds} 秒'; + @override String seekBackward({required Object seconds}) => '快退 ${seconds} 秒'; + @override String get doubleTapPause => '暫停'; + @override String get doubleTapPlay => '播放'; } // Path: anime @@ -1176,6 +1195,7 @@ class _StringsMyPlayerSettingsZhTw implements _StringsMyPlayerSettingsEn { @override String get hardwareAcceleration => '硬件解碼'; @override String get autoPlay => '自動播放'; @override String get autoJump => '自動跳轉'; + @override String get doubleTapSeekDuration => '雙擊跳轉時長'; @override String get autoJumpSubtitle => '跳轉到上次播放位置'; } @@ -1291,6 +1311,10 @@ extension on Translations { case 'video.playingCollection': return ({required Object title}) => 'Playing: ${title}'; case 'video.changeEpisode': return 'Change Episode'; case 'video.episodeTotal': return ({required Object total}) => 'total ${total} episodes'; + case 'video.seekForward': return ({required Object seconds}) => 'Fast forward ${seconds} s'; + case 'video.seekBackward': return ({required Object seconds}) => 'Rewind ${seconds} s'; + case 'video.doubleTapPause': return 'Paused'; + case 'video.doubleTapPlay': return 'Playing'; case 'anime.anime': return 'Anime'; case 'anime.serializing': return 'Serializing'; case 'anime.OVA': return 'OVA'; @@ -1317,6 +1341,7 @@ extension on Translations { case 'my.playerSettings.autoPlay': return 'Auto Play'; case 'my.playerSettings.autoJump': return 'Auto Jump'; case 'my.playerSettings.autoJumpSubtitle': return 'Jump to the position where you stopped last time'; + case 'my.playerSettings.doubleTapSeekDuration': return 'Double Tap fast forward/rewind seconds'; case 'my.danmakuSettings.title': return 'Danmaku Settings'; case 'my.danmakuSettings.defaultEnable': return 'Default Enable'; case 'my.danmakuSettings.defaultEnableSubtitle': return 'Whether to enable danmaku by default'; @@ -1395,6 +1420,10 @@ extension on _StringsZhCn { case 'video.playingCollection': return ({required Object title}) => '正在播放 ${title}'; case 'video.changeEpisode': return '切换选集'; case 'video.episodeTotal': return ({required Object total}) => '全 ${total} 话'; + case 'video.seekForward': return ({required Object seconds}) => '快进 ${seconds} 秒'; + case 'video.seekBackward': return ({required Object seconds}) => '快退 ${seconds} 秒'; + case 'video.doubleTapPause': return '暂停'; + case 'video.doubleTapPlay': return '播放'; case 'anime.anime': return '新番'; case 'anime.serializing': return '连载中'; case 'anime.OVA': return 'OVA'; @@ -1420,6 +1449,7 @@ extension on _StringsZhCn { case 'my.playerSettings.hardwareAcceleration': return '硬件解码'; case 'my.playerSettings.autoPlay': return '自动播放'; case 'my.playerSettings.autoJump': return '自动跳转'; + case 'my.playerSettings.doubleTapSeekDuration': return '双击跳转时长'; case 'my.playerSettings.autoJumpSubtitle': return '跳转到上次播放位置'; case 'my.danmakuSettings.title': return '弹幕设置'; case 'my.danmakuSettings.defaultEnable': return '默认开启'; @@ -1499,6 +1529,10 @@ extension on _StringsZhHk { case 'video.playingCollection': return ({required Object title}) => '正在播放 ${title}'; case 'video.changeEpisode': return '切換選集'; case 'video.episodeTotal': return ({required Object total}) => '全 ${total} 話'; + case 'video.seekForward': return ({required Object seconds}) => '快進 ${seconds} 秒'; + case 'video.seekBackward': return ({required Object seconds}) => '快退 ${seconds} 秒'; + case 'video.doubleTapPause': return '暫停'; + case 'video.doubleTapPlay': return '播放'; case 'anime.anime': return '新番'; case 'anime.serializing': return '連載中'; case 'anime.OVA': return 'OVA'; @@ -1524,6 +1558,7 @@ extension on _StringsZhHk { case 'my.playerSettings.hardwareAcceleration': return '硬件解碼'; case 'my.playerSettings.autoPlay': return '自動播放'; case 'my.playerSettings.autoJump': return '自動跳轉'; + case 'my.playerSettings.doubleTapSeekDuration': return '雙擊跳轉時長'; case 'my.playerSettings.autoJumpSubtitle': return '跳轉到上次播放位置'; case 'my.danmakuSettings.title': return '彈幕設置'; case 'my.danmakuSettings.defaultEnable': return '默認開啟'; @@ -1603,6 +1638,10 @@ extension on _StringsZhTw { case 'video.playingCollection': return ({required Object title}) => '正在播放 ${title}'; case 'video.changeEpisode': return '切換選集'; case 'video.episodeTotal': return ({required Object total}) => '全 ${total} 話'; + case 'video.seekForward': return ({required Object seconds}) => '快進 ${seconds} 秒'; + case 'video.seekBackward': return ({required Object seconds}) => '快退 ${seconds} 秒'; + case 'video.doubleTapPause': return '暫停'; + case 'video.doubleTapPlay': return '播放'; case 'anime.anime': return '新番'; case 'anime.serializing': return '連載中'; case 'anime.OVA': return 'OVA'; @@ -1628,6 +1667,7 @@ extension on _StringsZhTw { case 'my.playerSettings.hardwareAcceleration': return '硬件解碼'; case 'my.playerSettings.autoPlay': return '自動播放'; case 'my.playerSettings.autoJump': return '自動跳轉'; + case 'my.playerSettings.doubleTapSeekDuration': return '雙擊跳轉時長'; case 'my.playerSettings.autoJumpSubtitle': return '跳轉到上次播放位置'; case 'my.danmakuSettings.title': return '彈幕設置'; case 'my.danmakuSettings.defaultEnable': return '默認開啟'; diff --git a/lib/i18n/strings.i18n.json b/lib/i18n/strings.i18n.json index 2d19afc..b959be6 100644 --- a/lib/i18n/strings.i18n.json +++ b/lib/i18n/strings.i18n.json @@ -36,7 +36,11 @@ "collection": "Collection ", "playingCollection": "Playing: $title", "changeEpisode": "Change Episode", - "episodeTotal": "total $total episodes" + "episodeTotal": "total $total episodes", + "seekForward": "Fast forward $seconds s", + "seekBackward": "Rewind $seconds s", + "doubleTapPause": "Paused", + "doubleTapPlay": "Playing" }, "anime": { "anime": "Anime", @@ -77,7 +81,8 @@ "hardwareAcceleration": "Hardware Acceleration", "autoPlay": "Auto Play", "autoJump": "Auto Jump", - "autoJumpSubtitle": "Jump to the position where you stopped last time" + "autoJumpSubtitle": "Jump to the position where you stopped last time", + "doubleTapSeekDuration": "Double Tap fast forward/rewind seconds" }, "danmakuSettings": { "title": "Danmaku Settings", @@ -127,4 +132,4 @@ "currentVersion": "Current Version" } } -} \ No newline at end of file +} diff --git a/lib/i18n/strings_zh-CN.i18n.json b/lib/i18n/strings_zh-CN.i18n.json index a7962f3..5ae8d7b 100644 --- a/lib/i18n/strings_zh-CN.i18n.json +++ b/lib/i18n/strings_zh-CN.i18n.json @@ -36,7 +36,11 @@ "collection": "合集 ", "playingCollection": "正在播放 $title", "changeEpisode": "切换选集", - "episodeTotal": "全 $total 话" + "episodeTotal": "全 $total 话", + "seekForward": "快进 $seconds 秒", + "seekBackward": "快退 $seconds 秒", + "doubleTapPause": "暂停", + "doubleTapPlay": "播放" }, "anime": { "anime": "新番", @@ -77,6 +81,7 @@ "hardwareAcceleration": "硬件解码", "autoPlay": "自动播放", "autoJump": "自动跳转", + "doubleTapSeekDuration": "双击跳转时长", "autoJumpSubtitle": "跳转到上次播放位置" }, "danmakuSettings": { @@ -127,4 +132,4 @@ "currentVersion": "当前版本" } } -} \ No newline at end of file +} diff --git a/lib/i18n/strings_zh-HK.i18n.json b/lib/i18n/strings_zh-HK.i18n.json index ce454eb..131c039 100644 --- a/lib/i18n/strings_zh-HK.i18n.json +++ b/lib/i18n/strings_zh-HK.i18n.json @@ -36,7 +36,11 @@ "collection": "合集 ", "playingCollection": "正在播放 $title", "changeEpisode": "切換選集", - "episodeTotal": "全 $total 話" + "episodeTotal": "全 $total 話", + "seekForward": "快進 $seconds 秒", + "seekBackward": "快退 $seconds 秒", + "doubleTapPause": "暫停", + "doubleTapPlay": "播放" }, "anime": { "anime": "新番", @@ -77,6 +81,7 @@ "hardwareAcceleration": "硬件解碼", "autoPlay": "自動播放", "autoJump": "自動跳轉", + "doubleTapSeekDuration": "雙擊跳轉時長", "autoJumpSubtitle": "跳轉到上次播放位置" }, "danmakuSettings": { @@ -127,4 +132,4 @@ "currentVersion": "當前版本" } } -} \ No newline at end of file +} diff --git a/lib/i18n/strings_zh-TW.i18n.json b/lib/i18n/strings_zh-TW.i18n.json index ce454eb..131c039 100644 --- a/lib/i18n/strings_zh-TW.i18n.json +++ b/lib/i18n/strings_zh-TW.i18n.json @@ -36,7 +36,11 @@ "collection": "合集 ", "playingCollection": "正在播放 $title", "changeEpisode": "切換選集", - "episodeTotal": "全 $total 話" + "episodeTotal": "全 $total 話", + "seekForward": "快進 $seconds 秒", + "seekBackward": "快退 $seconds 秒", + "doubleTapPause": "暫停", + "doubleTapPlay": "播放" }, "anime": { "anime": "新番", @@ -77,6 +81,7 @@ "hardwareAcceleration": "硬件解碼", "autoPlay": "自動播放", "autoJump": "自動跳轉", + "doubleTapSeekDuration": "雙擊跳轉時長", "autoJumpSubtitle": "跳轉到上次播放位置" }, "danmakuSettings": { @@ -127,4 +132,4 @@ "currentVersion": "當前版本" } } -} \ No newline at end of file +} diff --git a/lib/pages/settings/player_settings_page.dart b/lib/pages/settings/player_settings_page.dart index e660ea7..2c54cfd 100644 --- a/lib/pages/settings/player_settings_page.dart +++ b/lib/pages/settings/player_settings_page.dart @@ -18,11 +18,21 @@ class _PlayerSettingsPageState extends State { dynamic navigationBarState; Box setting = GStorage.setting; late Translations i18n; + late int _seekDuration; final PopularController popularController = Modular.get(); @override void initState() { super.initState(); + _seekDuration = + setting.get(SettingBoxKey.doubleTapSeekDuration, defaultValue: 10); + } + + void _updateSeekDuration(int value) async { + await setting.put(SettingBoxKey.doubleTapSeekDuration, value); + setState(() { + _seekDuration = value; + }); } @override @@ -55,6 +65,34 @@ class _PlayerSettingsPageState extends State { defaultVal: false, ), ), + ListTile( + dense: false, + title: Text(i18n.my.playerSettings.doubleTapSeekDuration), + subtitle: Row( + children: [ + Expanded( + child: Slider( + value: _seekDuration.toDouble(), + min: 5, + max: 20, + divisions: 3, + label: '$_seekDuration s', + onChanged: (double value) { + _updateSeekDuration(value.toInt()); + }, + ), + ), + Text( + '$_seekDuration s', + style: Theme.of(context) + .textTheme + .labelMedium! + .copyWith(color: Theme.of(context).colorScheme.outline), + ), + const SizedBox(width: 8), + ], + ), + ), ], ), ); diff --git a/lib/pages/video/video_page.dart b/lib/pages/video/video_page.dart index 0f9f025..fc3dc5b 100644 --- a/lib/pages/video/video_page.dart +++ b/lib/pages/video/video_page.dart @@ -55,16 +55,34 @@ class _VideoPageState extends State // 界面管理 bool showPositioned = false; - bool showPosition = false; - bool showBrightness = false; - bool showVolume = false; - bool showPlaySpeed = false; Timer? hideTimer; Timer? playerTimer; Timer? mouseScrollerTimer; bool isPopping = false; + Offset? _doubleTapPosition; + Widget? _overlayWidget; + Timer? _overlayTimer; + + void _showOverlay(Widget child, {bool autoDismiss = true}) { + _overlayTimer?.cancel(); + setState(() { + _overlayWidget = child; + }); + if (autoDismiss) { + _overlayTimer = Timer(const Duration(seconds: 1), () { + if (mounted) setState(() => _overlayWidget = null); + _overlayTimer = null; + }); + } + } + + void _hideOverlay() { + _overlayTimer?.cancel(); + _overlayTimer = null; + setState(() => _overlayWidget = null); + } void _handleTap() { setState(() { @@ -85,19 +103,16 @@ class _VideoPageState extends State } void _handleMouseScroller() { - setState(() { - showVolume = true; - }); - if (mouseScrollerTimer != null) { - mouseScrollerTimer!.cancel(); - } - + _showOverlay( + Row(mainAxisSize: MainAxisSize.min, children: [ + const Icon(Icons.volume_down, color: Colors.white), + Text(' ${(videoController.volume * 100).toInt()}%', + style: const TextStyle(color: Colors.white)), + ]), + ); + if (mouseScrollerTimer != null) mouseScrollerTimer!.cancel(); mouseScrollerTimer = Timer(const Duration(seconds: 2), () { - if (mounted) { - setState(() { - showVolume = false; - }); - } + if (mounted) _hideOverlay(); mouseScrollerTimer = null; }); } @@ -107,10 +122,34 @@ class _VideoPageState extends State if (playerTimer != null) { playerTimer!.cancel(); } + final int seekSecs = + setting.get(SettingBoxKey.doubleTapSeekDuration, defaultValue: 10); + videoController.currentPosition = Duration( + seconds: videoController.currentPosition.inSeconds + seekSecs); + playerController.seek(videoController.currentPosition); + playerTimer = getPlayerTimer(); + _showOverlay(Text(i18n.video.seekForward(seconds: seekSecs), + style: const TextStyle(color: Colors.white))); + } catch (e) { + debugPrint(e.toString()); + } + } + + void _handleBackwardSeek() { + try { + if (playerTimer != null) { + playerTimer!.cancel(); + } + final int seekSecs = + setting.get(SettingBoxKey.doubleTapSeekDuration, defaultValue: 10); + final int newSeconds = + videoController.currentPosition.inSeconds - seekSecs; videoController.currentPosition = - Duration(seconds: videoController.currentPosition.inSeconds + 10); + Duration(seconds: newSeconds < 0 ? 0 : newSeconds); playerController.seek(videoController.currentPosition); playerTimer = getPlayerTimer(); + _showOverlay(Text(i18n.video.seekBackward(seconds: seekSecs), + style: const TextStyle(color: Colors.white))); } catch (e) { debugPrint(e.toString()); } @@ -666,29 +705,63 @@ class _VideoPageState extends State onTap: () { _handleTap(); }, + onDoubleTapDown: (TapDownDetails details) { + _doubleTapPosition = details.localPosition; + }, onDoubleTap: () { - _handleTap(); - _handleShortSeek(); + if (_doubleTapPosition == null) return; + final double width = + MediaQuery.of(context).size.width; + final double x = _doubleTapPosition!.dx; + if (x < width / 3) { + // Left zone: seek backward + _handleBackwardSeek(); + } else if (x > width * 2 / 3) { + // Right zone: seek forward + _handleShortSeek(); + } else { + // Middle zone: toggle play/pause + final bool wasPlaying = + playerController.playing; + _handleTap(); + if (wasPlaying) { + playerController.pause(); + videoController.playing = false; + _showOverlay(Text(i18n.video.doubleTapPause, + style: const TextStyle( + color: Colors.white))); + } else { + playerController.play(); + videoController.playing = true; + _showOverlay(Text(i18n.video.doubleTapPlay, + style: const TextStyle( + color: Colors.white))); + } + } }, onLongPressStart: (_) { - setState(() { - showPlaySpeed = true; - }); + _showOverlay( + const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.fast_forward, + color: Colors.white), + Text(' 倍速播放', + style: TextStyle(color: Colors.white)), + ], + ), + autoDismiss: false, + ); videoController.setPlaybackSpeed( videoController.playerSpeed * 2.5); }, onLongPressEnd: (_) { - setState(() { - showPlaySpeed = false; - }); + _hideOverlay(); videoController.setPlaybackSpeed( videoController.playerSpeed / 2.5); }, onHorizontalDragUpdate: (DragUpdateDetails details) { - setState(() { - showPosition = true; - }); if (playerTimer != null) { // debugPrint('检测到拖动, 定时器取消'); playerTimer!.cancel(); @@ -700,15 +773,32 @@ class _VideoPageState extends State milliseconds: videoController .currentPosition.inMilliseconds + (details.delta.dx * scale).round()); + _showOverlay( + Text( + videoController.currentPosition.compareTo( + playerController.position) > + 0 + ? i18n.video.seekForward( + seconds: videoController + .currentPosition.inSeconds - + playerController + .position.inSeconds) + : i18n.video.seekBackward( + seconds: playerController + .position.inSeconds - + videoController + .currentPosition.inSeconds), + style: const TextStyle(color: Colors.white), + ), + autoDismiss: false, + ); }, onHorizontalDragEnd: (DragEndDetails details) { playerController .seek(videoController.currentPosition); playerController.play(); playerTimer = getPlayerTimer(); - setState(() { - showPosition = false; - }); + _hideOverlay(); }, onVerticalDragUpdate: (DragUpdateDetails details) async { @@ -727,9 +817,6 @@ class _VideoPageState extends State } if (tapPosition < sectionWidth) { // 左边区域 - setState(() { - showBrightness = true; - }); try { videoController.brightness = await ScreenBrightness().current; @@ -742,142 +829,63 @@ class _VideoPageState extends State final double result = brightness.clamp(0.0, 1.0); setBrightness(result); + _showOverlay( + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.brightness_7, + color: Colors.white), + Text( + ' ${(videoController.brightness * 100).toInt()} %', + style: const TextStyle( + color: Colors.white)), + ]), + autoDismiss: false, + ); } else { // 右边区域 - setState(() { - showVolume = true; - }); final double level = (totalHeight) * 3; final double volume = videoController.volume - delta / level; final double result = volume.clamp(0.0, 1.0); setVolume(result); videoController.volume = result; + _showOverlay( + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.volume_down, + color: Colors.white), + Text( + ' ${(videoController.volume * 100).toInt()}%', + style: const TextStyle( + color: Colors.white)), + ]), + autoDismiss: false, + ); } }, onVerticalDragEnd: (DragEndDetails details) { - setState(() { - showBrightness = false; - showVolume = false; - }); + _hideOverlay(); })), - // 顶部进度条 - Positioned( - top: 25, - width: 200, - child: showPosition - ? Wrap( - alignment: WrapAlignment.center, - children: [ - Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.5), - borderRadius: - BorderRadius.circular(8.0), // 圆角 - ), - child: Text( - videoController.currentPosition.compareTo( - playerController.position) > - 0 - ? '快进 ${videoController.currentPosition.inSeconds - playerController.position.inSeconds} 秒' - : '快退 ${playerController.position.inSeconds - videoController.currentPosition.inSeconds} 秒', - style: const TextStyle( - color: Colors.white, - ), - ), - ), - ], - ) - : Container()), - // 顶部播放速度条 - Positioned( + // 统一信息气泡 + if (_overlayWidget != null) + Positioned( top: 25, - child: showPlaySpeed - ? Wrap( - alignment: WrapAlignment.center, - children: [ - Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.5), - borderRadius: - BorderRadius.circular(8.0), // 圆角 - ), - child: const Row( - children: [ - Icon(Icons.fast_forward, - color: Colors.white), - Text( - ' 倍速播放', - style: TextStyle( - color: Colors.white, - ), - ), - ], - ), - ), - ], - ) - : Container()), - // 亮度条 - Positioned( - top: 25, - child: showBrightness - ? Wrap( - alignment: WrapAlignment.center, - children: [ - Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.5), - borderRadius: - BorderRadius.circular(8.0), // 圆角 - ), - child: Row( - children: [ - const Icon(Icons.brightness_7, - color: Colors.white), - Text( - ' ${(videoController.brightness * 100).toInt()} %', - style: const TextStyle( - color: Colors.white, - ), - ), - ], - )), - ], - ) - : Container()), - // 音量条 - Positioned( - top: 25, - child: showVolume - ? Wrap( - alignment: WrapAlignment.center, - children: [ - Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.5), - borderRadius: - BorderRadius.circular(8.0), // 圆角 - ), - child: Row( - children: [ - const Icon(Icons.volume_down, - color: Colors.white), - Text( - ' ${(videoController.volume * 100).toInt()}%', - style: const TextStyle( - color: Colors.white, - ), - ), - ], - )), - ], - ) - : Container()), + left: 0, + right: 0, + child: Center( + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12.0, vertical: 8.0), + decoration: BoxDecoration( + color: Colors.black.withValues(alpha: 0.5), + borderRadius: BorderRadius.circular(8.0), + ), + child: _overlayWidget, + ), + ), + ), Positioned( top: 0, left: 0, @@ -896,11 +904,14 @@ class _VideoPageState extends State debugPrint('弹幕控制器创建成功'); }, option: DanmakuOption( - fontSize: _fontSize, - duration: _duration.toDouble(), - opacity: _opacity, - fontFamily: _danmakuUseSystemFont ? null : customAppFontFamily, - strokeWidth: _showStroke ? 1.5 : 0.0,), + fontSize: _fontSize, + duration: _duration.toDouble(), + opacity: _opacity, + fontFamily: _danmakuUseSystemFont + ? null + : customAppFontFamily, + strokeWidth: _showStroke ? 1.5 : 0.0, + ), ), ), diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 6480ea4..cedae18 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -61,7 +61,7 @@ class SettingBoxKey { static const String HAenable = 'HAenable', // 检查是否为第一次运行 firstRun = 'firstRun', - searchEnhanceEnable = 'searchEnhanceEnable', + searchEnhanceEnable = 'searchEnhanceEnable', autoUpdate = 'autoUpdate', alwaysOntop = 'alwaysOntop', danmakuEnhance = 'danmakuEnhance', @@ -81,8 +81,10 @@ class SettingBoxKey { playResume = 'playResume', oledEnhance = 'oledEnhance', displayMode = 'displayMode', + /// deprecated isWideScreen = 'isWideScreen', enableSystemProxy = 'enableSystemProxy', - useSystemFont = 'useSystemFont'; + useSystemFont = 'useSystemFont', + doubleTapSeekDuration = 'doubleTapSeekDuration'; }