From 471ab9674302a94eeae67f581264a1ef6fb92024 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Mon, 22 May 2023 12:54:40 -0700 Subject: [PATCH] windows fixes: especially new version of win toast --- lib/main.dart | 11 ++- lib/notification_manager.dart | 122 ++++++++++++++++++++++++------- windows/nsis/cwtch-installer.nsi | 2 +- windows/runner/Runner.rc | 10 +-- 4 files changed, 109 insertions(+), 36 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 31199ab6..94309a3d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -44,6 +44,8 @@ Future main() async { print("Cwtch version: ${EnvironmentConfig.BUILD_VER} built on: ${EnvironmentConfig.BUILD_DATE}"); LicenseRegistry.addLicense(() => licenses()); WidgetsFlutterBinding.ensureInitialized(); + // window_manager requires (await recommended but probably not required if not using immediately) + windowManager.ensureInitialized(); print("runApp()"); return runApp(Flwtch()); } @@ -104,9 +106,10 @@ class FlwtchState extends State with WindowListener { new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this); cwtch = CwtchFfi(cwtchNotifier); } - startConnectivityListener(); print("initState: invoking cwtch.Start()"); cwtch.Start(); + print("initState: starting connectivityListener"); + startConnectivityListener(); print("initState: done!"); super.initState(); } @@ -288,7 +291,8 @@ class FlwtchState extends State with WindowListener { ); // On Gnome follows up a clicked notification with a "Cwtch is ready" notification that takes you to the app. AFAICT just because Gnome is bad // https://askubuntu.com/questions/1286206/how-to-skip-the-is-ready-notification-and-directly-open-apps-in-ubuntu-20-4 - windowManager.focus(); + await windowManager.show(); + await windowManager.focus(); } // using windowManager flutter plugin until proper lifecycle management lands in desktop @@ -303,6 +307,9 @@ class FlwtchState extends State with WindowListener { globalAppState.focus = false; } + void onWindowClose() { + } + @override void dispose() { globalAppState.SetModalState(ModalState.shutdown); diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index dd3acb71..34ffe402 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -23,7 +23,8 @@ abstract class NotificationsManager { // NullNotificationsManager ignores all notification requests class NullNotificationsManager implements NotificationsManager { @override - Future notify(String message, String profile, int conversationId) async {} + Future notify( + String message, String profile, int conversationId) async {} } // Windows Notification Manager uses https://pub.dev/packages/desktoasts to implement @@ -31,11 +32,32 @@ class NullNotificationsManager implements NotificationsManager { class WindowsNotificationManager implements NotificationsManager { bool active = false; bool initialized = false; + late Future Function(String, int) notificationSelectConvo; - // TODO This needs testing and redefining... - WindowsNotificationManager() { + + WindowsNotificationManager(Future Function(String, int) notificationSelectConvo) { + this.notificationSelectConvo = notificationSelectConvo; scheduleMicrotask(() async { - initialized = await WinToast.instance().initialize(clsid: 'cwtch', displayName: 'Cwtch', aumId: 'Open Privacy Research Society', iconPath: ''); + //initialized = await WinToast.instance().initialize(clsid: 'cwtch', displayName: 'Cwtch', aumId: 'Open Privacy Research Society', iconPath: ''); + // initialize toast with you aumId, displayName and iconPath + var init = await WinToast.instance().initialize( + aumId: 'OpenPrivacyResearchSociety.Cwtch', + displayName: 'Cwtch', + iconPath: '', // TODO NEED ICON + clsid: 'cwtch', + ); + WinToast.instance().setActivatedCallback((event) { + if (event.argument != "close") { + try { + Map payloadMap = jsonDecode(event.argument); + var payload = NotificationPayload.fromJson(payloadMap); + notificationSelectConvo(payload.profileOnion, payload.convoId); + } catch (e) { + /* it failed, is ok, may have been 'close'? */ + } + } + }); + initialized = true; }); } @@ -43,14 +65,31 @@ class WindowsNotificationManager implements NotificationsManager { if (initialized && !globalAppState.focus) { if (!active) { active = true; - // WinToast.instance().clear(); - //final toast = await WinToast.instance().showToast(toast: Toast(children: ,type: ToastType.text01, title: message)); - //toast?.eventStream.listen((event) { - // if (event is ActivatedEvent) { - // WinToast.instance().bringWindowToFront(); - // } - active = false; - // }); + WinToast.instance().clear(); + await WinToast.instance().showToast( + toast: Toast( + duration: ToastDuration.short, + children: [ + ToastChildAudio(source: ToastAudioSource.im), + ToastChildVisual( + binding: ToastVisualBinding(children: [ + ToastVisualBindingChildText( + text: message, + id: 1, + ), + ])), + ToastChildActions(children: [ + ToastAction( + content: "Open", + arguments: jsonEncode(NotificationPayload(profile, conversationId)), + ), + ToastAction( + content: "Close", + arguments: "close", + ), + ]), + ])); + active = false; } } } @@ -87,7 +126,8 @@ class NixNotificationManager implements NotificationsManager { Future detectLinuxAssetsPath() async { var devStat = FileStat.stat("assets"); var localStat = FileStat.stat("data/flutter_assets"); - var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets"); + var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + + "/.local/share/cwtch/data/flutter_assets"); var rootStat = FileStat.stat("/usr/share/cwtch/data/flutter_assets"); if ((await devStat).type == FileSystemEntityType.directory) { @@ -95,14 +135,16 @@ class NixNotificationManager implements NotificationsManager { } else if ((await localStat).type == FileSystemEntityType.directory) { return path.join(Directory.current.path, "data/flutter_assets/"); } else if ((await homeStat).type == FileSystemEntityType.directory) { - return (Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets/"; + return (Platform.environment["HOME"] ?? "") + + "/.local/share/cwtch/data/flutter_assets/"; } else if ((await rootStat).type == FileSystemEntityType.directory) { return "/usr/share/cwtch/data/flutter_assets/"; } return ""; } - NixNotificationManager(Future Function(String, int) notificationSelectConvo) { + NixNotificationManager( + Future Function(String, int) notificationSelectConvo) { this.notificationSelectConvo = notificationSelectConvo; flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); @@ -113,24 +155,39 @@ class NixNotificationManager implements NotificationsManager { linuxAssetsPath = ""; } + var linuxIcon = + FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')); - var linuxIcon = FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')); + final LinuxInitializationSettings initializationSettingsLinux = + LinuxInitializationSettings( + defaultActionName: 'Open notification', + defaultIcon: linuxIcon, + defaultSuppressSound: true); - final LinuxInitializationSettings initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification', defaultIcon: linuxIcon, defaultSuppressSound: true); + final InitializationSettings initializationSettings = + InitializationSettings( + android: null, + iOS: null, + macOS: DarwinInitializationSettings(defaultPresentSound: false), + linux: initializationSettingsLinux); - final InitializationSettings initializationSettings = InitializationSettings(android: null, iOS: null, macOS: DarwinInitializationSettings(defaultPresentSound: false), linux: initializationSettingsLinux); - - flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions( + flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + MacOSFlutterLocalNotificationsPlugin>() + ?.requestPermissions( alert: true, badge: false, sound: false, ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings, ); + await flutterLocalNotificationsPlugin.initialize( + initializationSettings, + ); }); } - Future notify(String message, String profile, int conversationId) async { + Future notify( + String message, String profile, int conversationId) async { if (!globalAppState.focus) { // Warning: Only use title field on Linux, body field will render links as clickable await flutterLocalNotificationsPlugin.show( @@ -138,7 +195,11 @@ class NixNotificationManager implements NotificationsManager { message, '', NotificationDetails( - linux: LinuxNotificationDetails(suppressSound: true, category: LinuxNotificationCategory.imReceived, icon: FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')))), + linux: LinuxNotificationDetails( + suppressSound: true, + category: LinuxNotificationCategory.imReceived, + icon: FilePathLinuxIcon( + path.join(linuxAssetsPath, 'assets/knott.png')))), payload: jsonEncode(NotificationPayload(profile, conversationId))); } } @@ -153,7 +214,9 @@ class NixNotificationManager implements NotificationsManager { } } -NotificationsManager newDesktopNotificationsManager(Future Function(String profileOnion, int convoId) notificationSelectConvo) { +NotificationsManager newDesktopNotificationsManager( + Future Function(String profileOnion, int convoId) + notificationSelectConvo) { // We don't want notifications in Dev Mode if (EnvironmentConfig.TEST_MODE) { return NullNotificationsManager(); @@ -163,19 +226,22 @@ NotificationsManager newDesktopNotificationsManager(Future Function(String try { return NixNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog("Failed to create LinuxNotificationManager. Switching off notifications."); + EnvironmentConfig.debugLog( + "Failed to create LinuxNotificationManager. Switching off notifications."); } } else if (Platform.isMacOS) { try { return NixNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog("Failed to create NixNotificationManager. Switching off notifications."); + EnvironmentConfig.debugLog( + "Failed to create NixNotificationManager. Switching off notifications."); } } else if (Platform.isWindows) { try { - return WindowsNotificationManager(); + return WindowsNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog("Failed to create Windows desktoasts notification manager"); + EnvironmentConfig.debugLog( + "Failed to create Windows desktoasts notification manager"); } } diff --git a/windows/nsis/cwtch-installer.nsi b/windows/nsis/cwtch-installer.nsi index b9a3b274..a0495a97 100644 --- a/windows/nsis/cwtch-installer.nsi +++ b/windows/nsis/cwtch-installer.nsi @@ -81,7 +81,7 @@ ShowInstDetails show Section # define the output path for this file - SetOutPath $INSTDIR + SetOutPath "$INSTDIR" # define what to install and place it in the output path # Filler for .sh to populate with contents of deploy/windows diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index d0b33234..ec59a28f 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -69,14 +69,14 @@ IDI_APP_ICON_16 ICON "resources\\knot_16.ico" // Version // -#ifdef FLUTTER_BUILD_NUMBER -#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else -#define VERSION_AS_NUMBER 1,0,0 +#define VERSION_AS_NUMBER 1,0,0,0 #endif -#ifdef FLUTTER_BUILD_NAME -#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif