diff --git a/lib/models/messagecache.dart b/lib/models/messagecache.dart index fbcfb60d..1ad2ec59 100644 --- a/lib/models/messagecache.dart +++ b/lib/models/messagecache.dart @@ -165,7 +165,7 @@ class MessageCache extends ChangeNotifier { int size() { // very naive cache size, assuming MessageInfo are fairly large on average // and everything else is small in comparison - int cacheSize = cache.entries.map((e) => e.value.size()).fold(0, (previousValue, element) => previousValue! + element); + int cacheSize = cache.entries.map((e) => e.value.size()).fold(0, (previousValue, element) => previousValue + element); return cacheSize + cacheByHash.length * 64 + cacheByIndex.length * 16; } } diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index b9ba506e..a35e344d 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -3,8 +3,10 @@ import 'dart:convert'; import 'dart:io'; import 'package:cwtch/main.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; import 'package:win_toast/win_toast.dart'; -//import 'package:desktop_notifications/desktop_notifications.dart'; +import 'package:desktop_notifications/desktop_notifications.dart' as linux_notifications; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications_linux/flutter_local_notifications_linux.dart'; import 'package:flutter_local_notifications_linux/src/model/hint.dart'; @@ -53,6 +55,52 @@ class WindowsNotificationManager implements NotificationsManager { } } +// LinuxNotificationsManager uses the desktop_notifications package to implement +// the standard dbus-powered linux desktop notifications. +class LinuxNotificationsManager implements NotificationsManager { + int previous_id = 0; + late linux_notifications.NotificationsClient client; + late Future Function(String, int) notificationSelectConvo; + late String assetsPath; + + LinuxNotificationsManager(Future Function(String, int) notificationSelectConvo) { + this.client = linux_notifications.NotificationsClient(); + this.notificationSelectConvo = notificationSelectConvo; + scheduleMicrotask(() async { + assetsPath = await detectLinuxAssetsPath(); + }); + } + + // Cwtch can install in non flutter supported ways on linux, this code detects where the assets are on Linux + 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 rootStat = FileStat.stat("/usr/share/cwtch/data/flutter_assets"); + + if ((await devStat).type == FileSystemEntityType.directory) { + return Directory.current.path; //appPath; + } 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/"; + } else if ((await rootStat).type == FileSystemEntityType.directory) { + return "/usr/share/cwtch/data/flutter_assets/"; + } + return ""; + } + + Future notify(String message, String profile, int conversationId) async { + var iconPath = Uri.file(path.join(assetsPath, "assets/knott.png")); + client.notify(message, appName: "cwtch", appIcon: iconPath.toString(), replacesId: this.previous_id).then((linux_notifications.Notification value) async { + previous_id = value.id; + if ((await value.closeReason) == linux_notifications.NotificationClosedReason.dismissed) { + this.notificationSelectConvo(profile, conversationId); + } + }); + } +} + class NotificationPayload { late String profileOnion; late int convoId; @@ -67,12 +115,13 @@ class NotificationPayload { convoId = json['convoId']; Map toJson() => { - 'profileOnion': profileOnion, - 'convoId': convoId, - }; + 'profileOnion': profileOnion, + 'convoId': convoId, + }; } -// FlutterLocalNotificationsPlugin based NotificationManager that handles Linux and MacOS +// FlutterLocalNotificationsPlugin based NotificationManager that handles MacOS +// Todo: work with author to allow settings of asset_path so we can use this for Linux and deprecate the LinuxNotificationManager // Todo: it can also handle Android, do we want to migrate away from our manual solution? class NixNotificationManager implements NotificationsManager { late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin; @@ -81,19 +130,19 @@ class NixNotificationManager implements NotificationsManager { NixNotificationManager(Future Function(String, int) notificationSelectConvo) { this.notificationSelectConvo = notificationSelectConvo; flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + final MacOSInitializationSettings initializationSettingsMacOS = MacOSInitializationSettings(defaultPresentSound: false); final LinuxInitializationSettings initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification', defaultIcon: AssetsLinuxIcon('assets/knott.png'), defaultSuppressSound: true); final InitializationSettings initializationSettings = InitializationSettings(android: null, iOS: null, macOS: initializationSettingsMacOS, linux: initializationSettingsLinux); - - flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions( - alert: true, - badge: false, - sound: false, - ); - scheduleMicrotask(() async { + flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions( + alert: true, + badge: false, + sound: false, + ); + await flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: selectNotification); }); } @@ -117,7 +166,13 @@ class NixNotificationManager implements NotificationsManager { } NotificationsManager newDesktopNotificationsManager(Future Function(String profileOnion, int convoId) notificationSelectConvo) { - if ((Platform.isLinux && !Platform.isAndroid) || Platform.isMacOS) { + if (Platform.isLinux && !Platform.isAndroid) { + try { + return LinuxNotificationsManager(notificationSelectConvo); + } catch (e) { + EnvironmentConfig.debugLog("Failed to create LinuxNotificationManager. Switching off notifications."); + } + } else if (Platform.isMacOS) { try { return NixNotificationManager(notificationSelectConvo); } catch (e) { diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 4109f39f..4b36eca8 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -130,7 +130,7 @@ class _ContactsViewState extends State { floatingActionButton: FloatingActionButton( onPressed: _modalAddImportChoice, tooltip: AppLocalizations.of(context)!.tooltipAddContact, - child: const Icon(CwtchIcons.person_add_alt_1_24px), + child: Icon(CwtchIcons.person_add_alt_1_24px, color: Provider.of(context).theme.defaultButtonTextColor,), ), body: showSearchBar || Provider.of(context).isFiltered ? _buildFilterable() : _buildContactList()); } diff --git a/lib/views/groupsettingsview.dart b/lib/views/groupsettingsview.dart index 2962bd4d..21f92fb6 100644 --- a/lib/views/groupsettingsview.dart +++ b/lib/views/groupsettingsview.dart @@ -183,7 +183,7 @@ class _GroupSettingsViewState extends State { onPressed: () { showAlertDialog(context); }, - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.transparent)), + style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Provider.of(context).theme.backgroundPaneColor), foregroundColor: MaterialStateProperty.all(Provider.of(context).theme.mainTextColor)), icon: Icon(CwtchIcons.leave_group), label: Text( AppLocalizations.of(context)!.leaveConversation, diff --git a/lib/views/peersettingsview.dart b/lib/views/peersettingsview.dart index 9486a98a..f391f82b 100644 --- a/lib/views/peersettingsview.dart +++ b/lib/views/peersettingsview.dart @@ -269,7 +269,7 @@ class _PeerSettingsViewState extends State { onPressed: () { showAlertDialog(context); }, - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.transparent)), + style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Provider.of(context).theme.backgroundPaneColor), foregroundColor: MaterialStateProperty.all(Provider.of(context).theme.mainTextColor)), icon: Icon(CwtchIcons.leave_group), label: Text( AppLocalizations.of(context)!.leaveConversation, diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index 829ba74e..1d48ff0c 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -75,6 +75,7 @@ class _ProfileMgrViewState extends State { child: Icon( Icons.add, semanticLabel: AppLocalizations.of(context)!.addNewProfileBtn, + color: Provider.of(context).theme.defaultButtonTextColor, ), ), body: _buildProfileManager(), diff --git a/lib/views/serversview.dart b/lib/views/serversview.dart index d413f2b2..cb7608e6 100644 --- a/lib/views/serversview.dart +++ b/lib/views/serversview.dart @@ -41,6 +41,7 @@ class _ServersView extends State { child: Icon( Icons.add, semanticLabel: AppLocalizations.of(context)!.addServerTooltip, + color: Provider.of(context).theme.defaultButtonTextColor, ), ), body: Consumer( diff --git a/pubspec.lock b/pubspec.lock index 422ef085..b393355b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -190,6 +190,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.7.1" + desktop_notifications: + dependency: "direct main" + description: + name: desktop_notifications + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" fake_async: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b855591d..5b900dd9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,8 +42,10 @@ dependencies: file_picker_desktop: ^1.1.0 url_launcher: ^6.0.18 window_manager: ^0.1.4 + # notification plugins win_toast: ^0.0.2 flutter_local_notifications: 9.3.2 + desktop_notifications: ^0.6.3 dev_dependencies: msix: ^2.1.3