diff --git a/lib/hooks/use_player_core.dart b/lib/hooks/use_player_core.dart index f2e2c16..fd501cf 100644 --- a/lib/hooks/use_player_core.dart +++ b/lib/hooks/use_player_core.dart @@ -1,5 +1,4 @@ import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_zustand/flutter_zustand.dart'; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cc3f15c..ba51087 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -31,7 +31,7 @@ "version": "Version", "source_code": "Source Code", "author": "Author", - "theme_color": "Theme Color", + "theme_mode": "Theme Mode", "auto": "Auto", "light": "Light", "dark": "Datk", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index ed83e01..9b9cf43 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -31,7 +31,7 @@ "version": "版本", "source_code": "源码", "author": "作者", - "theme_color": "主题颜色", + "theme_mode": "主题模式", "auto": "自动", "light": "亮色", "dark": "暗色", diff --git a/lib/main.dart b/lib/main.dart index 29d9ae3..de5b9a8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_zustand/flutter_zustand.dart'; @@ -6,7 +8,6 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:iris/info.dart'; import 'package:iris/pages/home_page.dart'; import 'package:iris/store/use_app_store.dart'; -import 'package:iris/utils/is_desktop.dart'; import 'package:media_kit/media_kit.dart'; import 'package:window_manager/window_manager.dart'; import 'package:dynamic_color/dynamic_color.dart'; @@ -15,11 +16,11 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); MediaKit.ensureInitialized(); - if (isDesktop()) { + if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) { await windowManager.ensureInitialized(); WindowOptions windowOptions = const WindowOptions( - size: Size(1280, 720), + size: Size(800, 600), minimumSize: Size(480, 270), center: true, backgroundColor: Colors.transparent, @@ -27,6 +28,7 @@ void main() async { titleBarStyle: TitleBarStyle.hidden, title: INFO.title, ); + windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.show(); await windowManager.focus(); diff --git a/lib/models/store/app_state.dart b/lib/models/store/app_state.dart index b42cfb3..462d53f 100644 --- a/lib/models/store/app_state.dart +++ b/lib/models/store/app_state.dart @@ -2,8 +2,6 @@ class AppState { bool autoPlay; bool loop; int volume; - bool isMaximized; - bool isFullScreen; bool isMuted; String theme; String subtitleLanguage; @@ -14,8 +12,6 @@ class AppState { this.autoPlay = false, this.loop = false, this.volume = 100, - this.isMaximized = false, - this.isFullScreen = false, this.isMuted = false, this.theme = 'auto', this.subtitleLanguage = 'auto', @@ -27,8 +23,6 @@ class AppState { bool? autoPlay, bool? loop, int? volume, - bool? isMaximized, - bool? isFullScreen, bool? isMuted, String? theme, String? subtitleLanguage, @@ -39,8 +33,6 @@ class AppState { autoPlay: autoPlay ?? this.autoPlay, loop: loop ?? this.loop, volume: volume ?? this.volume, - isMaximized: isMaximized ?? this.isMaximized, - isFullScreen: isFullScreen ?? this.isFullScreen, isMuted: isMuted ?? this.isMuted, theme: theme ?? this.theme, subtitleLanguage: subtitleLanguage ?? this.subtitleLanguage, @@ -53,8 +45,6 @@ class AppState { 'autoPlay': autoPlay, 'loop': loop, 'volume': volume, - 'isMaximized': isMaximized, - 'isFullScreen': isFullScreen, 'isMuted': isMuted, 'theme': theme, 'subtitleLanguage': subtitleLanguage, @@ -68,8 +58,6 @@ class AppState { autoPlay: json['autoPlay'] ?? true, loop: json['loop'] ?? false, volume: json['volume'] ?? 100, - isMaximized: json['isMaximized'] ?? false, - isFullScreen: json['isFullScreen'] ?? false, isMuted: json['isMuted'] ?? false, theme: json['theme'] ?? 'auto', subtitleLanguage: json['subtitleLanguage'] ?? 'auto', diff --git a/lib/pages/player/control_bar.dart b/lib/pages/player/control_bar.dart index 1e2f3e0..9ca620d 100644 --- a/lib/pages/player/control_bar.dart +++ b/lib/pages/player/control_bar.dart @@ -1,3 +1,4 @@ +import 'dart:io'; import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -7,11 +8,10 @@ import 'package:iris/hooks/use_player_core.dart'; import 'package:iris/models/storages/local_storage.dart'; import 'package:iris/pages/player/subtitles_menu_button.dart'; import 'package:iris/pages/settings/settings.dart'; -import 'package:iris/store/use_app_store.dart'; import 'package:iris/store/use_play_queue_store.dart'; import 'package:iris/utils/get_localizations.dart'; -import 'package:iris/utils/is_desktop.dart'; import 'package:iris/pages/player/play_queue.dart'; +import 'package:iris/utils/resize_window.dart'; import 'package:iris/widgets/show_popup.dart'; import 'package:iris/pages/storages/storages.dart'; import 'package:window_manager/window_manager.dart'; @@ -39,8 +39,9 @@ class ControlBar extends HookWidget { @override Widget build(BuildContext context) { final t = getLocalizations(context); - final isFullScreen = - useAppStore().select(context, (state) => state.isFullScreen); + bool isDesktop = useMemoized( + (() => Platform.isWindows || Platform.isLinux || Platform.isMacOS)); + final playQueueLength = usePlayQueueStore().select(context, (state) => state.playQueue.length); final currentIndex = @@ -64,7 +65,8 @@ class ControlBar extends HookWidget { Text( formatDurationToMinutes(playerCore.position), style: TextStyle( - color: Theme.of(context).colorScheme.onSurface, + color: + Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 14, decoration: TextDecoration.none), ), @@ -73,7 +75,7 @@ class ControlBar extends HookWidget { data: SliderTheme.of(context).copyWith( thumbColor: Theme.of(context) .colorScheme - .onSurface + .onSurfaceVariant .withAlpha(222), thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 6, @@ -86,11 +88,11 @@ class ControlBar extends HookWidget { overlayRadius: 12), activeTrackColor: Theme.of(context) .colorScheme - .onSurface + .onSurfaceVariant .withOpacity(0.75), inactiveTrackColor: Theme.of(context) .colorScheme - .onSurface + .onSurfaceVariant .withOpacity(0.5), trackHeight: 4, ), @@ -119,7 +121,8 @@ class ControlBar extends HookWidget { Text( formatDurationToMinutes(playerCore.duration), style: TextStyle( - color: Theme.of(context).colorScheme.onSurface, + color: + Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 14, decoration: TextDecoration.none), ), @@ -208,7 +211,7 @@ class ControlBar extends HookWidget { if (playerCore.playing == true) { playerController.pause(); } else { - if (isDesktop()) { + if (isDesktop) { windowManager.setTitle(playerCore.title); } playerController.play(); @@ -256,21 +259,33 @@ class ControlBar extends HookWidget { child: SubtitlesMenuButton(playerCore: playerCore), ), Visibility( - visible: isDesktop() && + visible: isDesktop && MediaQuery.of(context).size.width > 600, - child: IconButton( - tooltip: isFullScreen - ? t.exit_fullscreen - : t.enter_fullscreen, - icon: Icon( - isFullScreen - ? Icons.close_fullscreen_rounded - : Icons.open_in_full_rounded, - size: 18, - ), - onPressed: () { - showControl(); - useAppStore().toggleFullScreen(); + child: FutureBuilder( + future: windowManager.isFullScreen(), + builder: (BuildContext context, + AsyncSnapshot snapshot) { + final isFullScreen = snapshot.data ?? false; + return IconButton( + tooltip: isFullScreen + ? t.exit_fullscreen + : t.enter_fullscreen, + icon: Icon( + isFullScreen + ? Icons.close_fullscreen_rounded + : Icons.open_in_full_rounded, + size: 18, + ), + onPressed: () async { + showControl(); + if (isFullScreen) { + await windowManager.setFullScreen(false); + await resizeWindow(playerCore.aspectRatio); + } else { + await windowManager.setFullScreen(true); + } + }, + ); }, ), ), diff --git a/lib/pages/player/iris_player.dart b/lib/pages/player/iris_player.dart index fb3602e..54268e0 100644 --- a/lib/pages/player/iris_player.dart +++ b/lib/pages/player/iris_player.dart @@ -1,17 +1,15 @@ import 'dart:async'; +import 'dart:io'; import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:flutter_zustand/flutter_zustand.dart'; import 'package:iris/hooks/use_player_controller.dart'; import 'package:iris/hooks/use_player_core.dart'; import 'package:iris/info.dart'; import 'package:iris/models/storages/local_storage.dart'; import 'package:iris/pages/player/subtitles_menu_button.dart'; import 'package:iris/pages/settings/settings.dart'; -import 'package:iris/store/use_app_store.dart'; import 'package:iris/utils/get_localizations.dart'; -import 'package:iris/utils/is_desktop.dart'; import 'package:iris/utils/resize_window.dart'; import 'package:iris/widgets/custom_app_bar.dart'; import 'package:iris/pages/player/control_bar.dart'; @@ -35,51 +33,27 @@ class IrisPlayer extends HookWidget { return player.dispose; }, []); + bool isDesktop = useMemoized( + (() => Platform.isWindows || Platform.isLinux || Platform.isMacOS)); + PlayerCore playerCore = usePlayerCore(context, player); PlayerController playerController = usePlayerController(context, playerCore); final isShowControl = useState(true); - final isHover = useState(true); - final isTouch = useState(false); + final isHover = useState(false); final hideTimer = useRef(null); - final isMaximized = - useAppStore().select(context, (state) => state.isMaximized); - final isFullScreen = - useAppStore().select(context, (state) => state.isFullScreen); - double width = MediaQuery.of(context).size.width; double controlBarWidth = width > 632 ? 600 : width - 32; useEffect(() { - if (isDesktop()) { - () async { - if (isMaximized) { - await windowManager.maximize(); - } else { - await windowManager.unmaximize(); - if (playerCore.aspectRatio != null) { - resizeWindow(playerCore.aspectRatio!); - } - } - }(); + if (isDesktop) { + resizeWindow(playerCore.aspectRatio); } return; - }, [isMaximized]); - - useEffect(() { - if (isDesktop()) { - () async { - await windowManager.setFullScreen(isFullScreen); - if (!isFullScreen && playerCore.aspectRatio != null) { - resizeWindow(playerCore.aspectRatio!); - } - }(); - } - return; - }, [isFullScreen]); + }, [playerCore.aspectRatio]); void startHideTimer() { hideTimer.value = Timer(const Duration(seconds: 5), () { @@ -96,11 +70,13 @@ class IrisPlayer extends HookWidget { void showControl() { isShowControl.value = true; + isHover.value = false; resetHideTimer(); } void hideControl() { isShowControl.value = false; + isHover.value = false; hideTimer.value?.cancel(); } @@ -110,25 +86,13 @@ class IrisPlayer extends HookWidget { }, []); useEffect(() { - if (isDesktop()) { + if (isDesktop) { windowManager .setTitle(playerCore.title.isEmpty ? INFO.title : playerCore.title); } return; }, [playerCore.title]); - useEffect(() { - if (isDesktop() && - !isFullScreen && - !isMaximized && - playerCore.aspectRatio != null) { - () async { - resizeWindow(playerCore.aspectRatio!); - }(); - } - return; - }, [playerCore.aspectRatio]); - return Stack( children: [ // Video @@ -141,36 +105,20 @@ class IrisPlayer extends HookWidget { cursor: isShowControl.value || !playerCore.playing ? SystemMouseCursors.basic : SystemMouseCursors.none, - onEnter: (event) { - if (event.kind != PointerDeviceKind.touch) { - isHover.value = false; - showControl(); - } - }, - onExit: (event) { - if (event.kind != PointerDeviceKind.touch) { - isHover.value = false; - if (playerCore.playing) { - hideControl(); - } - } - }, onHover: (event) { if (event.kind != PointerDeviceKind.touch) { - isHover.value = false; showControl(); } }, child: GestureDetector( onTap: () { - isHover.value = false; if (isShowControl.value) { hideControl(); } else { showControl(); } }, - onDoubleTapDown: (details) { + onDoubleTapDown: (details) async { showControl(); if (details.kind == PointerDeviceKind.touch) { double position = details.globalPosition.dx / width; @@ -186,8 +134,13 @@ class IrisPlayer extends HookWidget { : player.play(); } } else { - if (isDesktop()) { - useAppStore().toggleFullScreen(); + if (isDesktop) { + if (await windowManager.isFullScreen()) { + await windowManager.setFullScreen(false); + await resizeWindow(playerCore.aspectRatio); + } else { + await windowManager.setFullScreen(true); + } } } }, @@ -200,16 +153,14 @@ class IrisPlayer extends HookWidget { // onLongPressUp: () => playerCore.updateRate(1.0), // onLongPressEnd: (details) => playerCore.updateRate(1.0), // onLongPressCancel: () => playerCore.updateRate(1.0), - onPanStart: (details) { - if (details.kind == PointerDeviceKind.touch) { - isTouch.value = true; - } else { - isTouch.value = false; - } - }, - onPanUpdate: (details) { - if (isDesktop() && !isTouch.value) { - windowManager.startDragging(); + onPanStart: (details) async { + if (isDesktop) { + isHover.value = true; + await windowManager.startDragging(); + if (isShowControl.value) { + resetHideTimer(); + } + isHover.value = false; } }, child: Video( @@ -248,18 +199,6 @@ class IrisPlayer extends HookWidget { left: 0, right: 0, child: MouseRegion( - onEnter: (event) { - if (event.kind != PointerDeviceKind.touch) { - isHover.value = true; - showControl(); - } - }, - onExit: (event) { - if (event.kind != PointerDeviceKind.touch) { - isHover.value = false; - resetHideTimer(); - } - }, onHover: (event) { if (event.kind != PointerDeviceKind.touch) { isHover.value = true; @@ -267,14 +206,28 @@ class IrisPlayer extends HookWidget { } }, child: GestureDetector( - onTapDown: (details) { - if (details.kind == PointerDeviceKind.touch) { + onTap: () => showControl(), + onDoubleTap: () async { + if (isDesktop && await windowManager.isMaximized()) { + await windowManager.unmaximize(); + await resizeWindow(playerCore.aspectRatio); + } else { + await windowManager.maximize(); + } + }, + onPanStart: (details) async { + if (isDesktop) { + isHover.value = true; + await windowManager.startDragging(); + if (isShowControl.value) { + resetHideTimer(); + } isHover.value = false; } - showControl(); }, child: CustomAppBar( title: playerCore.title, + playerCore: playerCore, actions: [ width > 600 ? const SizedBox(width: 8) @@ -315,20 +268,34 @@ class IrisPlayer extends HookWidget { }, ), Visibility( - visible: isDesktop(), - child: IconButton( - tooltip: isFullScreen - ? t.exit_fullscreen - : t.enter_fullscreen, - icon: Icon( - isFullScreen - ? Icons.close_fullscreen_rounded - : Icons.open_in_full_rounded, - size: 18, - ), - onPressed: () { - showControl(); - useAppStore().toggleFullScreen(); + visible: isDesktop, + child: FutureBuilder( + future: windowManager.isFullScreen(), + builder: (BuildContext context, + AsyncSnapshot snapshot) { + final isFullScreen = snapshot.data ?? false; + return IconButton( + tooltip: isFullScreen + ? t.exit_fullscreen + : t.enter_fullscreen, + icon: Icon( + isFullScreen + ? Icons.close_fullscreen_rounded + : Icons.open_in_full_rounded, + size: 18, + ), + onPressed: () async { + showControl(); + if (isFullScreen) { + await windowManager + .setFullScreen(false); + await resizeWindow( + playerCore.aspectRatio); + } else { + await windowManager.setFullScreen(true); + } + }, + ); }, ), ), @@ -352,18 +319,6 @@ class IrisPlayer extends HookWidget { child: SizedBox( width: controlBarWidth, child: MouseRegion( - onEnter: (event) { - if (event.kind != PointerDeviceKind.touch) { - isHover.value = true; - showControl(); - } - }, - onExit: (event) { - if (event.kind != PointerDeviceKind.touch) { - isHover.value = false; - resetHideTimer(); - } - }, onHover: (event) { if (event.kind != PointerDeviceKind.touch) { isHover.value = true; @@ -371,12 +326,7 @@ class IrisPlayer extends HookWidget { } }, child: GestureDetector( - onTapDown: (details) { - if (details.kind == PointerDeviceKind.touch) { - isHover.value = false; - } - showControl(); - }, + onTap: () => showControl(), child: ControlBar( playerCore: playerCore, playerController: playerController, diff --git a/lib/pages/settings/general.dart b/lib/pages/settings/general.dart index 0bacb77..ce37ee0 100644 --- a/lib/pages/settings/general.dart +++ b/lib/pages/settings/general.dart @@ -31,7 +31,7 @@ class General extends HookWidget { : theme == 'dark' ? Icons.dark_mode_rounded : Icons.contrast_rounded), - title: Text(t.theme_color), + title: Text(t.theme_mode), subtitle: Text(() { switch (theme) { case 'auto': diff --git a/lib/store/use_app_store.dart b/lib/store/use_app_store.dart index 32986f3..45b42a4 100644 --- a/lib/store/use_app_store.dart +++ b/lib/store/use_app_store.dart @@ -11,13 +11,6 @@ class AppStore extends PersistentStore { Future updateAutoPlay(bool autoPlay) async => set(state.copyWith(autoPlay: autoPlay)); - Future toggleMaximize() async { - set(state.copyWith(isMaximized: !state.isMaximized)); - } - - Future toggleFullScreen() async => - set(state.copyWith(isFullScreen: !state.isFullScreen)); - Future updateTheme(String theme) async { set(state.copyWith(theme: theme)); save(state); @@ -40,8 +33,6 @@ class AppStore extends PersistentStore { if (appState != null) { return AppState.fromJson(json.decode(appState)).copyWith( autoPlay: false, - isFullScreen: false, - isMaximized: false, ); } } catch (e) { diff --git a/lib/utils/is_desktop.dart b/lib/utils/is_desktop.dart deleted file mode 100644 index 0364e7c..0000000 --- a/lib/utils/is_desktop.dart +++ /dev/null @@ -1,3 +0,0 @@ -import 'dart:io'; - -bool isDesktop() => Platform.isWindows || Platform.isLinux || Platform.isMacOS; diff --git a/lib/utils/logger.dart b/lib/utils/logger.dart new file mode 100644 index 0000000..998bc34 --- /dev/null +++ b/lib/utils/logger.dart @@ -0,0 +1,3 @@ +import 'dart:developer'; + +const logger = log; diff --git a/lib/utils/resize_window.dart b/lib/utils/resize_window.dart index fd47adb..40d772b 100644 --- a/lib/utils/resize_window.dart +++ b/lib/utils/resize_window.dart @@ -1,11 +1,14 @@ import 'dart:ui'; - -import 'package:iris/utils/is_desktop.dart'; +import 'package:iris/utils/logger.dart'; import 'package:window_manager/window_manager.dart'; import 'package:window_size/window_size.dart'; -Future resizeWindow(double videoAspectRatio) async { - if (!isDesktop()) return; +Future resizeWindow(double? videoAspectRatio) async { + if (await windowManager.isFullScreen() || + await windowManager.isMaximized() || + videoAspectRatio == null) { + return; + } windowManager.setAspectRatio(videoAspectRatio); @@ -27,11 +30,13 @@ Future resizeWindow(double videoAspectRatio) async { final height = screenHeight * 0.8 / screen.scaleFactor; final width = height * videoAspectRatio; // windowManager.setAspectRatio(videoAspectRatio); + logger('Window resize: width: $width, height: $height'); windowManager.setSize(Size(width, height)); } else { final width = screenWidth * 0.8 / screen.scaleFactor; final height = width / videoAspectRatio; // windowManager.setAspectRatio(videoAspectRatio); + logger('Window resize: width: $width, height: $height'); windowManager.setSize(Size(width, height)); } } diff --git a/lib/widgets/custom_app_bar.dart b/lib/widgets/custom_app_bar.dart index d13513f..f0dcec6 100644 --- a/lib/widgets/custom_app_bar.dart +++ b/lib/widgets/custom_app_bar.dart @@ -1,107 +1,120 @@ +import 'dart:io'; import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:flutter_zustand/flutter_zustand.dart'; +import 'package:iris/hooks/use_player_core.dart'; import 'package:iris/info.dart'; -import 'package:iris/store/use_app_store.dart'; -import 'package:iris/utils/is_desktop.dart'; +import 'package:iris/utils/resize_window.dart'; import 'package:window_manager/window_manager.dart'; class CustomAppBar extends HookWidget { const CustomAppBar({ super.key, this.title, + required this.playerCore, this.actions, }); final String? title; + final PlayerCore playerCore; final List? actions; @override Widget build(BuildContext context) { - final isMaximized = - useAppStore().select(context, (state) => state.isMaximized); - final isFullScreen = - useAppStore().select(context, (state) => state.isFullScreen); + bool isDesktop = useMemoized( + (() => Platform.isWindows || Platform.isLinux || Platform.isMacOS)); - return GestureDetector( - onPanStart: (details) { - if (isDesktop()) { - windowManager.startDragging(); - } - }, - onDoubleTap: () { - if (isDesktop()) { - useAppStore().toggleMaximize(); - } - }, - child: ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Container( - padding: const EdgeInsets.fromLTRB(16, 4, 4, 4), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface.withOpacity(0.75), - ), - child: Row( - children: [ - Expanded( - child: Text( - title!.isEmpty ? INFO.title : title!, - maxLines: 1, - style: TextStyle( - fontSize: 18, - overflow: TextOverflow.ellipsis, - color: Theme.of(context).colorScheme.onSurface, - ), + return ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: Container( + padding: const EdgeInsets.fromLTRB(16, 4, 4, 4), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface.withOpacity(0.75), + ), + child: Row( + children: [ + Expanded( + child: Text( + title!.isEmpty ? INFO.title : title!, + maxLines: 1, + textAlign: !isDesktop && actions != null + ? TextAlign.center + : TextAlign.start, + style: TextStyle( + fontSize: 18, + overflow: TextOverflow.ellipsis, + color: Theme.of(context).colorScheme.onSurface, ), ), - Row( - children: [ - ...actions ?? [], - if (isDesktop()) ...[ - IconButton( - onPressed: () => windowManager.minimize(), - icon: const Icon(Icons.remove_rounded), - ), - IconButton( - onPressed: () async => isFullScreen - ? useAppStore().toggleFullScreen() - : useAppStore().toggleMaximize(), - icon: isFullScreen == true - ? const Icon(Icons.close_fullscreen_rounded, - size: 20) - : isMaximized == true - ? const RotatedBox( - quarterTurns: 2, - child: Icon( - Icons.filter_none_rounded, - size: 18, - )) - : const Icon( - Icons.crop_din_rounded, - size: 20, - ), - ), - IconButton( - onPressed: () => windowManager.close(), - icon: const Icon(Icons.close_rounded), - style: ButtonStyle( - overlayColor: WidgetStateProperty.resolveWith( - (Set states) { - if (states.contains(WidgetState.pressed)) { - return Colors.red.withOpacity(0.4); - } else if (states.contains(WidgetState.hovered)) { - return Colors.red.withOpacity(0.5); - } - return null; // 默认颜色 - }), - ), + ), + Row( + children: [ + ...actions ?? [], + if (isDesktop) ...[ + IconButton( + onPressed: () => windowManager.minimize(), + icon: const Icon(Icons.remove_rounded), + ), + FutureBuilder( + future: windowManager.isFullScreen(), + builder: + (BuildContext context, AsyncSnapshot snapshot) { + final isFullScreen = snapshot.data ?? false; + return FutureBuilder( + future: windowManager.isMaximized(), + builder: (BuildContext context, + AsyncSnapshot snapshot) { + final isMaximized = snapshot.data ?? false; + return IconButton( + onPressed: () async { + if (isFullScreen) { + await windowManager.setFullScreen(false); + await resizeWindow(playerCore.aspectRatio); + } else if (isMaximized) { + await windowManager.unmaximize(); + await resizeWindow(playerCore.aspectRatio); + } else { + await windowManager.maximize(); + } + }, + icon: isFullScreen == true + ? const Icon(Icons.close_fullscreen_rounded, + size: 20) + : isMaximized == true + ? const RotatedBox( + quarterTurns: 2, + child: Icon( + Icons.filter_none_rounded, + size: 18, + )) + : const Icon( + Icons.crop_din_rounded, + size: 20, + ), + ); + }, + ); + }, + ), + IconButton( + onPressed: () => windowManager.close(), + icon: const Icon(Icons.close_rounded), + style: ButtonStyle( + overlayColor: WidgetStateProperty.resolveWith( + (Set states) { + if (states.contains(WidgetState.pressed)) { + return Colors.red.withOpacity(0.4); + } else if (states.contains(WidgetState.hovered)) { + return Colors.red.withOpacity(0.5); + } + return null; // 默认颜色 + }), ), - ], + ), ], - ), - ], - ), + ], + ), + ], ), ), ), diff --git a/lib/widgets/dialog/show_theme_color_dialog.dart b/lib/widgets/dialog/show_theme_color_dialog.dart index e479f00..ac89c1d 100644 --- a/lib/widgets/dialog/show_theme_color_dialog.dart +++ b/lib/widgets/dialog/show_theme_color_dialog.dart @@ -24,7 +24,7 @@ class ThemeColorDialog extends HookWidget { } return AlertDialog( - title: Text(t.theme_color), + title: Text(t.theme_mode), content: SingleChildScrollView( child: Column( children: [ diff --git a/lib/widgets/show_popup.dart b/lib/widgets/show_popup.dart index ea1592d..c85b470 100644 --- a/lib/widgets/show_popup.dart +++ b/lib/widgets/show_popup.dart @@ -1,7 +1,6 @@ +import 'dart:io'; import 'dart:ui'; - import 'package:flutter/material.dart'; -import 'package:iris/utils/is_desktop.dart'; import 'package:window_manager/window_manager.dart'; enum PopupDirection { left, right } @@ -53,7 +52,7 @@ class Popup extends PopupRoute { bottom: 0, child: GestureDetector( onPanStart: (details) { - if (isDesktop()) { + if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) { windowManager.startDragging(); } }, @@ -61,7 +60,9 @@ class Popup extends PopupRoute { ), ), Positioned( - top: isDesktop() ? 64 : 16, + top: Platform.isWindows || Platform.isLinux || Platform.isMacOS + ? 64 + : 16, left: direction == PopupDirection.left ? 16 : null, right: direction == PopupDirection.right ? 16 : null, bottom: 16,