Add window manager

This commit is contained in:
Hillel Coren 2022-07-31 18:27:12 +03:00
parent dd91864b3b
commit a8fe9c3dca
14 changed files with 156 additions and 23 deletions

View File

@ -91,6 +91,8 @@ enum AppEnvironment {
const String kSharedPrefs = 'shared_prefs'; const String kSharedPrefs = 'shared_prefs';
const String kSharedPrefUrl = 'url'; const String kSharedPrefUrl = 'url';
const String kSharedPrefToken = 'checksum'; const String kSharedPrefToken = 'checksum';
const String kSharedPrefWidth = 'width';
const String kSharedPrefHeight = 'height';
const String kProductProPlanMonth = 'pro_plan'; const String kProductProPlanMonth = 'pro_plan';
const String kProductEnterprisePlanMonth_2 = 'enterprise_plan'; const String kProductEnterprisePlanMonth_2 = 'enterprise_plan';

View File

@ -58,9 +58,23 @@ import 'package:invoiceninja_flutter/utils/web_stub.dart'
// STARTER: import - do not remove comment // STARTER: import - do not remove comment
import 'package:invoiceninja_flutter/redux/purchase_order/purchase_order_middleware.dart'; import 'package:invoiceninja_flutter/redux/purchase_order/purchase_order_middleware.dart';
import 'package:window_manager/window_manager.dart';
void main({bool isTesting = false}) async { void main({bool isTesting = false}) async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await windowManager.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
windowManager.waitUntilReadyToShow(
WindowOptions(
size: Size(
prefs.getDouble(kSharedPrefWidth) ?? 800,
prefs.getDouble(kSharedPrefHeight) ?? 600,
),
), () async {
await windowManager.show();
await windowManager.focus();
});
final store = Store<AppState>(appReducer, final store = Store<AppState>(appReducer,
initialState: await _initialState(isTesting), initialState: await _initialState(isTesting),

View File

@ -147,7 +147,9 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
void initState() { void initState() {
super.initState(); super.initState();
WebUtils.warnChanges(widget.store); if (kIsWeb) {
WebUtils.warnChanges(widget.store);
}
Timer.periodic(Duration(milliseconds: kMillisecondsToTimerRefreshData), Timer.periodic(Duration(milliseconds: kMillisecondsToTimerRefreshData),
(_) { (_) {

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
// Package imports: // Package imports:
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/ui/app/app_title_bar.dart'; import 'package:invoiceninja_flutter/ui/app/app_title_bar.dart';
import 'package:invoiceninja_flutter/ui/app/window_manager.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/edit/purchase_order_edit_vm.dart'; import 'package:invoiceninja_flutter/ui/purchase_order/edit/purchase_order_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_email_vm.dart'; import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_email_vm.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_pdf_vm.dart'; import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_pdf_vm.dart';
@ -302,29 +303,31 @@ class MainScreen extends StatelessWidget {
return false; return false;
}, },
child: DesktopSessionTimeout( child: WindowManager(
child: SafeArea( child: DesktopSessionTimeout(
child: FocusTraversalGroup( child: SafeArea(
policy: ReadingOrderTraversalPolicy(), child: FocusTraversalGroup(
child: Column( policy: ReadingOrderTraversalPolicy(),
children: [ child: Column(
if (isWindows()) AppTitleBar(), children: [
Expanded( if (isWindows()) AppTitleBar(),
child: ChangeLayoutBanner( Expanded(
appLayout: prefState.appLayout, child: ChangeLayoutBanner(
suggestedLayout: AppLayout.desktop, appLayout: prefState.appLayout,
child: Row(children: <Widget>[ suggestedLayout: AppLayout.desktop,
if (prefState.showMenu) MenuDrawerBuilder(), child: Row(children: <Widget>[
Expanded( if (prefState.showMenu) MenuDrawerBuilder(),
child: AppBorder( Expanded(
child: screen, child: AppBorder(
isLeft: prefState.showMenu && child: screen,
(!state.isFullScreen || showFilterSidebar), isLeft: prefState.showMenu &&
)), (!state.isFullScreen || showFilterSidebar),
]), )),
]),
),
), ),
), ],
], ),
), ),
), ),
), ),

View File

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/main_app.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/app/dialogs/alert_dialog.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart';
class WindowManager extends StatefulWidget {
const WindowManager({Key key, this.child}) : super(key: key);
final Widget child;
@override
State<WindowManager> createState() => _WindowManagerState();
}
class _WindowManagerState extends State<WindowManager> with WindowListener {
@override
void initState() {
windowManager.addListener(this);
_init();
super.initState();
}
void _init() async {
await windowManager.setPreventClose(true);
setState(() {});
}
@override
void onWindowResize() async {
final size = await windowManager.getSize();
final prefs = await SharedPreferences.getInstance();
prefs.setDouble(kSharedPrefWidth, size.width);
prefs.setDouble(kSharedPrefHeight, size.height);
}
@override
void onWindowClose() async {
final localization = AppLocalization.of(context);
final store = StoreProvider.of<AppState>(navigatorKey.currentContext);
final state = store.state;
if (await windowManager.isPreventClose()) {
if (state.hasChanges()) {
showDialog<void>(
context: context,
builder: (context) => MessageDialog(
localization.errorUnsavedChanges,
dismissLabel: localization.continueEditing,
onDiscard: () async {
await windowManager.destroy();
},
));
} else {
await windowManager.destroy();
}
}
}
@override
void dispose() {
windowManager.removeListener(this);
super.dispose();
}
@override
Widget build(BuildContext context) => widget.child;
}

View File

@ -7,17 +7,25 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <printing/printing_plugin.h> #include <printing/printing_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <sentry_flutter/sentry_flutter_plugin.h> #include <sentry_flutter/sentry_flutter_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
#include <window_manager/window_manager_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) printing_registrar = g_autoptr(FlPluginRegistrar) printing_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "PrintingPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "PrintingPlugin");
printing_plugin_register_with_registrar(printing_registrar); printing_plugin_register_with_registrar(printing_registrar);
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
g_autoptr(FlPluginRegistrar) sentry_flutter_registrar = g_autoptr(FlPluginRegistrar) sentry_flutter_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin");
sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar); sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
g_autoptr(FlPluginRegistrar) window_manager_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
window_manager_plugin_register_with_registrar(window_manager_registrar);
} }

View File

@ -4,8 +4,10 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
printing printing
screen_retriever
sentry_flutter sentry_flutter
url_launcher_linux url_launcher_linux
window_manager
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -10,11 +10,13 @@ import package_info
import package_info_plus_macos import package_info_plus_macos
import path_provider_macos import path_provider_macos
import printing import printing
import screen_retriever
import sentry_flutter import sentry_flutter
import shared_preferences_macos import shared_preferences_macos
import sign_in_with_apple import sign_in_with_apple
import sqflite import sqflite
import url_launcher_macos import url_launcher_macos
import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin")) InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
@ -22,9 +24,11 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin")) PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin")) SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin")) SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
} }

View File

@ -74,6 +74,7 @@ dependencies:
image_cropper: ^2.0.2 image_cropper: ^2.0.2
msal_js: ^2.14.0 msal_js: ^2.14.0
sign_in_with_apple: ^4.0.0 sign_in_with_apple: ^4.0.0
window_manager: ^0.2.5
# bitsdojo_window: ^0.1.2 # bitsdojo_window: ^0.1.2
# quick_actions: ^0.2.1 # quick_actions: ^0.2.1
# idb_shim: ^1.11.1+1 # idb_shim: ^1.11.1+1

View File

@ -1015,6 +1015,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.27.3" version: "0.27.3"
screen_retriever:
dependency: transitive
description:
name: screen_retriever
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
sentry: sentry:
dependency: transitive dependency: transitive
description: description:
@ -1463,6 +1470,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.5.1" version: "2.5.1"
window_manager:
dependency: "direct main"
description:
name: window_manager
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.5"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@ -74,6 +74,7 @@ dependencies:
image_cropper: ^2.0.2 image_cropper: ^2.0.2
msal_js: ^2.14.0 msal_js: ^2.14.0
sign_in_with_apple: ^4.0.0 sign_in_with_apple: ^4.0.0
window_manager: ^0.2.5
# bitsdojo_window: ^0.1.2 # bitsdojo_window: ^0.1.2
# quick_actions: ^0.2.1 # quick_actions: ^0.2.1
# idb_shim: ^1.11.1+1 # idb_shim: ^1.11.1+1

View File

@ -74,6 +74,7 @@ dependencies:
image_cropper: ^2.0.2 image_cropper: ^2.0.2
msal_js: ^2.14.0 msal_js: ^2.14.0
sign_in_with_apple: ^4.0.0 sign_in_with_apple: ^4.0.0
window_manager: ^0.2.5
# bitsdojo_window: ^0.1.2 # bitsdojo_window: ^0.1.2
# quick_actions: ^0.2.1 # quick_actions: ^0.2.1
# idb_shim: ^1.11.1+1 # idb_shim: ^1.11.1+1

View File

@ -7,14 +7,20 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <printing/printing_plugin.h> #include <printing/printing_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <sentry_flutter/sentry_flutter_plugin.h> #include <sentry_flutter/sentry_flutter_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
#include <window_manager/window_manager_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
PrintingPluginRegisterWithRegistrar( PrintingPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PrintingPlugin")); registry->GetRegistrarForPlugin("PrintingPlugin"));
ScreenRetrieverPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
SentryFlutterPluginRegisterWithRegistrar( SentryFlutterPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SentryFlutterPlugin")); registry->GetRegistrarForPlugin("SentryFlutterPlugin"));
UrlLauncherWindowsRegisterWithRegistrar( UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows")); registry->GetRegistrarForPlugin("UrlLauncherWindows"));
WindowManagerPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("WindowManagerPlugin"));
} }

View File

@ -4,8 +4,10 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
printing printing
screen_retriever
sentry_flutter sentry_flutter
url_launcher_windows url_launcher_windows
window_manager
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST