LCOV - code coverage report
Current view: top level - lib - notification_manager.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 71 0.0 %
Date: 2024-10-10 18:23:49 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : import 'dart:convert';
       3             : import 'dart:io';
       4             : 
       5             : import 'package:cwtch/main.dart';
       6             : import 'package:win_toast/win_toast.dart';
       7             : import 'package:flutter_local_notifications/flutter_local_notifications.dart';
       8             : 
       9             : import 'package:path/path.dart' as path;
      10             : 
      11             : import 'config.dart';
      12             : 
      13             : // NotificationsManager provides a wrapper around platform specific notifications logic.
      14             : abstract class NotificationsManager {
      15             :   Future<void> notify(String message, String profile, int conversationId);
      16             : }
      17             : 
      18             : // NullNotificationsManager ignores all notification requests
      19             : class NullNotificationsManager implements NotificationsManager {
      20           0 :   @override
      21             :   Future<void> notify(String message, String profile, int conversationId) async {}
      22             : }
      23             : 
      24             : // Windows Notification Manager uses https://pub.dev/packages/desktoasts to implement
      25             : // windows notifications
      26             : class WindowsNotificationManager implements NotificationsManager {
      27             :   bool active = false;
      28             :   bool initialized = false;
      29             :   late Future<void> Function(String, int) notificationSelectConvo;
      30             : 
      31           0 :   WindowsNotificationManager(Future<void> Function(String, int) notificationSelectConvo) {
      32           0 :     this.notificationSelectConvo = notificationSelectConvo;
      33           0 :     scheduleMicrotask(() async {
      34           0 :       initialized = await WinToast.instance().initialize(appName: 'cwtch', productName: 'Cwtch', companyName: 'Open Privacy Research Society');
      35             :       /*
      36             :        * WinToast 0.3.0 code for when we can compile it
      37             :        *
      38             :       var init = await WinToast.instance().initialize(
      39             :         aumId: 'OpenPrivacyResearchSociety.Cwtch',
      40             :         displayName: 'Cwtch',
      41             :         iconPath: '', // TODO NEED ICON
      42             :         clsid: 'cwtch',
      43             :       );
      44             :       WinToast.instance().setActivatedCallback((event) {
      45             :         if (event.argument != "close") {
      46             :           try {
      47             :             Map<String, dynamic> payloadMap = jsonDecode(event.argument);
      48             :             var payload = NotificationPayload.fromJson(payloadMap);
      49             :             notificationSelectConvo(payload.profileOnion, payload.convoId);
      50             :           } catch (e) {
      51             :             /* it failed, is ok, may have been 'close'? */
      52             :           }
      53             :         }
      54             :       });*/
      55           0 :       initialized = true;
      56             :     });
      57             :   }
      58             : 
      59           0 :   Future<void> notify(String message, String profile, int conversationId) async {
      60           0 :     if (initialized && !globalAppState.focus) {
      61           0 :       if (!active) {
      62           0 :         active = true;
      63           0 :         WinToast.instance().clear();
      64           0 :         final toast = await WinToast.instance().showToast(type: ToastType.text01, title: message);
      65           0 :         toast?.eventStream.listen((event) {
      66           0 :           if (event is ActivatedEvent) {
      67           0 :             WinToast.instance().bringWindowToFront();
      68             :           }
      69           0 :           active = false;
      70             :         });
      71             :       }
      72             : 
      73             :       /*
      74             :        * WinToast 0.3.0 code for when we can compile it
      75             :        *  
      76             :         WinToast.instance().clear();
      77             :         await WinToast.instance().showToast(
      78             :             toast: Toast(duration: ToastDuration.short, children: [
      79             :           ToastChildAudio(source: ToastAudioSource.im),
      80             :           ToastChildVisual(
      81             :               binding: ToastVisualBinding(children: [
      82             :             ToastVisualBindingChildText(
      83             :               text: message,
      84             :               id: 1,
      85             :             ),
      86             :           ])),
      87             :           ToastChildActions(children: [
      88             :             ToastAction(
      89             :               content: "Open",
      90             :               arguments: jsonEncode(NotificationPayload(profile, conversationId)),
      91             :             ),
      92             :             ToastAction(
      93             :               content: "Close",
      94             :               arguments: "close",
      95             :             ),
      96             :           ]),
      97             :         ]));
      98             :         active = false;
      99             :       }*/
     100             :     }
     101             :   }
     102             : }
     103             : 
     104             : class NotificationPayload {
     105             :   late String profileOnion;
     106             :   late int convoId;
     107             : 
     108           0 :   NotificationPayload(String po, int cid) {
     109           0 :     profileOnion = po;
     110           0 :     convoId = cid;
     111             :   }
     112             : 
     113           0 :   NotificationPayload.fromJson(Map<String, dynamic> json)
     114           0 :       : profileOnion = json['profileOnion'],
     115           0 :         convoId = json['convoId'];
     116             : 
     117           0 :   Map<String, dynamic> toJson() => {
     118           0 :         'profileOnion': profileOnion,
     119           0 :         'convoId': convoId,
     120             :       };
     121             : }
     122             : 
     123             : // FlutterLocalNotificationsPlugin based NotificationManager that handles MacOS <s>and Linux</s>
     124             : // TODO: Upgrade from 9.6 to 12.x but there are breaking changes (including for mac)
     125             : // TODO: Windows support is being worked on, check back and migrate to that too when it lands
     126             : class NixNotificationManager implements NotificationsManager {
     127             :   late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
     128             :   late Future<void> Function(String, int) notificationSelectConvo;
     129             :   late String linuxAssetsPath;
     130             : 
     131             :   // Cwtch can install in non flutter supported ways on linux, this code detects where the assets are on Linux
     132           0 :   Future<String> detectLinuxAssetsPath() async {
     133           0 :     var devStat = FileStat.stat("assets");
     134           0 :     var localStat = FileStat.stat("data/flutter_assets");
     135           0 :     var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets");
     136           0 :     var rootStat = FileStat.stat("/usr/share/cwtch/data/flutter_assets");
     137             : 
     138           0 :     if ((await devStat).type == FileSystemEntityType.directory) {
     139           0 :       return Directory.current.path; //appPath;
     140           0 :     } else if ((await localStat).type == FileSystemEntityType.directory) {
     141           0 :       return path.join(Directory.current.path, "data/flutter_assets/");
     142           0 :     } else if ((await homeStat).type == FileSystemEntityType.directory) {
     143           0 :       return (Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets/";
     144           0 :     } else if ((await rootStat).type == FileSystemEntityType.directory) {
     145             :       return "/usr/share/cwtch/data/flutter_assets/";
     146             :     }
     147             :     return "";
     148             :   }
     149             : 
     150           0 :   NixNotificationManager(Future<void> Function(String, int) notificationSelectConvo) {
     151           0 :     this.notificationSelectConvo = notificationSelectConvo;
     152           0 :     flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
     153             : 
     154           0 :     scheduleMicrotask(() async {
     155           0 :       if (Platform.isLinux) {
     156           0 :         linuxAssetsPath = await detectLinuxAssetsPath();
     157             :       } else {
     158           0 :         linuxAssetsPath = "";
     159             :       }
     160             : 
     161           0 :       var linuxIcon = FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png'));
     162             : 
     163           0 :       final LinuxInitializationSettings initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification', defaultIcon: linuxIcon, defaultSuppressSound: true);
     164             : 
     165             :       final InitializationSettings initializationSettings =
     166           0 :           InitializationSettings(android: null, iOS: null, macOS: DarwinInitializationSettings(defaultPresentSound: false), linux: initializationSettingsLinux);
     167             : 
     168           0 :       flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<MacOSFlutterLocalNotificationsPlugin>()?.requestPermissions(
     169             :             alert: true,
     170             :             badge: false,
     171             :             sound: false,
     172             :           );
     173             : 
     174           0 :       await flutterLocalNotificationsPlugin.initialize(
     175             :         initializationSettings,
     176             :       );
     177             :     });
     178             :   }
     179             : 
     180           0 :   Future<void> notify(String message, String profile, int conversationId) async {
     181           0 :     if (!globalAppState.focus) {
     182             :       // Warning: Only use title field on Linux, body field will render links as clickable
     183           0 :       await flutterLocalNotificationsPlugin.show(
     184             :           0,
     185             :           message,
     186             :           '',
     187           0 :           NotificationDetails(
     188           0 :               linux: LinuxNotificationDetails(suppressSound: true, category: LinuxNotificationCategory.imReceived, icon: FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')))),
     189           0 :           payload: jsonEncode(NotificationPayload(profile, conversationId)));
     190             :     }
     191             :   }
     192             : 
     193             :   // Notification click response function, triggers ui jump to conversation
     194           0 :   void selectNotification(String? payloadJson) async {
     195             :     if (payloadJson != null) {
     196           0 :       Map<String, dynamic> payloadMap = jsonDecode(payloadJson);
     197           0 :       var payload = NotificationPayload.fromJson(payloadMap);
     198           0 :       notificationSelectConvo(payload.profileOnion, payload.convoId);
     199             :     }
     200             :   }
     201             : }
     202             : 
     203           0 : NotificationsManager newDesktopNotificationsManager(Future<void> Function(String profileOnion, int convoId) notificationSelectConvo) {
     204             :   // We don't want notifications in Dev Mode
     205             :   if (EnvironmentConfig.TEST_MODE) {
     206           0 :     return NullNotificationsManager();
     207             :   }
     208             : 
     209           0 :   if (Platform.isLinux && !Platform.isAndroid) {
     210             :     try {
     211           0 :       return NixNotificationManager(notificationSelectConvo);
     212             :     } catch (e) {
     213           0 :       EnvironmentConfig.debugLog("Failed to create LinuxNotificationManager. Switching off notifications.");
     214             :     }
     215           0 :   } else if (Platform.isMacOS) {
     216             :     try {
     217           0 :       return NixNotificationManager(notificationSelectConvo);
     218             :     } catch (e) {
     219           0 :       EnvironmentConfig.debugLog("Failed to create NixNotificationManager. Switching off notifications.");
     220             :     }
     221           0 :   } else if (Platform.isWindows) {
     222             :     try {
     223           0 :       return WindowsNotificationManager(notificationSelectConvo);
     224             :     } catch (e) {
     225           0 :       EnvironmentConfig.debugLog("Failed to create Windows desktoasts notification manager");
     226             :     }
     227             :   }
     228             : 
     229           0 :   return NullNotificationsManager();
     230             : }

Generated by: LCOV version 1.14