fix: doesn't minimize to tray when system title bar close button is used #866

This commit is contained in:
Kingkor Roy Tirtho 2023-12-02 23:18:07 +06:00
parent 5f1df5a87d
commit bb8f250f5f
4 changed files with 236 additions and 16 deletions

View File

@ -11,16 +11,6 @@ import 'dart:io' show Platform, exit;
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:local_notifier/local_notifier.dart'; import 'package:local_notifier/local_notifier.dart';
final closeNotification = DesktopTools.createNotification(
title: 'Spotube',
message: 'Running in background. Minimized to System Tray',
actions: [
LocalNotificationAction(text: 'Close The App'),
],
)?..onClickAction = (value) {
exit(0);
};
class PageWindowTitleBar extends StatefulHookConsumerWidget class PageWindowTitleBar extends StatefulHookConsumerWidget
implements PreferredSizeWidget { implements PreferredSizeWidget {
final Widget? leading; final Widget? leading;
@ -113,12 +103,7 @@ class WindowTitleBarButtons extends HookConsumerWidget {
const type = ThemeType.auto; const type = ThemeType.auto;
Future<void> onClose() async { Future<void> onClose() async {
if (preferences.closeBehavior == CloseBehavior.close) { await DesktopTools.window.close();
exit(0);
} else {
await DesktopTools.window.hide();
await closeNotification?.show();
}
} }
useEffect(() { useEffect(() {

View File

@ -0,0 +1,32 @@
import 'dart:io';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/hooks/configurators/use_window_listener.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:local_notifier/local_notifier.dart';
final closeNotification = DesktopTools.createNotification(
title: 'Spotube',
message: 'Running in background. Minimized to System Tray',
actions: [
LocalNotificationAction(text: 'Close The App'),
],
)?..onClickAction = (value) {
exit(0);
};
void useCloseBehavior(WidgetRef ref) {
useWindowListener(
onWindowClose: () async {
final preferences = ref.read(userPreferencesProvider);
if (preferences.closeBehavior == CloseBehavior.minimizeToTray) {
await DesktopTools.window.hide();
closeNotification?.show();
} else {
exit(0);
}
},
);
}

View File

@ -0,0 +1,197 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class CallbackWindowListener implements WindowListener {
final VoidCallback? _onWindowClose;
final VoidCallback? _onWindowFocus;
final VoidCallback? _onWindowBlur;
final VoidCallback? _onWindowMaximize;
final VoidCallback? _onWindowUnmaximize;
final VoidCallback? _onWindowMinimize;
final VoidCallback? _onWindowRestore;
final VoidCallback? _onWindowResize;
final VoidCallback? _onWindowResized;
final VoidCallback? _onWindowMove;
final VoidCallback? _onWindowMoved;
final VoidCallback? _onWindowEnterFullScreen;
final VoidCallback? _onWindowLeaveFullScreen;
final VoidCallback? _onWindowDocked;
final VoidCallback? _onWindowUndocked;
final VoidCallback? _onWindowEvent;
const CallbackWindowListener({
VoidCallback? onWindowClose,
VoidCallback? onWindowFocus,
VoidCallback? onWindowBlur,
VoidCallback? onWindowMaximize,
VoidCallback? onWindowUnmaximize,
VoidCallback? onWindowMinimize,
VoidCallback? onWindowRestore,
VoidCallback? onWindowResize,
VoidCallback? onWindowResized,
VoidCallback? onWindowMove,
VoidCallback? onWindowMoved,
VoidCallback? onWindowEnterFullScreen,
VoidCallback? onWindowLeaveFullScreen,
VoidCallback? onWindowDocked,
VoidCallback? onWindowUndocked,
VoidCallback? onWindowEvent,
}) : _onWindowClose = onWindowClose,
_onWindowFocus = onWindowFocus,
_onWindowBlur = onWindowBlur,
_onWindowMaximize = onWindowMaximize,
_onWindowUnmaximize = onWindowUnmaximize,
_onWindowMinimize = onWindowMinimize,
_onWindowRestore = onWindowRestore,
_onWindowResize = onWindowResize,
_onWindowResized = onWindowResized,
_onWindowMove = onWindowMove,
_onWindowMoved = onWindowMoved,
_onWindowEnterFullScreen = onWindowEnterFullScreen,
_onWindowLeaveFullScreen = onWindowLeaveFullScreen,
_onWindowDocked = onWindowDocked,
_onWindowUndocked = onWindowUndocked,
_onWindowEvent = onWindowEvent;
@override
void onWindowBlur() {
return _onWindowBlur?.call();
}
@override
void onWindowClose() {
return _onWindowClose?.call();
}
@override
void onWindowDocked() {
return _onWindowDocked?.call();
}
@override
void onWindowEnterFullScreen() {
return _onWindowEnterFullScreen?.call();
}
@override
void onWindowEvent(String eventName) {
return _onWindowEvent?.call();
}
@override
void onWindowFocus() {
return _onWindowFocus?.call();
}
@override
void onWindowLeaveFullScreen() {
return _onWindowLeaveFullScreen?.call();
}
@override
void onWindowMaximize() {
return _onWindowMaximize?.call();
}
@override
void onWindowMinimize() {
return _onWindowMinimize?.call();
}
@override
void onWindowMove() {
return _onWindowMove?.call();
}
@override
void onWindowMoved() {
return _onWindowMoved?.call();
}
@override
void onWindowResize() {
return _onWindowResize?.call();
}
@override
void onWindowResized() {
return _onWindowResized?.call();
}
@override
void onWindowRestore() {
return _onWindowRestore?.call();
}
@override
void onWindowUndocked() {
return _onWindowUndocked?.call();
}
@override
void onWindowUnmaximize() {
return _onWindowUnmaximize?.call();
}
}
void useWindowListener({
VoidCallback? onWindowClose,
VoidCallback? onWindowFocus,
VoidCallback? onWindowBlur,
VoidCallback? onWindowMaximize,
VoidCallback? onWindowUnmaximize,
VoidCallback? onWindowMinimize,
VoidCallback? onWindowRestore,
VoidCallback? onWindowResize,
VoidCallback? onWindowResized,
VoidCallback? onWindowMove,
VoidCallback? onWindowMoved,
VoidCallback? onWindowEnterFullScreen,
VoidCallback? onWindowLeaveFullScreen,
VoidCallback? onWindowDocked,
VoidCallback? onWindowUndocked,
VoidCallback? onWindowEvent,
}) {
useEffect(() {
final listener = CallbackWindowListener(
onWindowClose: onWindowClose,
onWindowFocus: onWindowFocus,
onWindowBlur: onWindowBlur,
onWindowMaximize: onWindowMaximize,
onWindowUnmaximize: onWindowUnmaximize,
onWindowMinimize: onWindowMinimize,
onWindowRestore: onWindowRestore,
onWindowResize: onWindowResize,
onWindowResized: onWindowResized,
onWindowMove: onWindowMove,
onWindowMoved: onWindowMoved,
onWindowEnterFullScreen: onWindowEnterFullScreen,
onWindowLeaveFullScreen: onWindowLeaveFullScreen,
onWindowDocked: onWindowDocked,
onWindowUndocked: onWindowUndocked,
onWindowEvent: onWindowEvent,
);
DesktopTools.window.addListener(listener);
return () {
DesktopTools.window.removeListener(listener);
};
}, [
onWindowClose,
onWindowFocus,
onWindowBlur,
onWindowMaximize,
onWindowUnmaximize,
onWindowMinimize,
onWindowRestore,
onWindowResize,
onWindowResized,
onWindowMove,
onWindowMoved,
onWindowEnterFullScreen,
onWindowLeaveFullScreen,
onWindowDocked,
onWindowUndocked,
onWindowEvent,
]);
}

View File

@ -15,6 +15,7 @@ import 'package:metadata_god/metadata_god.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotube/collections/routes.dart'; import 'package:spotube/collections/routes.dart';
import 'package:spotube/collections/intents.dart'; import 'package:spotube/collections/intents.dart';
import 'package:spotube/hooks/configurators/use_close_behavior.dart';
import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart'; import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart';
import 'package:spotube/hooks/configurators/use_get_storage_perms.dart'; import 'package:spotube/hooks/configurators/use_get_storage_perms.dart';
import 'package:spotube/l10n/l10n.dart'; import 'package:spotube/l10n/l10n.dart';
@ -49,6 +50,10 @@ Future<void> main(List<String> rawArgs) async {
await FlutterDisplayMode.setHighRefreshRate(); await FlutterDisplayMode.setHighRefreshRate();
} }
if (DesktopTools.platform.isDesktop) {
await DesktopTools.window.setPreventClose(true);
}
await DesktopTools.ensureInitialized( await DesktopTools.ensureInitialized(
DesktopWindowOptions( DesktopWindowOptions(
hideTitleBar: true, hideTitleBar: true,
@ -177,6 +182,7 @@ class SpotubeState extends ConsumerState<Spotube> {
ref.watch(paletteProvider.select((s) => s?.dominantColor?.color)); ref.watch(paletteProvider.select((s) => s?.dominantColor?.color));
useInitSysTray(ref); useInitSysTray(ref);
useCloseBehavior(ref);
useEffect(() { useEffect(() {
FlutterNativeSplash.remove(); FlutterNativeSplash.remove();