-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[flutter_local_notifications] linux support #888
Changes from 1 commit
03a46ee
a1aac0e
543d8c9
89be469
c3a8ad7
783a0b9
f38460f
5b29ec9
738d8de
53f631c
dd6d96b
d7e69e3
9163283
09ecd86
84f1683
15ce2da
b6d24d2
2096542
276af10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ class NotificationDetails { | |
/// Notification details for iOS. | ||
final IOSNotificationDetails iOS; | ||
|
||
/// Notification details for Linux. | ||
final LinuxNotificationDetails linux; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here :) |
||
|
||
/// Notification details for macOS. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,12 +16,12 @@ import 'platform_specifics/ios/enums.dart'; | |
import 'platform_specifics/ios/initialization_settings.dart'; | ||
import 'platform_specifics/ios/method_channel_mappers.dart'; | ||
import 'platform_specifics/ios/notification_details.dart'; | ||
import 'platform_specifics/macos/initialization_settings.dart'; | ||
import 'platform_specifics/macos/method_channel_mappers.dart'; | ||
import 'platform_specifics/macos/notification_details.dart'; | ||
import 'platform_specifics/linux/initialization_settings.dart'; | ||
import 'platform_specifics/linux/method_channel_mappers.dart'; | ||
import 'platform_specifics/linux/notification_details.dart'; | ||
import 'platform_specifics/macos/initialization_settings.dart'; | ||
import 'platform_specifics/macos/method_channel_mappers.dart'; | ||
import 'platform_specifics/macos/notification_details.dart'; | ||
import 'type_mappers.dart'; | ||
import 'typedefs.dart'; | ||
import 'types.dart'; | ||
|
@@ -667,21 +667,24 @@ class MacOSFlutterLocalNotificationsPlugin | |
class LinuxFlutterLocalNotificationsPlugin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there are some analysis warnings here and there in |
||
extends MethodChannelFlutterLocalNotificationsPlugin { | ||
SelectNotificationCallback _onSelectNotification; | ||
Map<int, Map<String, LinuxNotificationButtonHandler>> _notificationButtonHandlerMap; | ||
Map<int, Map<String, LinuxNotificationButtonHandler>> _periodicalNotificationButtonHandlerMap; | ||
final Map<int, Map<String, LinuxNotificationButtonHandler>> | ||
_notificationButtonHandlerMap = | ||
<int, Map<String, LinuxNotificationButtonHandler>>{}; | ||
final Map<int, Map<String, LinuxNotificationButtonHandler>> | ||
_periodicNotificationButtonHandlerMap = | ||
<int, Map<String, LinuxNotificationButtonHandler>>{}; | ||
|
||
Future<bool> initialize( | ||
LinuxInitializationSettings initializationSettings, { | ||
SelectNotificationCallback onSelectNotification, | ||
}) async { | ||
_onSelectNotification = onSelectNotification; | ||
_notificationButtonHandlerMap = Map(); | ||
_periodicalNotificationButtonHandlerMap = Map(); | ||
_channel.setMethodCallHandler(_handleMethod); | ||
return await _channel.invokeMethod( | ||
'initialize', initializationSettings?.toMap()); | ||
} | ||
|
||
@override | ||
Future<void> show( | ||
int id, | ||
String title, | ||
|
@@ -690,11 +693,11 @@ class LinuxFlutterLocalNotificationsPlugin | |
String payload, | ||
}) { | ||
validateId(id); | ||
_notificationButtonHandlerMap[id] = notificationDetails != null ? Map.fromIterable( | ||
notificationDetails.buttons, | ||
key: (button) => button.buttonId, | ||
value: (button) => button.handler, | ||
) : null; | ||
_notificationButtonHandlerMap[id] = notificationDetails != null | ||
? <String, LinuxNotificationButtonHandler> { | ||
for (final LinuxNotificationButton button in notificationDetails.buttons) | ||
button.buttonId : button.handler, | ||
} : null; | ||
return _channel.invokeMethod('show', <String, Object> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be the only method that specifies It also prevents the show method on the C++ side from being responsible for triggering notifications in multiple ways as is the case right now. This makes it more risky to change code as a common method is being used for the various plugin APIs. I get why it was done as I did a similar thing in the past but that caused issues with maintenance. Making the change should also resolve the comment @jpnurmi raised on how the implementation of |
||
'id': id, | ||
'title': title, | ||
|
@@ -704,6 +707,7 @@ class LinuxFlutterLocalNotificationsPlugin | |
}); | ||
} | ||
|
||
@override | ||
Future<void> periodicallyShow( | ||
int id, | ||
String title, | ||
|
@@ -713,11 +717,11 @@ class LinuxFlutterLocalNotificationsPlugin | |
String payload, | ||
}) { | ||
validateId(id); | ||
_periodicalNotificationButtonHandlerMap[id] = notificationDetails != null ? Map.fromIterable( | ||
notificationDetails.buttons, | ||
key: (button) => button.buttonId, | ||
value: (button) => button.handler, | ||
) : null; | ||
_periodicNotificationButtonHandlerMap[id] = notificationDetails != null | ||
? <String, LinuxNotificationButtonHandler> { | ||
for (final LinuxNotificationButton button in notificationDetails.buttons) | ||
button.buttonId : button.handler, | ||
} : null; | ||
return _channel.invokeMethod('show', <String, Object> { | ||
'id': id, | ||
'title': title, | ||
|
@@ -739,7 +743,13 @@ class LinuxFlutterLocalNotificationsPlugin | |
}) async { | ||
validateId(id); | ||
validateDateIsInTheFuture(scheduledDate); | ||
final serializedPlatformSpecifics = notificationDetails?.toMap(); | ||
_periodicNotificationButtonHandlerMap[id] = notificationDetails != null | ||
? <String, LinuxNotificationButtonHandler> { | ||
for (final LinuxNotificationButton button in notificationDetails.buttons) | ||
button.buttonId : button.handler, | ||
} : null; | ||
final Map<String, Object> serializedPlatformSpecifics | ||
= notificationDetails?.toMap(); | ||
await _channel.invokeMethod( | ||
'show', | ||
<String, Object>{ | ||
|
@@ -754,48 +764,54 @@ class LinuxFlutterLocalNotificationsPlugin | |
..addAll(scheduledDate.toMap())); | ||
} | ||
|
||
@override | ||
Future<void> cancel(int id) { | ||
validateId(id); | ||
if (_notificationButtonHandlerMap.remove(id) != null) { | ||
return _channel.invokeMethod('cancel', id); | ||
} else if (_periodicalNotificationButtonHandlerMap.remove(id) != null) { | ||
} else if (_periodicNotificationButtonHandlerMap.remove(id) != null) { | ||
return _channel.invokeMethod('cancelPeriodicNotification', id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Call |
||
} else { | ||
throw ArgumentError.value(id, "id", "id is invalid"); | ||
throw ArgumentError.value(id, 'id', 'id is invalid'); | ||
} | ||
} | ||
|
||
@override | ||
Future<void> cancelAll() async { | ||
for (final id in _notificationButtonHandlerMap.keys) { | ||
for (final int id in _notificationButtonHandlerMap.keys) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if the user triggers a notification that is displayed, leaves the notification there and restarts the app? If I'm not mistaken, looks as though cancelling notifications and handling buttons would rely on having the same app session active. FYI that cancelling notifications and handling when the user taps on a notification (note: other platforms don't support action buttons at the moment) for all other platforms can be done even if the user restarted the app so if what I described is indeed how it works right now (as I'm still having some trouble with my Linux environment to test) then a solution will need to be found for Linux to behave the same. I imagine, this would potentially need to rely on persisting some information about the notification |
||
await _channel.invokeMethod('cancel', id); | ||
} | ||
for (final id in _periodicalNotificationButtonHandlerMap.keys) { | ||
for (final int id in _periodicNotificationButtonHandlerMap.keys) { | ||
await _channel.invokeMethod('cancelPeriodicNotification', id); | ||
} | ||
_notificationButtonHandlerMap.clear(); | ||
_periodicalNotificationButtonHandlerMap.clear(); | ||
_periodicNotificationButtonHandlerMap.clear(); | ||
} | ||
|
||
Future<void> _handleMethod(MethodCall call) { | ||
switch (call.method) { | ||
case 'selectNotification': | ||
final args = call.arguments as Map; | ||
final Map<dynamic, dynamic> args = call.arguments; | ||
_notificationButtonHandlerMap.remove(args['id']); | ||
_onSelectNotification(args['payload']); | ||
break; | ||
case 'selectNotificationButton': | ||
final args = call.arguments as Map; | ||
final id = args['id'] as int; | ||
final buttonId = args['buttonId'] as String; | ||
final buttonHandlerMap = _notificationButtonHandlerMap.remove(id) ?? _periodicalNotificationButtonHandlerMap[id]; | ||
assert(buttonHandlerMap != null, "Handler map is corrupted"); | ||
final handler = buttonHandlerMap[buttonId]; | ||
final Map<dynamic, dynamic> args = call.arguments; | ||
final int id = args['id']; | ||
final String buttonId = args['buttonId']; | ||
final Map<String, LinuxNotificationButtonHandler> buttonHandlerMap | ||
= _notificationButtonHandlerMap.remove(id) | ||
?? _periodicNotificationButtonHandlerMap[id]; | ||
assert(buttonHandlerMap != null, 'Handler map is corrupted'); | ||
final LinuxNotificationButtonHandler handler = | ||
buttonHandlerMap[buttonId]; | ||
if (handler != null) { | ||
handler(id, buttonId); | ||
} | ||
break; | ||
default: | ||
return Future<void>.error('Method not defined'); | ||
} | ||
return Future<void>.value(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,8 @@ class LinuxFileIcon implements LinuxIcon { | |
} | ||
|
||
/// Represents an icon from binary data | ||
/// The binary data should be in an image file format which supported by glib, such as common formats like jpg and png | ||
/// The binary data should be in an image file format which supported by glib, | ||
/// such as common formats like jpg and png | ||
class BytesLinuxIcon implements LinuxIcon { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This reads slight awkward. Could this perhaps be renamed to something else like |
||
const BytesLinuxIcon(this.data); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,34 +5,33 @@ import 'notification_details.dart'; | |
extension LinuxIconMapper on LinuxIcon { | ||
Map<String, Object> toMap() { | ||
return <String, Object> { | ||
"icon": content, | ||
"iconSource": source.index, | ||
'icon': content, | ||
'iconSource': source.index, | ||
}; | ||
} | ||
} | ||
|
||
extension LinuxInitializationSettingsMapper on LinuxInitializationSettings { | ||
Map<String, Object> toMap() { | ||
return <String, Object> { | ||
"defaultIcon": defaultIcon?.toMap(), | ||
'defaultIcon': defaultIcon?.toMap(), | ||
}; | ||
} | ||
} | ||
|
||
extension LinuxNotificationButtonSetMapper on Set<LinuxNotificationButton> { | ||
List<Map<String, String>> serializeToList() { | ||
return map((e) => <String, String>{ | ||
"buttonLabel": e.label, | ||
"buttonId": e.buttonId, | ||
List<Map<String, String>> serializeToList() => | ||
map((LinuxNotificationButton e) => <String, String>{ | ||
'buttonLabel': e.label, | ||
'buttonId': e.buttonId, | ||
}).toList(growable: false); | ||
} | ||
} | ||
|
||
extension LinuxNotificationDetailsMapper on LinuxNotificationDetails { | ||
Map<String, Object> toMap() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. analysis is picking up that this should use |
||
return <String, Object> { | ||
"icon": icon?.toMap(), | ||
"buttons": buttons?.serializeToList(), | ||
'icon': icon?.toMap(), | ||
'buttons': buttons?.serializeToList(), | ||
}; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add the same one-liner doc as the others around, to avoid affecting pub score?