diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index b13c83036..3b43c2034 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:io'; // ignore: unnecessary_import import 'dart:typed_data'; +import 'dart:ui'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/cupertino.dart'; @@ -12,7 +13,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_timezone/flutter_timezone.dart'; import 'package:http/http.dart' as http; -import 'package:image/image.dart' as image; import 'package:path_provider/path_provider.dart'; import 'package:timezone/data/latest_all.dart' as tz; import 'package:timezone/timezone.dart' as tz; @@ -52,10 +52,10 @@ class ReceivedNotification { String? selectedNotificationPayload; /// A notification action which triggers a url launch event -const String urlLaunchActionId = 'id_1'; +const String urlLaunchActionId = 'id1'; /// A notification action which triggers a App navigation event -const String navigationActionId = 'id_3'; +const String navigationActionId = 'id3'; /// Defines a iOS/MacOS notification category for text input actions. const String darwinNotificationCategoryText = 'textCategory'; @@ -1138,8 +1138,12 @@ class _HomePageState extends State { linux: linuxNotificationDetails, ); await flutterLocalNotificationsPlugin.show( - id++, 'plain title', 'plain body', notificationDetails, - payload: 'item z'); + id++, + 'plain title', + 'plain body', + notificationDetails, + payload: 'item z', + ); } Future _showNotificationWithTextAction() async { @@ -2771,17 +2775,20 @@ Future _showLinuxNotificationWithByteDataIcon() async { final ByteData assetIcon = await rootBundle.load( 'icons/app_icon_density.png', ); - final image.Image? iconData = image.decodePng( - assetIcon.buffer.asUint8List().toList(), - ); - final Uint8List iconBytes = iconData!.getBytes(); + + final Uint8List iconBytes = assetIcon.buffer.asUint8List(); + final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(iconBytes); + final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); + final int width = descriptor.width; + final int height = descriptor.height; + final LinuxNotificationDetails linuxPlatformChannelSpecifics = LinuxNotificationDetails( icon: ByteDataLinuxIcon( LinuxRawIconData( data: iconBytes, - width: iconData.width, - height: iconData.height, + width: width, + height: height, channels: 4, // The icon has an alpha channel hasAlpha: true, ), diff --git a/flutter_local_notifications/pubspec.yaml b/flutter_local_notifications/pubspec.yaml index 546bb9463..871047d3c 100644 --- a/flutter_local_notifications/pubspec.yaml +++ b/flutter_local_notifications/pubspec.yaml @@ -14,6 +14,10 @@ dependencies: flutter_local_notifications_platform_interface: ^7.0.0 timezone: ^0.9.0 +dependency_overrides: + flutter_local_notifications_linux: + path: ../flutter_local_notifications_linux + dev_dependencies: flutter_driver: sdk: flutter diff --git a/flutter_local_notifications_linux/assets/icons/app_icon.png b/flutter_local_notifications_linux/assets/icons/app_icon.png new file mode 100644 index 000000000..c4cc798d7 Binary files /dev/null and b/flutter_local_notifications_linux/assets/icons/app_icon.png differ diff --git a/flutter_local_notifications_linux/lib/flutter_local_notifications_linux.dart b/flutter_local_notifications_linux/lib/flutter_local_notifications_linux.dart index 8aeaafb6e..5a1e74e24 100644 --- a/flutter_local_notifications_linux/lib/flutter_local_notifications_linux.dart +++ b/flutter_local_notifications_linux/lib/flutter_local_notifications_linux.dart @@ -1,7 +1,7 @@ /// The Linux implementation of `flutter_local_notifications`. library flutter_local_notifications_linux; -// flutter_local_notifications_linux depends on dbus and posix +// flutter_local_notifications_linux depends on posix // which uses FFI internally; export a stub for platforms that don't // support FFI (e.g., web) to avoid having transitive dependencies // break web compilation. diff --git a/flutter_local_notifications_linux/lib/src/dbus_wrapper.dart b/flutter_local_notifications_linux/lib/src/dbus_wrapper.dart deleted file mode 100644 index 95237941c..000000000 --- a/flutter_local_notifications_linux/lib/src/dbus_wrapper.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'dart:async'; - -import 'package:dbus/dbus.dart'; - -/// Mockable [DBusRemoteObject] wrapper -class DBusWrapper { - late final DBusRemoteObject _object; - late final String _destination; - - /// Build an instance of [DBusRemoteObject] - void build({ - required String destination, - required String path, - }) { - _destination = destination; - _object = DBusRemoteObject( - DBusClient.session(), - name: destination, - path: DBusObjectPath(path), - ); - } - - /// Invokes a method on this [DBusRemoteObject]. - /// Throws [DBusMethodResponseException] if the remote side returns an error. - /// - /// If [replySignature] is provided this causes this method to throw a - /// [DBusReplySignatureException] if the result is successful but the returned - /// values do not match the provided signature. - Future callMethod( - String? interface, - String name, - Iterable values, { - DBusSignature? replySignature, - bool noReplyExpected = false, - bool noAutoStart = false, - bool allowInteractiveAuthorization = false, - }) => - _object.callMethod( - interface, - name, - values, - replySignature: replySignature, - noReplyExpected: noReplyExpected, - noAutoStart: noAutoStart, - allowInteractiveAuthorization: allowInteractiveAuthorization, - ); - - /// Creates a stream of signal with the given [name]. - DBusRemoteObjectSignalStream subscribeSignal(String name) => - DBusRemoteObjectSignalStream( - object: _object, interface: _destination, name: name); -} diff --git a/flutter_local_notifications_linux/lib/src/flutter_local_notifications.dart b/flutter_local_notifications_linux/lib/src/flutter_local_notifications.dart index cf48a3be0..5809a66ca 100644 --- a/flutter_local_notifications_linux/lib/src/flutter_local_notifications.dart +++ b/flutter_local_notifications_linux/lib/src/flutter_local_notifications.dart @@ -77,14 +77,4 @@ class LinuxFlutterLocalNotificationsPlugin @override Future getCapabilities() => _manager.getCapabilities(); - - /// Returns a [Map] with the specified notification id as the key - /// and the id, assigned by the system, as the value. - /// - /// Note: the system ID is unique only within the current user session, - /// so it's undesirable to save it to persistable storage without any - /// invalidation/update. For more information, please see - /// Desktop Notifications Specification https://specifications.freedesktop.org/notification-spec/latest/ar01s02.html - @override - Future> getSystemIdMap() => _manager.getSystemIdMap(); } diff --git a/flutter_local_notifications_linux/lib/src/flutter_local_notifications_platform_linux.dart b/flutter_local_notifications_linux/lib/src/flutter_local_notifications_platform_linux.dart index 04adc5faf..fde798d59 100644 --- a/flutter_local_notifications_linux/lib/src/flutter_local_notifications_platform_linux.dart +++ b/flutter_local_notifications_linux/lib/src/flutter_local_notifications_platform_linux.dart @@ -36,13 +36,4 @@ abstract class FlutterLocalNotificationsPlatformLinux /// Some functionality may not be implemented by the notification server, /// conforming clients should check if it is available before using it. Future getCapabilities(); - - /// Returns a [Map] with the specified notification id as the key - /// and the id, assigned by the system, as the value. - /// - /// Note: the system ID is unique only within the current user session, - /// so it's undesirable to save it to persistable storage without any - /// invalidation/update. For more information, please see - /// Desktop Notifications Specification https://specifications.freedesktop.org/notification-spec/latest/ar01s02.html - Future> getSystemIdMap(); } diff --git a/flutter_local_notifications_linux/lib/src/flutter_local_notifications_stub.dart b/flutter_local_notifications_linux/lib/src/flutter_local_notifications_stub.dart index 859a6a80b..0eedb6a95 100644 --- a/flutter_local_notifications_linux/lib/src/flutter_local_notifications_stub.dart +++ b/flutter_local_notifications_linux/lib/src/flutter_local_notifications_stub.dart @@ -49,12 +49,4 @@ class LinuxFlutterLocalNotificationsPlugin assert(false); throw UnimplementedError(); } - - /// Errors on attempted calling of the stub. It exists only to satisfy - /// compile-time dependencies, and should never actually be called. - @override - Future> getSystemIdMap() async { - assert(false); - throw UnimplementedError(); - } } diff --git a/flutter_local_notifications_linux/lib/src/helpers.dart b/flutter_local_notifications_linux/lib/src/helpers.dart deleted file mode 100644 index ef2c9503d..000000000 --- a/flutter_local_notifications_linux/lib/src/helpers.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:dbus/dbus.dart'; - -import 'model/enums.dart'; -import 'model/hint.dart'; - -/// [LinuxHintValue] utils. -extension LinuxHintValueExtension on LinuxHintValue { - /// Convert value to [DBusValue]. - DBusValue toDBusValue() { - switch (type) { - case LinuxHintValueType.array: - final List l = value as List; - return DBusArray( - l.first.toDBusValue().signature, - l.map((LinuxHintValue v) => v.toDBusValue()), - ); - case LinuxHintValueType.boolean: - return DBusBoolean(value); - case LinuxHintValueType.byte: - return DBusByte(value); - case LinuxHintValueType.dict: - final Map m = - value as Map; - return DBusDict( - m.keys.first.toDBusValue().signature, - m.values.first.toDBusValue().signature, - m.map( - (LinuxHintValue key, LinuxHintValue value) => - MapEntry( - key.toDBusValue(), - value.toDBusValue(), - ), - ), - ); - case LinuxHintValueType.double: - return DBusDouble(value); - case LinuxHintValueType.int16: - return DBusInt16(value); - case LinuxHintValueType.int32: - return DBusInt32(value); - case LinuxHintValueType.int64: - return DBusInt64(value); - case LinuxHintValueType.string: - return DBusString(value); - case LinuxHintValueType.struct: - return DBusStruct( - (value as List).map( - (LinuxHintValue v) => v.toDBusValue(), - ), - ); - case LinuxHintValueType.uint16: - return DBusUint16(value); - case LinuxHintValueType.uint32: - return DBusUint32(value); - case LinuxHintValueType.uint64: - return DBusUint64(value); - case LinuxHintValueType.variant: - return DBusVariant((value as LinuxHintValue).toDBusValue()); - } - } -} diff --git a/flutter_local_notifications_linux/lib/src/notification_info.dart b/flutter_local_notifications_linux/lib/src/notification_info.dart index b89d9afb1..7f9c979d7 100644 --- a/flutter_local_notifications_linux/lib/src/notification_info.dart +++ b/flutter_local_notifications_linux/lib/src/notification_info.dart @@ -6,7 +6,6 @@ class LinuxNotificationInfo { /// Constructs an instance of [LinuxPlatformInfoData]. const LinuxNotificationInfo({ required this.id, - required this.systemId, this.payload, this.actions = const [], }); @@ -21,7 +20,6 @@ class LinuxNotificationInfo { .toList(); return LinuxNotificationInfo( id: json['id'] as int, - systemId: json['systemId'] as int, payload: json['payload'] as String?, actions: actions ?? [], ); @@ -30,10 +28,6 @@ class LinuxNotificationInfo { /// Notification id final int id; - /// Notification id, which is returned by the system, - /// see Desktop Notifications Specification https://specifications.freedesktop.org/notification-spec/latest/ - final int systemId; - /// Notification payload, that will be passed back to the app /// when a notification is tapped on. final String? payload; @@ -44,7 +38,6 @@ class LinuxNotificationInfo { /// Returns the object as a key-value map Map toJson() => { 'id': id, - 'systemId': systemId, 'payload': payload, 'actions': actions.map((LinuxNotificationActionInfo a) => a.toJson()).toList(), @@ -60,7 +53,6 @@ class LinuxNotificationInfo { }) => LinuxNotificationInfo( id: id ?? this.id, - systemId: systemId ?? this.systemId, payload: payload ?? this.payload, actions: actions ?? this.actions, ); @@ -73,14 +65,12 @@ class LinuxNotificationInfo { return other is LinuxNotificationInfo && other.id == id && - other.systemId == systemId && other.payload == payload && listEquals(other.actions, actions); } @override - int get hashCode => - id.hashCode ^ systemId.hashCode ^ payload.hashCode ^ actions.hashCode; + int get hashCode => id.hashCode ^ payload.hashCode ^ actions.hashCode; } /// Represents a Linux notification action information diff --git a/flutter_local_notifications_linux/lib/src/notifications_manager.dart b/flutter_local_notifications_linux/lib/src/notifications_manager.dart index 0fe413ced..3c9d6037c 100644 --- a/flutter_local_notifications_linux/lib/src/notifications_manager.dart +++ b/flutter_local_notifications_linux/lib/src/notifications_manager.dart @@ -1,21 +1,17 @@ import 'dart:async'; +import 'dart:io'; -import 'package:dbus/dbus.dart'; +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; import 'package:path/path.dart' as path; +import 'package:xdg_desktop_portal/xdg_desktop_portal.dart'; -import 'dbus_wrapper.dart'; -import 'helpers.dart'; import 'model/capabilities.dart'; import 'model/enums.dart'; -import 'model/hint.dart'; import 'model/icon.dart'; import 'model/initialization_settings.dart'; -import 'model/location.dart'; import 'model/notification_details.dart'; -import 'model/sound.dart'; -import 'model/timeout.dart'; import 'notification_info.dart'; import 'platform_info.dart'; import 'storage.dart'; @@ -24,7 +20,7 @@ import 'storage.dart'; class LinuxNotificationManager { /// Constructs an instance of of [LinuxNotificationManager] LinuxNotificationManager() - : _dbus = DBusWrapper(), + : _portal = XdgDesktopPortalClient().notification, _platformInfo = LinuxPlatformInfo(), _storage = NotificationStorage(); @@ -32,14 +28,14 @@ class LinuxNotificationManager { /// with the given class dependencies. @visibleForTesting LinuxNotificationManager.private({ - DBusWrapper? dbus, + XdgNotificationPortal? portal, LinuxPlatformInfo? platformInfo, NotificationStorage? storage, - }) : _dbus = dbus ?? DBusWrapper(), + }) : _portal = portal ?? XdgDesktopPortalClient().notification, _platformInfo = platformInfo ?? LinuxPlatformInfo(), _storage = storage ?? NotificationStorage(); - final DBusWrapper _dbus; + final XdgNotificationPortal _portal; final LinuxPlatformInfo _platformInfo; final NotificationStorage _storage; @@ -62,10 +58,6 @@ class LinuxNotificationManager { _initialized = true; _initializationSettings = initializationSettings; _onDidReceiveNotificationResponse = onDidReceiveNotificationResponse; - _dbus.build( - destination: _DBusInterfaceSpec.destination, - path: _DBusInterfaceSpec.path, - ); _platformData = await _platformInfo.getAll(); await _storage.forceReloadCache(); @@ -85,32 +77,27 @@ class LinuxNotificationManager { final LinuxNotificationIcon? defaultIcon = _initializationSettings.defaultIcon; - final DBusMethodSuccessResponse result = await _dbus.callMethod( - _DBusInterfaceSpec.destination, - _DBusMethodsSpec.notify, - [ - // app_name - DBusString(_platformData.appName ?? ''), - // replaces_id - DBusUint32(prevNotify?.systemId ?? 0), - // app_icon - DBusString(_getAppIcon(details?.icon ?? defaultIcon) ?? ''), - // summary - DBusString(title ?? ''), - // body - DBusString(body ?? ''), - // actions - DBusArray.string(_buildActions(details, _initializationSettings)), - // hints - DBusDict.stringVariant(_buildHints(details, _initializationSettings)), - // expire_timeout - DBusInt32( - details?.timeout.value ?? - const LinuxNotificationTimeout.systemDefault().value, - ), - ], - replySignature: DBusSignature('u'), + final XdgNotificationIcon? icon = await _getAppIcon( + details?.icon ?? defaultIcon, + ); + + final XdgNotificationPriority priority = _getPriority(details); + + final String defaultAction = details?.defaultActionName ?? // + _kDefaultActionName; + + final List actions = _buildActions(details); + + await _portal.addNotification( + '$id', + title: title, + body: body, + icon: icon, + priority: priority, + defaultAction: defaultAction, + buttons: actions, ); + final List? actionsInfo = details?.actions .map( (LinuxNotificationAction action) => LinuxNotificationActionInfo( @@ -119,119 +106,33 @@ class LinuxNotificationManager { ) .toList(); - final int systemId = (result.returnValues[0] as DBusUint32).value; final LinuxNotificationInfo notify = prevNotify?.copyWith( - systemId: systemId, + systemId: id, payload: payload, actions: actionsInfo, ) ?? LinuxNotificationInfo( id: id, - systemId: systemId, payload: payload, actions: actionsInfo ?? [], ); + await _storage.insert(notify); } - Map _buildHints( - LinuxNotificationDetails? details, - LinuxInitializationSettings initSettings, - ) { - final Map hints = {}; - final LinuxNotificationIcon? icon = - details?.icon ?? initSettings.defaultIcon; - if (icon?.type == LinuxIconType.byteData) { - final LinuxRawIconData data = icon!.content as LinuxRawIconData; - hints['image-data'] = DBusStruct( - [ - DBusInt32(data.width), - DBusInt32(data.height), - DBusInt32(data.rowStride), - DBusBoolean(data.hasAlpha), - DBusInt32(data.bitsPerSample), - DBusInt32(data.channels), - DBusArray.byte(data.data), - ], - ); - } - final LinuxNotificationSound? sound = - details?.sound ?? initSettings.defaultSound; - if (sound != null) { - switch (sound.type) { - case LinuxSoundType.assets: - hints['sound-file'] = DBusString( - path.join( - _platformData.assetsPath!, - sound.content as String, - ), - ); - break; - case LinuxSoundType.theme: - hints['sound-name'] = DBusString(sound.content as String); - break; - } - } - if (details?.category != null) { - hints['category'] = DBusString(details!.category!.name); - } - if (details?.urgency != null) { - hints['urgency'] = DBusByte(details!.urgency!.index); - } - if (details?.resident ?? false) { - hints['resident'] = const DBusBoolean(true); - } - final bool? suppressSound = - details?.suppressSound ?? initSettings.defaultSuppressSound; - if (suppressSound ?? false) { - hints['suppress-sound'] = const DBusBoolean(true); - } - if (details?.transient ?? false) { - hints['transient'] = const DBusBoolean(true); - } - if (details?.location != null) { - final LinuxNotificationLocation location = details!.location!; - hints['x'] = DBusByte(location.x); - hints['y'] = DBusByte(location.y); - } - if (details?.actionKeyAsIconName ?? false) { - hints['action-icons'] = const DBusBoolean(true); - } - if (details?.customHints != null) { - hints.addAll(_buildCustomHints(details!.customHints!)); - } + List _buildActions(LinuxNotificationDetails? details) { + final List actions = []; - return hints; - } + if (details == null) { + return actions; + } - Map _buildCustomHints( - List hints, - ) => - Map.fromEntries( - hints.map( - (LinuxNotificationCustomHint hint) => MapEntry( - hint.name, - hint.value.toDBusValue(), - ), - ), + for (final LinuxNotificationAction action in details.actions) { + actions.add( + XdgNotificationButton(action: action.key, label: action.label), ); - - List _buildActions( - LinuxNotificationDetails? details, - LinuxInitializationSettings initSettings, - ) { - // Add default action, which is triggered when the notification is clicked - final List actions = [ - _kDefaultActionName, - details?.defaultActionName ?? initSettings.defaultActionName, - ]; - if (details != null) { - for (final LinuxNotificationAction action in details.actions) { - actions - ..add(action.key) - ..add(action.label); - } } + return actions; } @@ -240,7 +141,7 @@ class LinuxNotificationManager { final LinuxNotificationInfo? notify = await _storage.getById(id); await _storage.removeById(id); if (notify != null) { - await _dbusCancel(notify.systemId); + await _portal.removeNotification('$id'); } } @@ -250,60 +151,32 @@ class LinuxNotificationManager { final List idList = []; for (final LinuxNotificationInfo notify in notifyList) { idList.add(notify.id); - await _dbusCancel(notify.systemId); + await _portal.removeNotification('${notify.id}'); } await _storage.removeByIdList(idList); } /// Returns the system notification server capabilities. - Future getCapabilities() async { - final DBusMethodSuccessResponse result = await _dbus.callMethod( - _DBusInterfaceSpec.destination, - _DBusMethodsSpec.getCapabilities, - [], - replySignature: DBusSignature('as'), - ); - final Set capsSet = (result.returnValues[0] as DBusArray) - .children - .map((DBusValue c) => (c as DBusString).value) - .toSet(); - - final LinuxServerCapabilities capabilities = LinuxServerCapabilities( - otherCapabilities: const {}, - body: capsSet.remove('body'), - bodyHyperlinks: capsSet.remove('body-hyperlinks'), - bodyImages: capsSet.remove('body-images'), - bodyMarkup: capsSet.remove('body-markup'), - iconMulti: capsSet.remove('icon-multi'), - iconStatic: capsSet.remove('icon-static'), - persistence: capsSet.remove('persistence'), - sound: capsSet.remove('sound'), - actions: capsSet.remove('actions'), - actionIcons: capsSet.remove('action-icons'), - ); - return capabilities.copyWith(otherCapabilities: capsSet); - } - - /// Returns a [Map] with the specified notification id as the key - /// and the id, assigned by the system, as the value. - Future> getSystemIdMap() async => - Map.fromEntries(await _storage.getAll().then( - (List list) => list.map( - (LinuxNotificationInfo notify) => MapEntry( - notify.id, - notify.systemId, - ), - ), - )); - - Future _dbusCancel(int systemId) => _dbus.callMethod( - _DBusInterfaceSpec.destination, - _DBusMethodsSpec.closeNotification, - [DBusUint32(systemId)], - replySignature: DBusSignature(''), + Future getCapabilities() async => + const LinuxServerCapabilities( + otherCapabilities: {}, + body: true, + bodyHyperlinks: true, + bodyImages: false, + bodyMarkup: true, + iconMulti: false, + iconStatic: false, + persistence: true, + sound: false, + actions: true, + actionIcons: false, ); - String? _getAppIcon(LinuxNotificationIcon? icon) { + /// Returns an icon compatible with the portal. + /// + /// The portal requires the icon either a theme name or bytes, so we convert + /// it if necessary. + Future _getAppIcon(LinuxNotificationIcon? icon) async { if (icon == null) { return null; } @@ -313,33 +186,60 @@ class LinuxNotificationManager { return null; } else { final String relativePath = icon.content as String; - return path.join(_platformData.assetsPath!, relativePath); + final File file = File(path.join( + _platformData.assetsPath!, + relativePath, + )); + if (!file.existsSync()) { + return null; + } + final Uint8List bytes = await file.readAsBytes(); + return XdgNotificationIconData(bytes); } case LinuxIconType.byteData: - return null; + final LinuxRawIconData content = icon.content as LinuxRawIconData; + final Uint8List bytes = Uint8List.fromList(content.data); + return XdgNotificationIconData(bytes); case LinuxIconType.theme: - return icon.content as String; + final String content = icon.content as String; + final List themeNames = [content]; + return XdgNotificationIconThemed(themeNames); case LinuxIconType.filePath: - return icon.content as String; + final File file = File(icon.content as String); + if (!file.existsSync()) { + return null; + } + final Uint8List bytes = await file.readAsBytes(); + return XdgNotificationIconData(bytes); + } + } + + XdgNotificationPriority _getPriority(LinuxNotificationDetails? details) { + if (details == null) { + return XdgNotificationPriority.normal; + } + switch (details.urgency) { + case LinuxNotificationUrgency.low: + return XdgNotificationPriority.low; + case LinuxNotificationUrgency.normal: + return XdgNotificationPriority.normal; + case LinuxNotificationUrgency.critical: + return XdgNotificationPriority.urgent; + default: + return XdgNotificationPriority.normal; } } /// Subscribe to the signals for actions and closing notifications. void _subscribeSignals() { - _dbus.subscribeSignal(_DBusMethodsSpec.actionInvoked).listen( - (DBusSignal s) async { - if (s.signature != DBusSignature('us')) { - return; - } - - final int systemId = (s.values[0] as DBusUint32).value; - final String actionKey = (s.values[1] as DBusString).value; - final LinuxNotificationInfo? notify = - await _storage.getBySystemId(systemId); + _portal.actionInvoked.listen( + (XdgNotificationActionInvokedEvent event) async { + final LinuxNotificationInfo? notify = await _storage // + .getById(int.parse(event.id)); if (notify == null) { return; } - if (actionKey == _kDefaultActionName) { + if (event.action == _kDefaultActionName) { _onDidReceiveNotificationResponse?.call( NotificationResponse( id: notify.id, @@ -349,9 +249,10 @@ class LinuxNotificationManager { ), ); } else { - final LinuxNotificationActionInfo? actionInfo = - notify.actions.firstWhere( - (LinuxNotificationActionInfo a) => a.key == actionKey, + final LinuxNotificationActionInfo? actionInfo = notify // + .actions + .firstWhereOrNull( + (LinuxNotificationActionInfo a) => a.key == event.action, ); if (actionInfo == null) { return; @@ -359,40 +260,20 @@ class LinuxNotificationManager { _onDidReceiveNotificationResponse?.call( NotificationResponse( id: notify.id, - actionId: actionInfo.key, payload: notify.payload, + actionId: actionInfo.key, notificationResponseType: NotificationResponseType.selectedNotificationAction, ), ); } - }, - ); - - _dbus.subscribeSignal(_DBusMethodsSpec.notificationClosed).listen( - (DBusSignal s) async { - if (s.signature != DBusSignature('uu')) { - return; - } - final int systemId = (s.values[0] as DBusUint32).value; - await _storage.removeBySystemId(systemId); + await _storage.removeById(notify.id); }, ); - } -} -const String _kDefaultActionName = 'default'; - -class _DBusInterfaceSpec { - static const String destination = 'org.freedesktop.Notifications'; - static const String path = '/org/freedesktop/Notifications'; + return; + } } -class _DBusMethodsSpec { - static const String notify = 'Notify'; - static const String closeNotification = 'CloseNotification'; - static const String actionInvoked = 'ActionInvoked'; - static const String notificationClosed = 'NotificationClosed'; - static const String getCapabilities = 'GetCapabilities'; -} +const String _kDefaultActionName = 'Open notification'; diff --git a/flutter_local_notifications_linux/lib/src/storage.dart b/flutter_local_notifications_linux/lib/src/storage.dart index 3bba1ed72..0cab0ca49 100644 --- a/flutter_local_notifications_linux/lib/src/storage.dart +++ b/flutter_local_notifications_linux/lib/src/storage.dart @@ -32,12 +32,6 @@ class NotificationStorage { return cache.toImmutableMap().values.toList(); } - /// Get notification by [LinuxNotificationInfo.id]. - Future getBySystemId(int systemId) async { - final _Cache cache = await _readInfoMap(); - return cache.getBySystemId(systemId); - } - /// Get notification by [LinuxNotificationInfo.systemId]. Future getById(int id) async { final _Cache cache = await _readInfoMap(); @@ -60,17 +54,6 @@ class NotificationStorage { return _writeInfoList(cache.values.toList()); } - /// Remove notification from the storage by [LinuxNotificationInfo.systemId]. - /// Returns `true` if the operation succeeded. - Future removeBySystemId(int systemId) async { - final _Cache cache = await _readInfoMap(); - final LinuxNotificationInfo? info = cache.getBySystemId(systemId); - if (info != null) { - cache.removeById(info.id); - } - return _writeInfoList(cache.values.toList()); - } - /// Remove notification from the storage by [idList]. /// Returns `true` if the operation succeeded. Future removeByIdList(List idList) async { @@ -148,28 +131,15 @@ class NotificationStorage { } class _Cache { - _Cache() - : _infoMap = {}, - _systemIdMap = {}; + _Cache() : _infoMap = {}; final Map _infoMap; - /// System ID to ID map. - final Map _systemIdMap; - LinuxNotificationInfo? getById(int? id) => _infoMap[id]; - LinuxNotificationInfo? getBySystemId(int? id) => _infoMap[_systemIdMap[id]]; + void insert(LinuxNotificationInfo info) => _infoMap[info.id] = info; - void insert(LinuxNotificationInfo info) { - _infoMap[info.id] = info; - _systemIdMap[info.systemId] = info.id; - } - - void removeById(int id) { - final LinuxNotificationInfo? info = _infoMap.remove(id); - _systemIdMap.remove(info?.systemId); - } + void removeById(int id) => _infoMap.remove(id); Iterable get values => _infoMap.values; diff --git a/flutter_local_notifications_linux/pubspec.yaml b/flutter_local_notifications_linux/pubspec.yaml index 8c25242af..a03215155 100644 --- a/flutter_local_notifications_linux/pubspec.yaml +++ b/flutter_local_notifications_linux/pubspec.yaml @@ -4,14 +4,21 @@ version: 4.0.0+1 homepage: https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications dependencies: - dbus: ^0.7.8 ffi: ^2.0.1 flutter: sdk: flutter flutter_local_notifications_platform_interface: ^7.0.0 path: ^1.8.0 + xdg_desktop_portal: ^0.1.12 xdg_directories: ">=0.2.0+1 <2.0.0" +dependency_overrides: + # Temporarily use a fork of xdg_desktop_portal to support the ActionInvoked signal + xdg_desktop_portal: + git: + url: https://github.com/Merrit/xdg_desktop_portal.dart.git + ref: 8d18d560ba3388627c998011a0803defc0e84c30 + dev_dependencies: build_runner: ^2.3.3 flutter_test: diff --git a/flutter_local_notifications_linux/test/notifications_manager_test.dart b/flutter_local_notifications_linux/test/notifications_manager_test.dart index a67aff759..5fb257ce4 100644 --- a/flutter_local_notifications_linux/test/notifications_manager_test.dart +++ b/flutter_local_notifications_linux/test/notifications_manager_test.dart @@ -1,10 +1,8 @@ import 'dart:async'; +import 'dart:io'; import 'dart:typed_data'; -import 'package:dbus/dbus.dart'; import 'package:flutter_local_notifications_linux/flutter_local_notifications_linux.dart'; -import 'package:flutter_local_notifications_linux/src/dbus_wrapper.dart'; -import 'package:flutter_local_notifications_linux/src/model/hint.dart'; import 'package:flutter_local_notifications_linux/src/notification_info.dart'; import 'package:flutter_local_notifications_linux/src/notifications_manager.dart'; import 'package:flutter_local_notifications_linux/src/platform_info.dart'; @@ -14,36 +12,31 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:path/path.dart' as path; +import 'package:xdg_desktop_portal/xdg_desktop_portal.dart'; @GenerateNiceMocks(>[ - MockSpec(), - MockSpec(), MockSpec(), MockSpec(), MockSpec(), + MockSpec(), ]) import 'notifications_manager_test.mocks.dart'; -class FakeStreamSubscription extends Fake implements StreamSubscription {} - // ignore: one_member_abstracts abstract class DidReceiveNotificationResponseCallback { Future call(NotificationResponse notificationResponse); } -/*class MockDidReceiveNotificationResponseCallback extends Mock - implements _DidReceiveNotificationResponseCallback {}*/ +const String kDefaultActionName = 'Open notification'; void main() { group('Notifications manager |', () { late LinuxNotificationManager manager; - late final MockDBusWrapper mockDbus; - late final MockDBusRemoteObjectSignalStream mockActionInvokedSignal; - late final MockDBusRemoteObjectSignalStream mockNotifyClosedSignal; late final MockLinuxPlatformInfo mockPlatformInfo; late final MockNotificationStorage mockStorage; late final MockDidReceiveNotificationResponseCallback mockDidReceiveNotificationResponseCallback; + late final MockXdgNotificationPortal mockXdgNotificationPortal; const LinuxPlatformInfoData platformInfo = LinuxPlatformInfoData( appName: 'Test', @@ -52,13 +45,11 @@ void main() { ); setUpAll(() { - mockDbus = MockDBusWrapper(); - mockActionInvokedSignal = MockDBusRemoteObjectSignalStream(); - mockNotifyClosedSignal = MockDBusRemoteObjectSignalStream(); mockPlatformInfo = MockLinuxPlatformInfo(); mockStorage = MockNotificationStorage(); mockDidReceiveNotificationResponseCallback = MockDidReceiveNotificationResponseCallback(); + mockXdgNotificationPortal = MockXdgNotificationPortal(); when( mockPlatformInfo.getAll(), @@ -66,58 +57,32 @@ void main() { when( mockStorage.forceReloadCache(), ).thenAnswer((_) async => {}); - when( - mockDbus.build( - destination: 'org.freedesktop.Notifications', - path: '/org/freedesktop/Notifications', - ), - ).thenAnswer((_) => {}); - when( - mockDbus.subscribeSignal('ActionInvoked'), - ).thenAnswer((_) => mockActionInvokedSignal); - when( - mockDbus.subscribeSignal('NotificationClosed'), - ).thenAnswer((_) => mockNotifyClosedSignal); when( mockDidReceiveNotificationResponseCallback.call(any), ).thenAnswer((_) async => {}); + when(mockXdgNotificationPortal.addNotification(any)).thenAnswer( + (_) async => 0, + ); + when(mockXdgNotificationPortal.removeNotification(any)).thenAnswer( + (_) async => {}, + ); + when(mockXdgNotificationPortal.actionInvoked).thenAnswer( + (_) => Stream.fromIterable( + [], + ), + ); }); setUp(() { manager = LinuxNotificationManager.private( - dbus: mockDbus, + portal: mockXdgNotificationPortal, platformInfo: mockPlatformInfo, storage: mockStorage, ); - when( - mockActionInvokedSignal.listen(any), - ).thenReturn(FakeStreamSubscription()); - when( - mockNotifyClosedSignal.listen(any), - ).thenReturn(FakeStreamSubscription()); + reset(mockStorage); }); - void mockCloseMethod() => when( - mockDbus.callMethod( - 'org.freedesktop.Notifications', - 'CloseNotification', - any, - replySignature: DBusSignature(''), - ), - ).thenAnswer( - (_) async => DBusMethodSuccessResponse(), - ); - - VerificationResult verifyCloseMethod(int systemId) => verify( - mockDbus.callMethod( - 'org.freedesktop.Notifications', - 'CloseNotification', - [DBusUint32(systemId)], - replySignature: DBusSignature(''), - ), - ); - test('Initialize', () async { const LinuxInitializationSettings initSettings = LinuxInitializationSettings( @@ -128,87 +93,18 @@ void main() { verify(mockPlatformInfo.getAll()).called(1); verify(mockStorage.forceReloadCache()).called(1); - verify( - mockDbus.build( - destination: 'org.freedesktop.Notifications', - path: '/org/freedesktop/Notifications', - ), - ).called(1); - verify(mockActionInvokedSignal.listen(any)).called(1); - verify(mockNotifyClosedSignal.listen(any)).called(1); + verify(mockXdgNotificationPortal.actionInvoked).called(1); }); - const String kDefaultActionName = 'Open notification'; - group('Show |', () { - List buildNotifyMethodValues({ - int? replacesId, - String? appIcon, - String? title, - String? body, - List? actions, - Map? hints, - int? expireTimeout, - }) => - [ - // app_name - DBusString(platformInfo.appName!), - // replaces_id - DBusUint32(replacesId ?? 0), - // app_icon - DBusString(appIcon ?? ''), - // summary - DBusString(title ?? ''), - // body - DBusString(body ?? ''), - // actions - DBusArray.string( - ['default', kDefaultActionName, ...?actions]), - // hints - DBusDict.stringVariant(hints ?? {}), - // expire_timeout - DBusInt32( - expireTimeout ?? - const LinuxNotificationTimeout.systemDefault().value, - ), - ]; - - void mockNotifyMethod(int systemId) => when( - mockDbus.callMethod( - 'org.freedesktop.Notifications', - 'Notify', - any, - replySignature: DBusSignature('u'), - ), - ).thenAnswer( - (_) async => DBusMethodSuccessResponse( - [DBusUint32(systemId)], - ), - ); - - VerificationResult verifyNotifyMethod(List values) => - verify(mockDbus.callMethod( - 'org.freedesktop.Notifications', - 'Notify', - values, - replySignature: DBusSignature('u'), - )); - test('Simple notification', () async { const LinuxInitializationSettings initSettings = LinuxInitializationSettings(defaultActionName: kDefaultActionName); const LinuxNotificationInfo notify = LinuxNotificationInfo( id: 0, - systemId: 1, - ); - - final List values = buildNotifyMethodValues( - title: 'Title', - body: 'Body', ); - mockNotifyMethod(notify.systemId); when( mockStorage.getById(notify.id), ).thenAnswer((_) async => null); @@ -216,496 +112,33 @@ void main() { mockStorage.insert(notify), ).thenAnswer((_) async => true); + const String title = 'Title'; + const String body = 'Body'; await manager.initialize(initSettings); - await manager.show(notify.id, 'Title', 'Body'); + await manager.show(notify.id, title, body); - verifyNotifyMethod(values).called(1); verify( - mockStorage.insert(notify), - ).called(1); - }); - - test('Simple notification without title and body', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final List values = buildNotifyMethodValues(); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null); - - verifyNotifyMethod(values).called(1); - verify( - mockStorage.insert(notify), - ).called(1); - }); - - test('Replace previous notification', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo prevNotify = LinuxNotificationInfo( - id: 0, - systemId: 1, - payload: 'payload', - ); - const LinuxNotificationInfo newNotify = LinuxNotificationInfo( - id: 0, - systemId: 2, - payload: 'payload', - ); - - final List values = buildNotifyMethodValues( - replacesId: prevNotify.systemId, - title: 'Title', - body: 'Body', - ); - - mockNotifyMethod(newNotify.systemId); - when( - mockStorage.getById(newNotify.id), - ).thenAnswer((_) async => prevNotify); - when( - mockStorage.insert(newNotify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(newNotify.id, 'Title', 'Body'); - - verifyNotifyMethod(values).called(1); - verify( - mockStorage.insert(newNotify), - ).called(1); - }); - - test('Assets details icon', () async { - final LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - defaultIcon: AssetsLinuxIcon('icon.png'), - ); - - final LinuxNotificationDetails details = LinuxNotificationDetails( - icon: AssetsLinuxIcon('details_icon.png'), - ); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final List values = buildNotifyMethodValues( - appIcon: path.join(platformInfo.assetsPath!, 'details_icon.png'), - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); - }); - - test('Byte details icon', () async { - final LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - defaultIcon: AssetsLinuxIcon('icon.png'), - ); - - final ByteDataLinuxIcon icon = ByteDataLinuxIcon( - LinuxRawIconData( - data: Uint8List(64), - width: 8, - height: 8, + mockXdgNotificationPortal.addNotification( + '${notify.id}', + title: title, + body: body, + priority: XdgNotificationPriority.normal, + defaultAction: kDefaultActionName, + buttons: List.empty(), ), - ); - final LinuxNotificationDetails details = LinuxNotificationDetails( - icon: icon, - ); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final List values = buildNotifyMethodValues( - hints: { - 'image-data': DBusStruct( - [ - DBusInt32(icon.iconData.width), - DBusInt32(icon.iconData.height), - DBusInt32(icon.iconData.rowStride), - DBusBoolean(icon.iconData.hasAlpha), - DBusInt32(icon.iconData.bitsPerSample), - DBusInt32(icon.iconData.channels), - DBusArray.byte(icon.iconData.data), - ], - ), - }, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); - }); - - test('Theme details icon', () async { - final LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - defaultIcon: AssetsLinuxIcon('icon.png'), - ); - - final LinuxNotificationDetails details = LinuxNotificationDetails( - icon: ThemeLinuxIcon('test'), - ); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final List values = buildNotifyMethodValues( - appIcon: details.icon!.content as String, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); - }); - - test('Default icon', () async { - final LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - defaultIcon: AssetsLinuxIcon('icon.png'), - ); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final List values = buildNotifyMethodValues( - appIcon: path.join(platformInfo.assetsPath!, 'icon.png'), - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null); - - verifyNotifyMethod(values).called(1); - }); - - test('Timeout', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - const LinuxNotificationDetails details = LinuxNotificationDetails( - timeout: LinuxNotificationTimeout(100), - ); - - final List values = buildNotifyMethodValues( - expireTimeout: details.timeout.value, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); - }); - - test('Assets sound in details', () async { - final LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - defaultSound: AssetsLinuxSound('default_sound.mp3'), - ); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final LinuxNotificationDetails details = LinuxNotificationDetails( - sound: AssetsLinuxSound('sound.mp3'), - ); - - final List values = buildNotifyMethodValues( - hints: { - 'sound-file': DBusString( - path.join( - platformInfo.assetsPath!, - details.sound!.content as String, - ), - ), - }, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); - }); - - test('Theme sound in details', () async { - final LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - defaultSound: AssetsLinuxSound('default_sound.mp3'), - ); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final LinuxNotificationDetails details = LinuxNotificationDetails( - sound: ThemeLinuxSound('test'), - ); - - final List values = buildNotifyMethodValues( - hints: { - 'sound-name': DBusString(details.sound!.content as String), - }, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); - }); - - test('Default sound', () async { - final LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - defaultSound: AssetsLinuxSound('sound.mp3'), - ); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final List values = buildNotifyMethodValues( - hints: { - 'sound-file': DBusString( - path.join( - platformInfo.assetsPath!, - initSettings.defaultSound!.content as String, - ), - ), - }, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null); - - verifyNotifyMethod(values).called(1); - }); - - test('Category', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - const LinuxNotificationDetails details = LinuxNotificationDetails( - category: LinuxNotificationCategory.email, - ); - - final List values = buildNotifyMethodValues( - hints: { - 'category': DBusString(details.category!.name), - }, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); - }); - - test('Urgency', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - const LinuxNotificationDetails details = LinuxNotificationDetails( - urgency: LinuxNotificationUrgency.normal, - ); - - final List values = buildNotifyMethodValues( - hints: { - 'urgency': DBusByte(details.urgency!.index), - }, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); - }); - - test('Resident notification', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - const LinuxNotificationDetails details = LinuxNotificationDetails( - resident: true, - ); - - final List values = buildNotifyMethodValues( - hints: { - 'resident': DBusBoolean(details.resident), - }, - ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); + ).called(1); - verifyNotifyMethod(values).called(1); + verify(mockStorage.insert(notify)).called(1); }); - test('Suppress sound in details', () async { + test('Simple notification without title and body', () async { const LinuxInitializationSettings initSettings = LinuxInitializationSettings(defaultActionName: kDefaultActionName); const LinuxNotificationInfo notify = LinuxNotificationInfo( id: 0, - systemId: 1, - ); - - const LinuxNotificationDetails details = LinuxNotificationDetails( - suppressSound: true, - ); - - final List values = buildNotifyMethodValues( - hints: { - 'suppress-sound': DBusBoolean(details.suppressSound), - }, ); - mockNotifyMethod(notify.systemId); when( mockStorage.getById(notify.id), ).thenAnswer((_) async => null); @@ -714,30 +147,33 @@ void main() { ).thenAnswer((_) async => true); await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); + await manager.show(notify.id, null, null); + + verify( + mockXdgNotificationPortal.addNotification( + '${notify.id}', + priority: XdgNotificationPriority.normal, + defaultAction: kDefaultActionName, + buttons: List.empty(), + ), + ).called(1); - verifyNotifyMethod(values).called(1); + verify(mockStorage.insert(notify)).called(1); }); - test('Default suppress sound', () async { - const LinuxInitializationSettings initSettings = + test('Assets details icon', () async { + final LinuxInitializationSettings initSettings = LinuxInitializationSettings( defaultActionName: kDefaultActionName, - defaultSuppressSound: true, + defaultIcon: AssetsLinuxIcon('icon.png'), ); - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, + final LinuxNotificationDetails details = LinuxNotificationDetails( + icon: AssetsLinuxIcon('icons/app_icon.png'), ); - final List values = buildNotifyMethodValues( - hints: { - 'suppress-sound': DBusBoolean(initSettings.defaultSuppressSound), - }, - ); + const LinuxNotificationInfo notify = LinuxNotificationInfo(id: 0); - mockNotifyMethod(notify.systemId); when( mockStorage.getById(notify.id), ).thenAnswer((_) async => null); @@ -746,31 +182,50 @@ void main() { ).thenAnswer((_) async => true); await manager.initialize(initSettings); - await manager.show(notify.id, null, null); + await manager.show(notify.id, null, null, details: details); - verifyNotifyMethod(values).called(1); + final File iconFile = File(path.join( + 'assets', + details.icon!.content as String, + )); + + final Uint8List iconBytes = await iconFile.readAsBytes(); + + expect( + verify( + mockXdgNotificationPortal.addNotification( + '${notify.id}', + priority: XdgNotificationPriority.normal, + defaultAction: kDefaultActionName, + buttons: List.empty(), + icon: captureAnyNamed('icon'), + ), + ).captured.cast().single.data, + iconBytes, + ); }); - test('Transient notification', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, + test('Byte details icon', () async { + final LinuxInitializationSettings initSettings = + LinuxInitializationSettings( + defaultActionName: kDefaultActionName, + defaultIcon: AssetsLinuxIcon('icon.png'), ); - const LinuxNotificationDetails details = LinuxNotificationDetails( - transient: true, + final ByteDataLinuxIcon icon = ByteDataLinuxIcon( + LinuxRawIconData( + data: Uint8List(64), + width: 8, + height: 8, + ), ); - final List values = buildNotifyMethodValues( - hints: { - 'transient': DBusBoolean(details.transient), - }, + final LinuxNotificationDetails details = LinuxNotificationDetails( + icon: icon, ); - mockNotifyMethod(notify.systemId); + const LinuxNotificationInfo notify = LinuxNotificationInfo(id: 0); + when( mockStorage.getById(notify.id), ).thenAnswer((_) async => null); @@ -781,30 +236,33 @@ void main() { await manager.initialize(initSettings); await manager.show(notify.id, null, null, details: details); - verifyNotifyMethod(values).called(1); + expect( + verify( + mockXdgNotificationPortal.addNotification( + '${notify.id}', + priority: XdgNotificationPriority.normal, + defaultAction: kDefaultActionName, + buttons: List.empty(), + icon: captureAnyNamed('icon'), + ), + ).captured.cast().single.data, + icon.iconData.data, + ); }); - test('Notification location', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, + test('Theme details icon', () async { + final LinuxInitializationSettings initSettings = + LinuxInitializationSettings( + defaultActionName: kDefaultActionName, + defaultIcon: AssetsLinuxIcon('icon.png'), ); - const LinuxNotificationDetails details = LinuxNotificationDetails( - location: LinuxNotificationLocation(50, 100), + final LinuxNotificationDetails details = LinuxNotificationDetails( + icon: ThemeLinuxIcon('test'), ); - final List values = buildNotifyMethodValues( - hints: { - 'x': DBusByte(details.location!.x), - 'y': DBusByte(details.location!.y), - }, - ); + const LinuxNotificationInfo notify = LinuxNotificationInfo(id: 0); - mockNotifyMethod(notify.systemId); when( mockStorage.getById(notify.id), ).thenAnswer((_) async => null); @@ -815,132 +273,30 @@ void main() { await manager.initialize(initSettings); await manager.show(notify.id, null, null, details: details); - verifyNotifyMethod(values).called(1); + expect( + verify( + mockXdgNotificationPortal.addNotification( + '${notify.id}', + priority: XdgNotificationPriority.normal, + defaultAction: kDefaultActionName, + buttons: List.empty(), + icon: captureAnyNamed('icon'), + ), + ).captured.cast().single.names, + [details.icon!.content as String], + ); }); - test('Custom hints', () async { + test('Urgency default', () async { const LinuxInitializationSettings initSettings = LinuxInitializationSettings(defaultActionName: kDefaultActionName); - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - final LinuxNotificationDetails details = LinuxNotificationDetails( - customHints: [ - LinuxNotificationCustomHint( - 'array-hint', - LinuxHintArrayValue( - [ - LinuxHintStringValue('1'), - LinuxHintStringValue('2'), - ], - ), - ), - LinuxNotificationCustomHint( - 'bool-hint', - LinuxHintBoolValue(true), - ), - LinuxNotificationCustomHint( - 'byte-hint', - LinuxHintByteValue(1), - ), - LinuxNotificationCustomHint( - 'dict-hint', - LinuxHintDictValue( - { - LinuxHintByteValue(1): LinuxHintStringValue('1'), - LinuxHintByteValue(2): LinuxHintStringValue('2'), - }, - ), - ), - LinuxNotificationCustomHint( - 'double-hint', - LinuxHintDoubleValue(1.1), - ), - LinuxNotificationCustomHint( - 'int16-hint', - LinuxHintInt16Value(1), - ), - LinuxNotificationCustomHint( - 'int32-hint', - LinuxHintInt32Value(1), - ), - LinuxNotificationCustomHint( - 'int64-hint', - LinuxHintInt64Value(1), - ), - LinuxNotificationCustomHint( - 'string-hint', - LinuxHintStringValue('test'), - ), - LinuxNotificationCustomHint( - 'struct-hint', - LinuxHintStructValue( - [ - LinuxHintStringValue('test'), - LinuxHintBoolValue(true), - ], - ), - ), - LinuxNotificationCustomHint( - 'uint16-hint', - LinuxHintUint16Value(1), - ), - LinuxNotificationCustomHint( - 'uint32-hint', - LinuxHintUint32Value(1), - ), - LinuxNotificationCustomHint( - 'uint64-hint', - LinuxHintUint64Value(1), - ), - LinuxNotificationCustomHint( - 'variant-hint', - LinuxHintVariantValue(LinuxHintByteValue(1)), - ), - ], - ); + const LinuxNotificationInfo notify = LinuxNotificationInfo(id: 0); - final List values = buildNotifyMethodValues( - hints: { - 'array-hint': DBusArray( - DBusSignature('s'), - [ - const DBusString('1'), - const DBusString('2'), - ], - ), - 'bool-hint': const DBusBoolean(true), - 'byte-hint': const DBusByte(1), - 'dict-hint': DBusDict( - DBusSignature('y'), - DBusSignature('s'), - { - const DBusByte(1): const DBusString('1'), - const DBusByte(2): const DBusString('2'), - }, - ), - 'double-hint': const DBusDouble(1.1), - 'int16-hint': const DBusInt16(1), - 'int32-hint': const DBusInt32(1), - 'int64-hint': const DBusInt64(1), - 'string-hint': const DBusString('test'), - 'struct-hint': DBusStruct( - [ - const DBusString('test'), - const DBusBoolean(true), - ], - ), - 'uint16-hint': const DBusUint16(1), - 'uint32-hint': const DBusUint32(1), - 'uint64-hint': const DBusUint64(1), - 'variant-hint': const DBusVariant(DBusByte(1)), - }, + const LinuxNotificationDetails details = LinuxNotificationDetails( + urgency: LinuxNotificationUrgency.normal, ); - mockNotifyMethod(notify.systemId); when( mockStorage.getById(notify.id), ).thenAnswer((_) async => null); @@ -951,29 +307,26 @@ void main() { await manager.initialize(initSettings); await manager.show(notify.id, null, null, details: details); - verifyNotifyMethod(values).called(1); + verify( + mockXdgNotificationPortal.addNotification( + '${notify.id}', + priority: XdgNotificationPriority.normal, + defaultAction: kDefaultActionName, + buttons: List.empty(), + ), + ).called(1); }); - test('File path details icon', () async { - final LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - defaultIcon: FilePathLinuxIcon('/foo/bar/icon.png'), - ); + test('Urgency high', () async { + const LinuxInitializationSettings initSettings = + LinuxInitializationSettings(defaultActionName: kDefaultActionName); - final LinuxNotificationDetails details = LinuxNotificationDetails( - icon: FilePathLinuxIcon('/foo/bar/icon.png'), - ); + const LinuxNotificationInfo notify = LinuxNotificationInfo(id: 0); - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, + const LinuxNotificationDetails details = LinuxNotificationDetails( + urgency: LinuxNotificationUrgency.critical, ); - final List values = - buildNotifyMethodValues(appIcon: '/foo/bar/icon.png'); - - mockNotifyMethod(notify.systemId); when( mockStorage.getById(notify.id), ).thenAnswer((_) async => null); @@ -984,7 +337,14 @@ void main() { await manager.initialize(initSettings); await manager.show(notify.id, null, null, details: details); - verifyNotifyMethod(values).called(1); + verify( + mockXdgNotificationPortal.addNotification( + '${notify.id}', + priority: XdgNotificationPriority.urgent, + defaultAction: kDefaultActionName, + buttons: List.empty(), + ), + ).called(1); }); test('Notification actions', () async { @@ -993,7 +353,6 @@ void main() { const LinuxNotificationInfo notify = LinuxNotificationInfo( id: 0, - systemId: 1, actions: [ LinuxNotificationActionInfo(key: '1'), LinuxNotificationActionInfo(key: '2'), @@ -1013,16 +372,6 @@ void main() { ], ); - final List values = buildNotifyMethodValues( - actions: [ - '1', - 'action1', - '2', - 'action2', - ], - ); - - mockNotifyMethod(notify.systemId); when( mockStorage.getById(notify.id), ).thenAnswer((_) async => null); @@ -1033,53 +382,36 @@ void main() { await manager.initialize(initSettings); await manager.show(notify.id, null, null, details: details); - verifyNotifyMethod(values).called(1); - }); - - test('Notification action key as icon', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings(defaultActionName: kDefaultActionName); - - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - actions: [ - LinuxNotificationActionInfo(key: 'media-eject'), - ], - ); - - const LinuxNotificationDetails details = LinuxNotificationDetails( - actions: [ - LinuxNotificationAction( - key: 'media-eject', - label: 'eject', + expect( + verify( + mockXdgNotificationPortal.addNotification( + '${notify.id}', + priority: XdgNotificationPriority.normal, + defaultAction: kDefaultActionName, + buttons: captureAnyNamed('buttons'), ), + ) + .captured + .cast>() + .map((List buttons) => buttons + .map((XdgNotificationButton button) => { + 'action': button.action, + 'label': button.label, + }) + .toList()), + >>[ + >[ + { + 'action': '1', + 'label': 'action1', + }, + { + 'action': '2', + 'label': 'action2', + }, + ], ], - actionKeyAsIconName: true, - ); - - final List values = buildNotifyMethodValues( - actions: [ - 'media-eject', - 'eject', - ], - hints: { - 'action-icons': const DBusBoolean(true), - }, ); - - mockNotifyMethod(notify.systemId); - when( - mockStorage.getById(notify.id), - ).thenAnswer((_) async => null); - when( - mockStorage.insert(notify), - ).thenAnswer((_) async => true); - - await manager.initialize(initSettings); - await manager.show(notify.id, null, null, details: details); - - verifyNotifyMethod(values).called(1); }); }); @@ -1090,12 +422,7 @@ void main() { defaultSuppressSound: true, ); - const LinuxNotificationInfo notify = LinuxNotificationInfo( - id: 0, - systemId: 1, - ); - - mockCloseMethod(); + const LinuxNotificationInfo notify = LinuxNotificationInfo(id: 0); when( mockStorage.getById(notify.id), @@ -1107,7 +434,10 @@ void main() { await manager.initialize(initSettings); await manager.cancel(notify.id); - verifyCloseMethod(notify.systemId).called(1); + verify( + mockXdgNotificationPortal.removeNotification('${notify.id}'), + ).called(1); + verify( mockStorage.removeById(notify.id), ).called(1); @@ -1120,18 +450,10 @@ void main() { ); const List notifications = [ - LinuxNotificationInfo( - id: 0, - systemId: 1, - ), - LinuxNotificationInfo( - id: 1, - systemId: 2, - ), + LinuxNotificationInfo(id: 0), + LinuxNotificationInfo(id: 1), ]; - mockCloseMethod(); - when( mockStorage.getAll(), ).thenAnswer((_) async => notifications); @@ -1145,8 +467,11 @@ void main() { await manager.cancelAll(); for (final LinuxNotificationInfo notify in notifications) { - verifyCloseMethod(notify.systemId).called(1); + verify( + mockXdgNotificationPortal.removeNotification('${notify.id}'), + ).called(1); } + verify( mockStorage.removeByIdList( notifications.map((LinuxNotificationInfo n) => n.id).toList(), @@ -1154,7 +479,9 @@ void main() { ).called(1); }); - test('Notification closed by system', () async { + /// When a notification is invoked, the notification is removed from the + /// storage and the callback is called. + test('Open notification', () async { const LinuxInitializationSettings initSettings = LinuxInitializationSettings( defaultActionName: kDefaultActionName, @@ -1163,217 +490,81 @@ void main() { const List notifications = [ LinuxNotificationInfo( id: 0, - systemId: 1, + payload: 'payload1', ), LinuxNotificationInfo( id: 1, - systemId: 2, + payload: 'payload2', ), ]; - final List> completers = >[]; for (final LinuxNotificationInfo notify in notifications) { when( - mockStorage.removeBySystemId(notify.systemId), - ).thenAnswer((_) async => true); + mockStorage.getById(notify.id), + ).thenAnswer((_) async => notify); } - when( - mockNotifyClosedSignal.listen(any), - ).thenAnswer((Invocation invocation) { - final Future Function(DBusSignal) callback = - invocation.positionalArguments.single; - for (final LinuxNotificationInfo notify in notifications) { - callback( - DBusSignal( - sender: '', - path: DBusObjectPath('/org/freedesktop/Notifications'), - interface: 'org.freedesktop.Notifications', - name: 'NotificationClosed', - values: [ - DBusUint32(notify.systemId), - const DBusUint32(1), - ], - ), - ).then((_) { - for (final Completer completer in completers) { - if (!completer.isCompleted) { - completer.complete(); - } - } - }); - } - return FakeStreamSubscription(); - }); + final StreamController controller = + StreamController.broadcast(); - await manager.initialize(initSettings); - await Future.forEach( - completers, - (Completer completer) => completer.future, + when(mockXdgNotificationPortal.actionInvoked) + .thenAnswer((_) => controller.stream); + + await manager.initialize( + initSettings, + onDidReceiveNotificationResponse: + mockDidReceiveNotificationResponseCallback, ); for (final LinuxNotificationInfo notify in notifications) { - verify( - mockStorage.removeBySystemId(notify.systemId), - ).called(1); + controller.add( + XdgNotificationActionInvokedEvent( + '${notify.id}', + 'Open notification', + ), + ); } - }); - - test('Open notification', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - ); - const List notifications = [ - LinuxNotificationInfo( - id: 0, - systemId: 1, - payload: 'payload1', - ), - LinuxNotificationInfo( - id: 1, - systemId: 2, - payload: 'payload2', - ), - ]; + await Future.delayed(const Duration(milliseconds: 100)); - final List> completers = >[]; for (final LinuxNotificationInfo notify in notifications) { - when( - mockStorage.getBySystemId(notify.systemId), - ).thenAnswer((_) async => notify); - completers.add(Completer()); + verify( + mockStorage.getById(notify.id), + ).called(1); } - when( - mockActionInvokedSignal.listen(any), - ).thenAnswer((Invocation invocation) { - final Future Function(DBusSignal) callback = - invocation.positionalArguments.single; - for (final LinuxNotificationInfo notify in notifications) { - callback( - DBusSignal( - sender: '', - path: DBusObjectPath('/org/freedesktop/Notifications'), - interface: 'org.freedesktop.Notifications', - name: 'ActionInvoked', - values: [ - DBusUint32(notify.systemId), - const DBusString('default'), - ], - ), - ).then((_) { - for (final Completer completer in completers) { - if (!completer.isCompleted) { - completer.complete(); - } - } - }); - } - return FakeStreamSubscription(); - }); - await manager.initialize( - initSettings, - onDidReceiveNotificationResponse: - mockDidReceiveNotificationResponseCallback, - ); - await Future.forEach( - completers, - (Completer completer) => completer.future, - ); + verify( + mockDidReceiveNotificationResponseCallback.call(captureAny), + ).called(notifications.length); for (final LinuxNotificationInfo notify in notifications) { verify( - mockStorage.getBySystemId(notify.systemId), + mockStorage.removeById(notify.id), ).called(1); } + + await controller.close(); }); test('Notification server capabilities', () async { const LinuxInitializationSettings initSettings = LinuxInitializationSettings(defaultActionName: kDefaultActionName); - when( - mockDbus.callMethod( - 'org.freedesktop.Notifications', - 'GetCapabilities', - [], - replySignature: DBusSignature('as'), - ), - ).thenAnswer( - (_) async => DBusMethodSuccessResponse( - [ - DBusArray( - DBusSignature('s'), - [ - const DBusString('body'), - const DBusString('body-hyperlinks'), - const DBusString('body-images'), - const DBusString('body-markup'), - const DBusString('icon-multi'), - const DBusString('icon-static'), - const DBusString('persistence'), - const DBusString('sound'), - const DBusString('test-cap'), - const DBusString('actions'), - const DBusString('action-icons'), - ], - ), - ], - ), - ); - await manager.initialize(initSettings); expect( await manager.getCapabilities(), const LinuxServerCapabilities( - otherCapabilities: {'test-cap'}, + otherCapabilities: {}, body: true, bodyHyperlinks: true, - bodyImages: true, + bodyImages: false, bodyMarkup: true, - iconMulti: true, - iconStatic: true, + iconMulti: false, + iconStatic: false, persistence: true, - sound: true, + sound: false, actions: true, - actionIcons: true, - ), - ); - }); - - test('Get system ID map', () async { - const LinuxInitializationSettings initSettings = - LinuxInitializationSettings( - defaultActionName: kDefaultActionName, - ); - - const List notifications = [ - LinuxNotificationInfo( - id: 0, - systemId: 1, - ), - LinuxNotificationInfo( - id: 1, - systemId: 2, - ), - ]; - - when( - mockStorage.getAll(), - ).thenAnswer((_) async => notifications); - - await manager.initialize(initSettings); - expect( - await manager.getSystemIdMap(), - Map.fromEntries( - notifications.map( - (LinuxNotificationInfo notify) => MapEntry( - notify.id, - notify.systemId, - ), - ), + actionIcons: false, ), ); }); @@ -1387,70 +578,64 @@ void main() { const List notifications = [ LinuxNotificationInfo( id: 0, - systemId: 1, actions: [ LinuxNotificationActionInfo(key: '1'), ], ), LinuxNotificationInfo( id: 1, - systemId: 2, actions: [ LinuxNotificationActionInfo(key: '2'), ], ), ]; - final List> completers = >[]; for (final LinuxNotificationInfo notify in notifications) { when( - mockStorage.getBySystemId(notify.systemId), + mockStorage.getById(notify.id), ).thenAnswer((_) async => notify); - completers.add(Completer()); } - when( - mockActionInvokedSignal.listen(any), - ).thenAnswer((Invocation invocation) { - final Future Function(DBusSignal) callback = - invocation.positionalArguments.single; - for (final LinuxNotificationInfo notify in notifications) { - callback( - DBusSignal( - sender: '', - path: DBusObjectPath('/org/freedesktop/Notifications'), - interface: 'org.freedesktop.Notifications', - name: 'ActionInvoked', - values: [ - DBusUint32(notify.systemId), - DBusString(notify.actions[0].key), - ], - ), - ).then((_) { - for (final Completer completer in completers) { - if (!completer.isCompleted) { - completer.complete(); - } - } - }); - } - return FakeStreamSubscription(); - }); + + final StreamController controller = + StreamController.broadcast(); + + when(mockXdgNotificationPortal.actionInvoked) + .thenAnswer((_) => controller.stream); await manager.initialize( initSettings, onDidReceiveNotificationResponse: mockDidReceiveNotificationResponseCallback, ); - await Future.forEach( - completers, - (Completer completer) => completer.future, - ); + + for (final LinuxNotificationInfo notify in notifications) { + controller.add( + XdgNotificationActionInvokedEvent( + '${notify.id}', + notify.actions.first.key, + ), + ); + } + + await Future.delayed(const Duration(milliseconds: 100)); + + for (final LinuxNotificationInfo notify in notifications) { + verify( + mockStorage.getById(notify.id), + ).called(1); + } + + verify( + mockDidReceiveNotificationResponseCallback.call(captureAny), + ).called(notifications.length); for (final LinuxNotificationInfo notify in notifications) { verify( - mockStorage.getBySystemId(notify.systemId), + mockStorage.removeById(notify.id), ).called(1); } + + await controller.close(); }); }); } diff --git a/flutter_local_notifications_linux/test/notifications_manager_test.mocks.dart b/flutter_local_notifications_linux/test/notifications_manager_test.mocks.dart index a038b2b21..8c87dd132 100644 --- a/flutter_local_notifications_linux/test/notifications_manager_test.mocks.dart +++ b/flutter_local_notifications_linux/test/notifications_manager_test.mocks.dart @@ -5,18 +5,17 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; -import 'package:dbus/dbus.dart' as _i2; -import 'package:flutter_local_notifications_linux/src/dbus_wrapper.dart' as _i5; import 'package:flutter_local_notifications_linux/src/notification_info.dart' - as _i7; + as _i5; import 'package:flutter_local_notifications_linux/src/platform_info.dart' - as _i4; -import 'package:flutter_local_notifications_linux/src/storage.dart' as _i6; + as _i2; +import 'package:flutter_local_notifications_linux/src/storage.dart' as _i4; import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart' - as _i9; + as _i7; import 'package:mockito/mockito.dart' as _i1; +import 'package:xdg_desktop_portal/xdg_desktop_portal.dart' as _i8; -import 'notifications_manager_test.dart' as _i8; +import 'notifications_manager_test.dart' as _i6; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -29,30 +28,9 @@ import 'notifications_manager_test.dart' as _i8; // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class -class _FakeDBusMethodSuccessResponse_0 extends _i1.SmartFake - implements _i2.DBusMethodSuccessResponse { - _FakeDBusMethodSuccessResponse_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeDBusRemoteObjectSignalStream_1 extends _i1.SmartFake - implements _i2.DBusRemoteObjectSignalStream { - _FakeDBusRemoteObjectSignalStream_1( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeDBusSignal_2 extends _i1.SmartFake implements _i2.DBusSignal { - _FakeDBusSignal_2( +class _FakeLinuxPlatformInfoData_0 extends _i1.SmartFake + implements _i2.LinuxPlatformInfoData { + _FakeLinuxPlatformInfoData_0( Object parent, Invocation parentInvocation, ) : super( @@ -61,763 +39,65 @@ class _FakeDBusSignal_2 extends _i1.SmartFake implements _i2.DBusSignal { ); } -class _FakeStreamSubscription_3 extends _i1.SmartFake - implements _i3.StreamSubscription { - _FakeStreamSubscription_3( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeFuture_4 extends _i1.SmartFake implements _i3.Future { - _FakeFuture_4( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeLinuxPlatformInfoData_5 extends _i1.SmartFake - implements _i4.LinuxPlatformInfoData { - _FakeLinuxPlatformInfoData_5( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -/// A class which mocks [DBusWrapper]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockDBusWrapper extends _i1.Mock implements _i5.DBusWrapper { - @override - void build({ - required String? destination, - required String? path, - }) => - super.noSuchMethod( - Invocation.method( - #build, - [], - { - #destination: destination, - #path: path, - }, - ), - returnValueForMissingStub: null, - ); - @override - _i3.Future<_i2.DBusMethodSuccessResponse> callMethod( - String? interface, - String? name, - Iterable<_i2.DBusValue>? values, { - _i2.DBusSignature? replySignature, - bool? noReplyExpected = false, - bool? noAutoStart = false, - bool? allowInteractiveAuthorization = false, - }) => - (super.noSuchMethod( - Invocation.method( - #callMethod, - [ - interface, - name, - values, - ], - { - #replySignature: replySignature, - #noReplyExpected: noReplyExpected, - #noAutoStart: noAutoStart, - #allowInteractiveAuthorization: allowInteractiveAuthorization, - }, - ), - returnValue: _i3.Future<_i2.DBusMethodSuccessResponse>.value( - _FakeDBusMethodSuccessResponse_0( - this, - Invocation.method( - #callMethod, - [ - interface, - name, - values, - ], - { - #replySignature: replySignature, - #noReplyExpected: noReplyExpected, - #noAutoStart: noAutoStart, - #allowInteractiveAuthorization: allowInteractiveAuthorization, - }, - ), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusMethodSuccessResponse>.value( - _FakeDBusMethodSuccessResponse_0( - this, - Invocation.method( - #callMethod, - [ - interface, - name, - values, - ], - { - #replySignature: replySignature, - #noReplyExpected: noReplyExpected, - #noAutoStart: noAutoStart, - #allowInteractiveAuthorization: allowInteractiveAuthorization, - }, - ), - )), - ) as _i3.Future<_i2.DBusMethodSuccessResponse>); - @override - _i2.DBusRemoteObjectSignalStream subscribeSignal(String? name) => - (super.noSuchMethod( - Invocation.method( - #subscribeSignal, - [name], - ), - returnValue: _FakeDBusRemoteObjectSignalStream_1( - this, - Invocation.method( - #subscribeSignal, - [name], - ), - ), - returnValueForMissingStub: _FakeDBusRemoteObjectSignalStream_1( - this, - Invocation.method( - #subscribeSignal, - [name], - ), - ), - ) as _i2.DBusRemoteObjectSignalStream); -} - -/// A class which mocks [DBusRemoteObjectSignalStream]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockDBusRemoteObjectSignalStream extends _i1.Mock - implements _i2.DBusRemoteObjectSignalStream { - @override - bool get isBroadcast => (super.noSuchMethod( - Invocation.getter(#isBroadcast), - returnValue: false, - returnValueForMissingStub: false, - ) as bool); - @override - _i3.Future get length => (super.noSuchMethod( - Invocation.getter(#length), - returnValue: _i3.Future.value(0), - returnValueForMissingStub: _i3.Future.value(0), - ) as _i3.Future); - @override - _i3.Future get isEmpty => (super.noSuchMethod( - Invocation.getter(#isEmpty), - returnValue: _i3.Future.value(false), - returnValueForMissingStub: _i3.Future.value(false), - ) as _i3.Future); - @override - _i3.Future<_i2.DBusSignal> get first => (super.noSuchMethod( - Invocation.getter(#first), - returnValue: _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.getter(#first), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.getter(#first), - )), - ) as _i3.Future<_i2.DBusSignal>); - @override - _i3.Future<_i2.DBusSignal> get last => (super.noSuchMethod( - Invocation.getter(#last), - returnValue: _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.getter(#last), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.getter(#last), - )), - ) as _i3.Future<_i2.DBusSignal>); - @override - _i3.Future<_i2.DBusSignal> get single => (super.noSuchMethod( - Invocation.getter(#single), - returnValue: _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.getter(#single), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.getter(#single), - )), - ) as _i3.Future<_i2.DBusSignal>); - @override - _i3.StreamSubscription<_i2.DBusSignal> listen( - void Function(_i2.DBusSignal)? onData, { - Function? onError, - void Function()? onDone, - bool? cancelOnError, - }) => - (super.noSuchMethod( - Invocation.method( - #listen, - [onData], - { - #onError: onError, - #onDone: onDone, - #cancelOnError: cancelOnError, - }, - ), - returnValue: _FakeStreamSubscription_3<_i2.DBusSignal>( - this, - Invocation.method( - #listen, - [onData], - { - #onError: onError, - #onDone: onDone, - #cancelOnError: cancelOnError, - }, - ), - ), - returnValueForMissingStub: _FakeStreamSubscription_3<_i2.DBusSignal>( - this, - Invocation.method( - #listen, - [onData], - { - #onError: onError, - #onDone: onDone, - #cancelOnError: cancelOnError, - }, - ), - ), - ) as _i3.StreamSubscription<_i2.DBusSignal>); - @override - _i3.Stream<_i2.DBusSignal> asBroadcastStream({ - void Function(_i3.StreamSubscription<_i2.DBusSignal>)? onListen, - void Function(_i3.StreamSubscription<_i2.DBusSignal>)? onCancel, - }) => - (super.noSuchMethod( - Invocation.method( - #asBroadcastStream, - [], - { - #onListen: onListen, - #onCancel: onCancel, - }, - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); - @override - _i3.Stream<_i2.DBusSignal> where(bool Function(_i2.DBusSignal)? test) => - (super.noSuchMethod( - Invocation.method( - #where, - [test], - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); - @override - _i3.Stream map(S Function(_i2.DBusSignal)? convert) => - (super.noSuchMethod( - Invocation.method( - #map, - [convert], - ), - returnValue: _i3.Stream.empty(), - returnValueForMissingStub: _i3.Stream.empty(), - ) as _i3.Stream); - @override - _i3.Stream asyncMap( - _i3.FutureOr Function(_i2.DBusSignal)? convert) => - (super.noSuchMethod( - Invocation.method( - #asyncMap, - [convert], - ), - returnValue: _i3.Stream.empty(), - returnValueForMissingStub: _i3.Stream.empty(), - ) as _i3.Stream); - @override - _i3.Stream asyncExpand( - _i3.Stream? Function(_i2.DBusSignal)? convert) => - (super.noSuchMethod( - Invocation.method( - #asyncExpand, - [convert], - ), - returnValue: _i3.Stream.empty(), - returnValueForMissingStub: _i3.Stream.empty(), - ) as _i3.Stream); - @override - _i3.Stream<_i2.DBusSignal> handleError( - Function? onError, { - bool Function(dynamic)? test, - }) => - (super.noSuchMethod( - Invocation.method( - #handleError, - [onError], - {#test: test}, - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); - @override - _i3.Stream expand(Iterable Function(_i2.DBusSignal)? convert) => - (super.noSuchMethod( - Invocation.method( - #expand, - [convert], - ), - returnValue: _i3.Stream.empty(), - returnValueForMissingStub: _i3.Stream.empty(), - ) as _i3.Stream); - @override - _i3.Future pipe( - _i3.StreamConsumer<_i2.DBusSignal>? streamConsumer) => - (super.noSuchMethod( - Invocation.method( - #pipe, - [streamConsumer], - ), - returnValue: _i3.Future.value(), - returnValueForMissingStub: _i3.Future.value(), - ) as _i3.Future); - @override - _i3.Stream transform( - _i3.StreamTransformer<_i2.DBusSignal, S>? streamTransformer) => - (super.noSuchMethod( - Invocation.method( - #transform, - [streamTransformer], - ), - returnValue: _i3.Stream.empty(), - returnValueForMissingStub: _i3.Stream.empty(), - ) as _i3.Stream); - @override - _i3.Future<_i2.DBusSignal> reduce( - _i2.DBusSignal Function( - _i2.DBusSignal, - _i2.DBusSignal, - )? combine) => - (super.noSuchMethod( - Invocation.method( - #reduce, - [combine], - ), - returnValue: _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #reduce, - [combine], - ), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #reduce, - [combine], - ), - )), - ) as _i3.Future<_i2.DBusSignal>); - @override - _i3.Future fold( - S? initialValue, - S Function( - S, - _i2.DBusSignal, - )? combine, - ) => - (super.noSuchMethod( - Invocation.method( - #fold, - [ - initialValue, - combine, - ], - ), - returnValue: _FakeFuture_4( - this, - Invocation.method( - #fold, - [ - initialValue, - combine, - ], - ), - ), - returnValueForMissingStub: _FakeFuture_4( - this, - Invocation.method( - #fold, - [ - initialValue, - combine, - ], - ), - ), - ) as _i3.Future); - @override - _i3.Future join([String? separator = r'']) => (super.noSuchMethod( - Invocation.method( - #join, - [separator], - ), - returnValue: _i3.Future.value(''), - returnValueForMissingStub: _i3.Future.value(''), - ) as _i3.Future); - @override - _i3.Future contains(Object? needle) => (super.noSuchMethod( - Invocation.method( - #contains, - [needle], - ), - returnValue: _i3.Future.value(false), - returnValueForMissingStub: _i3.Future.value(false), - ) as _i3.Future); - @override - _i3.Future forEach(void Function(_i2.DBusSignal)? action) => - (super.noSuchMethod( - Invocation.method( - #forEach, - [action], - ), - returnValue: _i3.Future.value(), - returnValueForMissingStub: _i3.Future.value(), - ) as _i3.Future); - @override - _i3.Future every(bool Function(_i2.DBusSignal)? test) => - (super.noSuchMethod( - Invocation.method( - #every, - [test], - ), - returnValue: _i3.Future.value(false), - returnValueForMissingStub: _i3.Future.value(false), - ) as _i3.Future); - @override - _i3.Future any(bool Function(_i2.DBusSignal)? test) => - (super.noSuchMethod( - Invocation.method( - #any, - [test], - ), - returnValue: _i3.Future.value(false), - returnValueForMissingStub: _i3.Future.value(false), - ) as _i3.Future); - @override - _i3.Stream cast() => (super.noSuchMethod( - Invocation.method( - #cast, - [], - ), - returnValue: _i3.Stream.empty(), - returnValueForMissingStub: _i3.Stream.empty(), - ) as _i3.Stream); - @override - _i3.Future> toList() => (super.noSuchMethod( - Invocation.method( - #toList, - [], - ), - returnValue: _i3.Future>.value(<_i2.DBusSignal>[]), - returnValueForMissingStub: - _i3.Future>.value(<_i2.DBusSignal>[]), - ) as _i3.Future>); - @override - _i3.Future> toSet() => (super.noSuchMethod( - Invocation.method( - #toSet, - [], - ), - returnValue: _i3.Future>.value(<_i2.DBusSignal>{}), - returnValueForMissingStub: - _i3.Future>.value(<_i2.DBusSignal>{}), - ) as _i3.Future>); - @override - _i3.Future drain([E? futureValue]) => (super.noSuchMethod( - Invocation.method( - #drain, - [futureValue], - ), - returnValue: _FakeFuture_4( - this, - Invocation.method( - #drain, - [futureValue], - ), - ), - returnValueForMissingStub: _FakeFuture_4( - this, - Invocation.method( - #drain, - [futureValue], - ), - ), - ) as _i3.Future); - @override - _i3.Stream<_i2.DBusSignal> take(int? count) => (super.noSuchMethod( - Invocation.method( - #take, - [count], - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); - @override - _i3.Stream<_i2.DBusSignal> takeWhile(bool Function(_i2.DBusSignal)? test) => - (super.noSuchMethod( - Invocation.method( - #takeWhile, - [test], - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); - @override - _i3.Stream<_i2.DBusSignal> skip(int? count) => (super.noSuchMethod( - Invocation.method( - #skip, - [count], - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); - @override - _i3.Stream<_i2.DBusSignal> skipWhile(bool Function(_i2.DBusSignal)? test) => - (super.noSuchMethod( - Invocation.method( - #skipWhile, - [test], - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); - @override - _i3.Stream<_i2.DBusSignal> distinct( - [bool Function( - _i2.DBusSignal, - _i2.DBusSignal, - )? equals]) => - (super.noSuchMethod( - Invocation.method( - #distinct, - [equals], - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); - @override - _i3.Future<_i2.DBusSignal> firstWhere( - bool Function(_i2.DBusSignal)? test, { - _i2.DBusSignal Function()? orElse, - }) => - (super.noSuchMethod( - Invocation.method( - #firstWhere, - [test], - {#orElse: orElse}, - ), - returnValue: _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #firstWhere, - [test], - {#orElse: orElse}, - ), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #firstWhere, - [test], - {#orElse: orElse}, - ), - )), - ) as _i3.Future<_i2.DBusSignal>); - @override - _i3.Future<_i2.DBusSignal> lastWhere( - bool Function(_i2.DBusSignal)? test, { - _i2.DBusSignal Function()? orElse, - }) => - (super.noSuchMethod( - Invocation.method( - #lastWhere, - [test], - {#orElse: orElse}, - ), - returnValue: _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #lastWhere, - [test], - {#orElse: orElse}, - ), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #lastWhere, - [test], - {#orElse: orElse}, - ), - )), - ) as _i3.Future<_i2.DBusSignal>); - @override - _i3.Future<_i2.DBusSignal> singleWhere( - bool Function(_i2.DBusSignal)? test, { - _i2.DBusSignal Function()? orElse, - }) => - (super.noSuchMethod( - Invocation.method( - #singleWhere, - [test], - {#orElse: orElse}, - ), - returnValue: _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #singleWhere, - [test], - {#orElse: orElse}, - ), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #singleWhere, - [test], - {#orElse: orElse}, - ), - )), - ) as _i3.Future<_i2.DBusSignal>); - @override - _i3.Future<_i2.DBusSignal> elementAt(int? index) => (super.noSuchMethod( - Invocation.method( - #elementAt, - [index], - ), - returnValue: _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #elementAt, - [index], - ), - )), - returnValueForMissingStub: - _i3.Future<_i2.DBusSignal>.value(_FakeDBusSignal_2( - this, - Invocation.method( - #elementAt, - [index], - ), - )), - ) as _i3.Future<_i2.DBusSignal>); - @override - _i3.Stream<_i2.DBusSignal> timeout( - Duration? timeLimit, { - void Function(_i3.EventSink<_i2.DBusSignal>)? onTimeout, - }) => - (super.noSuchMethod( - Invocation.method( - #timeout, - [timeLimit], - {#onTimeout: onTimeout}, - ), - returnValue: _i3.Stream<_i2.DBusSignal>.empty(), - returnValueForMissingStub: _i3.Stream<_i2.DBusSignal>.empty(), - ) as _i3.Stream<_i2.DBusSignal>); -} - /// A class which mocks [LinuxPlatformInfo]. /// /// See the documentation for Mockito's code generation for more information. -class MockLinuxPlatformInfo extends _i1.Mock implements _i4.LinuxPlatformInfo { +class MockLinuxPlatformInfo extends _i1.Mock implements _i2.LinuxPlatformInfo { @override - _i3.Future<_i4.LinuxPlatformInfoData> getAll() => (super.noSuchMethod( + _i3.Future<_i2.LinuxPlatformInfoData> getAll() => (super.noSuchMethod( Invocation.method( #getAll, [], ), - returnValue: _i3.Future<_i4.LinuxPlatformInfoData>.value( - _FakeLinuxPlatformInfoData_5( + returnValue: _i3.Future<_i2.LinuxPlatformInfoData>.value( + _FakeLinuxPlatformInfoData_0( this, Invocation.method( #getAll, [], ), )), - returnValueForMissingStub: _i3.Future<_i4.LinuxPlatformInfoData>.value( - _FakeLinuxPlatformInfoData_5( + returnValueForMissingStub: _i3.Future<_i2.LinuxPlatformInfoData>.value( + _FakeLinuxPlatformInfoData_0( this, Invocation.method( #getAll, [], ), )), - ) as _i3.Future<_i4.LinuxPlatformInfoData>); + ) as _i3.Future<_i2.LinuxPlatformInfoData>); } /// A class which mocks [NotificationStorage]. /// /// See the documentation for Mockito's code generation for more information. class MockNotificationStorage extends _i1.Mock - implements _i6.NotificationStorage { + implements _i4.NotificationStorage { @override - _i3.Future> getAll() => (super.noSuchMethod( + _i3.Future> getAll() => (super.noSuchMethod( Invocation.method( #getAll, [], ), - returnValue: _i3.Future>.value( - <_i7.LinuxNotificationInfo>[]), - returnValueForMissingStub: - _i3.Future>.value( - <_i7.LinuxNotificationInfo>[]), - ) as _i3.Future>); - @override - _i3.Future<_i7.LinuxNotificationInfo?> getBySystemId(int? systemId) => - (super.noSuchMethod( - Invocation.method( - #getBySystemId, - [systemId], - ), - returnValue: _i3.Future<_i7.LinuxNotificationInfo?>.value(), + returnValue: _i3.Future>.value( + <_i5.LinuxNotificationInfo>[]), returnValueForMissingStub: - _i3.Future<_i7.LinuxNotificationInfo?>.value(), - ) as _i3.Future<_i7.LinuxNotificationInfo?>); + _i3.Future>.value( + <_i5.LinuxNotificationInfo>[]), + ) as _i3.Future>); @override - _i3.Future<_i7.LinuxNotificationInfo?> getById(int? id) => + _i3.Future<_i5.LinuxNotificationInfo?> getById(int? id) => (super.noSuchMethod( Invocation.method( #getById, [id], ), - returnValue: _i3.Future<_i7.LinuxNotificationInfo?>.value(), + returnValue: _i3.Future<_i5.LinuxNotificationInfo?>.value(), returnValueForMissingStub: - _i3.Future<_i7.LinuxNotificationInfo?>.value(), - ) as _i3.Future<_i7.LinuxNotificationInfo?>); + _i3.Future<_i5.LinuxNotificationInfo?>.value(), + ) as _i3.Future<_i5.LinuxNotificationInfo?>); @override - _i3.Future insert(_i7.LinuxNotificationInfo? notification) => + _i3.Future insert(_i5.LinuxNotificationInfo? notification) => (super.noSuchMethod( Invocation.method( #insert, @@ -836,15 +116,6 @@ class MockNotificationStorage extends _i1.Mock returnValueForMissingStub: _i3.Future.value(false), ) as _i3.Future); @override - _i3.Future removeBySystemId(int? systemId) => (super.noSuchMethod( - Invocation.method( - #removeBySystemId, - [systemId], - ), - returnValue: _i3.Future.value(false), - returnValueForMissingStub: _i3.Future.value(false), - ) as _i3.Future); - @override _i3.Future removeByIdList(List? idList) => (super.noSuchMethod( Invocation.method( #removeByIdList, @@ -868,9 +139,9 @@ class MockNotificationStorage extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockDidReceiveNotificationResponseCallback extends _i1.Mock - implements _i8.DidReceiveNotificationResponseCallback { + implements _i6.DidReceiveNotificationResponseCallback { @override - _i3.Future call(_i9.NotificationResponse? notificationResponse) => + _i3.Future call(_i7.NotificationResponse? notificationResponse) => (super.noSuchMethod( Invocation.method( #call, @@ -880,3 +151,62 @@ class MockDidReceiveNotificationResponseCallback extends _i1.Mock returnValueForMissingStub: _i3.Future.value(), ) as _i3.Future); } + +/// A class which mocks [XdgNotificationPortal]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockXdgNotificationPortal extends _i1.Mock + implements _i8.XdgNotificationPortal { + @override + _i3.Stream<_i8.XdgNotificationActionInvokedEvent> get actionInvoked => + (super.noSuchMethod( + Invocation.getter(#actionInvoked), + returnValue: _i3.Stream<_i8.XdgNotificationActionInvokedEvent>.empty(), + returnValueForMissingStub: + _i3.Stream<_i8.XdgNotificationActionInvokedEvent>.empty(), + ) as _i3.Stream<_i8.XdgNotificationActionInvokedEvent>); + @override + _i3.Future getVersion() => (super.noSuchMethod( + Invocation.method( + #getVersion, + [], + ), + returnValue: _i3.Future.value(0), + returnValueForMissingStub: _i3.Future.value(0), + ) as _i3.Future); + @override + _i3.Future addNotification( + String? id, { + String? title, + String? body, + _i8.XdgNotificationIcon? icon, + _i8.XdgNotificationPriority? priority, + String? defaultAction, + List<_i8.XdgNotificationButton>? buttons = const [], + }) => + (super.noSuchMethod( + Invocation.method( + #addNotification, + [id], + { + #title: title, + #body: body, + #icon: icon, + #priority: priority, + #defaultAction: defaultAction, + #buttons: buttons, + }, + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override + _i3.Future removeNotification(String? id) => (super.noSuchMethod( + Invocation.method( + #removeNotification, + [id], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); +} diff --git a/flutter_local_notifications_linux/test/storage_test.dart b/flutter_local_notifications_linux/test/storage_test.dart index 634de78f6..b7b7b2d7c 100644 --- a/flutter_local_notifications_linux/test/storage_test.dart +++ b/flutter_local_notifications_linux/test/storage_test.dart @@ -55,15 +55,10 @@ void main() { test('Insert', () async { const List notifications = [ - LinuxNotificationInfo(id: 1, systemId: 1), - LinuxNotificationInfo( - id: 2, - systemId: 2, - payload: 'test', - ), + LinuxNotificationInfo(id: 1), + LinuxNotificationInfo(id: 2, payload: 'test'), LinuxNotificationInfo( id: 3, - systemId: 3, payload: 'test', actions: [ LinuxNotificationActionInfo(key: '1'), @@ -100,12 +95,8 @@ void main() { test('Remove', () async { const List notifications = [ - LinuxNotificationInfo(id: 1, systemId: 1), - LinuxNotificationInfo( - id: 2, - systemId: 2, - payload: 'test', - ), + LinuxNotificationInfo(id: 1), + LinuxNotificationInfo(id: 2, payload: 'test'), ]; when(mockStorageFile.existsSync()).thenReturn(true); @@ -134,15 +125,10 @@ void main() { test('Get all', () async { const List notifications = [ - LinuxNotificationInfo(id: 1, systemId: 1), - LinuxNotificationInfo( - id: 2, - systemId: 2, - payload: 'test', - ), + LinuxNotificationInfo(id: 1), + LinuxNotificationInfo(id: 2, payload: 'test'), LinuxNotificationInfo( id: 3, - systemId: 3, payload: 'test', actions: [ LinuxNotificationActionInfo(key: '1'), @@ -179,7 +165,6 @@ void main() { test('Get by ID', () async { const LinuxNotificationInfo notification = LinuxNotificationInfo( id: 1, - systemId: 1, ); when(mockStorageFile.existsSync()).thenReturn(true); @@ -204,25 +189,6 @@ void main() { expect(await storage.getById(notification.id), notification); }); - test('Get by system ID', () async { - const LinuxNotificationInfo notification = LinuxNotificationInfo( - id: 1, - systemId: 2, - ); - - when(mockStorageFile.existsSync()).thenReturn(true); - when( - mockStorageFile.writeAsStringSync(any), - ).thenAnswer((_) => {}); - - when( - mockStorageFile.readAsStringSync(), - ).thenReturn(jsonEncode(notification)); - await storage.insert(notification); - - expect(await storage.getBySystemId(notification.systemId), notification); - }); - test('Get all, file does not exist', () async { when(mockStorageFile.existsSync()).thenReturn(false); expect(await storage.getAll(), []); @@ -230,12 +196,8 @@ void main() { test('Remove by ID list', () async { const List notifications = [ - LinuxNotificationInfo(id: 1, systemId: 1), - LinuxNotificationInfo( - id: 2, - systemId: 2, - payload: 'test', - ), + LinuxNotificationInfo(id: 1), + LinuxNotificationInfo(id: 2, payload: 'test'), ]; when(mockStorageFile.existsSync()).thenReturn(true); @@ -261,28 +223,5 @@ void main() { ), ).called(1); }); - - test('Remove by system ID', () async { - const LinuxNotificationInfo notification = LinuxNotificationInfo( - id: 1, - systemId: 2, - ); - - when(mockStorageFile.existsSync()).thenReturn(true); - when( - mockStorageFile.writeAsStringSync(any), - ).thenAnswer((_) => {}); - when(mockStorageFile.readAsStringSync()).thenReturn(''); - - await storage.insert(notification); - - expect(await storage.removeBySystemId(notification.systemId), isTrue); - - verify( - mockStorageFile.writeAsStringSync( - jsonEncode([]), - ), - ).called(1); - }); }); }