diff --git a/lib/app.dart b/lib/app.dart index 0c31f645..bca55123 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart' hide MenuItem; +import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:tray_manager/tray_manager.dart'; import 'package:window_manager/window_manager.dart'; @@ -37,7 +37,7 @@ class _AppState extends State with TrayListener, WindowListener { /// Only working on Windows for some reason. /// Linux will use `flutter_window_close` instead. if (settingsCubit.state.closeToTray) { - NyrnaWindow().hide(); + NyrnaWindow.instance.hide(); return; } else { super.onWindowClose(); diff --git a/lib/apps_list/apps_list_page.dart b/lib/apps_list/apps_list_page.dart index a3caefe5..09ad1fb5 100644 --- a/lib/apps_list/apps_list_page.dart +++ b/lib/apps_list/apps_list_page.dart @@ -5,6 +5,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import '../app/app.dart'; import '../settings/cubit/settings_cubit.dart'; import '../theme/theme.dart'; +import '../window/nyrna_window.dart'; import 'apps_list.dart'; /// The main screen for Nyrna. @@ -56,7 +57,7 @@ class _AppsListPageState extends State final updatedWindowSize = WidgetsBinding.instance.window.physicalSize; if (_appWindowSize != updatedWindowSize) { _appWindowSize = updatedWindowSize; - settingsCubit.saveWindowSize(); + NyrnaWindow.instance.saveWindowSize(); } super.didChangeMetrics(); } diff --git a/lib/main.dart b/lib/main.dart index 5f632113..cede39af 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,7 +9,6 @@ import 'package:helpers/helpers.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:window_manager/window_manager.dart'; -import 'package:window_size/window_size.dart' as window; import 'active_window/active_window.dart'; import 'app.dart'; @@ -59,14 +58,12 @@ Future main(List args) async { exit(0); } else {} - final nyrnaWindow = NyrnaWindow(); + final nyrnaWindow = NyrnaWindow(storage); // Created outside runApp so it can be accessed for window settings below. final settingsCubit = await SettingsCubit.init( desktopIntegration: await _initDesktopIntegration(), - getWindowInfo: window.getWindowInfo, hotkeyService: HotkeyService(activeWindow), - nyrnaWindow: nyrnaWindow, storage: storage, ); @@ -109,18 +106,9 @@ Future main(List args) async { final systemTray = SystemTrayManager(nyrnaWindow); await systemTray.initialize(); - final savedWindowSize = await settingsCubit.savedWindowSize(); - if (savedWindowSize != null) { - window.setWindowFrame(savedWindowSize); - } - - bool visible = true; bool? startHiddenInTray = await storage.getValue('startHiddenInTray'); - if (startHiddenInTray == true) { - visible = false; - } - window.setWindowVisibility(visible: visible); + if (startHiddenInTray != true) await nyrnaWindow.show(); } /// Message to be displayed if Nyrna is called with an unknown argument. diff --git a/lib/settings/cubit/settings_cubit.dart b/lib/settings/cubit/settings_cubit.dart index 170f5ea1..cbb3a92d 100644 --- a/lib/settings/cubit/settings_cubit.dart +++ b/lib/settings/cubit/settings_cubit.dart @@ -1,12 +1,9 @@ import 'dart:convert'; -import 'dart:ui'; import 'package:desktop_integration/desktop_integration.dart'; import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hotkey_manager/hotkey_manager.dart'; -import 'package:window_size/window_size.dart' show PlatformWindow; import '../../apps_list/apps_list.dart'; import '../../core/core.dart'; @@ -20,29 +17,23 @@ late SettingsCubit settingsCubit; class SettingsCubit extends Cubit { final DesktopIntegration _desktopIntegration; - final Future Function() _getWindowInfo; final HotkeyService _hotkeyService; - final NyrnaWindow _nyrnaWindow; final StorageRepository _storage; SettingsCubit._( this._desktopIntegration, - this._getWindowInfo, this._hotkeyService, - this._nyrnaWindow, this._storage, { required SettingsState initialState, }) : super(initialState) { settingsCubit = this; _hotkeyService.updateHotkey(state.hotKey); - _nyrnaWindow.preventClose(state.closeToTray); + NyrnaWindow.instance.preventClose(state.closeToTray); } static Future init({ required DesktopIntegration desktopIntegration, - required Future Function() getWindowInfo, required HotkeyService hotkeyService, - required NyrnaWindow nyrnaWindow, required StorageRepository storage, }) async { bool autoStart = await storage.getValue('autoStart') ?? false; @@ -66,9 +57,7 @@ class SettingsCubit extends Cubit { return SettingsCubit._( desktopIntegration, - getWindowInfo, hotkeyService, - nyrnaWindow, storage, initialState: SettingsState( autoStart: autoStart, @@ -121,7 +110,7 @@ class SettingsCubit extends Cubit { Future updateCloseToTray([bool? closeToTray]) async { if (closeToTray == null) return; - await _nyrnaWindow.preventClose(closeToTray); + await NyrnaWindow.instance.preventClose(closeToTray); await _storage.saveValue(key: 'closeToTray', value: closeToTray); emit(state.copyWith(closeToTray: closeToTray)); } @@ -160,21 +149,4 @@ class SettingsCubit extends Cubit { value: jsonEncode(newHotKey.toJson()), ); } - - /// Save the current window size & position to storage. - /// - /// Allows the app to remember its window size for next launch. - Future saveWindowSize() async { - final windowInfo = await _getWindowInfo(); - final rectJson = windowInfo.frame.toJson(); - await _storage.saveValue(key: 'windowSize', value: rectJson); - } - - /// Returns if available the last window size and position. - Future savedWindowSize() async { - String? rectJson = await _storage.getValue('windowSize'); - if (rectJson == null) return null; - final windowRect = RectConverter.fromJson(rectJson); - return windowRect; - } } diff --git a/lib/window/nyrna_window.dart b/lib/window/nyrna_window.dart index 0dafba15..8ea94603 100644 --- a/lib/window/nyrna_window.dart +++ b/lib/window/nyrna_window.dart @@ -2,13 +2,20 @@ import 'dart:io'; import 'dart:ui'; import 'package:flutter_window_close/flutter_window_close.dart'; -import 'package:window_size/window_size.dart'; import 'package:window_manager/window_manager.dart'; +import '../core/helpers/json_converters.dart'; +import '../logs/logs.dart'; import '../settings/settings.dart'; +import '../storage/storage_repository.dart'; class NyrnaWindow { - NyrnaWindow() { + final StorageRepository _storage; + + static late final NyrnaWindow instance; + + NyrnaWindow(this._storage) { + instance = this; _listenForWindowClose(); } @@ -20,11 +27,12 @@ class NyrnaWindow { /// some reason. Probably best to switch to only using `window_manager` if /// it starts also working on Linux in the future. FlutterWindowClose.setWindowShouldCloseHandler(() async { - if (!settingsCubit.state.closeToTray) return true; + await hide(); + final shouldExitProgram = (settingsCubit.state.closeToTray) // + ? false + : true; - hide(); - await settingsCubit.saveWindowSize(); - return false; + return shouldExitProgram; }); } @@ -35,14 +43,29 @@ class NyrnaWindow { void close() => exit(0); Future hide() async { - setWindowVisibility(visible: false); - await settingsCubit.saveWindowSize(); + await saveWindowSize(); + await windowManager.hide(); } Future show() async { - final Rect? savedWindowSize = await settingsCubit.savedWindowSize(); - if (savedWindowSize != null) setWindowFrame(savedWindowSize); + final Rect? savedWindowSize = await getSavedWindowSize(); + if (savedWindowSize != null) windowManager.setBounds(savedWindowSize); + await windowManager.show(); + } + + Future saveWindowSize() async { + final windowInfo = await windowManager.getBounds(); + final rectJson = windowInfo.toJson(); + log.v('Saving window info:\n$rectJson'); + await _storage.saveValue(key: 'windowSize', value: rectJson); + } - setWindowVisibility(visible: true); + /// Returns if available the last window size and position. + Future getSavedWindowSize() async { + String? rectJson = await _storage.getValue('windowSize'); + if (rectJson == null) return null; + log.v('Retrieved saved window info:\n$rectJson'); + final windowRect = RectConverter.fromJson(rectJson); + return windowRect; } } diff --git a/test/settings/cubit/settings_cubit_test.dart b/test/settings/cubit/settings_cubit_test.dart index b8d516cb..b8281c6b 100644 --- a/test/settings/cubit/settings_cubit_test.dart +++ b/test/settings/cubit/settings_cubit_test.dart @@ -1,16 +1,12 @@ -import 'dart:ui'; - import 'package:desktop_integration/desktop_integration.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:hotkey_manager/hotkey_manager.dart'; import 'package:mocktail/mocktail.dart'; import 'package:nyrna/apps_list/cubit/apps_list_cubit.dart'; -import 'package:nyrna/core/helpers/helpers.dart'; import 'package:nyrna/hotkey/hotkey_service.dart'; import 'package:nyrna/settings/settings.dart'; import 'package:nyrna/storage/storage_repository.dart'; import 'package:nyrna/window/nyrna_window.dart'; -import 'package:window_size/window_size.dart'; class FakeDesktopIntegration extends Fake implements DesktopIntegration { @override @@ -30,9 +26,7 @@ class MockNyrnaWindow extends Mock implements NyrnaWindow {} class MockStorageRepository extends Mock implements StorageRepository {} -late Future Function() getWindowInfo; HotkeyService hotkeyService = MockHotkeyService(); -NyrnaWindow nyrnaWindow = MockNyrnaWindow(); StorageRepository storage = MockStorageRepository(); /// Cubit being tested @@ -41,20 +35,14 @@ late SettingsCubit cubit; SettingsState get state => cubit.state; void main() { - final fallbackPlatformWindow = PlatformWindow( - const Rect.fromLTWH(0, 0, 100, 100), - 1, - null, - ); - setUpAll((() { + NyrnaWindow.instance = MockNyrnaWindow(); appsListCubit = MockAppsListCubit(); when(() => appsListCubit.setAutoRefresh( autoRefresh: any(named: 'autoRefresh'), refreshInterval: any(named: 'refreshInterval'), )).thenReturn(null); - getWindowInfo = () async => fallbackPlatformWindow; registerFallbackValue(HotKey(KeyCode.abort)); })); @@ -62,7 +50,8 @@ void main() { when(() => hotkeyService.updateHotkey(any())).thenAnswer((_) async {}); when(() => hotkeyService.removeHotkey()).thenAnswer((_) async {}); - when(() => nyrnaWindow.preventClose(any())).thenAnswer((_) async {}); + when(() => NyrnaWindow.instance.preventClose(any())) + .thenAnswer((_) async {}); when(() => storage.getValue('hotkey')).thenAnswer((_) async {}); when(() => storage.deleteValue(any())).thenAnswer((_) async {}); @@ -92,9 +81,7 @@ void main() { cubit = await SettingsCubit.init( desktopIntegration: FakeDesktopIntegration(), - getWindowInfo: getWindowInfo, hotkeyService: hotkeyService, - nyrnaWindow: nyrnaWindow, storage: storage, ); })); @@ -243,9 +230,7 @@ void main() { ); cubit = await SettingsCubit.init( desktopIntegration: FakeDesktopIntegration(), - getWindowInfo: getWindowInfo, hotkeyService: hotkeyService, - nyrnaWindow: nyrnaWindow, storage: storage, ); expect(state.hotKey.keyCode, KeyCode.insert); @@ -263,20 +248,5 @@ void main() { verify(() => storage.deleteValue('hotkey')).called(1); }); }); - test('saveWindowSize works', () async { - await cubit.saveWindowSize(); - verify(() => storage.saveValue( - key: 'windowSize', - value: fallbackPlatformWindow.frame.toJson(), - )).called(1); - }); - - test('savedWindowSize works', () async { - when(() => storage.getValue('windowSize')).thenAnswer( - (_) async => fallbackPlatformWindow.frame.toJson(), - ); - final rect = await cubit.savedWindowSize(); - expect(rect, fallbackPlatformWindow.frame); - }); }); }