diff --git a/lib/bean/appbar/sys_app_bar.dart b/lib/bean/appbar/sys_app_bar.dart index 580f13f0..cf4affbe 100644 --- a/lib/bean/appbar/sys_app_bar.dart +++ b/lib/bean/appbar/sys_app_bar.dart @@ -4,6 +4,7 @@ import 'package:kazumi/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:window_manager/window_manager.dart'; import 'package:flutter/services.dart'; +import 'package:kazumi/utils/storage.dart'; class SysAppBar extends StatelessWidget implements PreferredSizeWidget { final double? toolbarHeight; @@ -58,6 +59,11 @@ class SysAppBar extends StatelessWidget implements PreferredSizeWidget { }); } + bool showWindowButton() { + return GStorage.setting + .get(SettingBoxKey.showWindowButton, defaultValue: false); + } + @override Widget build(BuildContext context) { List acs = []; @@ -66,13 +72,13 @@ class SysAppBar extends StatelessWidget implements PreferredSizeWidget { } if (Utils.isDesktop()) { // acs.add(IconButton(onPressed: () => windowManager.minimize(), icon: const Icon(Icons.minimize))); - if (!Platform.isMacOS) { + if (!showWindowButton()) { acs.add(CloseButton(onPressed: () => _handleCloseEvent())); } acs.add(const SizedBox(width: 8)); } return SafeArea( - minimum: (Platform.isMacOS && needTopOffset) + minimum: (Platform.isMacOS && needTopOffset && showWindowButton()) ? const EdgeInsets.only(top: 22) : EdgeInsets.zero, child: GestureDetector( @@ -107,7 +113,7 @@ class SysAppBar extends StatelessWidget implements PreferredSizeWidget { @override Size get preferredSize { - if (Platform.isMacOS && needTopOffset) { + if (Platform.isMacOS && needTopOffset && showWindowButton()) { if (toolbarHeight != null) { return Size.fromHeight(toolbarHeight! + 22); } else { diff --git a/lib/main.dart b/lib/main.dart index c2ba1170..a0633d39 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,22 +18,6 @@ import 'package:provider/provider.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); MediaKit.ensureInitialized(); - if (Utils.isDesktop()) { - await windowManager.ensureInitialized(); - bool isLowResolution = await Utils.isLowResolution(); - WindowOptions windowOptions = WindowOptions( - size: isLowResolution ? const Size(800, 600) : const Size(1280, 860), - center: true, - // backgroundColor: Colors.white, - skipTaskbar: false, - titleBarStyle: TitleBarStyle.hidden, - windowButtonVisibility: Platform.isMacOS ? true : false, - ); - windowManager.waitUntilReadyToShow(windowOptions, () async { - await windowManager.show(); - await windowManager.focus(); - }); - } if (Platform.isAndroid || Platform.isIOS) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( @@ -54,6 +38,27 @@ void main() async { })); return; } + bool showWindowButton = await GStorage.setting + .get(SettingBoxKey.showWindowButton, defaultValue: false); + if (Utils.isDesktop()) { + await windowManager.ensureInitialized(); + bool isLowResolution = await Utils.isLowResolution(); + WindowOptions windowOptions = WindowOptions( + size: isLowResolution ? const Size(800, 600) : const Size(1280, 860), + center: true, + // backgroundColor: Colors.white, + skipTaskbar: false, + titleBarStyle: (Platform.isMacOS || !showWindowButton) + ? TitleBarStyle.hidden + : TitleBarStyle.normal, + windowButtonVisibility: showWindowButton, + title: 'Kazumi', + ); + windowManager.waitUntilReadyToShow(windowOptions, () async { + await windowManager.show(); + await windowManager.focus(); + }); + } Request(); await Request.setCookie(); runApp( diff --git a/lib/pages/menu/side_menu.dart b/lib/pages/menu/side_menu.dart index 144807b6..d549be1d 100644 --- a/lib/pages/menu/side_menu.dart +++ b/lib/pages/menu/side_menu.dart @@ -1,9 +1,9 @@ import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:kazumi/pages/router.dart'; import 'package:provider/provider.dart'; +import 'package:kazumi/utils/storage.dart'; class SideMenu extends StatefulWidget { //const SideMenu({Key? key}) : super(key: key); @@ -38,6 +38,8 @@ class SideNavigationBarState extends ChangeNotifier { } class _SideMenu extends State { + bool showWindowButton = GStorage.setting + .get(SettingBoxKey.showWindowButton, defaultValue: false); @override Widget build(BuildContext context) { return ChangeNotifierProvider( @@ -55,7 +57,7 @@ class _SideMenu extends State { leading: SizedBox( width: 50, child: Padding( - padding: Platform.isMacOS + padding: (Platform.isMacOS && showWindowButton) ? const EdgeInsets.only(top: 30) : const EdgeInsets.only(top: 8), child: ClipOval( diff --git a/lib/pages/player/player_item_panel.dart b/lib/pages/player/player_item_panel.dart index e992bed4..b60cbacb 100644 --- a/lib/pages/player/player_item_panel.dart +++ b/lib/pages/player/player_item_panel.dart @@ -58,6 +58,7 @@ class PlayerItemPanel extends StatefulWidget { class _PlayerItemPanelState extends State { Box setting = GStorage.setting; late bool haEnable; + late bool showWindowButton; late Animation topOffsetAnimation; late Animation bottomOffsetAnimation; late Animation leftOffsetAnimation; @@ -319,6 +320,8 @@ class _PlayerItemPanelState extends State { curve: Curves.easeInOut, )); haEnable = setting.get(SettingBoxKey.hAenable, defaultValue: true); + showWindowButton = + setting.get(SettingBoxKey.showWindowButton, defaultValue: false); } Widget forwardIcon() { @@ -357,26 +360,16 @@ class _PlayerItemPanelState extends State { visible: !playerController.lockPanel, child: SlideTransition( position: topOffsetAnimation, - child: SafeArea( - left: false, - top: true, - right: false, - bottom: false, - minimum: - (Platform.isMacOS && !videoPageController.isFullscreen) - ? const EdgeInsets.only(top: 22) - : EdgeInsets.zero, - child: Container( - height: 50, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.black45, - Colors.transparent, - ], - ), + child: Container( + height: 50, + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black45, + Colors.transparent, + ], ), ), ), @@ -570,124 +563,138 @@ class _PlayerItemPanelState extends State { visible: !playerController.lockPanel, child: SlideTransition( position: topOffsetAnimation, - child: MouseRegion( - cursor: (videoPageController.isFullscreen && - !playerController.showVideoController) - ? SystemMouseCursors.none - : SystemMouseCursors.basic, - onEnter: (_) { - widget.cancelHideTimer(); - }, - onExit: (_) { - widget.cancelHideTimer(); - widget.startHideTimer(); - }, - child: Row( - children: [ - IconButton( - color: Colors.white, - icon: const Icon(Icons.arrow_back_rounded), - onPressed: () { - widget.onBackPressed(context); - }, - ), - (videoPageController.isFullscreen || Utils.isDesktop()) - ? Text( - ' ${videoPageController.title} [${videoPageController.roadList[videoPageController.currentRoad].identifier[videoPageController.currentEpisode - 1]}]', - style: TextStyle( - color: Colors.white, - fontSize: Theme.of(context) - .textTheme - .titleMedium! - .fontSize), - ) - : Container(), - // 拖动条 - const Expanded( - child: dtb.DragToMoveArea(child: SizedBox(height: 40)), - ), - // 跳过 - forwardIcon(), - // 追番 - CollectButton( - bangumiItem: infoController.bangumiItem, - onOpen: () { - widget.cancelHideTimer(); - playerController.canHidePlayerPanel = false; - }, - onClose: () { - widget.cancelHideTimer(); - widget.startHideTimer(); - playerController.canHidePlayerPanel = true; - }, - ), - MenuAnchor( - consumeOutsideTap: true, - onOpen: () { - widget.cancelHideTimer(); - playerController.canHidePlayerPanel = false; - }, - onClose: () { - widget.cancelHideTimer(); - widget.startHideTimer(); - playerController.canHidePlayerPanel = true; - }, - builder: (BuildContext context, - MenuController controller, Widget? child) { - return IconButton( - onPressed: () { - if (controller.isOpen) { - controller.close(); - } else { - controller.open(); - } - }, - icon: const Icon( - Icons.more_vert, - color: Colors.white, - ), - ); - }, - menuChildren: [ - MenuItemButton( - onPressed: () { - widget.showDanmakuSwitch(); - }, - child: const Padding( - padding: EdgeInsets.fromLTRB(0, 10, 10, 10), - child: Text("弹幕切换"), + child: SafeArea( + left: false, + top: true, + right: false, + bottom: false, + minimum: (Platform.isMacOS && + !videoPageController.isFullscreen && + showWindowButton) + ? const EdgeInsets.only(top: 22) + : EdgeInsets.zero, + child: MouseRegion( + cursor: (videoPageController.isFullscreen && + !playerController.showVideoController) + ? SystemMouseCursors.none + : SystemMouseCursors.basic, + onEnter: (_) { + widget.cancelHideTimer(); + }, + onExit: (_) { + widget.cancelHideTimer(); + widget.startHideTimer(); + }, + child: Row( + children: [ + IconButton( + color: Colors.white, + icon: const Icon(Icons.arrow_back_rounded), + onPressed: () { + widget.onBackPressed(context); + }, + ), + (videoPageController.isFullscreen || Utils.isDesktop()) + ? Text( + ' ${videoPageController.title} [${videoPageController.roadList[videoPageController.currentRoad].identifier[videoPageController.currentEpisode - 1]}]', + style: TextStyle( + color: Colors.white, + fontSize: Theme.of(context) + .textTheme + .titleMedium! + .fontSize), + ) + : Container(), + // 拖动条 + const Expanded( + child: + dtb.DragToMoveArea(child: SizedBox(height: 40)), + ), + // 跳过 + forwardIcon(), + // 追番 + CollectButton( + bangumiItem: infoController.bangumiItem, + onOpen: () { + widget.cancelHideTimer(); + playerController.canHidePlayerPanel = false; + }, + onClose: () { + widget.cancelHideTimer(); + widget.startHideTimer(); + playerController.canHidePlayerPanel = true; + }, + ), + MenuAnchor( + consumeOutsideTap: true, + onOpen: () { + widget.cancelHideTimer(); + playerController.canHidePlayerPanel = false; + }, + onClose: () { + widget.cancelHideTimer(); + widget.startHideTimer(); + playerController.canHidePlayerPanel = true; + }, + builder: (BuildContext context, + MenuController controller, Widget? child) { + return IconButton( + onPressed: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + icon: const Icon( + Icons.more_vert, + color: Colors.white, + ), + ); + }, + menuChildren: [ + MenuItemButton( + onPressed: () { + widget.showDanmakuSwitch(); + }, + child: const Padding( + padding: EdgeInsets.fromLTRB(0, 10, 10, 10), + child: Text("弹幕切换"), + ), ), - ), - MenuItemButton( - onPressed: () { - showVideoInfo(); - }, - child: const Padding( - padding: EdgeInsets.fromLTRB(0, 10, 10, 10), - child: Text("视频详情"), + MenuItemButton( + onPressed: () { + showVideoInfo(); + }, + child: const Padding( + padding: EdgeInsets.fromLTRB(0, 10, 10, 10), + child: Text("视频详情"), + ), ), - ), - MenuItemButton( - onPressed: () { - bool needRestart = playerController.playing; - playerController.pause(); - RemotePlay() - .castVideo(context, - videoPageController.currentPlugin.referer) - .whenComplete(() { - if (needRestart) { - playerController.play(); - } - }); - }, - child: const Padding( - padding: EdgeInsets.fromLTRB(0, 10, 10, 10), - child: Text("远程播放"), + MenuItemButton( + onPressed: () { + bool needRestart = playerController.playing; + playerController.pause(); + RemotePlay() + .castVideo( + context, + videoPageController + .currentPlugin.referer) + .whenComplete(() { + if (needRestart) { + playerController.play(); + } + }); + }, + child: const Padding( + padding: EdgeInsets.fromLTRB(0, 10, 10, 10), + child: Text("远程播放"), + ), ), - ), - ], - ), - ], + ], + ), + ], + ), ), ), ), diff --git a/lib/pages/settings/theme_settings_page.dart b/lib/pages/settings/theme_settings_page.dart index aa1ab36a..570f94fb 100644 --- a/lib/pages/settings/theme_settings_page.dart +++ b/lib/pages/settings/theme_settings_page.dart @@ -12,6 +12,7 @@ import 'package:kazumi/bean/settings/color_type.dart'; import 'package:kazumi/utils/utils.dart'; import 'package:card_settings_ui/card_settings_ui.dart'; import 'package:provider/provider.dart'; +import 'package:window_manager/window_manager.dart'; class ThemeSettingsPage extends StatefulWidget { const ThemeSettingsPage({super.key}); @@ -27,6 +28,7 @@ class _ThemeSettingsPageState extends State { late dynamic defaultThemeColor; late bool oledEnhance; late bool useDynamicColor; + late bool showWindowButton; final PopularController popularController = Modular.get(); late final ThemeProvider themeProvider; @@ -40,6 +42,8 @@ class _ThemeSettingsPageState extends State { oledEnhance = setting.get(SettingBoxKey.oledEnhance, defaultValue: false); useDynamicColor = setting.get(SettingBoxKey.useDynamicColor, defaultValue: false); + showWindowButton = + setting.get(SettingBoxKey.showWindowButton, defaultValue: false); themeProvider = Provider.of(context, listen: false); } @@ -275,18 +279,33 @@ class _ThemeSettingsPageState extends State { ), ], ), - SettingsSection( - bottomInfo: const Text('仅安卓可以修改'), - tiles: [ - SettingsTile.navigation( - enabled: Platform.isAndroid, - onPressed: (_) async { - Modular.to.pushNamed('/settings/theme/display'); - }, - title: const Text('屏幕帧率'), - ), - ], - ), + if (Utils.isDesktop()) + SettingsSection( + tiles: [ + SettingsTile.switchTile( + onToggle: (value) async { + showWindowButton = value ?? !showWindowButton; + await setting.put( + SettingBoxKey.showWindowButton, showWindowButton); + setState(() {}); + }, + title: const Text('使用系统标题栏'), + description: const Text('重启应用生效'), + initialValue: showWindowButton, + ), + ], + ), + if (Platform.isAndroid) + SettingsSection( + tiles: [ + SettingsTile.navigation( + onPressed: (_) async { + Modular.to.pushNamed('/settings/theme/display'); + }, + title: const Text('屏幕帧率'), + ), + ], + ), ], ), ), diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 89239ba8..7db4c2d7 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -135,5 +135,6 @@ class SettingBoxKey { webDavPassword = 'webDavPasswd', lowMemoryMode = 'lowMemoryMode', useDynamicColor = 'useDynamicColor', - defaultSuperResolutionType = 'defaultSuperResolutionType'; + defaultSuperResolutionType = 'defaultSuperResolutionType', + showWindowButton = 'showWindowButton'; }