Skip to content

Commit 5dc3022

Browse files
committed
Merge branch 'master' into prod
2 parents 6fb395d + 0d89d3c commit 5dc3022

File tree

9 files changed

+134
-10
lines changed

9 files changed

+134
-10
lines changed

lib/interop/js_notification/js_notification.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,21 @@ class JSNotification implements Serializable {
1010
/// See: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification#options
1111
final JSNotificationOptions? options;
1212

13-
JSNotification(this.title, [this.options]);
13+
const JSNotification(this.title, [this.options]);
14+
15+
JSNotification copyWithSelf(JSNotification other) {
16+
return JSNotification(
17+
other.title,
18+
other.options,
19+
);
20+
}
21+
22+
JSNotification copyWith({String? title, JSNotificationOptions? options}) {
23+
return JSNotification(
24+
title ?? this.title,
25+
options ?? this.options,
26+
);
27+
}
1428

1529
@override
1630
Map<String, dynamic> toMap() {

lib/interop/js_notification/js_notification_action.dart

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,35 @@ class JSNotificationAction implements Serializable {
1414

1515
const JSNotificationAction({required this.action, required this.title, this.icon});
1616

17-
factory JSNotificationAction.fromTitle(String title, {bool actionToLowerCase = true}) {
18-
final action = actionToLowerCase ? title.toLowerCase() : title;
17+
factory JSNotificationAction.fromTitle(String title, {bool transformToLowerCase = true}) {
18+
final action = transformToLowerCase ? title.toLowerCase() : title;
1919
return JSNotificationAction(action: action, title: title);
2020
}
2121

22-
factory JSNotificationAction.fromAction(String action, {bool capatlizeTitle = true}) {
23-
final title = capatlizeTitle ? action.capitalize() : action;
22+
factory JSNotificationAction.fromAction(String action, {bool capitalize = true}) {
23+
final title = capitalize ? action.capitalize() : action;
2424
return JSNotificationAction(action: action, title: title);
2525
}
2626

2727
factory JSNotificationAction.simpleWithIcon(String title, String icon) =>
2828
JSNotificationAction(action: title, title: title, icon: icon);
2929

30+
JSNotificationAction copyWithSelf(JSNotificationAction other) {
31+
return JSNotificationAction(
32+
action: other.action,
33+
title: other.title,
34+
icon: other.icon,
35+
);
36+
}
37+
38+
JSNotificationAction copyWith({String? action, String? title, String? icon}) {
39+
return JSNotificationAction(
40+
action: action ?? this.action,
41+
title: title ?? this.title,
42+
icon: icon ?? this.icon,
43+
);
44+
}
45+
3046
@override
3147
Map<String, dynamic> toMap() {
3248
final map = {

lib/interop/js_notification/js_notification_options.dart

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,59 @@ class JSNotificationOptions implements Serializable {
6868
this.vibrate,
6969
});
7070

71+
JSNotificationOptions copyWithSelf({JSNotificationOptions? options}) {
72+
return JSNotificationOptions(
73+
actions: options?.actions ?? actions,
74+
badge: options?.badge ?? badge,
75+
body: options?.body ?? body,
76+
data: options?.data ?? data,
77+
dir: options?.dir ?? dir,
78+
icon: options?.icon ?? icon,
79+
image: options?.image ?? image,
80+
lang: options?.lang ?? lang,
81+
renotify: options?.renotify ?? renotify,
82+
requireInteraction: options?.requireInteraction ?? requireInteraction,
83+
silent: options?.silent ?? silent,
84+
tag: options?.tag ?? tag,
85+
timestamp: options?.timestamp ?? timestamp,
86+
vibrate: options?.vibrate ?? vibrate,
87+
);
88+
}
89+
90+
JSNotificationOptions copyWith({
91+
List<JSNotificationAction>? actions,
92+
int? badge,
93+
String? body,
94+
Map<String, dynamic>? data,
95+
JSNotificationDirection? dir,
96+
String? icon,
97+
String? image,
98+
String? lang,
99+
bool? renotify,
100+
bool? requireInteraction,
101+
bool? silent,
102+
String? tag,
103+
int? timestamp,
104+
VibratePattern? vibrate,
105+
}) {
106+
return JSNotificationOptions(
107+
actions: actions ?? this.actions,
108+
badge: badge ?? this.badge,
109+
body: body ?? this.body,
110+
data: data ?? this.data,
111+
dir: dir ?? this.dir,
112+
icon: icon ?? this.icon,
113+
image: image ?? this.image,
114+
lang: lang ?? this.lang,
115+
renotify: renotify ?? this.renotify,
116+
requireInteraction: requireInteraction ?? this.requireInteraction,
117+
silent: silent ?? this.silent,
118+
tag: tag ?? this.tag,
119+
timestamp: timestamp ?? this.timestamp,
120+
vibrate: vibrate ?? this.vibrate,
121+
);
122+
}
123+
71124
@override
72125
Map<String, dynamic> toMap() {
73126
final Map<String, dynamic> map = {};

lib/js_notifications_web.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class JsNotificationsWeb extends JsNotificationsPlatform {
2323

2424
StreamController<NotificationActionResult>? _dismissStream;
2525
StreamController<NotificationActionResult>? _actionStream;
26+
StreamController<NotificationActionResult>? _tapStream;
2627

2728
static String _scopeUrl = defaultScope;
2829

@@ -37,11 +38,16 @@ class JsNotificationsWeb extends JsNotificationsPlatform {
3738

3839
void _setup() {
3940
serviceWorkerManager = ServiceWorkerManager(
41+
onNotificationTap: _onNotificationTap,
4042
onNotificationAction: _onNotificationAction,
4143
onNotificationDismiss: (t) => _onNotificationDismiss,
4244
scopeUrl: _scopeUrl);
4345
}
4446

47+
void _onNotificationTap(NotificationActionResult e) {
48+
_tapStream?.add(e);
49+
}
50+
4551
void _onNotificationAction(NotificationActionResult e) {
4652
_actionStream?.add(e);
4753
}
@@ -146,4 +152,10 @@ class JsNotificationsWeb extends JsNotificationsPlatform {
146152
_dismissStream ??= StreamController<NotificationActionResult>.broadcast();
147153
return _dismissStream!.stream;
148154
}
155+
156+
@override
157+
Stream<NotificationActionResult> get tapStream {
158+
_tapStream ??= StreamController<NotificationActionResult>.broadcast();
159+
return _tapStream!.stream;
160+
}
149161
}

lib/managers/service_worker_manager.dart

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ class ServiceWorkerManager {
1919

2020
late final String _scope;
2121

22-
ServiceWorkerManager({this.onNotificationAction, this.onNotificationDismiss, required String scopeUrl}){
22+
ServiceWorkerManager({this.onNotificationTap, this.onNotificationAction, this.onNotificationDismiss, required String scopeUrl}){
2323
_scope = scopeUrl;
2424
_notificationApi = interop.NotificationsAPI.instance;
2525
_setupServiceWorker();
2626
}
2727

2828
Consumer<NotificationActionResult>? onNotificationAction;
2929
Consumer<NotificationActionResult>? onNotificationDismiss;
30+
Consumer<NotificationActionResult>? onNotificationTap;
3031

3132
html.ServiceWorkerContainer? _webServiceWorkerContainerDelegate;
3233

@@ -162,12 +163,30 @@ class ServiceWorkerManager {
162163
void _onServiceWorkerContainerMessageEvent(html.MessageEvent event) {
163164
printDebug("Service worker container message event: $event", tag);
164165
final map = Map<String, dynamic>.from(event.data);
165-
final action = NotificationActionResult.fromJson(map);
166+
final result = NotificationActionResult.fromJson(map);
166167
final type = map["type"];
167168
if(type == SWEvents.click) {
168-
onNotificationAction?.call(action);
169+
/// Custom notification event, not part of the standard Notification API.
170+
/// Used to describe clicking on a notification.
171+
/// This may be confused with an empty notification action event.
172+
/// Sample:
173+
/// ```js
174+
/// notification.actions = [
175+
/// { action: "", title: "Open Window" },
176+
/// { action: "click", title: "Clicked me" },
177+
/// ];
178+
/// ```
179+
///
180+
/// The above action with title "Open Window" will be considered a tap action as the service worker does not
181+
/// distinguish between a normal notification click and a notification action with an empty action string
182+
/// (see "Open Window" action above).
183+
if(result.action == null || result.action!.isEmpty) {
184+
onNotificationTap?.call(result);
185+
} else {
186+
onNotificationAction?.call(result);
187+
}
169188
} else if (type == SWEvents.close) {
170-
onNotificationDismiss?.call(action);
189+
onNotificationDismiss?.call(result);
171190
} else {
172191
throw Exception("Unknown NotificationActionResult type $type");
173192
}

lib/method_channel/js_notifications_method_channel.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ class MethodChannelJsNotifications extends JsNotificationsPlatform {
6868
@override
6969
Stream<NotificationActionResult> get dismissStream => throw UnimplementedError();
7070

71+
@override
72+
Stream<NotificationActionResult> get tapStream => throw UnimplementedError();
73+
7174
@override
7275
set scopeUrl(String value) {
7376
// TODO: implement scopeUrl

lib/platform_interface/js_notifications_platform_interface.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,7 @@ abstract class JsNotificationsPlatform extends PlatformInterface {
8383

8484
/// Stream broadcasting notification close events with associated data
8585
Stream<NotificationActionResult> get dismissStream;
86+
87+
/// Stream broadcasting notification tap events with associated data
88+
Stream<NotificationActionResult> get tapStream;
8689
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: js_notifications
22
description: "An extended NotificationsAPI for Dart Web notifications."
3-
version: 0.0.1
3+
version: 0.0.2
44
homepage: https://github.com/cybex-dev/js_notifications
55

66
environment:

test/js_notifications_test.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ class MockJsNotificationsPlatform
6666
// TODO: implement notificationClose
6767
Stream<NotificationActionResult> get dismissStream => throw UnimplementedError();
6868

69+
@override
70+
// TODO: implement notificationTap
71+
Stream<NotificationActionResult> get tapStream => throw UnimplementedError();
72+
6973
@override
7074
set scopeUrl(String value) {
7175
// TODO: implement scopeUrl

0 commit comments

Comments
 (0)