From 67143d92c8a64a188816e5707ef548083a84bd9c Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 21:16:48 -0500 Subject: [PATCH 01/40] Example app runs on web --- flutter_local_notifications/example/lib/main.dart | 5 ++++- flutter_local_notifications/pubspec.yaml | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index bdb1122f3..e20434386 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -1,6 +1,6 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; +import 'dart:io' hide Platform; // ignore: unnecessary_import import 'dart:typed_data'; @@ -15,12 +15,15 @@ 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; +import 'package:universal_platform/universal_platform.dart'; import 'padded_button.dart'; import 'plugin.dart'; import 'repeating.dart' as repeating; import 'windows.dart' as windows; +typedef Platform = UniversalPlatform; + /// Streams are created so that app can respond to notification-related events /// since the plugin is initialized in the `main` function final StreamController selectNotificationStream = diff --git a/flutter_local_notifications/pubspec.yaml b/flutter_local_notifications/pubspec.yaml index 99c2a6108..27235da2f 100644 --- a/flutter_local_notifications/pubspec.yaml +++ b/flutter_local_notifications/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: flutter_local_notifications_windows: ^1.0.0-dev.1 flutter_local_notifications_platform_interface: ^8.1.0-dev.1 timezone: ^0.10.0 + universal_platform: ^1.1.0 dev_dependencies: flutter_driver: From 6cf51e6b994c8f6de249f77a0069447dbfe99da7 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 21:28:07 -0500 Subject: [PATCH 02/40] Example app recognizes Web plugin --- .../example/lib/main.dart | 3 ++ .../flutter_local_notifications_plugin.dart | 49 ++++++++++--------- .../platform_flutter_local_notifications.dart | 7 +++ flutter_local_notifications/pubspec.yaml | 3 ++ 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index e20434386..20f9845d5 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -297,6 +297,9 @@ class _HomePageState extends State { @override Widget build(BuildContext context) => Scaffold( + floatingActionButton: FloatingActionButton(onPressed: () => print( + flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation() + )), appBar: AppBar( title: const Text('Plugin example app'), ), diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index bc866a073..5fa749b33 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -45,35 +45,36 @@ class FlutterLocalNotificationsPlugin { 'The type argument must be a concrete subclass of ' 'FlutterLocalNotificationsPlatform'); } - if (kIsWeb) { - return null; - } - if (defaultTargetPlatform == TargetPlatform.android && - T == AndroidFlutterLocalNotificationsPlugin && - FlutterLocalNotificationsPlatform.instance - is AndroidFlutterLocalNotificationsPlugin) { - return FlutterLocalNotificationsPlatform.instance as T?; + final FlutterLocalNotificationsPlatform instance = + FlutterLocalNotificationsPlatform.instance; + if (kIsWeb && T == WebFlutterLocalNotificationsPlugin && instance is T) { + return instance; + } else if (defaultTargetPlatform == TargetPlatform.android && + T == AndroidFlutterLocalNotificationsPlugin && + instance is T + ) { + return instance; } else if (defaultTargetPlatform == TargetPlatform.iOS && - T == IOSFlutterLocalNotificationsPlugin && - FlutterLocalNotificationsPlatform.instance - is IOSFlutterLocalNotificationsPlugin) { - return FlutterLocalNotificationsPlatform.instance as T?; + T == IOSFlutterLocalNotificationsPlugin && + instance is T + ) { + return instance; } else if (defaultTargetPlatform == TargetPlatform.macOS && - T == MacOSFlutterLocalNotificationsPlugin && - FlutterLocalNotificationsPlatform.instance - is MacOSFlutterLocalNotificationsPlugin) { - return FlutterLocalNotificationsPlatform.instance as T?; + T == MacOSFlutterLocalNotificationsPlugin && + instance is T + ) { + return instance; } else if (defaultTargetPlatform == TargetPlatform.linux && - T == LinuxFlutterLocalNotificationsPlugin && - FlutterLocalNotificationsPlatform.instance - is LinuxFlutterLocalNotificationsPlugin) { - return FlutterLocalNotificationsPlatform.instance as T?; + T == LinuxFlutterLocalNotificationsPlugin && + instance is T + ) { + return instance; } else if (defaultTargetPlatform == TargetPlatform.windows && - T == FlutterLocalNotificationsWindows && - FlutterLocalNotificationsPlatform.instance - is FlutterLocalNotificationsWindows) { - return FlutterLocalNotificationsPlatform.instance as T?; + T == FlutterLocalNotificationsWindows && + instance is T + ) { + return instance; } return null; diff --git a/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart index 7781f4f21..547f6c7dd 100644 --- a/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart @@ -1004,6 +1004,13 @@ class MacOSFlutterLocalNotificationsPlugin } } +/// Web implementation of the local notifications plugin. +class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { + static void registerWith(_) { + FlutterLocalNotificationsPlatform.instance = WebFlutterLocalNotificationsPlugin(); + } +} + /// Checks [didReceiveBackgroundNotificationResponseCallback], if not `null`, /// for eligibility to be used as a background callback. /// diff --git a/flutter_local_notifications/pubspec.yaml b/flutter_local_notifications/pubspec.yaml index 27235da2f..7d1f4859e 100644 --- a/flutter_local_notifications/pubspec.yaml +++ b/flutter_local_notifications/pubspec.yaml @@ -41,6 +41,9 @@ flutter: default_package: flutter_local_notifications_linux windows: default_package: flutter_local_notifications_windows + web: + pluginClass: WebFlutterLocalNotificationsPlugin + fileName: "src/platform_flutter_local_notifications.dart" environment: sdk: ^3.3.0 From 2e662c3660ae28db983f60befe1219c4aee3eaa9 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 21:36:48 -0500 Subject: [PATCH 03/40] Tentative implementation of show() --- .../example/lib/main.dart | 6 +++--- .../lib/flutter_local_notifications.dart | 1 + .../flutter_local_notifications_plugin.dart | 6 ++++-- .../platform_flutter_local_notifications.dart | 6 ------ .../src/web_flutter_local_notifications.dart | 19 +++++++++++++++++++ flutter_local_notifications/pubspec.yaml | 2 +- 6 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 flutter_local_notifications/lib/src/web_flutter_local_notifications.dart diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index 20f9845d5..f07379025 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -297,9 +297,9 @@ class _HomePageState extends State { @override Widget build(BuildContext context) => Scaffold( - floatingActionButton: FloatingActionButton(onPressed: () => print( - flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation() - )), + floatingActionButton: FloatingActionButton(onPressed: () => + flutterLocalNotificationsPlugin.show(0, null, null, null), + ), appBar: AppBar( title: const Text('Plugin example app'), ), diff --git a/flutter_local_notifications/lib/flutter_local_notifications.dart b/flutter_local_notifications/lib/flutter_local_notifications.dart index c42e2ff4c..62505141b 100644 --- a/flutter_local_notifications/lib/flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/flutter_local_notifications.dart @@ -40,3 +40,4 @@ export 'src/platform_specifics/darwin/notification_enabled_options.dart'; export 'src/typedefs.dart'; export 'src/types.dart'; +export 'src/web_flutter_local_notifications.dart'; diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index 5fa749b33..eed60e542 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -11,6 +11,7 @@ import 'notification_details.dart'; import 'platform_flutter_local_notifications.dart'; import 'platform_specifics/android/schedule_mode.dart'; import 'types.dart'; +import 'web_flutter_local_notifications.dart'; /// Provides cross-platform functionality for displaying local notifications. /// @@ -46,7 +47,7 @@ class FlutterLocalNotificationsPlugin { 'FlutterLocalNotificationsPlatform'); } - final FlutterLocalNotificationsPlatform instance = + final FlutterLocalNotificationsPlatform instance = FlutterLocalNotificationsPlatform.instance; if (kIsWeb && T == WebFlutterLocalNotificationsPlugin && instance is T) { return instance; @@ -239,7 +240,8 @@ class FlutterLocalNotificationsPlugin { String? payload, }) async { if (kIsWeb) { - return; + await resolvePlatformSpecificImplementation() + ?.show(id, title, body, payload: payload); } if (defaultTargetPlatform == TargetPlatform.android) { await resolvePlatformSpecificImplementation< diff --git a/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart index 547f6c7dd..1d43150c6 100644 --- a/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart @@ -1004,12 +1004,6 @@ class MacOSFlutterLocalNotificationsPlugin } } -/// Web implementation of the local notifications plugin. -class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { - static void registerWith(_) { - FlutterLocalNotificationsPlatform.instance = WebFlutterLocalNotificationsPlugin(); - } -} /// Checks [didReceiveBackgroundNotificationResponseCallback], if not `null`, /// for eligibility to be used as a background callback. diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart new file mode 100644 index 000000000..185a337f9 --- /dev/null +++ b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart @@ -0,0 +1,19 @@ +import 'dart:js_interop'; + +import 'package:web/web.dart'; +import '../flutter_local_notifications.dart'; + +/// Web implementation of the local notifications plugin. +class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { + static void registerWith(_) { + FlutterLocalNotificationsPlatform.instance = WebFlutterLocalNotificationsPlugin(); + } + + @override + Future show(int id, String? title, String? body, {String? payload}) async { + final registration = await window.navigator.serviceWorker.getRegistration().toDart; + print("This is the registration: $registration"); + if (registration == null) return; + registration.showNotification(title ?? 'This is a notification'); + } +} diff --git a/flutter_local_notifications/pubspec.yaml b/flutter_local_notifications/pubspec.yaml index 7d1f4859e..ed9a3b19c 100644 --- a/flutter_local_notifications/pubspec.yaml +++ b/flutter_local_notifications/pubspec.yaml @@ -43,7 +43,7 @@ flutter: default_package: flutter_local_notifications_windows web: pluginClass: WebFlutterLocalNotificationsPlugin - fileName: "src/platform_flutter_local_notifications.dart" + fileName: "src/web_flutter_local_notifications.dart" environment: sdk: ^3.3.0 From a7458de5ded9a9ac2082b49e65c2a3d3d4c097e6 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 22:03:22 -0500 Subject: [PATCH 04/40] Added service worker to web example Also added getActiveNotifications --- flutter_local_notifications/example/.metadata | 16 +++---- .../example/lib/main.dart | 3 ++ .../example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../example/web/icons/Icon-maskable-192.png | Bin 0 -> 5594 bytes .../example/web/icons/Icon-maskable-512.png | Bin 0 -> 20998 bytes .../example/web/index.html | 38 +++++++++++++++++ .../example/web/manifest.json | 35 +++++++++++++++ .../flutter_local_notifications_plugin.dart | 3 +- .../src/web_flutter_local_notifications.dart | 40 ++++++++++++++++-- 11 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 flutter_local_notifications/example/web/favicon.png create mode 100644 flutter_local_notifications/example/web/icons/Icon-192.png create mode 100644 flutter_local_notifications/example/web/icons/Icon-512.png create mode 100644 flutter_local_notifications/example/web/icons/Icon-maskable-192.png create mode 100644 flutter_local_notifications/example/web/icons/Icon-maskable-512.png create mode 100644 flutter_local_notifications/example/web/index.html create mode 100644 flutter_local_notifications/example/web/manifest.json diff --git a/flutter_local_notifications/example/.metadata b/flutter_local_notifications/example/.metadata index aa7708c21..b603e3b8b 100644 --- a/flutter_local_notifications/example/.metadata +++ b/flutter_local_notifications/example/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 - channel: stable + revision: "603104015dd692ea3403755b55d07813d5cf8965" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 - base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 - - platform: macos - create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 - base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 + - platform: web + create_revision: 603104015dd692ea3403755b55d07813d5cf8965 + base_revision: 603104015dd692ea3403755b55d07813d5cf8965 # User provided section diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index f07379025..ba8309d2e 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -276,6 +276,9 @@ class _HomePageState extends State { setState(() { _notificationsEnabled = grantedNotificationPermission ?? false; }); + } else if (kIsWeb) { + await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation() + ?.requestNotificationsPermission(); } } diff --git a/flutter_local_notifications/example/web/favicon.png b/flutter_local_notifications/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/flutter_local_notifications/example/web/icons/Icon-192.png b/flutter_local_notifications/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/flutter_local_notifications/example/web/icons/Icon-512.png b/flutter_local_notifications/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/flutter_local_notifications/example/web/icons/Icon-maskable-192.png b/flutter_local_notifications/example/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9b4d76e525556d5d89141648c724331630325d GIT binary patch literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! literal 0 HcmV?d00001 diff --git a/flutter_local_notifications/example/web/icons/Icon-maskable-512.png b/flutter_local_notifications/example/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..d69c56691fbdb0b7efa65097c7cc1edac12a6d3e GIT binary patch literal 20998 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 MPgg&ebxsLQ025IeI{*Lx literal 0 HcmV?d00001 diff --git a/flutter_local_notifications/example/web/index.html b/flutter_local_notifications/example/web/index.html new file mode 100644 index 000000000..1aa025dd6 --- /dev/null +++ b/flutter_local_notifications/example/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + diff --git a/flutter_local_notifications/example/web/manifest.json b/flutter_local_notifications/example/web/manifest.json new file mode 100644 index 000000000..096edf8fe --- /dev/null +++ b/flutter_local_notifications/example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index eed60e542..a9d8146ac 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -119,7 +119,8 @@ class FlutterLocalNotificationsPlugin { onDidReceiveBackgroundNotificationResponse, }) async { if (kIsWeb) { - return true; + return resolvePlatformSpecificImplementation() + ?.initialize(); } if (defaultTargetPlatform == TargetPlatform.android) { diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart index 185a337f9..3c7e23e46 100644 --- a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:js_interop'; import 'package:web/web.dart'; @@ -9,11 +10,42 @@ class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatfo FlutterLocalNotificationsPlatform.instance = WebFlutterLocalNotificationsPlugin(); } + ServiceWorkerRegistration? _registration; + @override Future show(int id, String? title, String? body, {String? payload}) async { - final registration = await window.navigator.serviceWorker.getRegistration().toDart; - print("This is the registration: $registration"); - if (registration == null) return; - registration.showNotification(title ?? 'This is a notification'); + final data = {"id": id}; + final options = NotificationOptions(data: jsonEncode(data).toJS); + print("JSON: ${jsonEncode(data).toJS}"); + _registration?.showNotification(title ?? 'This is a notification', options); + } + + Future initialize() async { + _registration = await window.navigator.serviceWorker.getRegistration().toDart; + return true; + } + + + Future requestNotificationsPermission() async { + final JSString result = await Notification.requestPermission().toDart; + return result.toDart == 'granted'; + } + + @override + Future> getActiveNotifications() async { + if (_registration == null) return []; + final notificationsArray = await _registration!.getNotifications().toDart; + final result = []; + final ids = {}; + for (final jsNotification in notificationsArray.toDart) { + final data = jsonDecode(jsNotification.data.toString()); + if (data == null) continue; + final id = data["id"]; + if (id == null) continue; + final notif = ActiveNotification(id: id); + ids.add(id); + result.add(notif); + } + return result; } } From 7aff70d672b0a698ca200bf13e5e4c2a3c8b9447 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 22:13:14 -0500 Subject: [PATCH 05/40] Address lints --- .../flutter_local_notifications_plugin.dart | 10 ++-- .../src/web_flutter_local_notifications.dart | 57 +++++++++++++------ 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index a9d8146ac..3ff6c6b47 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -119,8 +119,9 @@ class FlutterLocalNotificationsPlugin { onDidReceiveBackgroundNotificationResponse, }) async { if (kIsWeb) { - return resolvePlatformSpecificImplementation() - ?.initialize(); + return resolvePlatformSpecificImplementation + () + ?.initialize(); } if (defaultTargetPlatform == TargetPlatform.android) { @@ -241,8 +242,9 @@ class FlutterLocalNotificationsPlugin { String? payload, }) async { if (kIsWeb) { - await resolvePlatformSpecificImplementation() - ?.show(id, title, body, payload: payload); + await resolvePlatformSpecificImplementation + () + ?.show(id, title, body, payload: payload); } if (defaultTargetPlatform == TargetPlatform.android) { await resolvePlatformSpecificImplementation< diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart index 3c7e23e46..e0c4a5463 100644 --- a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart @@ -5,27 +5,41 @@ import 'package:web/web.dart'; import '../flutter_local_notifications.dart'; /// Web implementation of the local notifications plugin. -class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { +class WebFlutterLocalNotificationsPlugin + extends FlutterLocalNotificationsPlatform +{ + /// Registers the web plugin with the platform interface. static void registerWith(_) { - FlutterLocalNotificationsPlatform.instance = WebFlutterLocalNotificationsPlugin(); + FlutterLocalNotificationsPlatform.instance = + WebFlutterLocalNotificationsPlugin(); } ServiceWorkerRegistration? _registration; @override - Future show(int id, String? title, String? body, {String? payload}) async { - final data = {"id": id}; - final options = NotificationOptions(data: jsonEncode(data).toJS); - print("JSON: ${jsonEncode(data).toJS}"); + Future show( + int id, String? title, String? body, {String? payload} + ) async { + final Map data = + {'id': id}; + final NotificationOptions options = NotificationOptions( + data: jsonEncode(data).toJS, + ); _registration?.showNotification(title ?? 'This is a notification', options); } + /// Initializes the plugin. Future initialize() async { - _registration = await window.navigator.serviceWorker.getRegistration().toDart; - return true; + _registration = await window.navigator.serviceWorker + .getRegistration().toDart; + return _registration != null; } + /// Requests notification permission from the browser. + /// + /// It is highly recommended and sometimes required that this be called only + /// in response to a user gesture, and not automatically. Future requestNotificationsPermission() async { final JSString result = await Notification.requestPermission().toDart; return result.toDart == 'granted'; @@ -33,16 +47,23 @@ class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatfo @override Future> getActiveNotifications() async { - if (_registration == null) return []; - final notificationsArray = await _registration!.getNotifications().toDart; - final result = []; - final ids = {}; - for (final jsNotification in notificationsArray.toDart) { - final data = jsonDecode(jsNotification.data.toString()); - if (data == null) continue; - final id = data["id"]; - if (id == null) continue; - final notif = ActiveNotification(id: id); + if (_registration == null) { + return []; + } + final JSArray notificationsArray = await _registration + !.getNotifications().toDart; + final List result = []; + final Set ids = {}; + for (final Notification jsNotification in notificationsArray.toDart) { + final dynamic data = jsonDecode(jsNotification.data.toString()); + if (data == null) { + continue; + } + final int? id = data['id']; + if (id == null) { + continue; + } + final ActiveNotification notif = ActiveNotification(id: id); ids.add(id); result.add(notif); } From 5599512bc333d410ad9e297a9bb69c1d46ca73ed Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 22:21:58 -0500 Subject: [PATCH 06/40] Use conditional imports to not break non-web platforms --- .../src/web_flutter_local_notifications.dart | 74 +------------------ .../lib/src/web_mock.dart | 8 ++ .../lib/src/web_real.dart | 72 ++++++++++++++++++ 3 files changed, 82 insertions(+), 72 deletions(-) create mode 100644 flutter_local_notifications/lib/src/web_mock.dart create mode 100644 flutter_local_notifications/lib/src/web_real.dart diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart index e0c4a5463..be03448ea 100644 --- a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart @@ -1,72 +1,2 @@ -import 'dart:convert'; -import 'dart:js_interop'; - -import 'package:web/web.dart'; -import '../flutter_local_notifications.dart'; - -/// Web implementation of the local notifications plugin. -class WebFlutterLocalNotificationsPlugin - extends FlutterLocalNotificationsPlatform -{ - /// Registers the web plugin with the platform interface. - static void registerWith(_) { - FlutterLocalNotificationsPlatform.instance = - WebFlutterLocalNotificationsPlugin(); - } - - ServiceWorkerRegistration? _registration; - - @override - Future show( - int id, String? title, String? body, {String? payload} - ) async { - final Map data = - {'id': id}; - final NotificationOptions options = NotificationOptions( - data: jsonEncode(data).toJS, - ); - _registration?.showNotification(title ?? 'This is a notification', options); - } - - /// Initializes the plugin. - Future initialize() async { - _registration = await window.navigator.serviceWorker - .getRegistration().toDart; - return _registration != null; - } - - - /// Requests notification permission from the browser. - /// - /// It is highly recommended and sometimes required that this be called only - /// in response to a user gesture, and not automatically. - Future requestNotificationsPermission() async { - final JSString result = await Notification.requestPermission().toDart; - return result.toDart == 'granted'; - } - - @override - Future> getActiveNotifications() async { - if (_registration == null) { - return []; - } - final JSArray notificationsArray = await _registration - !.getNotifications().toDart; - final List result = []; - final Set ids = {}; - for (final Notification jsNotification in notificationsArray.toDart) { - final dynamic data = jsonDecode(jsNotification.data.toString()); - if (data == null) { - continue; - } - final int? id = data['id']; - if (id == null) { - continue; - } - final ActiveNotification notif = ActiveNotification(id: id); - ids.add(id); - result.add(notif); - } - return result; - } -} +export "web_mock.dart" + if (dart.library.js_interop) "web_real.dart"; diff --git a/flutter_local_notifications/lib/src/web_mock.dart b/flutter_local_notifications/lib/src/web_mock.dart new file mode 100644 index 000000000..43b46d42a --- /dev/null +++ b/flutter_local_notifications/lib/src/web_mock.dart @@ -0,0 +1,8 @@ +import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; + +/// A stub implementation of the web plugin, for non-web platforms. +class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { + Future initialize() async { return null; } + + Future requestNotificationsPermission() async { return false; } +} diff --git a/flutter_local_notifications/lib/src/web_real.dart b/flutter_local_notifications/lib/src/web_real.dart new file mode 100644 index 000000000..e0c4a5463 --- /dev/null +++ b/flutter_local_notifications/lib/src/web_real.dart @@ -0,0 +1,72 @@ +import 'dart:convert'; +import 'dart:js_interop'; + +import 'package:web/web.dart'; +import '../flutter_local_notifications.dart'; + +/// Web implementation of the local notifications plugin. +class WebFlutterLocalNotificationsPlugin + extends FlutterLocalNotificationsPlatform +{ + /// Registers the web plugin with the platform interface. + static void registerWith(_) { + FlutterLocalNotificationsPlatform.instance = + WebFlutterLocalNotificationsPlugin(); + } + + ServiceWorkerRegistration? _registration; + + @override + Future show( + int id, String? title, String? body, {String? payload} + ) async { + final Map data = + {'id': id}; + final NotificationOptions options = NotificationOptions( + data: jsonEncode(data).toJS, + ); + _registration?.showNotification(title ?? 'This is a notification', options); + } + + /// Initializes the plugin. + Future initialize() async { + _registration = await window.navigator.serviceWorker + .getRegistration().toDart; + return _registration != null; + } + + + /// Requests notification permission from the browser. + /// + /// It is highly recommended and sometimes required that this be called only + /// in response to a user gesture, and not automatically. + Future requestNotificationsPermission() async { + final JSString result = await Notification.requestPermission().toDart; + return result.toDart == 'granted'; + } + + @override + Future> getActiveNotifications() async { + if (_registration == null) { + return []; + } + final JSArray notificationsArray = await _registration + !.getNotifications().toDart; + final List result = []; + final Set ids = {}; + for (final Notification jsNotification in notificationsArray.toDart) { + final dynamic data = jsonDecode(jsNotification.data.toString()); + if (data == null) { + continue; + } + final int? id = data['id']; + if (id == null) { + continue; + } + final ActiveNotification notif = ActiveNotification(id: id); + ids.add(id); + result.add(notif); + } + return result; + } +} From dc0b64476a99ffa148fd38df1773c498da73bec9 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 22:23:13 -0500 Subject: [PATCH 07/40] Address lints --- .../lib/src/web_flutter_local_notifications.dart | 4 ++-- flutter_local_notifications/lib/src/web_mock.dart | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart index be03448ea..e16ce2ffc 100644 --- a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart @@ -1,2 +1,2 @@ -export "web_mock.dart" - if (dart.library.js_interop) "web_real.dart"; +export 'web_mock.dart' + if (dart.library.js_interop) 'web_real.dart'; diff --git a/flutter_local_notifications/lib/src/web_mock.dart b/flutter_local_notifications/lib/src/web_mock.dart index 43b46d42a..65470f21a 100644 --- a/flutter_local_notifications/lib/src/web_mock.dart +++ b/flutter_local_notifications/lib/src/web_mock.dart @@ -1,8 +1,12 @@ import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; /// A stub implementation of the web plugin, for non-web platforms. -class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { - Future initialize() async { return null; } +class WebFlutterLocalNotificationsPlugin + extends FlutterLocalNotificationsPlatform +{ + /// Initializes the plugin. + Future initialize() async => null; - Future requestNotificationsPermission() async { return false; } + /// Requests permission to use the plugin. + Future requestNotificationsPermission() async => false; } From 29acdf21f2d87d834a263b9dd8ce1e7d4a16fd80 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 22:31:44 -0500 Subject: [PATCH 08/40] More formatting --- flutter_local_notifications/lib/src/web_real.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/flutter_local_notifications/lib/src/web_real.dart b/flutter_local_notifications/lib/src/web_real.dart index e0c4a5463..65d68b076 100644 --- a/flutter_local_notifications/lib/src/web_real.dart +++ b/flutter_local_notifications/lib/src/web_real.dart @@ -20,11 +20,9 @@ class WebFlutterLocalNotificationsPlugin Future show( int id, String? title, String? body, {String? payload} ) async { - final Map data = - {'id': id}; - final NotificationOptions options = NotificationOptions( - data: jsonEncode(data).toJS, - ); + final Map data = {'id': id}; + final NotificationOptions options = + NotificationOptions(data: jsonEncode(data).toJS); _registration?.showNotification(title ?? 'This is a notification', options); } From 2d7d1586836712d234d6fa2541d2d68ab9cbfd2e Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Thu, 14 Nov 2024 22:36:15 -0500 Subject: [PATCH 09/40] Used dart format --- .../example/lib/main.dart | 13 ++++--- .../flutter_local_notifications_plugin.dart | 35 ++++++++----------- .../platform_flutter_local_notifications.dart | 1 - .../src/web_flutter_local_notifications.dart | 3 +- .../lib/src/web_mock.dart | 3 +- .../lib/src/web_real.dart | 21 +++++------ 6 files changed, 34 insertions(+), 42 deletions(-) diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index ba8309d2e..f2f133974 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -277,8 +277,10 @@ class _HomePageState extends State { _notificationsEnabled = grantedNotificationPermission ?? false; }); } else if (kIsWeb) { - await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation() - ?.requestNotificationsPermission(); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + WebFlutterLocalNotificationsPlugin>() + ?.requestNotificationsPermission(); } } @@ -300,9 +302,10 @@ class _HomePageState extends State { @override Widget build(BuildContext context) => Scaffold( - floatingActionButton: FloatingActionButton(onPressed: () => - flutterLocalNotificationsPlugin.show(0, null, null, null), - ), + floatingActionButton: FloatingActionButton( + onPressed: () => + flutterLocalNotificationsPlugin.show(0, null, null, null), + ), appBar: AppBar( title: const Text('Plugin example app'), ), diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index 3ff6c6b47..db2811321 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -48,33 +48,28 @@ class FlutterLocalNotificationsPlugin { } final FlutterLocalNotificationsPlatform instance = - FlutterLocalNotificationsPlatform.instance; + FlutterLocalNotificationsPlatform.instance; if (kIsWeb && T == WebFlutterLocalNotificationsPlugin && instance is T) { return instance; } else if (defaultTargetPlatform == TargetPlatform.android && - T == AndroidFlutterLocalNotificationsPlugin && - instance is T - ) { + T == AndroidFlutterLocalNotificationsPlugin && + instance is T) { return instance; } else if (defaultTargetPlatform == TargetPlatform.iOS && - T == IOSFlutterLocalNotificationsPlugin && - instance is T - ) { + T == IOSFlutterLocalNotificationsPlugin && + instance is T) { return instance; } else if (defaultTargetPlatform == TargetPlatform.macOS && - T == MacOSFlutterLocalNotificationsPlugin && - instance is T - ) { + T == MacOSFlutterLocalNotificationsPlugin && + instance is T) { return instance; } else if (defaultTargetPlatform == TargetPlatform.linux && - T == LinuxFlutterLocalNotificationsPlugin && - instance is T - ) { + T == LinuxFlutterLocalNotificationsPlugin && + instance is T) { return instance; } else if (defaultTargetPlatform == TargetPlatform.windows && - T == FlutterLocalNotificationsWindows && - instance is T - ) { + T == FlutterLocalNotificationsWindows && + instance is T) { return instance; } @@ -119,8 +114,8 @@ class FlutterLocalNotificationsPlugin { onDidReceiveBackgroundNotificationResponse, }) async { if (kIsWeb) { - return resolvePlatformSpecificImplementation - () + return resolvePlatformSpecificImplementation< + WebFlutterLocalNotificationsPlugin>() ?.initialize(); } @@ -242,8 +237,8 @@ class FlutterLocalNotificationsPlugin { String? payload, }) async { if (kIsWeb) { - await resolvePlatformSpecificImplementation - () + await resolvePlatformSpecificImplementation< + WebFlutterLocalNotificationsPlugin>() ?.show(id, title, body, payload: payload); } if (defaultTargetPlatform == TargetPlatform.android) { diff --git a/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart index 1d43150c6..7781f4f21 100644 --- a/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart @@ -1004,7 +1004,6 @@ class MacOSFlutterLocalNotificationsPlugin } } - /// Checks [didReceiveBackgroundNotificationResponseCallback], if not `null`, /// for eligibility to be used as a background callback. /// diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart index e16ce2ffc..0464535b6 100644 --- a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart @@ -1,2 +1 @@ -export 'web_mock.dart' - if (dart.library.js_interop) 'web_real.dart'; +export 'web_mock.dart' if (dart.library.js_interop) 'web_real.dart'; diff --git a/flutter_local_notifications/lib/src/web_mock.dart b/flutter_local_notifications/lib/src/web_mock.dart index 65470f21a..09ad52df8 100644 --- a/flutter_local_notifications/lib/src/web_mock.dart +++ b/flutter_local_notifications/lib/src/web_mock.dart @@ -2,8 +2,7 @@ import 'package:flutter_local_notifications_platform_interface/flutter_local_not /// A stub implementation of the web plugin, for non-web platforms. class WebFlutterLocalNotificationsPlugin - extends FlutterLocalNotificationsPlatform -{ + extends FlutterLocalNotificationsPlatform { /// Initializes the plugin. Future initialize() async => null; diff --git a/flutter_local_notifications/lib/src/web_real.dart b/flutter_local_notifications/lib/src/web_real.dart index 65d68b076..00c9818e6 100644 --- a/flutter_local_notifications/lib/src/web_real.dart +++ b/flutter_local_notifications/lib/src/web_real.dart @@ -6,34 +6,31 @@ import '../flutter_local_notifications.dart'; /// Web implementation of the local notifications plugin. class WebFlutterLocalNotificationsPlugin - extends FlutterLocalNotificationsPlatform -{ + extends FlutterLocalNotificationsPlatform { /// Registers the web plugin with the platform interface. static void registerWith(_) { FlutterLocalNotificationsPlatform.instance = - WebFlutterLocalNotificationsPlugin(); + WebFlutterLocalNotificationsPlugin(); } ServiceWorkerRegistration? _registration; @override - Future show( - int id, String? title, String? body, {String? payload} - ) async { + Future show(int id, String? title, String? body, + {String? payload}) async { final Map data = {'id': id}; final NotificationOptions options = - NotificationOptions(data: jsonEncode(data).toJS); + NotificationOptions(data: jsonEncode(data).toJS); _registration?.showNotification(title ?? 'This is a notification', options); } /// Initializes the plugin. Future initialize() async { - _registration = await window.navigator.serviceWorker - .getRegistration().toDart; + _registration = + await window.navigator.serviceWorker.getRegistration().toDart; return _registration != null; } - /// Requests notification permission from the browser. /// /// It is highly recommended and sometimes required that this be called only @@ -48,8 +45,8 @@ class WebFlutterLocalNotificationsPlugin if (_registration == null) { return []; } - final JSArray notificationsArray = await _registration - !.getNotifications().toDart; + final JSArray notificationsArray = + await _registration!.getNotifications().toDart; final List result = []; final Set ids = {}; for (final Notification jsNotification in notificationsArray.toDart) { From dfde3342cdd4d93bb4a4a8a9e82354c6e0094b6e Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Fri, 15 Nov 2024 03:08:48 -0500 Subject: [PATCH 10/40] Implemented cancel() and cancelAll() --- .../flutter_local_notifications_plugin.dart | 7 +-- .../lib/src/web_mock.dart | 3 ++ .../lib/src/web_real.dart | 48 +++++++++++++++---- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index db2811321..83ab52b74 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -284,9 +284,10 @@ class FlutterLocalNotificationsPlugin { /// be canceled. `tag` has no effect on other platforms. Future cancel(int id, {String? tag}) async { if (kIsWeb) { - return; - } - if (defaultTargetPlatform == TargetPlatform.android) { + await resolvePlatformSpecificImplementation + () + ?.cancel(id, tag: tag); + } else if (defaultTargetPlatform == TargetPlatform.android) { await resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.cancel(id, tag: tag); diff --git a/flutter_local_notifications/lib/src/web_mock.dart b/flutter_local_notifications/lib/src/web_mock.dart index 09ad52df8..ca92ce443 100644 --- a/flutter_local_notifications/lib/src/web_mock.dart +++ b/flutter_local_notifications/lib/src/web_mock.dart @@ -8,4 +8,7 @@ class WebFlutterLocalNotificationsPlugin /// Requests permission to use the plugin. Future requestNotificationsPermission() async => false; + + @override + Future cancel(int id, {String? tag}) async { } } diff --git a/flutter_local_notifications/lib/src/web_real.dart b/flutter_local_notifications/lib/src/web_real.dart index 00c9818e6..da9e09ba1 100644 --- a/flutter_local_notifications/lib/src/web_real.dart +++ b/flutter_local_notifications/lib/src/web_real.dart @@ -45,16 +45,12 @@ class WebFlutterLocalNotificationsPlugin if (_registration == null) { return []; } - final JSArray notificationsArray = - await _registration!.getNotifications().toDart; final List result = []; final Set ids = {}; - for (final Notification jsNotification in notificationsArray.toDart) { - final dynamic data = jsonDecode(jsNotification.data.toString()); - if (data == null) { - continue; - } - final int? id = data['id']; + final List jsNotifs = + await _registration!.getDartNotifications(); + for (final Notification jsNotification in jsNotifs) { + final int? id = jsNotification.id; if (id == null) { continue; } @@ -64,4 +60,40 @@ class WebFlutterLocalNotificationsPlugin } return result; } + + @override + Future cancel(int id, {String? tag}) async { + if (_registration == null) { + return; + } + final List notifs = + await _registration!.getDartNotifications(); + for (final Notification notification in notifs) { + if (notification.id == id || (tag != null && tag == notification.tag)) { + notification.close(); + } + } + } + + @override + Future cancelAll() async { + if (_registration == null) { + return; + } + final List notifs = + await _registration!.getDartNotifications(); + for (final Notification notification in notifs) { + notification.close(); + } + } +} + +extension on Notification { + /// Gets the ID of the notification. + int? get id => jsonDecode(data.toString())?['id']; +} + +extension on ServiceWorkerRegistration { + Future> getDartNotifications() async => + (await getNotifications().toDart).toDart; } From 086041bee52c40f338fb698722941d73ee57dbf7 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Fri, 15 Nov 2024 03:11:28 -0500 Subject: [PATCH 11/40] Dart format --- .../lib/src/flutter_local_notifications_plugin.dart | 4 ++-- flutter_local_notifications/lib/src/web_mock.dart | 2 +- flutter_local_notifications/lib/src/web_real.dart | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index 83ab52b74..66168d12b 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -284,8 +284,8 @@ class FlutterLocalNotificationsPlugin { /// be canceled. `tag` has no effect on other platforms. Future cancel(int id, {String? tag}) async { if (kIsWeb) { - await resolvePlatformSpecificImplementation - () + await resolvePlatformSpecificImplementation< + WebFlutterLocalNotificationsPlugin>() ?.cancel(id, tag: tag); } else if (defaultTargetPlatform == TargetPlatform.android) { await resolvePlatformSpecificImplementation< diff --git a/flutter_local_notifications/lib/src/web_mock.dart b/flutter_local_notifications/lib/src/web_mock.dart index ca92ce443..e050b7dfe 100644 --- a/flutter_local_notifications/lib/src/web_mock.dart +++ b/flutter_local_notifications/lib/src/web_mock.dart @@ -10,5 +10,5 @@ class WebFlutterLocalNotificationsPlugin Future requestNotificationsPermission() async => false; @override - Future cancel(int id, {String? tag}) async { } + Future cancel(int id, {String? tag}) async {} } diff --git a/flutter_local_notifications/lib/src/web_real.dart b/flutter_local_notifications/lib/src/web_real.dart index da9e09ba1..f2e034494 100644 --- a/flutter_local_notifications/lib/src/web_real.dart +++ b/flutter_local_notifications/lib/src/web_real.dart @@ -48,7 +48,7 @@ class WebFlutterLocalNotificationsPlugin final List result = []; final Set ids = {}; final List jsNotifs = - await _registration!.getDartNotifications(); + await _registration!.getDartNotifications(); for (final Notification jsNotification in jsNotifs) { final int? id = jsNotification.id; if (id == null) { @@ -67,7 +67,7 @@ class WebFlutterLocalNotificationsPlugin return; } final List notifs = - await _registration!.getDartNotifications(); + await _registration!.getDartNotifications(); for (final Notification notification in notifs) { if (notification.id == id || (tag != null && tag == notification.tag)) { notification.close(); @@ -81,7 +81,7 @@ class WebFlutterLocalNotificationsPlugin return; } final List notifs = - await _registration!.getDartNotifications(); + await _registration!.getDartNotifications(); for (final Notification notification in notifs) { notification.close(); } @@ -95,5 +95,5 @@ extension on Notification { extension on ServiceWorkerRegistration { Future> getDartNotifications() async => - (await getNotifications().toDart).toDart; + (await getNotifications().toDart).toDart; } From 76656e10529943aa8690631d382ebedbda1d0785 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Sat, 16 Nov 2024 23:12:24 -0500 Subject: [PATCH 12/40] Added WebNotificationDetails --- analysis_options.yaml | 2 +- .../lib/src/notification_details.dart | 4 ++ .../src/platform_specifics/web/details.dart | 33 ++++++++++ .../src/platform_specifics/web/direction.dart | 9 +++ .../web/plugin.dart} | 60 +++++++++++++++++-- .../web/stub.dart} | 0 .../src/web_flutter_local_notifications.dart | 5 +- 7 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 flutter_local_notifications/lib/src/platform_specifics/web/details.dart create mode 100644 flutter_local_notifications/lib/src/platform_specifics/web/direction.dart rename flutter_local_notifications/lib/src/{web_real.dart => platform_specifics/web/plugin.dart} (55%) rename flutter_local_notifications/lib/src/{web_mock.dart => platform_specifics/web/stub.dart} (100%) diff --git a/analysis_options.yaml b/analysis_options.yaml index 343acd642..bfb209fe6 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -117,7 +117,7 @@ linter: - prefer_typing_uninitialized_variables - prefer_void_to_null - provide_deprecation_message - - public_member_api_docs + # - public_member_api_docs - recursive_getters - slash_for_doc_comments - sort_child_properties_last diff --git a/flutter_local_notifications/lib/src/notification_details.dart b/flutter_local_notifications/lib/src/notification_details.dart index 070b03ae1..b8e8e1ade 100644 --- a/flutter_local_notifications/lib/src/notification_details.dart +++ b/flutter_local_notifications/lib/src/notification_details.dart @@ -3,6 +3,7 @@ import 'package:flutter_local_notifications_windows/flutter_local_notifications_ import 'platform_specifics/android/notification_details.dart'; import 'platform_specifics/darwin/notification_details.dart'; +import 'platform_specifics/web/details.dart'; /// Contains notification details specific to each platform. class NotificationDetails { @@ -13,8 +14,11 @@ class NotificationDetails { this.macOS, this.linux, this.windows, + this.web, }); + final WebNotificationDetails? web; + /// Notification details for Android. final AndroidNotificationDetails? android; diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/details.dart b/flutter_local_notifications/lib/src/platform_specifics/web/details.dart new file mode 100644 index 000000000..c37493610 --- /dev/null +++ b/flutter_local_notifications/lib/src/platform_specifics/web/details.dart @@ -0,0 +1,33 @@ +import 'direction.dart'; + +export 'direction.dart'; + +class WebNotificationDetails { + const WebNotificationDetails({ + this.direction = WebNotificationDirection.auto, + this.badgeUrl, + this.body, + this.iconUrl, + this.lang, + this.requireInteraction = false, + this.isSilent = false, + this.tag, + this.imageUrl, + this.renotify = false, + this.timestamp, + this.vibrationPattern, + }); + + final WebNotificationDirection direction; + final Uri? badgeUrl; + final String? body; + final Uri? iconUrl; + final Uri? imageUrl; + final String? lang; + final bool requireInteraction; + final bool isSilent; + final String? tag; + final bool renotify; + final DateTime? timestamp; + final List? vibrationPattern; +} diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/direction.dart b/flutter_local_notifications/lib/src/platform_specifics/web/direction.dart new file mode 100644 index 000000000..514e6ab4d --- /dev/null +++ b/flutter_local_notifications/lib/src/platform_specifics/web/direction.dart @@ -0,0 +1,9 @@ +// https://developer.mozilla.org/en-US/docs/Web/API/Notification/dir +enum WebNotificationDirection { + auto('auto'), + leftToRight('ltr'), + rightToLeft('rtl'); + + const WebNotificationDirection(this.jsValue); + final String jsValue; +} diff --git a/flutter_local_notifications/lib/src/web_real.dart b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart similarity index 55% rename from flutter_local_notifications/lib/src/web_real.dart rename to flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart index f2e034494..7092cd9f2 100644 --- a/flutter_local_notifications/lib/src/web_real.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart @@ -1,8 +1,18 @@ import 'dart:convert'; import 'dart:js_interop'; +import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; import 'package:web/web.dart'; -import '../flutter_local_notifications.dart'; + +import 'details.dart'; + +extension on WebNotificationDetails { + JSArray? get vibrationPatternMs => vibrationPattern == null + ? null : [ + for (final Duration duration in vibrationPattern!) + duration.inMilliseconds.toJS, + ].toJS; +} /// Web implementation of the local notifications plugin. class WebFlutterLocalNotificationsPlugin @@ -17,11 +27,51 @@ class WebFlutterLocalNotificationsPlugin @override Future show(int id, String? title, String? body, - {String? payload}) async { + {String? payload, WebNotificationDetails? details}) async { + if (_registration == null) { + throw StateError( + 'FlutterLocalNotifications.show(): You must call initialize() before ' + 'calling this method', + ); + } else if (Notification.permission != 'granted') { + throw StateError( + 'FlutterLocalNotifications.show(): You must request notifications ' + 'permissions first', + ); + } else if (details?.isSilent == true && details?.vibrationPattern != null) { + throw ArgumentError( + 'WebNotificationDetails: Cannot specify both silent and a vibration ' + 'pattern', + ); + } else if (details?.renotify == true && details?.tag == null) { + throw ArgumentError( + 'WebNotificationDetails: If you specify renotify, you must also ' + 'specify a tag', + ); + } else if (_registration!.active == null) { + throw StateError( + 'FlutterLocalNotifications.show(): There is no active service worker. ' + 'Call initialize() first', + ); + } final Map data = {'id': id}; - final NotificationOptions options = - NotificationOptions(data: jsonEncode(data).toJS); - _registration?.showNotification(title ?? 'This is a notification', options); + final NotificationOptions options = NotificationOptions( + badge: details?.badgeUrl.toString() ?? '', + body: details?.body ?? '', + data: jsonEncode(data).toJS, + dir: details?.direction.jsValue ?? WebNotificationDirection.auto.jsValue, + icon: details?.iconUrl.toString() ?? '', + image: details?.imageUrl.toString() ?? '', + lang: details?.lang ?? '', + renotify: details?.renotify ?? false, + requireInteraction: details?.requireInteraction ?? false, + silent: details?.isSilent, + tag: details?.tag ?? '', + timestamp: (details?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, + vibrate: details?.vibrationPatternMs ?? [].toJS, + ); + await _registration + !.showNotification(title ?? 'This is a notification', options).toDart; } /// Initializes the plugin. diff --git a/flutter_local_notifications/lib/src/web_mock.dart b/flutter_local_notifications/lib/src/platform_specifics/web/stub.dart similarity index 100% rename from flutter_local_notifications/lib/src/web_mock.dart rename to flutter_local_notifications/lib/src/platform_specifics/web/stub.dart diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart index 0464535b6..6a636823f 100644 --- a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart @@ -1 +1,4 @@ -export 'web_mock.dart' if (dart.library.js_interop) 'web_real.dart'; +export 'platform_specifics/web/details.dart'; + +export 'platform_specifics/web/stub.dart' + if (dart.library.js_interop) 'platform_specifics/web/plugin.dart'; From 40729d962b0a2769c5eed7ec08ab4607963ea273 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Sat, 16 Nov 2024 23:13:52 -0500 Subject: [PATCH 13/40] Formatted --- .../src/platform_specifics/web/plugin.dart | 22 ++++++++++--------- .../src/web_flutter_local_notifications.dart | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart index 7092cd9f2..a1802fe11 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart @@ -6,14 +6,6 @@ import 'package:web/web.dart'; import 'details.dart'; -extension on WebNotificationDetails { - JSArray? get vibrationPatternMs => vibrationPattern == null - ? null : [ - for (final Duration duration in vibrationPattern!) - duration.inMilliseconds.toJS, - ].toJS; -} - /// Web implementation of the local notifications plugin. class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { @@ -70,8 +62,9 @@ class WebFlutterLocalNotificationsPlugin timestamp: (details?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, vibrate: details?.vibrationPatternMs ?? [].toJS, ); - await _registration - !.showNotification(title ?? 'This is a notification', options).toDart; + await _registration! + .showNotification(title ?? 'This is a notification', options) + .toDart; } /// Initializes the plugin. @@ -147,3 +140,12 @@ extension on ServiceWorkerRegistration { Future> getDartNotifications() async => (await getNotifications().toDart).toDart; } + +extension on WebNotificationDetails { + JSArray? get vibrationPatternMs => vibrationPattern == null + ? null + : [ + for (final Duration duration in vibrationPattern!) + duration.inMilliseconds.toJS, + ].toJS; +} diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart index 6a636823f..70eaf8ca7 100644 --- a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart @@ -1,4 +1,4 @@ export 'platform_specifics/web/details.dart'; export 'platform_specifics/web/stub.dart' - if (dart.library.js_interop) 'platform_specifics/web/plugin.dart'; + if (dart.library.js_interop) 'platform_specifics/web/plugin.dart'; From d117eb253fb49d2c07c5e24cc0a94428e358dba7 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Sat, 16 Nov 2024 23:22:27 -0500 Subject: [PATCH 14/40] Added WebNotificationAction --- .../src/platform_specifics/web/action.dart | 11 +++++ .../src/platform_specifics/web/details.dart | 4 ++ .../src/platform_specifics/web/plugin.dart | 45 ++++++++++++------- 3 files changed, 44 insertions(+), 16 deletions(-) create mode 100644 flutter_local_notifications/lib/src/platform_specifics/web/action.dart diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/action.dart b/flutter_local_notifications/lib/src/platform_specifics/web/action.dart new file mode 100644 index 000000000..f2dbba581 --- /dev/null +++ b/flutter_local_notifications/lib/src/platform_specifics/web/action.dart @@ -0,0 +1,11 @@ +class WebNotificationAction { + final String action; + final String title; + final Uri? icon; + + const WebNotificationAction({ + required this.action, + required this.title, + this.icon, + }); +} diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/details.dart b/flutter_local_notifications/lib/src/platform_specifics/web/details.dart index c37493610..365cc103d 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/web/details.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/web/details.dart @@ -1,9 +1,12 @@ +import 'action.dart'; import 'direction.dart'; +export 'action.dart'; export 'direction.dart'; class WebNotificationDetails { const WebNotificationDetails({ + this.actions = const [], this.direction = WebNotificationDirection.auto, this.badgeUrl, this.body, @@ -18,6 +21,7 @@ class WebNotificationDetails { this.vibrationPattern, }); + final List actions; final WebNotificationDirection direction; final Uri? badgeUrl; final String? body; diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart index a1802fe11..6e48ecd6f 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart @@ -46,24 +46,13 @@ class WebFlutterLocalNotificationsPlugin 'Call initialize() first', ); } - final Map data = {'id': id}; - final NotificationOptions options = NotificationOptions( - badge: details?.badgeUrl.toString() ?? '', - body: details?.body ?? '', - data: jsonEncode(data).toJS, - dir: details?.direction.jsValue ?? WebNotificationDirection.auto.jsValue, - icon: details?.iconUrl.toString() ?? '', - image: details?.imageUrl.toString() ?? '', - lang: details?.lang ?? '', - renotify: details?.renotify ?? false, - requireInteraction: details?.requireInteraction ?? false, - silent: details?.isSilent, - tag: details?.tag ?? '', - timestamp: (details?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, - vibrate: details?.vibrationPatternMs ?? [].toJS, + details ??= WebNotificationDetails( + actions: [ + WebNotificationAction(action: "action-1", title: "Action 1"), + ], ); await _registration! - .showNotification(title ?? 'This is a notification', options) + .showNotification(title ?? 'This is a notification', details.toJs(id)) .toDart; } @@ -149,3 +138,27 @@ extension on WebNotificationDetails { duration.inMilliseconds.toJS, ].toJS; } + +extension on WebNotificationDetails? { + NotificationOptions toJs(int id) => NotificationOptions( + actions: [ + for (final action in this?.actions ?? []) + NotificationAction(action: action.action, + title: action.title, + icon: action.icon?.toString() ?? ''), + ].toJS, + badge: this?.badgeUrl.toString() ?? '', + body: this?.body ?? '', + data: jsonEncode({'id': id}).toJS, + dir: this?.direction.jsValue ?? WebNotificationDirection.auto.jsValue, + icon: this?.iconUrl.toString() ?? '', + image: this?.imageUrl.toString() ?? '', + lang: this?.lang ?? '', + renotify: this?.renotify ?? false, + requireInteraction: this?.requireInteraction ?? false, + silent: this?.isSilent, + tag: this?.tag ?? '', + timestamp: (this?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, + vibrate: this?.vibrationPatternMs ?? [].toJS, + ); +} From fad569323f5e9c2eb20e4c96bce25eb4e6bac877 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Sun, 17 Nov 2024 00:09:45 -0500 Subject: [PATCH 15/40] Added text action and removed web examples that don't fit --- .../example/lib/main.dart | 105 +++++++++++------- .../flutter_local_notifications_plugin.dart | 8 +- .../src/platform_specifics/web/action.dart | 18 ++- .../src/platform_specifics/web/plugin.dart | 32 ++++-- .../lib/src/platform_specifics/web/stub.dart | 6 + 5 files changed, 112 insertions(+), 57 deletions(-) diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index f2f133974..720067696 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -302,10 +302,6 @@ class _HomePageState extends State { @override Widget build(BuildContext context) => Scaffold( - floatingActionButton: FloatingActionButton( - onPressed: () => - flutterLocalNotificationsPlugin.show(0, null, null, null), - ), appBar: AppBar( title: const Text('Plugin example app'), ), @@ -366,13 +362,14 @@ class _HomePageState extends State { await _showNotificationWithNoBody(); }, ), - PaddedElevatedButton( - buttonText: 'Show notification with custom sound', - onPressed: () async { - await _showNotificationCustomSound(); - }, - ), - if (kIsWeb || !Platform.isLinux) ...[ + if (Platform.isAndroid) + PaddedElevatedButton( + buttonText: 'Show notification with custom sound', + onPressed: () async { + await _showNotificationCustomSound(); + }, + ), + if (!kIsWeb && !Platform.isLinux) ...[ PaddedElevatedButton( buttonText: 'Schedule notification to appear in 5 seconds ' @@ -395,26 +392,28 @@ class _HomePageState extends State { await _checkPendingNotificationRequests(); }, ), + ], + if (!Platform.isLinux) PaddedElevatedButton( buttonText: 'Get active notifications', onPressed: () async { await _getActiveNotifications(); }, ), - ], PaddedElevatedButton( buttonText: 'Show notification from silent channel', onPressed: () async { await _showNotificationWithNoSound(); }, ), - PaddedElevatedButton( - buttonText: - 'Show silent notification from channel with sound', - onPressed: () async { - await _showNotificationSilently(); - }, - ), + if (!kIsWeb) + PaddedElevatedButton( + buttonText: + 'Show silent notification from channel with sound', + onPressed: () async { + await _showNotificationSilently(); + }, + ), PaddedElevatedButton( buttonText: 'Cancel latest notification', onPressed: () async { @@ -427,7 +426,8 @@ class _HomePageState extends State { await _cancelAllNotifications(); }, ), - if (!Platform.isWindows) ...repeating.examples(context), + if (!Platform.isWindows && !kIsWeb) + ...repeating.examples(context), const Divider(), const Text( 'Notifications with actions', @@ -454,7 +454,7 @@ class _HomePageState extends State { await _showNotificationWithTextAction(); }, ), - if (!Platform.isLinux) + if (!Platform.isLinux && !kIsWeb) PaddedElevatedButton( buttonText: 'Show notification with text choice', onPressed: () async { @@ -1062,24 +1062,35 @@ class _HomePageState extends State { ], ); - final WindowsNotificationDetails windowsNotificationsDetails = - WindowsNotificationDetails( - subtitle: 'Click the three dots for another button', - actions: [ - const WindowsAction( - content: 'Text', - arguments: 'text', - ), - WindowsAction( - content: 'Image', - arguments: 'image', - image: File('icons/coworker.png').absolute, - ), - const WindowsAction( - content: 'Context', - arguments: 'context', - placement: WindowsActionPlacement.contextMenu, - ), + final WindowsNotificationDetails? windowsNotificationsDetails = kIsWeb + ? null + : WindowsNotificationDetails( + subtitle: 'Click the three dots for another button', + actions: [ + const WindowsAction( + content: 'Text', + arguments: 'text', + ), + WindowsAction( + content: 'Image', + arguments: 'image', + image: File('icons/coworker.png').absolute, + ), + const WindowsAction( + content: 'Context', + arguments: 'context', + placement: WindowsActionPlacement.contextMenu, + ), + ], + ); + + final WebNotificationDetails webDetails = WebNotificationDetails( + actions: [ + const WebNotificationAction(action: 'Text', title: 'text'), + WebNotificationAction( + action: 'Image', + title: 'image', + icon: Uri.parse('https://picsum.photos/200')), ], ); @@ -1089,6 +1100,7 @@ class _HomePageState extends State { macOS: macOSNotificationDetails, linux: linuxNotificationDetails, windows: windowsNotificationsDetails, + web: webDetails, ); await flutterLocalNotificationsPlugin.show( id++, 'plain title', 'plain body', notificationDetails, @@ -1135,11 +1147,21 @@ class _HomePageState extends State { ], ); + const WebNotificationDetails webDetails = WebNotificationDetails( + actions: [ + WebNotificationAction( + action: 'text', + title: 'Send a reply', + type: WebNotificationActionType.textInput), + ], + ); + const NotificationDetails notificationDetails = NotificationDetails( android: androidNotificationDetails, iOS: darwinNotificationDetails, macOS: darwinNotificationDetails, windows: windowsNotificationDetails, + web: webDetails, ); await flutterLocalNotificationsPlugin.show(id++, 'Text Input Notification', @@ -1428,11 +1450,14 @@ class _HomePageState extends State { ); final WindowsNotificationDetails windowsDetails = WindowsNotificationDetails(audio: WindowsNotificationAudio.silent()); + const WebNotificationDetails webDetails = + WebNotificationDetails(isSilent: true); final NotificationDetails notificationDetails = NotificationDetails( windows: windowsDetails, android: androidNotificationDetails, iOS: darwinNotificationDetails, - macOS: darwinNotificationDetails); + macOS: darwinNotificationDetails, + web: webDetails); await flutterLocalNotificationsPlugin.show( id++, 'silent title', 'silent body', notificationDetails); } diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index 66168d12b..7b034ab4d 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -239,7 +239,13 @@ class FlutterLocalNotificationsPlugin { if (kIsWeb) { await resolvePlatformSpecificImplementation< WebFlutterLocalNotificationsPlugin>() - ?.show(id, title, body, payload: payload); + ?.show( + id, + title, + body, + payload: payload, + details: notificationDetails?.web, + ); } if (defaultTargetPlatform == TargetPlatform.android) { await resolvePlatformSpecificImplementation< diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/action.dart b/flutter_local_notifications/lib/src/platform_specifics/web/action.dart index f2dbba581..57d738b51 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/web/action.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/web/action.dart @@ -1,11 +1,21 @@ -class WebNotificationAction { - final String action; - final String title; - final Uri? icon; +enum WebNotificationActionType { + button('button'), + textInput('text'); + + const WebNotificationActionType(this.jsValue); + final String jsValue; +} +class WebNotificationAction { const WebNotificationAction({ required this.action, required this.title, this.icon, + this.type = WebNotificationActionType.button, }); + + final WebNotificationActionType type; + final String action; + final String title; + final Uri? icon; } diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart index 6e48ecd6f..6f5ff8b0d 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart @@ -46,11 +46,7 @@ class WebFlutterLocalNotificationsPlugin 'Call initialize() first', ); } - details ??= WebNotificationDetails( - actions: [ - WebNotificationAction(action: "action-1", title: "Action 1"), - ], - ); + await _registration! .showNotification(title ?? 'This is a notification', details.toJs(id)) .toDart; @@ -140,12 +136,18 @@ extension on WebNotificationDetails { } extension on WebNotificationDetails? { - NotificationOptions toJs(int id) => NotificationOptions( - actions: [ - for (final action in this?.actions ?? []) - NotificationAction(action: action.action, - title: action.title, - icon: action.icon?.toString() ?? ''), + NotificationOptions toJs(int id) { + final NotificationOptions options = NotificationOptions( + actions: [ + for (final WebNotificationAction action + in this?.actions ?? []) + // THis workaround is here because not all browsers support this + { + 'action': action.action, + 'title': action.title, + 'icon': action.icon?.toString(), + 'type': action.type.jsValue, + }.jsify() as NotificationAction, ].toJS, badge: this?.badgeUrl.toString() ?? '', body: this?.body ?? '', @@ -159,6 +161,12 @@ extension on WebNotificationDetails? { silent: this?.isSilent, tag: this?.tag ?? '', timestamp: (this?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, - vibrate: this?.vibrationPatternMs ?? [].toJS, ); + + final JSArray? vibration = this?.vibrationPatternMs; + if (vibration != null) { + options.vibrate = vibration; + } + return options; + } } diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/stub.dart b/flutter_local_notifications/lib/src/platform_specifics/web/stub.dart index e050b7dfe..1a4dbf310 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/web/stub.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/web/stub.dart @@ -1,5 +1,7 @@ import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; +import 'details.dart'; + /// A stub implementation of the web plugin, for non-web platforms. class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { @@ -11,4 +13,8 @@ class WebFlutterLocalNotificationsPlugin @override Future cancel(int id, {String? tag}) async {} + + @override + Future show(int id, String? title, String? body, + {String? payload, WebNotificationDetails? details}) async {} } From eeabab01a6c770ccef32dc9a65d3f43595997f19 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Sun, 17 Nov 2024 00:14:50 -0500 Subject: [PATCH 16/40] Implemented pending and periodically to no-op or throw --- .../src/platform_specifics/web/plugin.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart index 6f5ff8b0d..80673802e 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart @@ -114,6 +114,25 @@ class WebFlutterLocalNotificationsPlugin notification.close(); } } + + @override + Future> + pendingNotificationRequests() async => []; + + @override + Future periodicallyShow( + int id, String? title, String? body, RepeatInterval repeatInterval) { + throw UnsupportedError('periodicallyShow() is not supported on the web'); + } + + @override + Future periodicallyShowWithDuration( + int id, String? title, String? body, Duration repeatDurationInterval) { + throw UnsupportedError( + 'periodicallyShowWithDuration() is not supported ' + 'on the web', + ); + } } extension on Notification { From 87b91e587afc90eb7dc1a0707030a697cccd63d8 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 13:07:57 -0400 Subject: [PATCH 17/40] Web Package --- .../lib/flutter_local_notifications.dart | 2 +- .../flutter_local_notifications_plugin.dart | 2 +- .../lib/src/notification_details.dart | 2 +- .../src/web_flutter_local_notifications.dart | 4 - flutter_local_notifications/pubspec.yaml | 6 +- flutter_local_notifications_web/.gitignore | 33 ++++++++ flutter_local_notifications_web/.metadata | 30 +++++++ flutter_local_notifications_web/CHANGELOG.md | 3 + flutter_local_notifications_web/LICENSE | 1 + flutter_local_notifications_web/README.md | 18 +++++ .../lib/flutter_local_notifications_web.dart | 4 + .../lib/src}/action.dart | 0 .../lib/src}/details.dart | 0 .../lib/src}/direction.dart | 0 .../lib/src}/plugin.dart | 79 +++++-------------- .../lib/src}/stub.dart | 0 .../lib/src/utils.dart | 61 ++++++++++++++ .../notifs/flutter_service_worker.js | 12 +++ .../notifs/index.html | 31 ++++++++ .../notifs/temp.js | 12 +++ flutter_local_notifications_web/pubspec.yaml | 30 +++++++ .../web/notifications_service_worker.js | 9 +++ 22 files changed, 270 insertions(+), 69 deletions(-) delete mode 100644 flutter_local_notifications/lib/src/web_flutter_local_notifications.dart create mode 100644 flutter_local_notifications_web/.gitignore create mode 100644 flutter_local_notifications_web/.metadata create mode 100644 flutter_local_notifications_web/CHANGELOG.md create mode 100644 flutter_local_notifications_web/LICENSE create mode 100644 flutter_local_notifications_web/README.md create mode 100644 flutter_local_notifications_web/lib/flutter_local_notifications_web.dart rename {flutter_local_notifications/lib/src/platform_specifics/web => flutter_local_notifications_web/lib/src}/action.dart (100%) rename {flutter_local_notifications/lib/src/platform_specifics/web => flutter_local_notifications_web/lib/src}/details.dart (100%) rename {flutter_local_notifications/lib/src/platform_specifics/web => flutter_local_notifications_web/lib/src}/direction.dart (100%) rename {flutter_local_notifications/lib/src/platform_specifics/web => flutter_local_notifications_web/lib/src}/plugin.dart (66%) rename {flutter_local_notifications/lib/src/platform_specifics/web => flutter_local_notifications_web/lib/src}/stub.dart (100%) create mode 100644 flutter_local_notifications_web/lib/src/utils.dart create mode 100644 flutter_local_notifications_web/notifs/flutter_service_worker.js create mode 100644 flutter_local_notifications_web/notifs/index.html create mode 100644 flutter_local_notifications_web/notifs/temp.js create mode 100644 flutter_local_notifications_web/pubspec.yaml create mode 100644 flutter_local_notifications_web/web/notifications_service_worker.js diff --git a/flutter_local_notifications/lib/flutter_local_notifications.dart b/flutter_local_notifications/lib/flutter_local_notifications.dart index 62505141b..b6eda92c2 100644 --- a/flutter_local_notifications/lib/flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/flutter_local_notifications.dart @@ -2,6 +2,7 @@ export 'package:flutter_local_notifications_linux/flutter_local_notifications_li // Exports what's defined in platform interface but hide helper methods export 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart' hide validateId, validateRepeatDurationInterval; +export 'package:flutter_local_notifications_web/flutter_local_notifications_web.dart'; export 'package:flutter_local_notifications_windows/flutter_local_notifications_windows.dart'; export 'src/flutter_local_notifications_plugin.dart'; @@ -40,4 +41,3 @@ export 'src/platform_specifics/darwin/notification_enabled_options.dart'; export 'src/typedefs.dart'; export 'src/types.dart'; -export 'src/web_flutter_local_notifications.dart'; diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index 995efc6ac..def7d78a2 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter_local_notifications_linux/flutter_local_notifications_linux.dart'; import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; +import 'package:flutter_local_notifications_web/flutter_local_notifications_web.dart'; import 'package:flutter_local_notifications_windows/flutter_local_notifications_windows.dart'; import 'package:timezone/timezone.dart'; @@ -11,7 +12,6 @@ import 'notification_details.dart'; import 'platform_flutter_local_notifications.dart'; import 'platform_specifics/android/schedule_mode.dart'; import 'types.dart'; -import 'web_flutter_local_notifications.dart'; /// Provides cross-platform functionality for displaying local notifications. /// diff --git a/flutter_local_notifications/lib/src/notification_details.dart b/flutter_local_notifications/lib/src/notification_details.dart index b8e8e1ade..b04b6854b 100644 --- a/flutter_local_notifications/lib/src/notification_details.dart +++ b/flutter_local_notifications/lib/src/notification_details.dart @@ -1,9 +1,9 @@ import 'package:flutter_local_notifications_linux/flutter_local_notifications_linux.dart'; +import 'package:flutter_local_notifications_web/flutter_local_notifications_web.dart'; import 'package:flutter_local_notifications_windows/flutter_local_notifications_windows.dart'; import 'platform_specifics/android/notification_details.dart'; import 'platform_specifics/darwin/notification_details.dart'; -import 'platform_specifics/web/details.dart'; /// Contains notification details specific to each platform. class NotificationDetails { diff --git a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart deleted file mode 100644 index 70eaf8ca7..000000000 --- a/flutter_local_notifications/lib/src/web_flutter_local_notifications.dart +++ /dev/null @@ -1,4 +0,0 @@ -export 'platform_specifics/web/details.dart'; - -export 'platform_specifics/web/stub.dart' - if (dart.library.js_interop) 'platform_specifics/web/plugin.dart'; diff --git a/flutter_local_notifications/pubspec.yaml b/flutter_local_notifications/pubspec.yaml index d877aa832..7c7d8fe68 100644 --- a/flutter_local_notifications/pubspec.yaml +++ b/flutter_local_notifications/pubspec.yaml @@ -12,6 +12,9 @@ dependencies: sdk: flutter flutter_local_notifications_linux: ^6.0.0 flutter_local_notifications_windows: ^1.0.3 + # flutter_local_notifications_web: ^1.0.0 + flutter_local_notifications_web: + path: ../flutter_local_notifications_web flutter_local_notifications_platform_interface: ^9.1.0 timezone: ^0.10.0 universal_platform: ^1.1.0 @@ -42,8 +45,7 @@ flutter: windows: default_package: flutter_local_notifications_windows web: - pluginClass: WebFlutterLocalNotificationsPlugin - fileName: "src/web_flutter_local_notifications.dart" + default_package: flutter_local_notifications_web environment: sdk: ^3.4.0 diff --git a/flutter_local_notifications_web/.gitignore b/flutter_local_notifications_web/.gitignore new file mode 100644 index 000000000..e7d347d9d --- /dev/null +++ b/flutter_local_notifications_web/.gitignore @@ -0,0 +1,33 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +build/ diff --git a/flutter_local_notifications_web/.metadata b/flutter_local_notifications_web/.metadata new file mode 100644 index 000000000..a374771a5 --- /dev/null +++ b/flutter_local_notifications_web/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "edada7c56edf4a183c1735310e123c7f923584f1" + channel: "stable" + +project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: edada7c56edf4a183c1735310e123c7f923584f1 + base_revision: edada7c56edf4a183c1735310e123c7f923584f1 + - platform: web + create_revision: edada7c56edf4a183c1735310e123c7f923584f1 + base_revision: edada7c56edf4a183c1735310e123c7f923584f1 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/flutter_local_notifications_web/CHANGELOG.md b/flutter_local_notifications_web/CHANGELOG.md new file mode 100644 index 000000000..41cc7d819 --- /dev/null +++ b/flutter_local_notifications_web/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/flutter_local_notifications_web/LICENSE b/flutter_local_notifications_web/LICENSE new file mode 100644 index 000000000..ba75c69f7 --- /dev/null +++ b/flutter_local_notifications_web/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/flutter_local_notifications_web/README.md b/flutter_local_notifications_web/README.md new file mode 100644 index 000000000..1fc2dae8a --- /dev/null +++ b/flutter_local_notifications_web/README.md @@ -0,0 +1,18 @@ +# flutter_local_notifications_web + +A new Flutter plugin project. + +## Getting Started + +This project is a starting point for a Flutter +[plug-in package](https://flutter.dev/to/develop-plugins), +a specialized package that includes platform-specific implementation code for +Android and/or iOS. + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev), which offers tutorials, +samples, guidance on mobile development, and a full API reference. + +The plugin project was generated without specifying the `--platforms` flag, no platforms are currently supported. +To add platforms, run `flutter create -t plugin --platforms .` in this directory. +You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/to/pubspec-plugin-platforms. diff --git a/flutter_local_notifications_web/lib/flutter_local_notifications_web.dart b/flutter_local_notifications_web/lib/flutter_local_notifications_web.dart new file mode 100644 index 000000000..4fb6c30be --- /dev/null +++ b/flutter_local_notifications_web/lib/flutter_local_notifications_web.dart @@ -0,0 +1,4 @@ +export 'src/details.dart'; + +export 'src/stub.dart' + if (dart.library.js_interop) 'src/plugin.dart'; diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/action.dart b/flutter_local_notifications_web/lib/src/action.dart similarity index 100% rename from flutter_local_notifications/lib/src/platform_specifics/web/action.dart rename to flutter_local_notifications_web/lib/src/action.dart diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/details.dart b/flutter_local_notifications_web/lib/src/details.dart similarity index 100% rename from flutter_local_notifications/lib/src/platform_specifics/web/details.dart rename to flutter_local_notifications_web/lib/src/details.dart diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/direction.dart b/flutter_local_notifications_web/lib/src/direction.dart similarity index 100% rename from flutter_local_notifications/lib/src/platform_specifics/web/direction.dart rename to flutter_local_notifications_web/lib/src/direction.dart diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart b/flutter_local_notifications_web/lib/src/plugin.dart similarity index 66% rename from flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart rename to flutter_local_notifications_web/lib/src/plugin.dart index 80673802e..1dbe66ae7 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/web/plugin.dart +++ b/flutter_local_notifications_web/lib/src/plugin.dart @@ -1,10 +1,10 @@ -import 'dart:convert'; import 'dart:js_interop'; import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; import 'package:web/web.dart'; import 'details.dart'; +import 'utils.dart'; /// Web implementation of the local notifications plugin. class WebFlutterLocalNotificationsPlugin @@ -48,15 +48,29 @@ class WebFlutterLocalNotificationsPlugin } await _registration! - .showNotification(title ?? 'This is a notification', details.toJs(id)) + .showNotification( + title ?? 'This is a notification', + details.toJs(id), + ) .toDart; } /// Initializes the plugin. Future initialize() async { - _registration = - await window.navigator.serviceWorker.getRegistration().toDart; - return _registration != null; + // Get the service worker registration + final ServiceWorkerContainer serviceWorker = window.navigator.serviceWorker; + _registration = await serviceWorker.getRegistration().toDart; + if (_registration == null) { + return false; + } + + // Replace the default Flutter service worker with our own. + // This isn't supported at build time yet and so must be done at runtime. + // See: https://github.com/flutter/flutter/issues/145828 + await _registration!.unregister().toDart; + await serviceWorker.register('/notifications_service_worker.js'.toJS).toDart; + + return true; } /// Requests notification permission from the browser. @@ -134,58 +148,3 @@ class WebFlutterLocalNotificationsPlugin ); } } - -extension on Notification { - /// Gets the ID of the notification. - int? get id => jsonDecode(data.toString())?['id']; -} - -extension on ServiceWorkerRegistration { - Future> getDartNotifications() async => - (await getNotifications().toDart).toDart; -} - -extension on WebNotificationDetails { - JSArray? get vibrationPatternMs => vibrationPattern == null - ? null - : [ - for (final Duration duration in vibrationPattern!) - duration.inMilliseconds.toJS, - ].toJS; -} - -extension on WebNotificationDetails? { - NotificationOptions toJs(int id) { - final NotificationOptions options = NotificationOptions( - actions: [ - for (final WebNotificationAction action - in this?.actions ?? []) - // THis workaround is here because not all browsers support this - { - 'action': action.action, - 'title': action.title, - 'icon': action.icon?.toString(), - 'type': action.type.jsValue, - }.jsify() as NotificationAction, - ].toJS, - badge: this?.badgeUrl.toString() ?? '', - body: this?.body ?? '', - data: jsonEncode({'id': id}).toJS, - dir: this?.direction.jsValue ?? WebNotificationDirection.auto.jsValue, - icon: this?.iconUrl.toString() ?? '', - image: this?.imageUrl.toString() ?? '', - lang: this?.lang ?? '', - renotify: this?.renotify ?? false, - requireInteraction: this?.requireInteraction ?? false, - silent: this?.isSilent, - tag: this?.tag ?? '', - timestamp: (this?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, - ); - - final JSArray? vibration = this?.vibrationPatternMs; - if (vibration != null) { - options.vibrate = vibration; - } - return options; - } -} diff --git a/flutter_local_notifications/lib/src/platform_specifics/web/stub.dart b/flutter_local_notifications_web/lib/src/stub.dart similarity index 100% rename from flutter_local_notifications/lib/src/platform_specifics/web/stub.dart rename to flutter_local_notifications_web/lib/src/stub.dart diff --git a/flutter_local_notifications_web/lib/src/utils.dart b/flutter_local_notifications_web/lib/src/utils.dart new file mode 100644 index 000000000..dc31655dd --- /dev/null +++ b/flutter_local_notifications_web/lib/src/utils.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; +import 'dart:js_interop'; + +import 'package:web/web.dart'; + +import 'details.dart'; + +extension JSNotificationUtils on Notification { + /// Gets the ID of the notification. + int? get id => jsonDecode(data.toString())?['id']; +} + +extension ServiceWorkerUtils on ServiceWorkerRegistration { + Future> getDartNotifications() async => + (await getNotifications().toDart).toDart; +} + +extension WebNotificationDetailsUtils on WebNotificationDetails { + JSArray? get vibrationPatternMs => vibrationPattern == null + ? null + : [ + for (final Duration duration in vibrationPattern!) + duration.inMilliseconds.toJS, + ].toJS; +} + +extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { + NotificationOptions toJs(int id) { + final NotificationOptions options = NotificationOptions( + actions: [ + for (final WebNotificationAction action + in this?.actions ?? []) + // THis workaround is here because not all browsers support this + { + 'action': action.action, + 'title': action.title, + 'icon': action.icon?.toString(), + 'type': action.type.jsValue, + }.jsify() as NotificationAction, + ].toJS, + badge: this?.badgeUrl.toString() ?? '', + body: this?.body ?? '', + data: jsonEncode({'id': id}).toJS, + dir: this?.direction.jsValue ?? WebNotificationDirection.auto.jsValue, + icon: this?.iconUrl.toString() ?? '', + image: this?.imageUrl.toString() ?? '', + lang: this?.lang ?? '', + renotify: this?.renotify ?? false, + requireInteraction: this?.requireInteraction ?? false, + silent: this?.isSilent, + tag: this?.tag ?? '', + timestamp: (this?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, + ); + + final JSArray? vibration = this?.vibrationPatternMs; + if (vibration != null) { + options.vibrate = vibration; + } + return options; + } +} diff --git a/flutter_local_notifications_web/notifs/flutter_service_worker.js b/flutter_local_notifications_web/notifs/flutter_service_worker.js new file mode 100644 index 000000000..ca1df9de6 --- /dev/null +++ b/flutter_local_notifications_web/notifs/flutter_service_worker.js @@ -0,0 +1,12 @@ +'use strict'; +const MANIFEST = 'flutter-app-manifest'; +const TEMP = 'flutter-temp-cache'; +const CACHE_NAME = 'flutter-app-cache'; + +function _handleNotif(event) { + console.log(`Clicked: ${event}`); + clients.openWindow("/about"); + +} + +self.addEventListener("notificationclick", _handleNotif); diff --git a/flutter_local_notifications_web/notifs/index.html b/flutter_local_notifications_web/notifs/index.html new file mode 100644 index 000000000..6d0cafe55 --- /dev/null +++ b/flutter_local_notifications_web/notifs/index.html @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/flutter_local_notifications_web/notifs/temp.js b/flutter_local_notifications_web/notifs/temp.js new file mode 100644 index 000000000..ca1df9de6 --- /dev/null +++ b/flutter_local_notifications_web/notifs/temp.js @@ -0,0 +1,12 @@ +'use strict'; +const MANIFEST = 'flutter-app-manifest'; +const TEMP = 'flutter-temp-cache'; +const CACHE_NAME = 'flutter-app-cache'; + +function _handleNotif(event) { + console.log(`Clicked: ${event}`); + clients.openWindow("/about"); + +} + +self.addEventListener("notificationclick", _handleNotif); diff --git a/flutter_local_notifications_web/pubspec.yaml b/flutter_local_notifications_web/pubspec.yaml new file mode 100644 index 000000000..86cce5d7b --- /dev/null +++ b/flutter_local_notifications_web/pubspec.yaml @@ -0,0 +1,30 @@ +name: flutter_local_notifications_web +description: "A new Flutter plugin project." +version: 1.0.0 +homepage: + +environment: + sdk: ^3.4.0 + flutter: ">=3.22.0" + +dependencies: + flutter: + sdk: flutter + flutter_local_notifications_platform_interface: ^9.0.0 + web: ^1.1.1 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^5.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + plugin: + platforms: + web: + pluginClass: WebFlutterLocalNotificationsPlugin + fileName: "flutter_local_notifications_web.dart" diff --git a/flutter_local_notifications_web/web/notifications_service_worker.js b/flutter_local_notifications_web/web/notifications_service_worker.js new file mode 100644 index 000000000..926dd0d7d --- /dev/null +++ b/flutter_local_notifications_web/web/notifications_service_worker.js @@ -0,0 +1,9 @@ +'use strict'; + +function _handleNotif(event) { + console.log(`Clicked: ${event}`); + clients.openWindow("/about"); + +} + +self.addEventListener("notificationclick", _handleNotif); From f48aa5b0df1510039ff33e17807138fe4c0713ae Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 17:24:01 -0400 Subject: [PATCH 18/40] Added foreground callbacks --- .../example/.gitignore | 5 +- .../example/lib/main.dart | 72 ++++++++----------- .../flutter_local_notifications_plugin.dart | 4 +- flutter_local_notifications_web/README.md | 4 ++ .../lib/src/handler.dart | 31 ++++++++ .../lib/src/plugin.dart | 36 +++++++--- .../lib/src/stub.dart | 4 +- .../lib/src/utils.dart | 44 ++++++++---- .../notifs/flutter_service_worker.js | 24 +++++-- .../notifs/index.html | 18 ++--- .../notifs/temp.js | 12 ---- flutter_local_notifications_web/pubspec.yaml | 3 + .../web/notifications_service_worker.js | 21 ++++-- 13 files changed, 176 insertions(+), 102 deletions(-) create mode 100644 flutter_local_notifications_web/lib/src/handler.dart delete mode 100644 flutter_local_notifications_web/notifs/temp.js diff --git a/flutter_local_notifications/example/.gitignore b/flutter_local_notifications/example/.gitignore index d16b8eba3..a981f586a 100644 --- a/flutter_local_notifications/example/.gitignore +++ b/flutter_local_notifications/example/.gitignore @@ -30,8 +30,5 @@ .pub/ /build/ -# Web related -lib/generated_plugin_registrant.dart - # Exceptions to above rules. -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages \ No newline at end of file +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index 6491daed5..b793f3c83 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -50,8 +50,6 @@ class ReceivedNotification { final Map? data; } -String? selectedNotificationPayload; - /// A notification action which triggers a url launch event const String urlLaunchActionId = 'id_1'; @@ -171,9 +169,9 @@ Future main() async { ? null : await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails(); String initialRoute = HomePage.routeName; + NotificationResponse? initialNotification; if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) { - selectedNotificationPayload = - notificationAppLaunchDetails!.notificationResponse?.payload; + initialNotification = notificationAppLaunchDetails!.notificationResponse; initialRoute = SecondPage.routeName; } @@ -182,7 +180,7 @@ Future main() async { initialRoute: initialRoute, routes: { HomePage.routeName: (_) => HomePage(notificationAppLaunchDetails), - SecondPage.routeName: (_) => SecondPage(selectedNotificationPayload) + SecondPage.routeName: (_) => SecondPage.withResponse(initialNotification) }, ), ); @@ -315,8 +313,7 @@ class _HomePageState extends State { selectNotificationStream.stream .listen((NotificationResponse? response) async { await Navigator.of(context).push(MaterialPageRoute( - builder: (BuildContext context) => - SecondPage(response?.payload, data: response?.data), + builder: (BuildContext context) => SecondPage.withResponse(response), )); }); } @@ -3090,53 +3087,44 @@ Future getLinuxCapabilities() => .getCapabilities(); class SecondPage extends StatefulWidget { - const SecondPage( - this.payload, { - this.data, - Key? key, - }) : super(key: key); + const SecondPage.withResponse( + this.response, + {Key? key} + ) : super(key: key); static const String routeName = '/secondPage'; - final String? payload; - final Map? data; + final NotificationResponse? response; @override State createState() => SecondPageState(); } class SecondPageState extends State { - String? _payload; - Map? _data; - - @override - void initState() { - super.initState(); - _payload = widget.payload; - _data = widget.data; - } - @override Widget build(BuildContext context) => Scaffold( - appBar: AppBar( - title: const Text('Second Screen'), - ), - body: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text('payload ${_payload ?? ''}'), - Text('data ${_data ?? ''}'), - ElevatedButton( - onPressed: () { - Navigator.pop(context); - }, - child: const Text('Go back!'), - ), - ], + appBar: AppBar( + title: const Text('Second Screen'), + ), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Notification ID: ${widget.response?.id}'), + Text('Payload: ${widget.response?.payload}'), + Text('Action ID: ${widget.response?.actionId}'), + Text('Input: ${widget.response?.input}'), + Text('Data (Windows only): ${widget.response?.data}'), + ElevatedButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text('Go back!'), ), - ), - ); + ], + ), + ), + ); } class _InfoValueString extends StatelessWidget { diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index def7d78a2..767fa0c55 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -116,7 +116,9 @@ class FlutterLocalNotificationsPlugin { if (kIsWeb) { return resolvePlatformSpecificImplementation< WebFlutterLocalNotificationsPlugin>() - ?.initialize(); + ?.initialize( + onNotificationReceived: onDidReceiveNotificationResponse, + ); } if (defaultTargetPlatform == TargetPlatform.android) { diff --git a/flutter_local_notifications_web/README.md b/flutter_local_notifications_web/README.md index 1fc2dae8a..e042445ca 100644 --- a/flutter_local_notifications_web/README.md +++ b/flutter_local_notifications_web/README.md @@ -2,6 +2,10 @@ A new Flutter plugin project. +## Notes + +Only works with `-d web-server` + ## Getting Started This project is a starting point for a Flutter diff --git a/flutter_local_notifications_web/lib/src/handler.dart b/flutter_local_notifications_web/lib/src/handler.dart new file mode 100644 index 000000000..e39c0b36c --- /dev/null +++ b/flutter_local_notifications_web/lib/src/handler.dart @@ -0,0 +1,31 @@ +@JS() +library; + +import 'dart:js_interop'; + +import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; + +extension StringUtils on String { + String? get nullIfEmpty => isEmpty ? null : this; +} + +extension type JSNotificationData(JSObject _) implements JSObject { + external String action; + external String id; + external String? payload; + external String? reply; + + NotificationResponse get response { + final NotificationResponseType type = action.isEmpty + ? NotificationResponseType.selectedNotification + : NotificationResponseType.selectedNotificationAction; + + return NotificationResponse( + id: int.parse(id), + input: reply?.nullIfEmpty, + payload: payload?.nullIfEmpty, + actionId: action.nullIfEmpty, + notificationResponseType: type, + ); + } +} diff --git a/flutter_local_notifications_web/lib/src/plugin.dart b/flutter_local_notifications_web/lib/src/plugin.dart index 1dbe66ae7..f2a2f2eb7 100644 --- a/flutter_local_notifications_web/lib/src/plugin.dart +++ b/flutter_local_notifications_web/lib/src/plugin.dart @@ -4,17 +4,29 @@ import 'package:flutter_local_notifications_platform_interface/flutter_local_not import 'package:web/web.dart'; import 'details.dart'; +import 'handler.dart'; import 'utils.dart'; +void onNotificationClicked(MessageEvent event) { + final JSNotificationData data = event.data as JSNotificationData; + final NotificationResponse response = data.response; + WebFlutterLocalNotificationsPlugin.instance + ?._userCallback?.call(response); +} + /// Web implementation of the local notifications plugin. class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { + /// Registers the web plugin with the platform interface. static void registerWith(_) { FlutterLocalNotificationsPlatform.instance = WebFlutterLocalNotificationsPlugin(); } + static WebFlutterLocalNotificationsPlugin? instance; + + DidReceiveNotificationResponseCallback? _userCallback; ServiceWorkerRegistration? _registration; @override @@ -50,25 +62,29 @@ class WebFlutterLocalNotificationsPlugin await _registration! .showNotification( title ?? 'This is a notification', - details.toJs(id), + details.toJs(id, payload), ) .toDart; } /// Initializes the plugin. - Future initialize() async { - // Get the service worker registration - final ServiceWorkerContainer serviceWorker = window.navigator.serviceWorker; - _registration = await serviceWorker.getRegistration().toDart; - if (_registration == null) { - return false; - } + Future initialize({ + DidReceiveNotificationResponseCallback? onNotificationReceived, + }) async { + instance = this; + _userCallback = onNotificationReceived; // Replace the default Flutter service worker with our own. // This isn't supported at build time yet and so must be done at runtime. // See: https://github.com/flutter/flutter/issues/145828 - await _registration!.unregister().toDart; - await serviceWorker.register('/notifications_service_worker.js'.toJS).toDart; + final ServiceWorkerContainer serviceWorker = window.navigator.serviceWorker; + _registration = await serviceWorker.getRegistration().toDart; + await _registration?.unregister().toDart; + const String jsPath = './assets/packages/flutter_local_notifications_web/web/notifications_service_worker.js'; + _registration = await serviceWorker.register(jsPath.toJS).toDart; + + // Subscribe to messages from the service worker + serviceWorker.onmessage = onNotificationClicked.toJS; return true; } diff --git a/flutter_local_notifications_web/lib/src/stub.dart b/flutter_local_notifications_web/lib/src/stub.dart index 1a4dbf310..a6e7a5dcc 100644 --- a/flutter_local_notifications_web/lib/src/stub.dart +++ b/flutter_local_notifications_web/lib/src/stub.dart @@ -6,7 +6,9 @@ import 'details.dart'; class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { /// Initializes the plugin. - Future initialize() async => null; + Future initialize({ + DidReceiveNotificationResponseCallback? onNotificationReceived, + }) async => null; /// Requests permission to use the plugin. Future requestNotificationsPermission() async => false; diff --git a/flutter_local_notifications_web/lib/src/utils.dart b/flutter_local_notifications_web/lib/src/utils.dart index dc31655dd..3d0a81d70 100644 --- a/flutter_local_notifications_web/lib/src/utils.dart +++ b/flutter_local_notifications_web/lib/src/utils.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; import 'package:web/web.dart'; @@ -7,7 +8,8 @@ import 'details.dart'; extension JSNotificationUtils on Notification { /// Gets the ID of the notification. - int? get id => jsonDecode(data.toString())?['id']; + int? get id => int.tryParse(tag); + String? get payload => jsonDecode(data.toString())?['payload']; } extension ServiceWorkerUtils on ServiceWorkerRegistration { @@ -24,23 +26,34 @@ extension WebNotificationDetailsUtils on WebNotificationDetails { ].toJS; } +extension on WebNotificationAction { + // There is a WHATWG proposal to add text input notifications. + // Most browsers support this even though it is not standardized. + // Since it is not standard, the Dart API does not support it. + // See: https://github.com/whatwg/notifications/pull/132 + NotificationAction toJs() => { + 'action': action, + 'title': title, + 'icon': icon?.toString(), + 'type': type.jsValue, + }.jsify() as NotificationAction; +} + extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { - NotificationOptions toJs(int id) { + List get _actions => + this?.actions ?? []; + + NotificationOptions toJs(int id, String? payload) { final NotificationOptions options = NotificationOptions( + data: {'payload': payload}.jsify(), + tag: id.toString(), + // ----------------------------- actions: [ - for (final WebNotificationAction action - in this?.actions ?? []) - // THis workaround is here because not all browsers support this - { - 'action': action.action, - 'title': action.title, - 'icon': action.icon?.toString(), - 'type': action.type.jsValue, - }.jsify() as NotificationAction, + for (final WebNotificationAction action in _actions) + action.toJs(), ].toJS, badge: this?.badgeUrl.toString() ?? '', body: this?.body ?? '', - data: jsonEncode({'id': id}).toJS, dir: this?.direction.jsValue ?? WebNotificationDirection.auto.jsValue, icon: this?.iconUrl.toString() ?? '', image: this?.imageUrl.toString() ?? '', @@ -48,7 +61,6 @@ extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { renotify: this?.renotify ?? false, requireInteraction: this?.requireInteraction ?? false, silent: this?.isSilent, - tag: this?.tag ?? '', timestamp: (this?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, ); @@ -59,3 +71,9 @@ extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { return options; } } + +extension WebNotificationEventUtils on NotificationEvent { + // Support for getting text input. + // See: https://github.com/whatwg/notifications/pull/132 + String? get reply => (this['reply'] as JSString).toDart; +} diff --git a/flutter_local_notifications_web/notifs/flutter_service_worker.js b/flutter_local_notifications_web/notifs/flutter_service_worker.js index ca1df9de6..a3843fcd7 100644 --- a/flutter_local_notifications_web/notifs/flutter_service_worker.js +++ b/flutter_local_notifications_web/notifs/flutter_service_worker.js @@ -1,12 +1,22 @@ 'use strict'; -const MANIFEST = 'flutter-app-manifest'; -const TEMP = 'flutter-temp-cache'; -const CACHE_NAME = 'flutter-app-cache'; - -function _handleNotif(event) { - console.log(`Clicked: ${event}`); - clients.openWindow("/about"); +async function _handleNotif(event) { + let allClients = await clients.matchAll({includeUncontrolled: true}); + if (allClients.length == 0) { + // TODO: Background notification click + console.log("TODO: Background click") + } else { + let client = allClients[0]; + let message = { + action: event.action, + id: event.notification.tag, + payload: event.notification.data.payload, + reply: event.reply, + }; + client.postMessage(message); + } } self.addEventListener("notificationclick", _handleNotif); +self.addEventListener("install", event => { self.skipWaiting(); }); +self.addEventListener("activate", event => { event.waitUntil(clients.claim()); }); diff --git a/flutter_local_notifications_web/notifs/index.html b/flutter_local_notifications_web/notifs/index.html index 6d0cafe55..455f0271b 100644 --- a/flutter_local_notifications_web/notifs/index.html +++ b/flutter_local_notifications_web/notifs/index.html @@ -1,18 +1,19 @@ diff --git a/flutter_local_notifications_web/notifs/temp.js b/flutter_local_notifications_web/notifs/temp.js deleted file mode 100644 index ca1df9de6..000000000 --- a/flutter_local_notifications_web/notifs/temp.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; -const MANIFEST = 'flutter-app-manifest'; -const TEMP = 'flutter-temp-cache'; -const CACHE_NAME = 'flutter-app-cache'; - -function _handleNotif(event) { - console.log(`Clicked: ${event}`); - clients.openWindow("/about"); - -} - -self.addEventListener("notificationclick", _handleNotif); diff --git a/flutter_local_notifications_web/pubspec.yaml b/flutter_local_notifications_web/pubspec.yaml index 86cce5d7b..e70c9dca6 100644 --- a/flutter_local_notifications_web/pubspec.yaml +++ b/flutter_local_notifications_web/pubspec.yaml @@ -28,3 +28,6 @@ flutter: web: pluginClass: WebFlutterLocalNotificationsPlugin fileName: "flutter_local_notifications_web.dart" + + assets: + - web/notifications_service_worker.js diff --git a/flutter_local_notifications_web/web/notifications_service_worker.js b/flutter_local_notifications_web/web/notifications_service_worker.js index 926dd0d7d..a3843fcd7 100644 --- a/flutter_local_notifications_web/web/notifications_service_worker.js +++ b/flutter_local_notifications_web/web/notifications_service_worker.js @@ -1,9 +1,22 @@ 'use strict'; -function _handleNotif(event) { - console.log(`Clicked: ${event}`); - clients.openWindow("/about"); - +async function _handleNotif(event) { + let allClients = await clients.matchAll({includeUncontrolled: true}); + if (allClients.length == 0) { + // TODO: Background notification click + console.log("TODO: Background click") + } else { + let client = allClients[0]; + let message = { + action: event.action, + id: event.notification.tag, + payload: event.notification.data.payload, + reply: event.reply, + }; + client.postMessage(message); + } } self.addEventListener("notificationclick", _handleNotif); +self.addEventListener("install", event => { self.skipWaiting(); }); +self.addEventListener("activate", event => { event.waitUntil(clients.claim()); }); From 24fedf9225f8a3c86fa22e905165bf02e5ad59d8 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 18:20:33 -0400 Subject: [PATCH 19/40] Launch handler --- .../example/lib/main.dart | 7 ++-- .../flutter_local_notifications_plugin.dart | 6 +-- .../lib/src/plugin.dart | 29 ++++++++++++++ .../notifs/flutter_service_worker.js | 40 ++++++++++++++----- .../notifs/index.html | 3 +- .../web/notifications_service_worker.js | 40 ++++++++++++++----- 6 files changed, 97 insertions(+), 28 deletions(-) diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index b793f3c83..121a08129 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -164,10 +164,9 @@ Future main() async { onDidReceiveBackgroundNotificationResponse: notificationTapBackground, ); - final NotificationAppLaunchDetails? notificationAppLaunchDetails = !kIsWeb && - Platform.isLinux - ? null - : await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails(); + final NotificationAppLaunchDetails? notificationAppLaunchDetails = Platform.isLinux + ? null + : await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails(); String initialRoute = HomePage.routeName; NotificationResponse? initialNotification; if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) { diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index 767fa0c55..20b97993e 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -204,9 +204,9 @@ class FlutterLocalNotificationsPlugin { Future getNotificationAppLaunchDetails() async { if (kIsWeb) { - return null; - } - if (defaultTargetPlatform == TargetPlatform.android) { + return await resolvePlatformSpecificImplementation() + ?.getNotificationAppLaunchDetails(); + } else if (defaultTargetPlatform == TargetPlatform.android) { return await resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.getNotificationAppLaunchDetails(); diff --git a/flutter_local_notifications_web/lib/src/plugin.dart b/flutter_local_notifications_web/lib/src/plugin.dart index f2a2f2eb7..c7ec8c64d 100644 --- a/flutter_local_notifications_web/lib/src/plugin.dart +++ b/flutter_local_notifications_web/lib/src/plugin.dart @@ -98,6 +98,35 @@ class WebFlutterLocalNotificationsPlugin return result.toDart == 'granted'; } + @override + Future getNotificationAppLaunchDetails() + async + { + final Uri uri = Uri.parse(window.location.toString()); + final Map query = uri.queryParameters; + final String? id = query['notification_id']; + final String? payload = query['notification_payload']; + final String? action = query['notification_action']; + final String? reply = query['notification_reply']; + window.history.replaceState(null, '', '/'); + if (id == null || payload == null || action == null || reply == null) { + return null; + } else { + return NotificationAppLaunchDetails( + true, + notificationResponse: NotificationResponse( + notificationResponseType: action.isEmpty + ? NotificationResponseType.selectedNotification + : NotificationResponseType.selectedNotificationAction, + id: int.parse(id), + input: reply.nullIfEmpty, + payload: payload.nullIfEmpty, + actionId: action.nullIfEmpty, + ), + ); + } + } + @override Future> getActiveNotifications() async { if (_registration == null) { diff --git a/flutter_local_notifications_web/notifs/flutter_service_worker.js b/flutter_local_notifications_web/notifs/flutter_service_worker.js index a3843fcd7..d8b6a3acb 100644 --- a/flutter_local_notifications_web/notifs/flutter_service_worker.js +++ b/flutter_local_notifications_web/notifs/flutter_service_worker.js @@ -1,19 +1,39 @@ 'use strict'; +function saveMessage(message) { + let request = indexedDB.open("flutter_local_notifications", 1); + request.onupgradeneeded = (event) => { + let db = event.target.result; + db.createObjectStore("notifications", {keyPath: "idb_id"}); + } + request.onsuccess = (event) => { + let db = event.target.result; + let transaction = db.transaction(["notifications"], "readwrite"); + transaction.objectStore("notifications").add(message); + } +} + async function _handleNotif(event) { - let allClients = await clients.matchAll({includeUncontrolled: true}); + let allClientsPromise = clients.matchAll({includeUncontrolled: true}); + event.waitUntil(allClientsPromise); + let allClients = await allClientsPromise; + let message = { + id: event.notification.tag, + payload: event.notification.data.payload, + action: event.action, + reply: event.reply, + idb_id: "flutter_local_notifications", + }; + if (allClients.length == 0) { - // TODO: Background notification click - console.log("TODO: Background click") + let url = `/?notification_id=${encodeURIComponent(message.id)}` + + `¬ification_payload=${encodeURIComponent(message.payload)}` + + `¬ification_action=${encodeURIComponent(message.action)}` + + `¬ification_reply=${encodeURIComponent(message.reply)}`; + await clients.openWindow(url); } else { let client = allClients[0]; - let message = { - action: event.action, - id: event.notification.tag, - payload: event.notification.data.payload, - reply: event.reply, - }; - client.postMessage(message); + await client.postMessage(message); } } diff --git a/flutter_local_notifications_web/notifs/index.html b/flutter_local_notifications_web/notifs/index.html index 455f0271b..ebed62692 100644 --- a/flutter_local_notifications_web/notifs/index.html +++ b/flutter_local_notifications_web/notifs/index.html @@ -20,7 +20,8 @@ {action: "action2", title: "Action 2"}, ], body: "This was sent from JS", - data: "/path/to/notif", + data: {payload: "/path/to/notif"}, + tag: "1", requireInteraction: true, },); } diff --git a/flutter_local_notifications_web/web/notifications_service_worker.js b/flutter_local_notifications_web/web/notifications_service_worker.js index a3843fcd7..d8b6a3acb 100644 --- a/flutter_local_notifications_web/web/notifications_service_worker.js +++ b/flutter_local_notifications_web/web/notifications_service_worker.js @@ -1,19 +1,39 @@ 'use strict'; +function saveMessage(message) { + let request = indexedDB.open("flutter_local_notifications", 1); + request.onupgradeneeded = (event) => { + let db = event.target.result; + db.createObjectStore("notifications", {keyPath: "idb_id"}); + } + request.onsuccess = (event) => { + let db = event.target.result; + let transaction = db.transaction(["notifications"], "readwrite"); + transaction.objectStore("notifications").add(message); + } +} + async function _handleNotif(event) { - let allClients = await clients.matchAll({includeUncontrolled: true}); + let allClientsPromise = clients.matchAll({includeUncontrolled: true}); + event.waitUntil(allClientsPromise); + let allClients = await allClientsPromise; + let message = { + id: event.notification.tag, + payload: event.notification.data.payload, + action: event.action, + reply: event.reply, + idb_id: "flutter_local_notifications", + }; + if (allClients.length == 0) { - // TODO: Background notification click - console.log("TODO: Background click") + let url = `/?notification_id=${encodeURIComponent(message.id)}` + + `¬ification_payload=${encodeURIComponent(message.payload)}` + + `¬ification_action=${encodeURIComponent(message.action)}` + + `¬ification_reply=${encodeURIComponent(message.reply)}`; + await clients.openWindow(url); } else { let client = allClients[0]; - let message = { - action: event.action, - id: event.notification.tag, - payload: event.notification.data.payload, - reply: event.reply, - }; - client.postMessage(message); + await client.postMessage(message); } } From 3ceea7ed4e94c250bd5f462100aa77d7f93ee320 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 18:44:09 -0400 Subject: [PATCH 20/40] Formatted --- .../example/lib/main.dart | 58 +++++++++---------- .../flutter_local_notifications_plugin.dart | 9 +-- .../lib/flutter_local_notifications_web.dart | 3 +- .../lib/src/handler.dart | 4 +- .../lib/src/plugin.dart | 16 +++-- .../lib/src/stub.dart | 3 +- .../lib/src/utils.dart | 15 +++-- 7 files changed, 53 insertions(+), 55 deletions(-) diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index 121a08129..fafbc048c 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -164,9 +164,10 @@ Future main() async { onDidReceiveBackgroundNotificationResponse: notificationTapBackground, ); - final NotificationAppLaunchDetails? notificationAppLaunchDetails = Platform.isLinux - ? null - : await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails(); + final NotificationAppLaunchDetails? notificationAppLaunchDetails = Platform + .isLinux + ? null + : await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails(); String initialRoute = HomePage.routeName; NotificationResponse? initialNotification; if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) { @@ -179,7 +180,9 @@ Future main() async { initialRoute: initialRoute, routes: { HomePage.routeName: (_) => HomePage(notificationAppLaunchDetails), - SecondPage.routeName: (_) => SecondPage.withResponse(initialNotification) + SecondPage.routeName: (_) => SecondPage.withResponse( + initialNotification, + ) }, ), ); @@ -3086,10 +3089,7 @@ Future getLinuxCapabilities() => .getCapabilities(); class SecondPage extends StatefulWidget { - const SecondPage.withResponse( - this.response, - {Key? key} - ) : super(key: key); + const SecondPage.withResponse(this.response, {Key? key}) : super(key: key); static const String routeName = '/secondPage'; @@ -3102,28 +3102,28 @@ class SecondPage extends StatefulWidget { class SecondPageState extends State { @override Widget build(BuildContext context) => Scaffold( - appBar: AppBar( - title: const Text('Second Screen'), - ), - body: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text('Notification ID: ${widget.response?.id}'), - Text('Payload: ${widget.response?.payload}'), - Text('Action ID: ${widget.response?.actionId}'), - Text('Input: ${widget.response?.input}'), - Text('Data (Windows only): ${widget.response?.data}'), - ElevatedButton( - onPressed: () { - Navigator.pop(context); - }, - child: const Text('Go back!'), + appBar: AppBar( + title: const Text('Second Screen'), + ), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Notification ID: ${widget.response?.id}'), + Text('Payload: ${widget.response?.payload}'), + Text('Action ID: ${widget.response?.actionId}'), + Text('Input: ${widget.response?.input}'), + Text('Data (Windows only): ${widget.response?.data}'), + ElevatedButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text('Go back!'), + ), + ], ), - ], - ), - ), - ); + ), + ); } class _InfoValueString extends StatelessWidget { diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index 20b97993e..080fa0c66 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -117,8 +117,8 @@ class FlutterLocalNotificationsPlugin { return resolvePlatformSpecificImplementation< WebFlutterLocalNotificationsPlugin>() ?.initialize( - onNotificationReceived: onDidReceiveNotificationResponse, - ); + onNotificationReceived: onDidReceiveNotificationResponse, + ); } if (defaultTargetPlatform == TargetPlatform.android) { @@ -204,8 +204,9 @@ class FlutterLocalNotificationsPlugin { Future getNotificationAppLaunchDetails() async { if (kIsWeb) { - return await resolvePlatformSpecificImplementation() - ?.getNotificationAppLaunchDetails(); + return await resolvePlatformSpecificImplementation< + WebFlutterLocalNotificationsPlugin>() + ?.getNotificationAppLaunchDetails(); } else if (defaultTargetPlatform == TargetPlatform.android) { return await resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() diff --git a/flutter_local_notifications_web/lib/flutter_local_notifications_web.dart b/flutter_local_notifications_web/lib/flutter_local_notifications_web.dart index 4fb6c30be..0844b9c7f 100644 --- a/flutter_local_notifications_web/lib/flutter_local_notifications_web.dart +++ b/flutter_local_notifications_web/lib/flutter_local_notifications_web.dart @@ -1,4 +1,3 @@ export 'src/details.dart'; -export 'src/stub.dart' - if (dart.library.js_interop) 'src/plugin.dart'; +export 'src/stub.dart' if (dart.library.js_interop) 'src/plugin.dart'; diff --git a/flutter_local_notifications_web/lib/src/handler.dart b/flutter_local_notifications_web/lib/src/handler.dart index e39c0b36c..b651added 100644 --- a/flutter_local_notifications_web/lib/src/handler.dart +++ b/flutter_local_notifications_web/lib/src/handler.dart @@ -17,8 +17,8 @@ extension type JSNotificationData(JSObject _) implements JSObject { NotificationResponse get response { final NotificationResponseType type = action.isEmpty - ? NotificationResponseType.selectedNotification - : NotificationResponseType.selectedNotificationAction; + ? NotificationResponseType.selectedNotification + : NotificationResponseType.selectedNotificationAction; return NotificationResponse( id: int.parse(id), diff --git a/flutter_local_notifications_web/lib/src/plugin.dart b/flutter_local_notifications_web/lib/src/plugin.dart index c7ec8c64d..57fdebdba 100644 --- a/flutter_local_notifications_web/lib/src/plugin.dart +++ b/flutter_local_notifications_web/lib/src/plugin.dart @@ -10,14 +10,12 @@ import 'utils.dart'; void onNotificationClicked(MessageEvent event) { final JSNotificationData data = event.data as JSNotificationData; final NotificationResponse response = data.response; - WebFlutterLocalNotificationsPlugin.instance - ?._userCallback?.call(response); + WebFlutterLocalNotificationsPlugin.instance?._userCallback?.call(response); } /// Web implementation of the local notifications plugin. class WebFlutterLocalNotificationsPlugin extends FlutterLocalNotificationsPlatform { - /// Registers the web plugin with the platform interface. static void registerWith(_) { FlutterLocalNotificationsPlatform.instance = @@ -80,7 +78,8 @@ class WebFlutterLocalNotificationsPlugin final ServiceWorkerContainer serviceWorker = window.navigator.serviceWorker; _registration = await serviceWorker.getRegistration().toDart; await _registration?.unregister().toDart; - const String jsPath = './assets/packages/flutter_local_notifications_web/web/notifications_service_worker.js'; + const String jsPath = + './assets/packages/flutter_local_notifications_web/web/notifications_service_worker.js'; _registration = await serviceWorker.register(jsPath.toJS).toDart; // Subscribe to messages from the service worker @@ -99,9 +98,8 @@ class WebFlutterLocalNotificationsPlugin } @override - Future getNotificationAppLaunchDetails() - async - { + Future + getNotificationAppLaunchDetails() async { final Uri uri = Uri.parse(window.location.toString()); final Map query = uri.queryParameters; final String? id = query['notification_id']; @@ -116,8 +114,8 @@ class WebFlutterLocalNotificationsPlugin true, notificationResponse: NotificationResponse( notificationResponseType: action.isEmpty - ? NotificationResponseType.selectedNotification - : NotificationResponseType.selectedNotificationAction, + ? NotificationResponseType.selectedNotification + : NotificationResponseType.selectedNotificationAction, id: int.parse(id), input: reply.nullIfEmpty, payload: payload.nullIfEmpty, diff --git a/flutter_local_notifications_web/lib/src/stub.dart b/flutter_local_notifications_web/lib/src/stub.dart index a6e7a5dcc..21b812d5a 100644 --- a/flutter_local_notifications_web/lib/src/stub.dart +++ b/flutter_local_notifications_web/lib/src/stub.dart @@ -8,7 +8,8 @@ class WebFlutterLocalNotificationsPlugin /// Initializes the plugin. Future initialize({ DidReceiveNotificationResponseCallback? onNotificationReceived, - }) async => null; + }) async => + null; /// Requests permission to use the plugin. Future requestNotificationsPermission() async => false; diff --git a/flutter_local_notifications_web/lib/src/utils.dart b/flutter_local_notifications_web/lib/src/utils.dart index 3d0a81d70..f027bafea 100644 --- a/flutter_local_notifications_web/lib/src/utils.dart +++ b/flutter_local_notifications_web/lib/src/utils.dart @@ -32,16 +32,16 @@ extension on WebNotificationAction { // Since it is not standard, the Dart API does not support it. // See: https://github.com/whatwg/notifications/pull/132 NotificationAction toJs() => { - 'action': action, - 'title': title, - 'icon': icon?.toString(), - 'type': type.jsValue, - }.jsify() as NotificationAction; + 'action': action, + 'title': title, + 'icon': icon?.toString(), + 'type': type.jsValue, + }.jsify() as NotificationAction; } extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { List get _actions => - this?.actions ?? []; + this?.actions ?? []; NotificationOptions toJs(int id, String? payload) { final NotificationOptions options = NotificationOptions( @@ -49,8 +49,7 @@ extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { tag: id.toString(), // ----------------------------- actions: [ - for (final WebNotificationAction action in _actions) - action.toJs(), + for (final WebNotificationAction action in _actions) action.toJs(), ].toJS, badge: this?.badgeUrl.toString() ?? '', body: this?.body ?? '', From 2f6eda0095ee5c1ca5179288146fdaed24ec2a45 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 18:54:33 -0400 Subject: [PATCH 21/40] Documented actions --- analysis_options.yaml | 2 +- .../lib/src/action.dart | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 0da89a91d..955eee9f9 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -116,7 +116,7 @@ linter: - prefer_typing_uninitialized_variables - prefer_void_to_null - provide_deprecation_message - # - public_member_api_docs + - public_member_api_docs - recursive_getters - slash_for_doc_comments - sort_child_properties_last diff --git a/flutter_local_notifications_web/lib/src/action.dart b/flutter_local_notifications_web/lib/src/action.dart index 57d738b51..dc5936b9f 100644 --- a/flutter_local_notifications_web/lib/src/action.dart +++ b/flutter_local_notifications_web/lib/src/action.dart @@ -1,12 +1,23 @@ +/// The type of action for a web notification. +/// +/// Note: This is not standard yet, see: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification#browser_compatibility +/// Notably, Firefox and Safari do not support this yet. enum WebNotificationActionType { + /// This action is a button the user can press. button('button'), + + /// This action is an input field the user can type into. textInput('text'); const WebNotificationActionType(this.jsValue); + + /// A string to pass to the JavaScript functions that indicates this type. final String jsValue; } +/// A means for a user to interact with a web notification. class WebNotificationAction { + /// A const constructor. const WebNotificationAction({ required this.action, required this.title, @@ -14,8 +25,15 @@ class WebNotificationAction { this.type = WebNotificationActionType.button, }); + /// The type of action (button by default). final WebNotificationActionType type; + + /// A developer-facing string representing this action. final String action; + + /// A user-facing string to be shown next to this action. final String title; + + /// An optional icon to display next to the action. final Uri? icon; } From 85c0667683c98f775d64403639f92083a324c282 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 19:00:39 -0400 Subject: [PATCH 22/40] Documented direction --- flutter_local_notifications_web/lib/src/action.dart | 12 ++++++++++-- .../lib/src/direction.dart | 10 +++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/flutter_local_notifications_web/lib/src/action.dart b/flutter_local_notifications_web/lib/src/action.dart index dc5936b9f..ed73d819f 100644 --- a/flutter_local_notifications_web/lib/src/action.dart +++ b/flutter_local_notifications_web/lib/src/action.dart @@ -1,7 +1,10 @@ /// The type of action for a web notification. /// -/// Note: This is not standard yet, see: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification#browser_compatibility -/// Notably, Firefox and Safari do not support this yet. +/// This is a non-standard extension of `showNotification()`s `options.actions` +/// parameter. The proposal can be found [here](https://github.com/whatwg/notifications/pull/132). +/// +/// Web actions themselves are hardly supported at the time of writing. See +/// [WebNotificationAction] for more details. enum WebNotificationActionType { /// This action is a button the user can press. button('button'), @@ -16,6 +19,11 @@ enum WebNotificationActionType { } /// A means for a user to interact with a web notification. +/// +/// See: [`options.actions`](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification#actions) +/// +/// Note: This is not standard yet, see: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification#browser_compatibility +/// Notably, Firefox and Safari do not support this yet. class WebNotificationAction { /// A const constructor. const WebNotificationAction({ diff --git a/flutter_local_notifications_web/lib/src/direction.dart b/flutter_local_notifications_web/lib/src/direction.dart index 514e6ab4d..bf0a3e59b 100644 --- a/flutter_local_notifications_web/lib/src/direction.dart +++ b/flutter_local_notifications_web/lib/src/direction.dart @@ -1,9 +1,17 @@ -// https://developer.mozilla.org/en-US/docs/Web/API/Notification/dir +/// The text direction of a web notification. +/// +/// Note: This may be ignored by browsers. See the [docs](https://developer.mozilla.org/en-US/docs/Web/API/Notification/dir) enum WebNotificationDirection { + /// Adopt the browser's setting. auto('auto'), + + /// Left to right. leftToRight('ltr'), + + /// Right to left. rightToLeft('rtl'); const WebNotificationDirection(this.jsValue); + /// A string value to pass to JavaScript functions. final String jsValue; } From d23c04f3c95db46123351862edf08f955d30f104 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 19:08:42 -0400 Subject: [PATCH 23/40] Documented utils --- .../lib/src/action.dart | 4 ++- .../lib/src/utils.dart | 33 ++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/flutter_local_notifications_web/lib/src/action.dart b/flutter_local_notifications_web/lib/src/action.dart index ed73d819f..a354974fa 100644 --- a/flutter_local_notifications_web/lib/src/action.dart +++ b/flutter_local_notifications_web/lib/src/action.dart @@ -1,7 +1,9 @@ /// The type of action for a web notification. /// /// This is a non-standard extension of `showNotification()`s `options.actions` -/// parameter. The proposal can be found [here](https://github.com/whatwg/notifications/pull/132). +/// parameter that allows for buttons and text inputs. +/// +/// The proposal can be found [here](https://github.com/whatwg/notifications/pull/132). /// /// Web actions themselves are hardly supported at the time of writing. See /// [WebNotificationAction] for more details. diff --git a/flutter_local_notifications_web/lib/src/utils.dart b/flutter_local_notifications_web/lib/src/utils.dart index f027bafea..c74f5b59b 100644 --- a/flutter_local_notifications_web/lib/src/utils.dart +++ b/flutter_local_notifications_web/lib/src/utils.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'dart:js_interop'; import 'dart:js_interop_unsafe'; @@ -6,18 +5,22 @@ import 'package:web/web.dart'; import 'details.dart'; +/// Utility methods on JavaScript [Notification] objects. extension JSNotificationUtils on Notification { - /// Gets the ID of the notification. + /// The ID of the notification. int? get id => int.tryParse(tag); - String? get payload => jsonDecode(data.toString())?['payload']; } +/// Utility methods on [ServiceWorkerRegistration] objects. extension ServiceWorkerUtils on ServiceWorkerRegistration { + /// Gets a list of notifications (as Dart objects). Future> getDartNotifications() async => (await getNotifications().toDart).toDart; } +/// Utility methods on [WebNotificationDetails] objects. extension WebNotificationDetailsUtils on WebNotificationDetails { + /// A JavaScript array with the number of milliseconds in between vibrations. JSArray? get vibrationPatternMs => vibrationPattern == null ? null : [ @@ -26,11 +29,18 @@ extension WebNotificationDetailsUtils on WebNotificationDetails { ].toJS; } +/// Utility methods on [WebNotificationAction] objects. extension on WebNotificationAction { - // There is a WHATWG proposal to add text input notifications. - // Most browsers support this even though it is not standardized. - // Since it is not standard, the Dart API does not support it. - // See: https://github.com/whatwg/notifications/pull/132 + /// Converts this object to the format expected by `showNotifications()` + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/Notification/actions. + /// + /// Note: There is a WHATWG proposal to add button and text input actions. + /// This requires setting an additional `type` parameter, which is not yet + /// standardized, so is not a part of the Dart APIs. That's why we cannot rely + /// on `NotificationAction.toJs` for this function. + /// + /// The proposal can be found here: https://github.com/whatwg/notifications/pull/132 NotificationAction toJs() => { 'action': action, 'title': title, @@ -39,10 +49,13 @@ extension on WebNotificationAction { }.jsify() as NotificationAction; } +/// A useful way to convert a nullable details object to a JS payload. extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { + /// Converts the list of actions into a JS array (empty if needed). List get _actions => this?.actions ?? []; + /// Converts these nullable details to a JS [NotificationOptions] object. NotificationOptions toJs(int id, String? payload) { final NotificationOptions options = NotificationOptions( data: {'payload': payload}.jsify(), @@ -71,8 +84,10 @@ extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { } } +/// Utility methods on JavaScript [NotificationEvent] objects. extension WebNotificationEventUtils on NotificationEvent { - // Support for getting text input. - // See: https://github.com/whatwg/notifications/pull/132 + /// Gets text input from the action, if any. + /// + /// See [WebNotificationActionType] for details. String? get reply => (this['reply'] as JSString).toDart; } From 9ff83513a3d7ef2650ff3d9ba2578d599fad683c Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 19:17:26 -0400 Subject: [PATCH 24/40] Documented handler --- .../lib/src/handler.dart | 21 ++++++++++++++++--- .../lib/src/plugin.dart | 14 +++++++++++-- .../lib/src/utils.dart | 9 ++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/flutter_local_notifications_web/lib/src/handler.dart b/flutter_local_notifications_web/lib/src/handler.dart index b651added..dde97afec 100644 --- a/flutter_local_notifications_web/lib/src/handler.dart +++ b/flutter_local_notifications_web/lib/src/handler.dart @@ -4,17 +4,32 @@ library; import 'dart:js_interop'; import 'package:flutter_local_notifications_platform_interface/flutter_local_notifications_platform_interface.dart'; +import 'package:web/web.dart'; -extension StringUtils on String { - String? get nullIfEmpty => isEmpty ? null : this; -} +import 'utils.dart'; +/// An object representing a clicked notification. +/// +/// Notification clicks are handled by service workers. See `web/notification_service_worker.js` +/// for the source code there. When the service worker receives the +/// [NotificationEvent], it uses [Client.postMessage] to send a message back to +/// the currently open window/tab, if there is any. +/// +/// This is the object sent by the service worker via [Client.postMessage]. extension type JSNotificationData(JSObject _) implements JSObject { + /// A string rperesenting the [NotificationAction.action], if any. external String action; + + /// A string representing the [Notification.tag]; external String id; + + /// The original payload passed to [FlutterLocalNotificationsPlatform.show]. external String? payload; + + /// The reply entered by the user in the text field, if any. external String? reply; + /// The [NotificationResponse] that corresponds to this object. NotificationResponse get response { final NotificationResponseType type = action.isEmpty ? NotificationResponseType.selectedNotification diff --git a/flutter_local_notifications_web/lib/src/plugin.dart b/flutter_local_notifications_web/lib/src/plugin.dart index 57fdebdba..0e166d43b 100644 --- a/flutter_local_notifications_web/lib/src/plugin.dart +++ b/flutter_local_notifications_web/lib/src/plugin.dart @@ -7,7 +7,16 @@ import 'details.dart'; import 'handler.dart'; import 'utils.dart'; -void onNotificationClicked(MessageEvent event) { +/// Called when a notification has been clicked. +/// +/// Notification clicks are handled by service workers. See `web/notification_service_worker.js` +/// for the source code there. When the service worker receives the +/// [NotificationEvent], it uses [Client.postMessage] to send a message back to +/// the currently open window/tab, if there is any. +/// +/// This function creates a [NotificationResponse] object and calls the user's +/// callback they provided to [WebFlutterLocalNotificationsPlugin.initialize]. +void _onNotificationClicked(MessageEvent event) { final JSNotificationData data = event.data as JSNotificationData; final NotificationResponse response = data.response; WebFlutterLocalNotificationsPlugin.instance?._userCallback?.call(response); @@ -22,6 +31,7 @@ class WebFlutterLocalNotificationsPlugin WebFlutterLocalNotificationsPlugin(); } + /// The currently loaded web plugin object, if any. static WebFlutterLocalNotificationsPlugin? instance; DidReceiveNotificationResponseCallback? _userCallback; @@ -83,7 +93,7 @@ class WebFlutterLocalNotificationsPlugin _registration = await serviceWorker.register(jsPath.toJS).toDart; // Subscribe to messages from the service worker - serviceWorker.onmessage = onNotificationClicked.toJS; + serviceWorker.onmessage = _onNotificationClicked.toJS; return true; } diff --git a/flutter_local_notifications_web/lib/src/utils.dart b/flutter_local_notifications_web/lib/src/utils.dart index c74f5b59b..4b950cf2d 100644 --- a/flutter_local_notifications_web/lib/src/utils.dart +++ b/flutter_local_notifications_web/lib/src/utils.dart @@ -91,3 +91,12 @@ extension WebNotificationEventUtils on NotificationEvent { /// See [WebNotificationActionType] for details. String? get reply => (this['reply'] as JSString).toDart; } + +/// Helpful methods on strings. +extension StringUtils on String { + /// Returns null if this string is empty. + /// + /// Useful because JavaScript might prefer to represent a blank option with an + /// empty string, while Dart users would prefer `null` instead. + String? get nullIfEmpty => isEmpty ? null : this; +} From 12fcf51549477ccd8e27bf1498cafab4bddcfbe6 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 19:46:15 -0400 Subject: [PATCH 25/40] Documented details --- .../lib/src/details.dart | 43 ++++++++++++++++++- .../lib/src/plugin.dart | 5 --- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/flutter_local_notifications_web/lib/src/details.dart b/flutter_local_notifications_web/lib/src/details.dart index 365cc103d..6fa5b90dc 100644 --- a/flutter_local_notifications_web/lib/src/details.dart +++ b/flutter_local_notifications_web/lib/src/details.dart @@ -4,7 +4,13 @@ import 'direction.dart'; export 'action.dart'; export 'direction.dart'; +/// The web-specific details of a notification. +/// +/// See: https://developer.mozilla.org/en-US/docs/Web/API/Notification +/// +/// Note: The `tag` field is reserved for the notification ID. class WebNotificationDetails { + /// A const constructor. const WebNotificationDetails({ this.actions = const [], this.direction = WebNotificationDirection.auto, @@ -14,24 +20,57 @@ class WebNotificationDetails { this.lang, this.requireInteraction = false, this.isSilent = false, - this.tag, this.imageUrl, this.renotify = false, this.timestamp, this.vibrationPattern, }); + /// A list of actions to send with the notification. final List actions; + + /// The text direction of the notification. final WebNotificationDirection direction; + + /// An optional URL to a monochrome icon to show next to the title. final Uri? badgeUrl; + + /// An optional body text to show in the notification. final String? body; + + /// An optional URL to an image to show as the app icon. final Uri? iconUrl; + + /// An optional URL to an image to show in the notification. final Uri? imageUrl; + + /// The language code of the notification's content, eg `en-US`. final String? lang; + + /// Whether the notification should remain visible until manually dismissed. final bool requireInteraction; + + /// Whether the notification should be silent. final bool isSilent; - final String? tag; + + /// Whether the user should be notified if this notification is replaced. final bool renotify; + + /// The timestamp of the event that caused this notification. + /// + /// This doesn't always have to be the time the notification was sent. For + /// exmaple, if the notification represents a message that was sent a while + /// ago, you can back-date this timestamp to when the message was originally + /// sent instead of when it was received. final DateTime? timestamp; + + /// An optional vibration pattern + /// + /// This should be a list of milliseconds, starting with how long the device + /// should vibrate for, followed by how long it should pause. + /// + /// For examples, see: + /// - https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API#vibration_patterns + /// - https://web.dev/articles/push-notifications-display-a-notification#vibrate final List? vibrationPattern; } diff --git a/flutter_local_notifications_web/lib/src/plugin.dart b/flutter_local_notifications_web/lib/src/plugin.dart index 0e166d43b..97f5707e1 100644 --- a/flutter_local_notifications_web/lib/src/plugin.dart +++ b/flutter_local_notifications_web/lib/src/plugin.dart @@ -55,11 +55,6 @@ class WebFlutterLocalNotificationsPlugin 'WebNotificationDetails: Cannot specify both silent and a vibration ' 'pattern', ); - } else if (details?.renotify == true && details?.tag == null) { - throw ArgumentError( - 'WebNotificationDetails: If you specify renotify, you must also ' - 'specify a tag', - ); } else if (_registration!.active == null) { throw StateError( 'FlutterLocalNotifications.show(): There is no active service worker. ' From 0ce22e9f5424cdcd35d60b1f5080de5ae2ac61f3 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 20:43:08 -0400 Subject: [PATCH 26/40] Added web-specific examples --- .../example/lib/main.dart | 11 ++ .../example/lib/web.dart | 111 ++++++++++++++++++ .../lib/src/details.dart | 17 ++- .../lib/src/plugin.dart | 17 ++- .../lib/src/stub.dart | 8 +- .../lib/src/utils.dart | 10 +- 6 files changed, 159 insertions(+), 15 deletions(-) create mode 100644 flutter_local_notifications/example/lib/web.dart diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index fafbc048c..36c4f619b 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -20,6 +20,7 @@ import 'package:universal_platform/universal_platform.dart'; import 'padded_button.dart'; import 'plugin.dart'; import 'repeating.dart' as repeating; +import 'web.dart' as web; import 'windows.dart' as windows; typedef Platform = UniversalPlatform; @@ -62,6 +63,8 @@ const String darwinNotificationCategoryText = 'textCategory'; /// Defines a iOS/MacOS notification category for plain actions. const String darwinNotificationCategoryPlain = 'plainCategory'; +bool? hasPermission; + @pragma('vm:entry-point') void notificationTapBackground(NotificationResponse notificationResponse) { // ignore: avoid_print @@ -164,6 +167,12 @@ Future main() async { onDidReceiveBackgroundNotificationResponse: notificationTapBackground, ); + if (kIsWeb) { + hasPermission = flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation() + ?.hasPermission; + } + final NotificationAppLaunchDetails? notificationAppLaunchDetails = Platform .isLinux ? null @@ -1040,6 +1049,7 @@ class _HomePageState extends State { ), ], if (!kIsWeb && Platform.isWindows) ...windows.examples(), + if (kIsWeb) ...web.examples(hasPermission), ], ), ), @@ -1935,6 +1945,7 @@ class _HomePageState extends State { Future _cancelAllNotifications() async { await flutterLocalNotificationsPlugin.cancelAll(); + id = 0; } Future _cancelAllPendingNotifications() async { diff --git a/flutter_local_notifications/example/lib/web.dart b/flutter_local_notifications/example/lib/web.dart new file mode 100644 index 000000000..4aa22a53f --- /dev/null +++ b/flutter_local_notifications/example/lib/web.dart @@ -0,0 +1,111 @@ +import 'dart:ui_web'; + +import 'package:flutter/material.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; + +import 'padded_button.dart'; +import 'plugin.dart'; + +List examples(bool? hasPermission) => [ + const Text( + 'Windows-specific examples', + style: TextStyle(fontWeight: FontWeight.bold), + ), + if (hasPermission ?? false) + const Text('Notification permissions granted') + else + const Text('WARNING: The user did not grant permissions to show notifications'), + + const PaddedElevatedButton( + buttonText: 'Notification with images', + onPressed: _showImages, + ), + const PaddedElevatedButton( + buttonText: 'Right-to-left notification', + onPressed: _showRtl, + ), + const PaddedElevatedButton( + buttonText: 'Require interaction', + onPressed: _showInteraction, + ), + const PaddedElevatedButton( + buttonText: 'Replace notification', + onPressed: _showRenotify, + ), + const PaddedElevatedButton( + buttonText: 'Notification with an older timestamp', + onPressed: _showTimestamp, + ), + const PaddedElevatedButton( + buttonText: 'Notification with vibration', + onPressed: _showVibrate, + ), +]; + +final Uri imageUrl = Uri.parse('https://picsum.photos/500'); +final Uri iconUrl = Uri.parse('https://picsum.photos/100'); +final Uri badgeUrl = Uri.parse(AssetManager().getAssetUrl('icons/app_icon_density.png')); + +Future showDetails(WebNotificationDetails details) => flutterLocalNotificationsPlugin + .show( + id++, + 'This is a title', + 'This is a body', + NotificationDetails(web: details), + ); + +void _showTimestamp() => showDetails( + WebNotificationDetails(timestamp: DateTime(2020, 1, 5)) +); + +Future _showRenotify() async { + final int id2 = id++; + await flutterLocalNotificationsPlugin.show( + id2, + 'This is the original notification!', + 'Wait for it...', + const NotificationDetails(web: WebNotificationDetails(renotify: true)), + ); + await Future.delayed(const Duration(seconds: 1)); + await flutterLocalNotificationsPlugin.show( + id2, + 'This is the replacement!', + 'Notice there is no animation!', + null, + ); +} + +void _showInteraction() => showDetails( + const WebNotificationDetails(requireInteraction: true) +); + +void _showImages() => showDetails( + WebNotificationDetails( + imageUrl: imageUrl, + iconUrl: iconUrl, + badgeUrl: iconUrl, + ) +); + +void _showRtl() => flutterLocalNotificationsPlugin + .show( + id++, + 'This is in a right-to-left language', + 'שלום חביבי!', + const NotificationDetails( + web: WebNotificationDetails( + direction: WebNotificationDirection.rightToLeft, + ), + ), + ); + +// Star wars theme! +// See: https://tests.peter.sh/notification-generator/ +final List vibrationPattern = [ + 500, 110, 500, 110, 450, 110, 200, 110, 170, 40, 450, 110, 200, 110, 170, 40, 500, +]; +void _showVibrate() => showDetails( + WebNotificationDetails( + vibrationPattern: vibrationPattern, + ) +); diff --git a/flutter_local_notifications_web/lib/src/details.dart b/flutter_local_notifications_web/lib/src/details.dart index 6fa5b90dc..d89626f7e 100644 --- a/flutter_local_notifications_web/lib/src/details.dart +++ b/flutter_local_notifications_web/lib/src/details.dart @@ -15,7 +15,6 @@ class WebNotificationDetails { this.actions = const [], this.direction = WebNotificationDirection.auto, this.badgeUrl, - this.body, this.iconUrl, this.lang, this.requireInteraction = false, @@ -35,9 +34,6 @@ class WebNotificationDetails { /// An optional URL to a monochrome icon to show next to the title. final Uri? badgeUrl; - /// An optional body text to show in the notification. - final String? body; - /// An optional URL to an image to show as the app icon. final Uri? iconUrl; @@ -54,6 +50,14 @@ class WebNotificationDetails { final bool isSilent; /// Whether the user should be notified if this notification is replaced. + /// + /// If this is false, the new notification will replace this one silently. If + /// this is true, the device will notify the user any time the notification is + /// updated. + /// + /// For exmaple, when updating a loading notification, you want each update to + /// occur silently. But if you have a notification that represents a chat + /// thread, you'd want it to update when a new message is sent. final bool renotify; /// The timestamp of the event that caused this notification. @@ -72,5 +76,8 @@ class WebNotificationDetails { /// For examples, see: /// - https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API#vibration_patterns /// - https://web.dev/articles/push-notifications-display-a-notification#vibrate - final List? vibrationPattern; + /// + /// Note: This is not supported on Android as vibration patterns are set by + /// the notification channel, not an individual notification. + final List? vibrationPattern; } diff --git a/flutter_local_notifications_web/lib/src/plugin.dart b/flutter_local_notifications_web/lib/src/plugin.dart index 97f5707e1..f7835144c 100644 --- a/flutter_local_notifications_web/lib/src/plugin.dart +++ b/flutter_local_notifications_web/lib/src/plugin.dart @@ -45,7 +45,7 @@ class WebFlutterLocalNotificationsPlugin 'FlutterLocalNotifications.show(): You must call initialize() before ' 'calling this method', ); - } else if (Notification.permission != 'granted') { + } else if (!hasPermission) { throw StateError( 'FlutterLocalNotifications.show(): You must request notifications ' 'permissions first', @@ -64,8 +64,8 @@ class WebFlutterLocalNotificationsPlugin await _registration! .showNotification( - title ?? 'This is a notification', - details.toJs(id, payload), + title ?? '', + details.toJs(id, body, payload), ) .toDart; } @@ -95,13 +95,20 @@ class WebFlutterLocalNotificationsPlugin /// Requests notification permission from the browser. /// - /// It is highly recommended and sometimes required that this be called only - /// in response to a user gesture, and not automatically. + /// Be sure to only request permissions in response to a user gesture, or it + /// may be automatically rejected. Future requestNotificationsPermission() async { final JSString result = await Notification.requestPermission().toDart; return result.toDart == 'granted'; } + /// Whether the user has granted permission to show notifications. + /// + /// If this is false, you must call [requestNotificationsPermission]. Be sure + /// to only request permissions in response to a user gesture, or it may be + /// automatically rejected. + bool get hasPermission => Notification.permission == 'granted'; + @override Future getNotificationAppLaunchDetails() async { diff --git a/flutter_local_notifications_web/lib/src/stub.dart b/flutter_local_notifications_web/lib/src/stub.dart index 21b812d5a..97d8122cc 100644 --- a/flutter_local_notifications_web/lib/src/stub.dart +++ b/flutter_local_notifications_web/lib/src/stub.dart @@ -11,7 +11,10 @@ class WebFlutterLocalNotificationsPlugin }) async => null; - /// Requests permission to use the plugin. + /// Requests notification permission from the browser. + /// + /// Be sure to only request permissions in response to a user gesture, or it + /// may be automatically rejected. Future requestNotificationsPermission() async => false; @override @@ -20,4 +23,7 @@ class WebFlutterLocalNotificationsPlugin @override Future show(int id, String? title, String? body, {String? payload, WebNotificationDetails? details}) async {} + + /// Whether the user has granted permission to show notifications. + bool get hasPermission => false; } diff --git a/flutter_local_notifications_web/lib/src/utils.dart b/flutter_local_notifications_web/lib/src/utils.dart index 4b950cf2d..1e2bffd53 100644 --- a/flutter_local_notifications_web/lib/src/utils.dart +++ b/flutter_local_notifications_web/lib/src/utils.dart @@ -24,8 +24,8 @@ extension WebNotificationDetailsUtils on WebNotificationDetails { JSArray? get vibrationPatternMs => vibrationPattern == null ? null : [ - for (final Duration duration in vibrationPattern!) - duration.inMilliseconds.toJS, + for (final int duration in vibrationPattern!) + duration.toJS, ].toJS; } @@ -56,7 +56,7 @@ extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { this?.actions ?? []; /// Converts these nullable details to a JS [NotificationOptions] object. - NotificationOptions toJs(int id, String? payload) { + NotificationOptions toJs(int id, String? body, String? payload) { final NotificationOptions options = NotificationOptions( data: {'payload': payload}.jsify(), tag: id.toString(), @@ -65,7 +65,7 @@ extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { for (final WebNotificationAction action in _actions) action.toJs(), ].toJS, badge: this?.badgeUrl.toString() ?? '', - body: this?.body ?? '', + body: body ?? '', dir: this?.direction.jsValue ?? WebNotificationDirection.auto.jsValue, icon: this?.iconUrl.toString() ?? '', image: this?.imageUrl.toString() ?? '', @@ -76,10 +76,12 @@ extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { timestamp: (this?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, ); + final JSArray? vibration = this?.vibrationPatternMs; if (vibration != null) { options.vibrate = vibration; } + return options; } } From 5f6819f19a6185482e818fe93fc908c24e0a2b39 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 20:44:56 -0400 Subject: [PATCH 27/40] Formatted --- .../example/lib/main.dart | 5 +- .../example/lib/web.dart | 153 ++++++++++-------- .../lib/src/direction.dart | 1 + .../lib/src/utils.dart | 4 +- 4 files changed, 87 insertions(+), 76 deletions(-) diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index 36c4f619b..6fd4f1090 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -169,8 +169,9 @@ Future main() async { if (kIsWeb) { hasPermission = flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation() - ?.hasPermission; + .resolvePlatformSpecificImplementation< + WebFlutterLocalNotificationsPlugin>() + ?.hasPermission; } final NotificationAppLaunchDetails? notificationAppLaunchDetails = Platform diff --git a/flutter_local_notifications/example/lib/web.dart b/flutter_local_notifications/example/lib/web.dart index 4aa22a53f..4c4598895 100644 --- a/flutter_local_notifications/example/lib/web.dart +++ b/flutter_local_notifications/example/lib/web.dart @@ -7,56 +7,57 @@ import 'padded_button.dart'; import 'plugin.dart'; List examples(bool? hasPermission) => [ - const Text( - 'Windows-specific examples', - style: TextStyle(fontWeight: FontWeight.bold), - ), - if (hasPermission ?? false) - const Text('Notification permissions granted') - else - const Text('WARNING: The user did not grant permissions to show notifications'), - - const PaddedElevatedButton( - buttonText: 'Notification with images', - onPressed: _showImages, - ), - const PaddedElevatedButton( - buttonText: 'Right-to-left notification', - onPressed: _showRtl, - ), - const PaddedElevatedButton( - buttonText: 'Require interaction', - onPressed: _showInteraction, - ), - const PaddedElevatedButton( - buttonText: 'Replace notification', - onPressed: _showRenotify, - ), - const PaddedElevatedButton( - buttonText: 'Notification with an older timestamp', - onPressed: _showTimestamp, - ), - const PaddedElevatedButton( - buttonText: 'Notification with vibration', - onPressed: _showVibrate, - ), -]; + const Text( + 'Windows-specific examples', + style: TextStyle(fontWeight: FontWeight.bold), + ), + if (hasPermission ?? false) + const Text('Notification permissions granted') + else + const Text( + 'WARNING: The user did not grant permissions to show notifications', + ), + const PaddedElevatedButton( + buttonText: 'Notification with images', + onPressed: _showImages, + ), + const PaddedElevatedButton( + buttonText: 'Right-to-left notification', + onPressed: _showRtl, + ), + const PaddedElevatedButton( + buttonText: 'Require interaction', + onPressed: _showInteraction, + ), + const PaddedElevatedButton( + buttonText: 'Replace notification', + onPressed: _showRenotify, + ), + const PaddedElevatedButton( + buttonText: 'Notification with an older timestamp', + onPressed: _showTimestamp, + ), + const PaddedElevatedButton( + buttonText: 'Notification with vibration', + onPressed: _showVibrate, + ), + ]; final Uri imageUrl = Uri.parse('https://picsum.photos/500'); final Uri iconUrl = Uri.parse('https://picsum.photos/100'); -final Uri badgeUrl = Uri.parse(AssetManager().getAssetUrl('icons/app_icon_density.png')); +final Uri badgeUrl = + Uri.parse(AssetManager().getAssetUrl('icons/app_icon_density.png')); -Future showDetails(WebNotificationDetails details) => flutterLocalNotificationsPlugin - .show( - id++, - 'This is a title', - 'This is a body', - NotificationDetails(web: details), - ); +Future showDetails(WebNotificationDetails details) => + flutterLocalNotificationsPlugin.show( + id++, + 'This is a title', + 'This is a body', + NotificationDetails(web: details), + ); -void _showTimestamp() => showDetails( - WebNotificationDetails(timestamp: DateTime(2020, 1, 5)) -); +void _showTimestamp() => + showDetails(WebNotificationDetails(timestamp: DateTime(2020, 1, 5))); Future _showRenotify() async { final int id2 = id++; @@ -75,37 +76,47 @@ Future _showRenotify() async { ); } -void _showInteraction() => showDetails( - const WebNotificationDetails(requireInteraction: true) -); +void _showInteraction() => + showDetails(const WebNotificationDetails(requireInteraction: true)); -void _showImages() => showDetails( - WebNotificationDetails( - imageUrl: imageUrl, - iconUrl: iconUrl, - badgeUrl: iconUrl, - ) -); +void _showImages() => showDetails(WebNotificationDetails( + imageUrl: imageUrl, + iconUrl: iconUrl, + badgeUrl: iconUrl, + )); -void _showRtl() => flutterLocalNotificationsPlugin - .show( - id++, - 'This is in a right-to-left language', - 'שלום חביבי!', - const NotificationDetails( - web: WebNotificationDetails( - direction: WebNotificationDirection.rightToLeft, +void _showRtl() => flutterLocalNotificationsPlugin.show( + id++, + 'This is in a right-to-left language', + 'שלום חביבי!', + const NotificationDetails( + web: WebNotificationDetails( + direction: WebNotificationDirection.rightToLeft, + ), ), - ), - ); + ); // Star wars theme! // See: https://tests.peter.sh/notification-generator/ final List vibrationPattern = [ - 500, 110, 500, 110, 450, 110, 200, 110, 170, 40, 450, 110, 200, 110, 170, 40, 500, + 500, + 110, + 500, + 110, + 450, + 110, + 200, + 110, + 170, + 40, + 450, + 110, + 200, + 110, + 170, + 40, + 500, ]; -void _showVibrate() => showDetails( - WebNotificationDetails( - vibrationPattern: vibrationPattern, - ) -); +void _showVibrate() => showDetails(WebNotificationDetails( + vibrationPattern: vibrationPattern, + )); diff --git a/flutter_local_notifications_web/lib/src/direction.dart b/flutter_local_notifications_web/lib/src/direction.dart index bf0a3e59b..2f163d001 100644 --- a/flutter_local_notifications_web/lib/src/direction.dart +++ b/flutter_local_notifications_web/lib/src/direction.dart @@ -12,6 +12,7 @@ enum WebNotificationDirection { rightToLeft('rtl'); const WebNotificationDirection(this.jsValue); + /// A string value to pass to JavaScript functions. final String jsValue; } diff --git a/flutter_local_notifications_web/lib/src/utils.dart b/flutter_local_notifications_web/lib/src/utils.dart index 1e2bffd53..f3f6bcb37 100644 --- a/flutter_local_notifications_web/lib/src/utils.dart +++ b/flutter_local_notifications_web/lib/src/utils.dart @@ -24,8 +24,7 @@ extension WebNotificationDetailsUtils on WebNotificationDetails { JSArray? get vibrationPatternMs => vibrationPattern == null ? null : [ - for (final int duration in vibrationPattern!) - duration.toJS, + for (final int duration in vibrationPattern!) duration.toJS, ].toJS; } @@ -76,7 +75,6 @@ extension NullableWebNotificationDetailsUtils on WebNotificationDetails? { timestamp: (this?.timestamp ?? DateTime.now()).millisecondsSinceEpoch, ); - final JSArray? vibration = this?.vibrationPatternMs; if (vibration != null) { options.vibrate = vibration; From 2939520dc7376a3c009a74e2e508431e44ed2992 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 21:39:03 -0400 Subject: [PATCH 28/40] More documentation --- flutter_local_notifications_web/README.md | 64 +++++++++++++++---- .../lib/src/plugin.dart | 1 - .../notifs/flutter_service_worker.js | 42 ------------ .../notifs/index.html | 34 ---------- .../web/notifications_service_worker.js | 20 ++++++ 5 files changed, 71 insertions(+), 90 deletions(-) delete mode 100644 flutter_local_notifications_web/notifs/flutter_service_worker.js delete mode 100644 flutter_local_notifications_web/notifs/index.html diff --git a/flutter_local_notifications_web/README.md b/flutter_local_notifications_web/README.md index e042445ca..8dd806ebf 100644 --- a/flutter_local_notifications_web/README.md +++ b/flutter_local_notifications_web/README.md @@ -1,22 +1,60 @@ # flutter_local_notifications_web -A new Flutter plugin project. +The web implementation of the `flutter_local_notifications` package. ## Notes -Only works with `-d web-server` +- If you are debugging with `flutter run -d chrome`, you will see notifications but they will not respond to being clicked! This is due to the private debugging window that Flutter opens, and they will respond properly in release builds. To test notification handlers, make sure to use `flutter run -d web-server`. If you find that hot reload is broken with `-d web-server`, try to test as much as possible with `-d chrome`. +- **You must request notification permissions before showing notifications -- but only in response to a user interaction.** If you try to request perimssions automatically, like on loading a page, not only may your request be automatically denied, but the browser may deem your site as abusive and no longer show any more prompts to the user, and just block everything going forward. +- Notification actions are supported by Chrome and Edge, but not Firefox or Safari. They may catch up soon, but text input fields use a standards _proposal_, not an accepted standard, and so may only work on Chrome for a while. +- Notifications with custom vibration are unsupported on Android browsers. +- Scheduled / periodic notifications are unsupported. -## Getting Started +## Using the plugin -This project is a starting point for a Flutter -[plug-in package](https://flutter.dev/to/develop-plugins), -a specialized package that includes platform-specific implementation code for -Android and/or iOS. +### Initialize the plugin -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +```dart +final plugin = FlutterLocalNotificationsPlugin(); +await plugin.initialize(); -The plugin project was generated without specifying the `--platforms` flag, no platforms are currently supported. -To add platforms, run `flutter create -t plugin --platforms .` in this directory. -You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/to/pubspec-plugin-platforms. +if (!plugin.hasPermission) { + // IMPORTANT: Only call this after a button press! + await plugin.requestNotificationsPermission(); +} +``` + +### Show a notification + +```dart +var id = 0; // increment this every time you show a notification +await plugin.show(id, "Title", "Body text", null); +``` + +### Use web-specific details +```dart +final webDetails = WebNotificationDetails(requireInteraction: true); +final details = NotificationDetails(web: webDetails); +await plugin.show(id, "Title", "Body text", details); +``` + +### Respond to notifications +```dart +// Handle incoming notifications when your site is open +void handleNotification(NotificationResponse notification) { + print("User clicked on notification: ${notification.id}"); +} + +final plugin = FlutterLocalNotificationsPlugin(); +await plugin.initialize(onNotificationReceived: handleNotification); + +// When your site is closed, clicking the notification will launch your site +// with special query parameters that include the notification details. +// When your site is opened, check if it was because of a notification: +final launchDetails = await plugin.getNotificationAppLaunchDetails(); +if (launchDetails != null) { + // The site was launched because a notification was clicked + final notification = launchDetails.notificationResponse; + print("User clicked on notification: ${notification.id}") +} +``` diff --git a/flutter_local_notifications_web/lib/src/plugin.dart b/flutter_local_notifications_web/lib/src/plugin.dart index f7835144c..a7c98b429 100644 --- a/flutter_local_notifications_web/lib/src/plugin.dart +++ b/flutter_local_notifications_web/lib/src/plugin.dart @@ -82,7 +82,6 @@ class WebFlutterLocalNotificationsPlugin // See: https://github.com/flutter/flutter/issues/145828 final ServiceWorkerContainer serviceWorker = window.navigator.serviceWorker; _registration = await serviceWorker.getRegistration().toDart; - await _registration?.unregister().toDart; const String jsPath = './assets/packages/flutter_local_notifications_web/web/notifications_service_worker.js'; _registration = await serviceWorker.register(jsPath.toJS).toDart; diff --git a/flutter_local_notifications_web/notifs/flutter_service_worker.js b/flutter_local_notifications_web/notifs/flutter_service_worker.js deleted file mode 100644 index d8b6a3acb..000000000 --- a/flutter_local_notifications_web/notifs/flutter_service_worker.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -function saveMessage(message) { - let request = indexedDB.open("flutter_local_notifications", 1); - request.onupgradeneeded = (event) => { - let db = event.target.result; - db.createObjectStore("notifications", {keyPath: "idb_id"}); - } - request.onsuccess = (event) => { - let db = event.target.result; - let transaction = db.transaction(["notifications"], "readwrite"); - transaction.objectStore("notifications").add(message); - } -} - -async function _handleNotif(event) { - let allClientsPromise = clients.matchAll({includeUncontrolled: true}); - event.waitUntil(allClientsPromise); - let allClients = await allClientsPromise; - let message = { - id: event.notification.tag, - payload: event.notification.data.payload, - action: event.action, - reply: event.reply, - idb_id: "flutter_local_notifications", - }; - - if (allClients.length == 0) { - let url = `/?notification_id=${encodeURIComponent(message.id)}` - + `¬ification_payload=${encodeURIComponent(message.payload)}` - + `¬ification_action=${encodeURIComponent(message.action)}` - + `¬ification_reply=${encodeURIComponent(message.reply)}`; - await clients.openWindow(url); - } else { - let client = allClients[0]; - await client.postMessage(message); - } -} - -self.addEventListener("notificationclick", _handleNotif); -self.addEventListener("install", event => { self.skipWaiting(); }); -self.addEventListener("activate", event => { event.waitUntil(clients.claim()); }); diff --git a/flutter_local_notifications_web/notifs/index.html b/flutter_local_notifications_web/notifs/index.html deleted file mode 100644 index ebed62692..000000000 --- a/flutter_local_notifications_web/notifs/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - diff --git a/flutter_local_notifications_web/web/notifications_service_worker.js b/flutter_local_notifications_web/web/notifications_service_worker.js index d8b6a3acb..7acb95265 100644 --- a/flutter_local_notifications_web/web/notifications_service_worker.js +++ b/flutter_local_notifications_web/web/notifications_service_worker.js @@ -1,5 +1,9 @@ 'use strict'; +// Experimental function to save a notification to the IndexedDB database +// +// This function isn't currently used but left because it may be helpful in other +// implementations of this plugin or custom needs for some apps. function saveMessage(message) { let request = indexedDB.open("flutter_local_notifications", 1); request.onupgradeneeded = (event) => { @@ -13,17 +17,29 @@ function saveMessage(message) { } } +// Handles a clicked notification. +// +// If the site is open, sends the information to the site using postMessage(). +// Otherwise, open the site with notification details as query parameters. async function _handleNotif(event) { + // We have to use `event.waitUntil()` to tell the browser that we're still + // processing this event. Without this, the event "expires" after the first + // `await`, and trying to call `clients.openWindow()` later results in a + // permission error, because the browser thinks they are unrelated events. let allClientsPromise = clients.matchAll({includeUncontrolled: true}); event.waitUntil(allClientsPromise); let allClients = await allClientsPromise; + let message = { id: event.notification.tag, payload: event.notification.data.payload, action: event.action, reply: event.reply, + // This is only used for saveMessage() above. idb_id: "flutter_local_notifications", }; + // If you need to hold onto the message: + // saveMessage(message) if (allClients.length == 0) { let url = `/?notification_id=${encodeURIComponent(message.id)}` @@ -37,6 +53,10 @@ async function _handleNotif(event) { } } +// Listen for notification events. self.addEventListener("notificationclick", _handleNotif); + +// Normally, a service worker only takes effect the _next_ time it is installed. +// These next lines make sure it takes effect the first time, self.addEventListener("install", event => { self.skipWaiting(); }); self.addEventListener("activate", event => { event.waitUntil(clients.claim()); }); From 88b2226240f5b4e98fe2e8cf0be7d800fc2a05e8 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 21:40:45 -0400 Subject: [PATCH 29/40] Changelog and License --- .../lib/src/notification_details.dart | 1 + flutter_local_notifications_web/CHANGELOG.md | 4 +-- flutter_local_notifications_web/LICENSE | 28 ++++++++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/flutter_local_notifications/lib/src/notification_details.dart b/flutter_local_notifications/lib/src/notification_details.dart index b04b6854b..5e6919e49 100644 --- a/flutter_local_notifications/lib/src/notification_details.dart +++ b/flutter_local_notifications/lib/src/notification_details.dart @@ -17,6 +17,7 @@ class NotificationDetails { this.web, }); + /// Notification details for web. final WebNotificationDetails? web; /// Notification details for Android. diff --git a/flutter_local_notifications_web/CHANGELOG.md b/flutter_local_notifications_web/CHANGELOG.md index 41cc7d819..b335a3157 100644 --- a/flutter_local_notifications_web/CHANGELOG.md +++ b/flutter_local_notifications_web/CHANGELOG.md @@ -1,3 +1,3 @@ -## 0.0.1 +## 1.0.0 -* TODO: Describe initial release. +Initial web release diff --git a/flutter_local_notifications_web/LICENSE b/flutter_local_notifications_web/LICENSE index ba75c69f7..0861b3c81 100644 --- a/flutter_local_notifications_web/LICENSE +++ b/flutter_local_notifications_web/LICENSE @@ -1 +1,27 @@ -TODO: Add your license here. +Copyright 2020 Michael Bui. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 95178a5702e64ab0a31ebe78c222ea1bd988d764 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 21:45:37 -0400 Subject: [PATCH 30/40] Fix notification handler on non-chrome --- flutter_local_notifications_web/lib/src/handler.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flutter_local_notifications_web/lib/src/handler.dart b/flutter_local_notifications_web/lib/src/handler.dart index dde97afec..198ba06d1 100644 --- a/flutter_local_notifications_web/lib/src/handler.dart +++ b/flutter_local_notifications_web/lib/src/handler.dart @@ -18,7 +18,7 @@ import 'utils.dart'; /// This is the object sent by the service worker via [Client.postMessage]. extension type JSNotificationData(JSObject _) implements JSObject { /// A string rperesenting the [NotificationAction.action], if any. - external String action; + external String? action; /// A string representing the [Notification.tag]; external String id; @@ -31,7 +31,7 @@ extension type JSNotificationData(JSObject _) implements JSObject { /// The [NotificationResponse] that corresponds to this object. NotificationResponse get response { - final NotificationResponseType type = action.isEmpty + final NotificationResponseType type = (action?.isEmpty ?? true) ? NotificationResponseType.selectedNotification : NotificationResponseType.selectedNotificationAction; @@ -39,7 +39,7 @@ extension type JSNotificationData(JSObject _) implements JSObject { id: int.parse(id), input: reply?.nullIfEmpty, payload: payload?.nullIfEmpty, - actionId: action.nullIfEmpty, + actionId: action?.nullIfEmpty, notificationResponseType: type, ); } From 1bdb58e2732ec4ca8565bd5cd1bd6fbd63334365 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 22:01:33 -0400 Subject: [PATCH 31/40] Bumped melos-config SDK versions --- pubspec.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index f913619b0..80c3a0f60 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,8 @@ name: flutter_local_notifications_workspace environment: - sdk: '>=3.0.0 <4.0.0' + sdk: ^3.4.0 + flutter: ">=3.22.0" + dev_dependencies: melos: ^6.1.0 From d7450ee3efdacb2e7aa6c781f1a671af26d3045e Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 22:07:53 -0400 Subject: [PATCH 32/40] Fix CI --- .github/workflows/validate.yml | 46 ++++++++++++++++++++++++++++++++++ melos.yaml | 10 ++++++++ 2 files changed, 56 insertions(+) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 85c7093b5..5efbf85e4 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -231,6 +231,52 @@ jobs: cd f\e dart pub get dart run msix:create + build_example_web_stable: + name: Build Web example app (stable channel) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - name: Install Tools + run: | + dart pub global activate melos + melos bootstrap + # Windows has a filename length limit, which this repo just hits + # This saves us precious characters during the compilation + - name: Rename directory + run: | + move flutter_local_notifications f + move f\example f\e + - name: Build + run: | + cd fflutter_local_notifications/example + dart pub get + flutter build web + build_example_web_3_22: + name: Build Web example app (3.22) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.22.0 + cache: true + cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:' + - name: Install Tools + run: | + dart pub global activate melos + melos bootstrap + move f\example f\e + - name: Build + run: | + cd fflutter_local_notifications/example + dart pub get + flutter build web unit_tests_dart: name: Run all unit tests except for Windows (Dart) runs-on: ubuntu-latest diff --git a/melos.yaml b/melos.yaml index 69d137022..63d7b52ff 100644 --- a/melos.yaml +++ b/melos.yaml @@ -4,6 +4,7 @@ packages: - flutter_local_notifications - flutter_local_notifications_linux - flutter_local_notifications_windows + - flutter_local_notifications_web - flutter_local_notifications_platform_interface - flutter_local_notifications/example/ @@ -88,6 +89,15 @@ scripts: dirExists: - windows scope: "*example*" + build:example_web: + run: | + melos exec -c 1 -- \ + "flutter build web" + description: Build a specific example app for Web. + packageFilters: + dirExists: + - web + scope: "*example*" clean: run: git clean -x -d -f -q From a7612c3ea1cd50cf39e119469d2ba9c43d6ff33f Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 22:11:06 -0400 Subject: [PATCH 33/40] Fix pubspecs --- README.md | 1 + flutter_local_notifications/pubspec.yaml | 4 +--- flutter_local_notifications_web/pubspec.yaml | 5 ----- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index acd67a5a8..cd766ff28 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ This repository consists hosts the following packages - [`flutter_local_notifications_platform_interface`](https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications_platform_interface): the code for the common platform interface - [`flutter_local_notifications_linux`](https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications_linux): the Linux implementation of [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications) - [`flutter_local_notifications_windows`](https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications_windows): the Windows implementation of [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications). +- [`flutter_local_notifications_web`](https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications_web): the Web implementation of [`flutter_local_notifications`](https://pub.dev/packages/flutter_local_notifications). These can be found in the corresponding directories within the same name. Most developers are likely here as they are looking to use the `flutter_local_notifications` plugin. There is a readme file within each directory with more information. diff --git a/flutter_local_notifications/pubspec.yaml b/flutter_local_notifications/pubspec.yaml index 7c7d8fe68..96cb84720 100644 --- a/flutter_local_notifications/pubspec.yaml +++ b/flutter_local_notifications/pubspec.yaml @@ -12,9 +12,7 @@ dependencies: sdk: flutter flutter_local_notifications_linux: ^6.0.0 flutter_local_notifications_windows: ^1.0.3 - # flutter_local_notifications_web: ^1.0.0 - flutter_local_notifications_web: - path: ../flutter_local_notifications_web + flutter_local_notifications_web: ^1.0.0 flutter_local_notifications_platform_interface: ^9.1.0 timezone: ^0.10.0 universal_platform: ^1.1.0 diff --git a/flutter_local_notifications_web/pubspec.yaml b/flutter_local_notifications_web/pubspec.yaml index e70c9dca6..9613fa4ed 100644 --- a/flutter_local_notifications_web/pubspec.yaml +++ b/flutter_local_notifications_web/pubspec.yaml @@ -13,11 +13,6 @@ dependencies: flutter_local_notifications_platform_interface: ^9.0.0 web: ^1.1.1 -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^5.0.0 - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec From c262a1b34a65e2fd60d3675d6b59887462450b6a Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 22:13:32 -0400 Subject: [PATCH 34/40] Typo --- .github/workflows/validate.yml | 11 ++--------- flutter_local_notifications/README.md | 1 + 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 5efbf85e4..8b0641fd5 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -245,15 +245,9 @@ jobs: run: | dart pub global activate melos melos bootstrap - # Windows has a filename length limit, which this repo just hits - # This saves us precious characters during the compilation - - name: Rename directory - run: | - move flutter_local_notifications f - move f\example f\e - name: Build run: | - cd fflutter_local_notifications/example + cd flutter_local_notifications/example dart pub get flutter build web build_example_web_3_22: @@ -271,10 +265,9 @@ jobs: run: | dart pub global activate melos melos bootstrap - move f\example f\e - name: Build run: | - cd fflutter_local_notifications/example + cd flutter_local_notifications/example dart pub get flutter build web unit_tests_dart: diff --git a/flutter_local_notifications/README.md b/flutter_local_notifications/README.md index b3eca84eb..9a58e6dc6 100644 --- a/flutter_local_notifications/README.md +++ b/flutter_local_notifications/README.md @@ -61,6 +61,7 @@ A cross platform plugin for displaying local notifications. * **macOS** Uses the [UserNotification APIs](https://developer.apple.com/documentation/usernotifications) (aka the User Notifications Framework) * **Linux**. Uses the [Desktop Notifications Specification](https://specifications.freedesktop.org/notification-spec/) * **Windows** Uses the [C++/WinRT](https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/) implementation of [Toast Notifications](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-notifications-overview) +* **Web** Uses the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API) Note: the plugin requires Flutter SDK 3.22 at a minimum. The list of support platforms for Flutter 3.22 itself can be found [here](https://github.com/flutter/website/blob/4fa26a1e909a2243fa18e4d101192bb5d400fcf2/src/_data/platforms.yml) From 752d8e553768e7716557708e0010455443a48632 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 22:16:37 -0400 Subject: [PATCH 35/40] Web stub for example --- flutter_local_notifications/example/lib/main.dart | 4 +++- flutter_local_notifications/example/lib/web_stub.dart | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 flutter_local_notifications/example/lib/web_stub.dart diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index 6fd4f1090..81854fa4e 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -20,7 +20,9 @@ import 'package:universal_platform/universal_platform.dart'; import 'padded_button.dart'; import 'plugin.dart'; import 'repeating.dart' as repeating; -import 'web.dart' as web; +import 'web_stub.dart' as web + if (dart.library.js_interop) 'web.dart'; + import 'windows.dart' as windows; typedef Platform = UniversalPlatform; diff --git a/flutter_local_notifications/example/lib/web_stub.dart b/flutter_local_notifications/example/lib/web_stub.dart new file mode 100644 index 000000000..901712c26 --- /dev/null +++ b/flutter_local_notifications/example/lib/web_stub.dart @@ -0,0 +1,3 @@ +import 'package:flutter/widgets.dart'; + +List examples(bool? hasPermission) => []; From 0675383f811680e6e5fef389de4fe319b87e4e39 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 22:28:03 -0400 Subject: [PATCH 36/40] Updated example and main readme --- flutter_local_notifications/README.md | 40 +++++++++++++++--- .../example/lib/main.dart | 4 +- .../example/lib/web.dart | 2 +- .../example/lib/web_stub.dart | 2 +- flutter_local_notifications_web/README.md | 5 +-- images/web_notifications.png | Bin 0 -> 244353 bytes 6 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 images/web_notifications.png diff --git a/flutter_local_notifications/README.md b/flutter_local_notifications/README.md index 9a58e6dc6..f606595d7 100644 --- a/flutter_local_notifications/README.md +++ b/flutter_local_notifications/README.md @@ -166,19 +166,28 @@ The `onDidReceiveNotificationResponse` callback runs on the main isolate of the - Windows does not support repeating notifications, so [`periodicallyShow`](https://pub.dev/documentation/flutter_local_notifications/latest/flutter_local_notifications/FlutterLocalNotificationsPlugin/periodicallyShow.html) and [`periodicallyShowWithDuration`](https://pub.dev/documentation/flutter_local_notifications/latest/flutter_local_notifications/FlutterLocalNotificationsPlugin/periodicallyShowWithDuration.html) will throw `UnsupportedError`s. - Windows only allows apps with package identity to retrieve previously shown notifications. This means that on an app that was not packaged as an [MSIX](https://learn.microsoft.com/en-us/windows/msix/overview) installer, [`cancel`](https://pub.dev/documentation/flutter_local_notifications/latest/flutter_local_notifications/FlutterLocalNotificationsPlugin/cancel.html) does nothing and [`getActiveNotifications`](https://pub.dev/documentation/flutter_local_notifications/latest/flutter_local_notifications/FlutterLocalNotificationsPlugin/getActiveNotifications.html) will return an empty list. To package your app as an MSIX, see [`package:msix`](https://pub.dev/packages/msix) and the `msix` section in [the example's `pubspec.yaml`](https://github.com/MaikuB/flutter_local_notifications/blob/master/flutter_local_notifications/example/pubspec.yaml). +### Web limitations + +- If you are debugging with `flutter run -d chrome`, you will see notifications but they will not respond to being clicked! This is due to the private debugging window that Flutter opens, and they will respond properly in release builds. To test notification handlers, make sure to use `flutter run -d web-server`. If you find that hot reload is broken with `-d web-server`, try to test as much as possible with `-d chrome`. +- ***\*****You must request notification permissions before showing notifications -- but only in response to a user interaction.*****\*** If you try to request permissions automatically, like on loading a page, not only may your request be automatically denied, but the browser may deem your site as abusive and no longer show any more prompts to the user, and just block everything going forward. +- Notification actions are supported by Chrome and Edge, but not Firefox or Safari. They may catch up soon, but text input fields use a standards *_**proposal**_*, not an accepted standard, and so may only work on Chrome for a while. + +- Browsers don't support scheduled or repeating notifications, and browsers on Android do not support custom vibration. + ### Notification payload Due to some limitations on iOS with how it treats null values in dictionaries, a null notification payload is coalesced to an empty string behind the scenes on all platforms for consistency. ## 📷 Screenshots -| Platform | Screenshot | -| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Android | | -| iOS | | -| macOS | | +| Platform | Screenshot | +| -------- | ------------------------------------------------------------ | +| Android | | +| iOS | | +| macOS | | | Linux | | -| Windows | | +| Windows | | +| Web | | ## 👏 Acknowledgements @@ -187,7 +196,8 @@ Due to some limitations on iOS with how it treats null values in dictionaries, a * [Jeff Scaturro](https://github.com/JeffScaturro) for submitting the PR to fix the iOS issue around showing daily and weekly notifications and migrating the plugin to AndroidX * [Ian Cavanaugh](https://github.com/icavanaugh95) for helping create a sample to reproduce the problem reported in [issue #88](https://github.com/MaikuB/flutter_local_notifications/issues/88) * [Zhang Jing](https://github.com/byrdkm17) for adding 'ticker' support for Android notifications -* [Kenneth](https://github.com/kennethnym), [lightrabbit](https://github.com/lightrabbit), and [Levi Lesches](https://github.com/Levi-Lesches) for adding Windows support +* [Levi Lesches](https://github.com/Levi-Lesches) for adding Windows and Web support +* [Kenneth](https://github.com/kennethnym) and [lightrabbit](https://github.com/lightrabbit) for their contributions to Windows support * ...and everyone else for their contributions. They are greatly appreciated ## 🔧 Android Setup @@ -474,6 +484,22 @@ By design, iOS applications *do not* display notifications while the app is in t For iOS 10+, use the presentation options to control the behaviour for when a notification is triggered while the app is in the foreground. The default settings of the plugin will configure these such that a notification will be displayed when the app is in the foreground. +## Web Setup + +No modifications to the HTML or JavaScript are necessary. But you must make sure to request permissions at runtime properly! + +```dart +final plugin = FlutterLocalNotificationsPlugin(); +await plugin.initialize(); + +if (!plugin.hasPermission) { + // IMPORTANT: Only call this after a button press! + await plugin.requestNotificationsPermission(); +} +``` + +Everything else works like the other platforms. + ## ❓ Usage Before going on to copy-paste the code snippets in this section, double-check you have configured your application correctly. diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index 81854fa4e..60907083d 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -20,7 +20,7 @@ import 'package:universal_platform/universal_platform.dart'; import 'padded_button.dart'; import 'plugin.dart'; import 'repeating.dart' as repeating; -import 'web_stub.dart' as web +import 'web_stub.dart' if (dart.library.js_interop) 'web.dart'; import 'windows.dart' as windows; @@ -1052,7 +1052,7 @@ class _HomePageState extends State { ), ], if (!kIsWeb && Platform.isWindows) ...windows.examples(), - if (kIsWeb) ...web.examples(hasPermission), + if (kIsWeb) ...webExamples(hasPermission), ], ), ), diff --git a/flutter_local_notifications/example/lib/web.dart b/flutter_local_notifications/example/lib/web.dart index 4c4598895..2cd9cb344 100644 --- a/flutter_local_notifications/example/lib/web.dart +++ b/flutter_local_notifications/example/lib/web.dart @@ -6,7 +6,7 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'padded_button.dart'; import 'plugin.dart'; -List examples(bool? hasPermission) => [ +List webExamples(bool? hasPermission) => [ const Text( 'Windows-specific examples', style: TextStyle(fontWeight: FontWeight.bold), diff --git a/flutter_local_notifications/example/lib/web_stub.dart b/flutter_local_notifications/example/lib/web_stub.dart index 901712c26..0394ea46d 100644 --- a/flutter_local_notifications/example/lib/web_stub.dart +++ b/flutter_local_notifications/example/lib/web_stub.dart @@ -1,3 +1,3 @@ import 'package:flutter/widgets.dart'; -List examples(bool? hasPermission) => []; +List webExamples(bool? hasPermission) => []; diff --git a/flutter_local_notifications_web/README.md b/flutter_local_notifications_web/README.md index 8dd806ebf..f6bc825f2 100644 --- a/flutter_local_notifications_web/README.md +++ b/flutter_local_notifications_web/README.md @@ -5,10 +5,9 @@ The web implementation of the `flutter_local_notifications` package. ## Notes - If you are debugging with `flutter run -d chrome`, you will see notifications but they will not respond to being clicked! This is due to the private debugging window that Flutter opens, and they will respond properly in release builds. To test notification handlers, make sure to use `flutter run -d web-server`. If you find that hot reload is broken with `-d web-server`, try to test as much as possible with `-d chrome`. -- **You must request notification permissions before showing notifications -- but only in response to a user interaction.** If you try to request perimssions automatically, like on loading a page, not only may your request be automatically denied, but the browser may deem your site as abusive and no longer show any more prompts to the user, and just block everything going forward. +- **You must request notification permissions before showing notifications -- but only in response to a user interaction.** If you try to request permissions automatically, like on loading a page, not only may your request be automatically denied, but the browser may deem your site as abusive and no longer show any more prompts to the user, and just block everything going forward. - Notification actions are supported by Chrome and Edge, but not Firefox or Safari. They may catch up soon, but text input fields use a standards _proposal_, not an accepted standard, and so may only work on Chrome for a while. -- Notifications with custom vibration are unsupported on Android browsers. -- Scheduled / periodic notifications are unsupported. +- Browsers don't support scheduled or repeating notifications, and browsers on Android do not support custom vibration. ## Using the plugin diff --git a/images/web_notifications.png b/images/web_notifications.png new file mode 100644 index 0000000000000000000000000000000000000000..76a108dfae8dc7aa78e4f1a1199c2ca52b4c6212 GIT binary patch literal 244353 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≀3Kr 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⪙-zRKa-`NAa3rN#uoEuWG&T>FT`us zoFgnLVNAA^p$2wRBcD0EOz*C=sc2d4_*7Z zvMtCtTsO=*U)z|{d2s4=PMdlwc){ywA6;M9vKEY>Dw@(OLrv=5D2oSGCYwEH-qmAP z`Yp)Kkk8u0#37;a74{sz{Z^LXwT#*!|Iml$iuHZ3a~FL#a!E*g%vTY-%A*UzLjLpN z*d;`i$(-8N29~5gKMI&|&hMTb^%I#TqP7>42bZj1|COJ)#MbPvtf3TF{|hc2a%pk+ zW>*JcOY)k4^O_U!1KaHY!ojY^@^GOo2K&DetJI0+)06P*s-y4wYhs_!s|@@pI^=q8 zuPLCbFF=Tp?UjzqkJ!$51>cGf^vlY2O2ilPg5xH95+-oui=r_fX6wp+CodYd9!?>8 zP(+Fx`!}t9O~r3JaZS26zZHAdtw}R)yw}YCn)m5bD~#?p)))V;t}%Gjj%49w#P-3C z4KEkWbf)q}?N`<22>}ye9jj+fAc@7RMRZ63KaksXW<=DnBH@Qa!j=oMHH|}R*9P0D zq(la4puw7e)YwIP6Cvul0%wYZ-9#ploJqjENsttiKQxT&6hpUQ@m?=s(z>C;ZrZ)F zUCtcKec`ZhNK+S+{3Dw)G*LRP=FBE+x-LyS`~4u@SY9N7E*?I!?wIysA`nu(GK1Ya z)MS48Dm#BjvbXk1&5{S%G$hMf^qm44t`i03cLBUA3(1#BQCR#({NHxU*E6-MohU#OY#b4>@zc4%L16 zmh$ECYW9-SU9%v#NsAocqKVRd5y;-~$~j1^k9Mta1tZy!QR3D4o}#b@*-`nwnaO~yxP+>r z!+`tpAJCI)b&rN$zOZJKOJ#TV@`{M09Vr9Cix%F$17IsdsR+jG{*4MSYI_4y$MVM& z=gd)-qL5K4*;sWKnU$KHQe5>6Wl&C}bo!vcA28rkK{FJy`EqRwigH3-{4w0(xbwub ziyDxpEYc>53)9;jW?;XR=|++T6BY8~haAw`>Sexj5x*U_9duU8wzN3wOFn;v8h2v7 z#6+Ewv{}2BpzH=MDchphZrOUS!@=!;QiR#T+AmC-`H7sCGEeeSZSfLI3b!XI(9LGp zMW~=j%zg2#MH(SK5FQnt7b3zP)>`q@dhO6F_{=(KK?fKaHX|gi2LAsDZXovTG3fFg zw_xxZ?4ZSOkIaTPy9h|nakUKK0WIwBOp@9*@`}o4 z)2xiZma@Y5s61GaEnu|k(^n*7v>5K2O3MQhr!p=*`g}U_anCoLUn%NL#bUlIT6+lb z)nQ?ErjStToS3F%rTRjXh{jEjB=je=@IV1PLuW!7Y|R;KzVJLvNl=Hi#qT-vS~AJsCz31|UO z@K*YTfVDR}o=cIF1BlUGSQnc6xpNP!*<4z>Pe%RwUQjuWqxkPsrYIG9<=3Ggluc~T zi~NecFr&8wMsH0BURiG_cj{CM>KneFBb;b?xkR5y?44)^{UC3zZQI(7gR6!7vw;h0 zTmeSXW1+QA+p3Fvnfd&5j1ie6Q5v}@nY*EPy2wuqx`PF&i%fI;I;I#_A z8=h%L$({&Inf~za)rsusjRU`agSVI1L3gZe5qMY#)XILf_~i?+uHcp7MolDGN5NJK z%CH3lo)6e+#>H4B9tIGtXf$ElFRoMht1hxV=ks;W`t%A`MZ~yZhTXv^T1L*Ft4lu-I8(8xl&w0SkQ{I9V6N6!rI6OW5FeOtB5< z8qPWySr7r_Lg2R^$V)o9ts*Y`o7y^meNT+QVo0>@={vsK{c^$Xdm_^a_)9biQ{!U6 ztP0G$FYto`@g$Z&WMSFz=$fNCuZZ^J2C!LnDclV;G{4!sVeW58i!ZEo<6tCZnp|VG zq|Zfc-GxRsZZSkCpg==9J>8TQ@%^^Fa7Pl0xgcbp8@;;0E^GuXZpLy9iSQ*4yLp#K z@}i+S=(V3LS5_jiP~e%qL{7ii|C?5@mf*;AK64!W6u*|q0%XB?jQTnM_}NpG8n_4u zo+2IrbRa*UfZqKLi$OBk1WvWhVE6jv)A_EGL61X%ynVC+z!AO?@*$UwPJIH*kV6pk zp{JqI&5i-WiWzYEzO4McNemcEB<=OlCWxX+`vSmt>j z4{~y+O=)J7y&*T2m`w(Ex{~Lt+%z>yw6!k58!I@o={W9#sQ{ewc?|_pBy#)w$0P-A zH{j!;cV|0H!J%vqDjb>EW!>RPfurdrhBoYmfulnGPxSuC?%P4}A=XevEShyff)SF2 z$U@g9oA3J>We%lMFJS6;?SzaNGT9n{aq$hIBz!N%O!(E_M}h?DX9YB0&CaC*RI%&2 z9rrU@ZJbu}%oBDTV791IA7l7`I0r|XVJxX-8MLK!(J}TZi4if1q_T z^}H_6vi&%A zf*3e;6F)t&3K^}1bQAI@{xZGWiwO9;0OMPfP1`L#`5S!LSjE!Xt+M}Gd)_?Uu37w0 z$CBV~33WCUq2gnOk`^b0Tl3<6K=`U8y8ZQw;rTf|c6O~_%F1}cRrHYG9pKM5*Sp!k zb{IGnBSuU|2Tg_TQ-^SJOZZLZvCNCV(6}+ zq(d5{Vd$0_LXZ}Q?rx-E2$7OTxqpdPXYGYvBud)(}TNjKy zqPDz2{6@QcZryIvNd$1>R%cjLN~w!UNu^9TmzC1_7YPp+D|XMcp?-(}Z$0kj7QRiq zE5z&m$^_tbwPCdm*>V5mWg4;Dk)w(n*p|L|qiw}+mPgr?z(Yujyos_{0ph>q&wr4i zfF|6&{wip|iJHQKp@+KrJ^d~nj;+u_3-!_7T zh$ArqmhKE{d|jof>F}Dw{C^Hd1(_{~@o^V=B$ZY2j~AquaIi~|m*Ku)xm;7*OkiFl zhEk_eV7P%v%3~oSSePUw6sBDn(Hw&5d*tT|ptr%4l_V;Mys9{nJj0YCInfAMLf)y!q(UcHJF&iE45GXm!VADCez zjQV!glE~Hy`(>sMqmm*a#dzz}6jjf1+$V-!54CbT#3YGnag2d7dT?ws?wzCzy>gcmIzPh~s>6-UJx3MnK^UHT}K&OzU`na7O*pvFjYjPGd zM`3QFFWF|?a5RZQdY-1ALsM`o= zj;_p1;U;njp+nu>hA>SGsaLl+S=8|HmYi`z2Sw?|+!!*LQw8h?dvt);es%tt=33k) zoOAK`34;BfUSONdI+lY4Da^`ceLX!$Y=6nvW;SBmx##57ceEYe;hbeHuE1yMuI9kZ z1H?u_qz~y*X}dZkNNZrIvx#F>Q;MKDDl4lNF<8iiBq_mj zZJDv~Wembi+fN7oc5YNZoQE8s;SYfB%|M9+u{}>cW1o`JTe`;-j!0^gvwyw{m&y=^ zA@IBD?4y%9jt^q;d)nqT2mCv2^fOTB(@V%4NgcQgMhk!wJsZdUg@Y~1GtQQ3nDR2{ zHA}^`o1zpiW5nlx3yaH}NvpiKy+xB}l-5y2r%ydC3cW~A!*e0nYP*RDfJNeU!H}c| zj`AdQWI<6c#X!8RtdFf zIUHHlT6z@tQZv38-{*y_kB<1QZ!d~kk1IMc_lKV-Lwk+XcB|;UyF2H`A`hLYgQIN) z^Ip9guY$g zSScN?RE2OfCg@Ye*5n@B;G7kAIB^in2lJX|X|a&-B`?iQpXS1(DnOd7#)*VjV&lv& zu5NWEv5t-_9;k#YM2kU0tG3X7bVhn#ika-|@P-07C4qMWd0I1SB|D4ojxw@mkse^U z%@E0k$)yH`60ccXYGISK&-wZuV0vl}Qjy_-jG3zM*UZK(D_&{D=@(tdME@ylqwJN8 zZ?a@T9I$e@90<5+WU~R*SKD}TAcKTk)8SZ|l*~;dv&8ycWHi;_IDj69WybFnJ3uBZ znk>8Fx<<2Y-R5Vs-!0vJHk-_ABH|RsqO-}2 z0=}ltf2en`g?MVkv)Ty0BN`F#t_SF?W8b%@g>K0Ac{VV_yEBjf{=JXcfIzqYtB8F_ z9F_+A&cvVt&^!Ci6s=Vs&%6^~!U4v^Y$ii@;6srdOxn1N^EqvWl}J5G70k}eC(?h^ zuJXEnywSQFb}icTm##k>eQbBs+;5*jjd1{V0X_Lu$rG$=46N&@dkr*}xd8U~4Gv~4 z5(4rVVY3N9)l8AoQX->*xrbq@*_g}xr8m~4w$c&i8el11%*aBw_X%}!plCzl@a!}o zyVh!L-f27z0kg!y(+Vu{1BXI0Lva>Z)S%%F6rpoobO2L1XRVGo9gKyj| zpM4Y334om7Mx6$v<`Whwa|(7&*I!bpU$`f6+fjq#u($-T5QZ}ZdQ)>Z%vE%Os&@<2 zHo|`SubQ1)OQ0J0WV;T$bi?#TkfFh71gn!nyE$}7pT%JYq)Ut8t(!GunR3lF6@W4h z<$fKOxUUJQZmYT zl36id@=`As;KltxiWYg&s2vbP__D>Z>2iXA*g14o@o80fjL7Va7VZgyWo;8T$={$9 zc=8B~h``)oI@CP$`lcHqSEUoP*FBQp9nQg~i7N$`ZQG~@z=%Lck>jqgFh7ro5CGCT zm?qQm^sKTcrjinYbKA7;%&}x59&LtYZfw=Xj(ca8KIjWMmC)2@)5pPAk6<2(`H~5N zgzZ<*>XV6Js{Cjt#JM%&a|HON1u`oiae|##CH@4bd`6{t{VhR&gMFmxxWlX<_b#6U z1PiS__O5#-cwokk0wfEj4C1hXKZ!EUNZ^Ip(cAZXy<#{_NKzm(00%y7JvARVB&5uF2|t=Hq=`!UeEI2ia`Wld z>zkG&(EX=h`{!vtlT<)q0^5BwFGEaC6YJiUQ^jCmXq7R1n$FDVQDQY9oI5)OWKuQ_#@K13y8x$Zcx1zzruPlu0&73$ zI|QaI>ItY#VF=zxB?5fc%sBQXN`<*Gp>l*tWm(yio;d{UY!<=7v$e^EqlTOHory>^ znp@N76SsLRvGlOS zp8eW-?0xqhFZgv7yAu~bzBD{G$^t)U4n-sJ?lpBS#-3bqUR!tl2NBaMhfD!HoGJ8_ z55(=B`G6rh30Kbbl11%m1QL;ld1H~e?7 zsqHeH=enP(dRKiPQIjDf>sXrXiVgy%_~+@wAlh&Xd7Uq#*bX&HdeoHheFUBecK1V2 z=--8yB~;4(@a3r9oQQ~s^>DM8-t5#o$`13NYQ@Hs{g;0(wX(i!)tS9F-Ks|CeFys9 z1(alf7NvvxklNC46%-k*Q>ti@n@B8P{xzrXC56%;9Oa4G?v zq4Pg%I1O0svC&5W^a?6d?fiXH2`Rvx$MSuyB9xp?;0Dd?!hj$sx#j9%*e(UD!37^p zhPz|r3qjQA+m=O$o4h$-gNnKr-!Yyvbh$(seK4owmOV=9m#3;R?*{>)C}}0sR*J9A zq#6W})O1SQSPT)LtBYO!!8rm(JO!0#G-*y)8&8>$H>urcd8IU%n4&t#@1Lvc%+R0r z9!%ThYOAJ^+TgGAPdC%8Rc=ewCz)BSd}VPmBL~M-RTklWevO1M4;jLf9F|Df1+XU2 zzQ>C@Ai?Yc1N?x!3kYbqDRt__@2irEbo@F<9MLog?H5*cL+P-zFmd*=aP0EI=DzWL zNoD1_*tqVrlDT&#r8eHN2CX_}srHvD6Mx>%oU`?85iSJCbh*jh-^1gTTg`%0OolCz0x3K0+xsLrJaA7Jof;QTpQ^I3HFcW0_wpKtb3SbBypXSUbL}x{=n}$KMD6)7Ei4niS@DH4%+#PQUy(X{Ov{sVP8? zdnLtAkiT;&z7oCl<#LsFDi3epvuh-cXgFiPoi;}$^xRj&340FwOXaiAr@ady%-%@N zrvGwKqlCgkRr>1jLVY!g(xdhPMZ&(%WCEUg4eRzY`dyb^J)dbptx1_ryMEL9!iCIUAD&cqB@YzuI867n~C z#4LCtV$e6+S=^ee?GpU*+sULl7V<9ksdk^^<(~$GV*&Aig710wbt4(L5$t*O2(!7B z{8|@>*M}P|tyo-6aBE?|Y=QS*08Y0?88EqLBCQ@IAg^ID;7-VoedVdzk62CWaH;47 zs0RF7p^d2+kDd~HvjEMBhoZzGTsQl*iDiK0fT`G-1Z@CGZ<&Ctj|K+%ryDBrA%VFu zMeSC*BTf6gKnNHT>e*WpplTfe>R|m{t8mM7F zv>2GM(Z>^^vNk_ocvZ>)WRZfmt!ua^)2w~yS`|L685~5L>y@BMR;HI7a+Re4-#8T@ zr|B!>^PMxm!xC^2+H{R~DMtgOoQ~@5sFWN<+WjuR1L1noeq&hSphgXlZY*z{DL(k; zW`Gt`iW+0GTO8@yPDWOi(#g7MJ?-yb@|8L+D?`8y4!|4h@xIv|sWQv;x;7CM>j8XY zhvq*$RA4`fd)WXyI;em6y-iG555t8PYTfXipbX6oOa9#DwX$5}@rcYu0saMjHS)a0 zit;U8{bG|DLO@NnMovUE{Vf5bB)+hw=92JMcZuIV@_TM6(gGpxl`fzR`6cHt8`DwZ z#!_}35S_Amq9X455zFZwh$e$#o!cs`tEn#E`_05b1uT2A(jtH1JlkkO)d3`66~`&t zJo_S3f^l6I;_u@(KN0r$zqQ+U{Y zJic&J@0Xs#%E-RD3Ix<1&uf*k10y}<01jaiwCD{qUob~w1}@~;Sm3!Bmn>33bqwMUG`7A& zT!i~4>&6MI>3s9DBKc`PfEnrqE)rd&ID{~N5zOutez)~o7#g0;T92#y)h+tSzFTil^7#lFDG;^21Q%$NXm2jIPn$q z)VVVW*oGOIzo-n@{T29;zEkUG(7`ILj;kcuTWrhO9utU{KF^tD{MbUrYU3`ISHUv-Z3h;Ry7+7ljeeLW>)yOYyecd};^SB3k+b@47)~ z`*fN-hXd|GS$X>cP;l+b=j79rlm;Z>ZKeRqe+dljn9X)hNk3pi$Jy>i_Z}i%iAn!58Idzo(>DVECLz!B^A4S4?!Z~3R6@JuXZH>C;j^6`FXC2MW!Y(8M>Vz*)5 z=4MhKoPuSh)mwhec@hiI}IN`#8o2s3Wni~`ih z@#b?^bkpY|MAYkx zZPT}_EBCgQJq6i~`>&WQ%lEZ_r8dM5L<{-x-{;@&RA{^!kQBdk*^!P^N_#w3fPM;6 zoRwHs0bKxineOe7U$GS431_3>H-(E<)kHM(m;AOcHaX=&wUGdAJDYEB**R@=1@klj zgM!(dRjxk_%ZYYqi&d%hR6>GlLxrOE*GGOjiZI@L6isVYl2ql1Z9Plj^!CtnZmrms zVf$2Kl~q;3N*wojxW8uNtl06Pq~(XzvH@{%ks!(GyY<>DB}WC?`15CzdX`!g9w@V7 z6@ir|i-1GDic4#X4~QOx>0UiHsaj)vE*;2&I^Cj*?}`YN-KU^Rc7Dx_bk=m{MsM&2dkHYE_Zj2ZMCwV9^tcP%aLq?&cwGd z6$8+e>f}Zzl8NC^C+{IjlDRuH8(seQU*1iXeU1Yc3xDxe*z|U4bL{9)=HgkBMGC&3 z8pDMqJ7-7FrIAe5@xp3K@L*UM()i%%7tfg0TNmR*{kw))6zFT)gf-nF>K~xUloA|W zS^-~eGLh5Wm2F+Pz}0ecxS}7gl(l8fbjwNZzz;nE+XPGSAvD0o@?Vl7z)il z+mOI77*WgOkf(W~Ok6=3HTpb2@&x%-CA#xiqMDA&R&kY9iP=wUf;Ml^SZd<+z~K;v z-3tm+-a6x2Bd5x^vP1h{nZfmny7I7eh?`o;lUS`$7I6Zl%qB5o)rF*3sHS3diC%2V zV^tb9v!*mQ8Zf1Fx$rdO16vi0dPFnb3t_?dclKx#Z*{c7a5OAPM+VuL^!%3$D_c~7 z7ovbEcJtgRH-2 z7j9q`a%?=6RtDtEgccmu57euNwQlU_;!l2S=|_L=m&pn=uC&R8a?b4Hh}G!YQ&%Rj zFA`jGMkvM~K;*zs;f@4ZO$hKPzSwF|cy#C_m!txTh)`<}JHftyDev~OQ+Txpsxun4 z2pjW6BO{IrtZuP-u?lEV(RA+Q{LeEW(rCUsL3M2WgKC_Bst`T;rK4tvu(Cs-*k)}T z6T-CC%qqc@Pc3*npbgD+2Rp@xV=t;@-Rq^vVH;*q{b4%Bdrwj-jr23fLaGSI`Ng81 zOPfIs88Fs9UaBn&vm}~+%gRZxY+zzE!TJwiAp$^$*|os7O`K_Cq>eljdt?-Endy8+ zJv6Xh2IlXVz?6|}gR3b@0t(NkG1XDk3Yno#eYEuUl`v~!!G~*SBlwZ8)z{u&eMJk> zVdALaAD6YTh_Osjt9RwaUP{vo&DcN2wjFT`i)EnN=l*~;tofGsr#_M)lQ1Vy-ADY)^OIA$ei4rR(a&8 z5_Z(0PaV(N`wDprS#QI3IKomQ}$vE^=VpHDc zhk_(8>k0BrtPk%(jhor7 zVF)uSq4y6(EUAM%czOe*M1ShOa{(!`FrG6&vqaz#O^V7pz#@$o!y#L@go+JZ;gN3x zB(CNT-h6{!X@Ps!%7zKhQfDA;gRcbaWO6JtBIU=}bRZ`|bI>K9B`lmzEu9xNZbBsv z)GMmKC7;A6cb_$WNUx>2y7Q+IFJ6WX%QUUvawaeB1jy0EZf_4vq~asz|gfQQh&blE9)(I zI+Kkvtuft^CoXotHVQcR;Zk_@pFyC%H&8`6gAv8(vbX!HOJ1HeAK0r~AgP7ixYaG5 zW-M3tMPD(}h&No8?(n6mX%e=xIFfWx4uGZl^n|jotP56GrkxJM`=*c6I9hGA{~F_z4L;P5(8-!h45MI}aF!hRpTzdR4k8$#cb4Bm7J zzz&`3js8z$%gKI=)?DkofbPF7qnFgqw!Nts&INW*{d-JM$dtD9KaMY>Qeu(nZc)%h ze|v+FWTe9rv_*ArE$(`c!U6v?HhDj7hOC^|O+(`9)lXtmaT&W*dDj{13RxK*mu z(+=S;;TCw+BFFV^=pdj$4{0&gdqEal4*`g?&=eRgYiKzkPCvch=4>%f-eS{AI*?v) z8K_)>4+RVHC^b485bbtOvz`Wt)y6@_4wTv294{jx(>Ylv^wt-JgAQJ52^shjw7aF% zFzo($1}+268uViR$70-HA4+QyHg#4v$qWuXCu`GQH)c&~lyJwx=&;}e)&kXub9#~&X`@6AsdBbZ=FoDQ z13>c8DqrkV(G7^{jT2JGh+?^_0TpV`+AU$gIg~jISi2LDf2P2*lvD^J;z;+oNi1R5 zF;#t`xdAH@!wrR} zl`->awXo@C8;o$X>9g6$!Bpd_1*yB3-IxYP)t(^lka5z%-r-+AI#3_ATCKIrBNUcm zm)veBio(D8p*K!OcyaJ$02SU=Iy=-I$CO$j^c9X|+;&!LMrZ?scv`%SX-!4;y+{9v z(OTSf8cC~H;&qbL1Q0F;md_Y;PZ&U@FZiq;$IUKy<+F1u94=2$nLeEIUZw=>V}>Qy znqx!NG(=1CIvw(^tEfWK=$Hqtj_+R3*!1KqgFL% ze1v2svBY*bo3!k960v9LZN|eH(M&PA3)0RmqoreTJ-x_^7%IGPeTg!jK_I<2oPz1# z@eX3ow{OfuqXtk(VF0OsU$!0}1Z;u4dp}a)bEfe}@*im75OaImnSvpWf-o=Iao3&o?61tvaGyv}s~(`hNZ(toJlW9k*vz@0kYSi%80HNb!gSvH9ALTuc4 z8$Sc`Tle-7XKGA4x59WKs6JA|IFB2u^R(W{{Ha}Zt<^zwy%)juR_tdI*k@_6Ad8y}*YNci;T@M)Anhp}|rhImKM z&h~cPuX6V4B{H+;DJ7f$-$i(WvdeC5{MUzU>h!L%SYf4iLhmQVvotu<(v4ND0j-`e zTpgj8K0L@)WQKU7V3y7uJRp9pB_FgJT?y6^6N|@P&u2>-Yf69s4n~`9b3A>~e0J7e zCoKM&^3z{=Sb|Abag7i@HKbx?P;KVK`U73x4z|X~&`)bYKg!6KniVI}=E7}uC|HC0 z*2n?0z<5GA2}GttnGgGRFo!u5=wV9Y(s2WhBdEe?ZzwmHvg%C@$qd&DTG%w*JxS;8 zx<_l<*78Q$f*>jO=p>zXf3~J^U$Jc53Qk~v%KJsUMNC69<4-YHwWPi*jz2rgO*@tj zJ-xi{ym)tu&3jEt7T!L5@v)X7x}lclsH5NechaE)UQwP3t6rq34p_yelYan}%x zeSKxPAia#kJt-+kOiHYT!~Nmc<$j9elc-QQ-^Oc1GiU&WEOpoDh)5*3IsyJ%lBr*I z90G7ss#?i3*Z6PHBAN^|2g+(bD0sb9sO@eg`_ZbZpG1yjYCE)a}PZV${gT+$!*K=uE?CZouk zw-~)4$L!ie@5#xdc2HkSxzYZh4j0^!%l8QG^w<*H|-A(IFxR?SLaSyoT zQA^1bo)f)OL{<#=y^&{3Y5Gz4sUdY!$oKO4$GWWHlBt=wTdY?+c~;@=<3*VF%W!+riooj-JOQOW~i*h-G^lO z0%=*U0HIrib;7-Mft&I7P)dXiAjpB z)a9}D0dn3l#_HfnSixMM8mg$d2zG+NY>pGYcYR^Ldg$Er9R&LHnT+|e2}%#K64Q9B znAR>WWlt8+E-i^Qc-~%rSTHiqU3}PGU#jR0#(;nbv1i*9>XxvxW(I)=;(t#XEP_Ju{!n<9>P zlV!*sG%CLPAOCL2yr|;JeEXu`=&5Et5I{ih;p@uiWY3k?1Vs{YY3h%ipLaO7rO=@G z(vEP{9CjwPR#hB7F?-I>p`AXY7&V$8ozI~ORdBEKNIHG3V1|IzEONi#0xrn9g@Yu{ z7}F@$n)zdk!&4?X-qDZ|%`lp!S^$2Vo5=jLhmf;5UpOwx(jyZ>ymfLZwlCoD8FJ5C zM@O&YA__nc{;hakw*!59k?K$Xc!185Q`l1GXoAmoUPSlzd9Q6J;FW5qX}vMi7V;EU zh-oQ$d6tv8;67yA%?1UNH-T&u`(SUtsc^QiSZ)2wRC1+;v@)(z`)m+@PG*^NeP0MI zMtd_}>?$l}9l#g?7PIXmclL4yxv;x@sd+g%T3S_Yr;DIAGj_dspeD~Q>yx-_XM@TE z@&h2N+oKAu@$E zJq&0qK@J0O3XirZ=;Rvo;>0vL8gqr!1#~UkTacbNIwWNY!zMAuSV-6I#JHGxLb=U5 zPfZ20iLyTa8$bkl>VyH0m0l}~9(A;uY!lsN zMDE(qP{E&1-#+nL{y-V6)n9xRx4`z5D{LjBE++WG+}MaBooLk_*;tUP2@s*VwV;NO zVB>wu`VVs9$7OzFJ8kE#$HSUseqp+C{+xHe7Z!l+shuxI(@^eEAIhGmd@jT@h|kb$ z!|ghDL`OO1#z%XznHhF2A-=gd*2Mg{4ye}erUapPyy_itz5BilE^Q{jdC2J~s^mJf zT?EQ8PoA|?qkI+Re5h^uQ>>T1=BkGJr2U7Oj)&PICAz@>nyb1wHDE>D4->FJYBP}1 zx^WxAcRUnh5|dqim9_n+bOEk`=H{IgDdj);U&Hq~6bqVuC(@%d&;{Rm4)BlAKJAp@ zXE4c}AbaY|?(+!?2Ypsq);PO#7ZA2EuYY1QAU6blzX(|ETVp<_&(jlh9I{;O>O!Q< z6dH4+T_cNx0k8ZZ6<*+@;G%k8(c!IbD@qB8{lTd!%ej{795sKLhW>A+yGO~*riVZ-ezD=43<299Plr3tn zBbA9jdT3S*(4o_gq%y!=E^>o2fvJLw)cU4Ut4+6CFibfsmF8caaw55i@{rnnOW%xK zI)@+Go`gKH5Y;SY7lG=0gXd@fp|d1qdy3&z8qLS%NnPOf2mcB0&b|O`@f^YTlLu?g zBc77ytY%^)vB54_mev`suu<#*O!aqh-CT=P**RffLN{<4D<|9i+z5!bxa3?k<*c(o z1pP~t)sZwL)~OlLBKnwj)W_o&TSd!t9jI{vxlYHo)Q+sayjp`Qk~e7OcIANe2I@`F zV&g{J_4aaIu?UR}iTN+L(_oi_A}wmkI< z9-%H#!hN5hFkR3b(thBT;Lh-jz*17uyWOZ8CX-a}fXG8{TujFyI|c&7xmJKz+q#fx zsGs(o3Q)ugPV8m*Py05%AUrOL22?GKk$Q=(@nX;qM{%#K&2f7!`{1jEBU}foNqe@p z{K7&~b&VQo41V);CQK* ziGCmiXgX-BE$Djf4&?j)Gt_=u9|F5V!=-@3>)_ylNk^1kvpKK|u^HbtH5SmH+D~_G z0FtR{L5=(h1@uJ$mlx$^G<+t-y0D0i#E2`2B;9DauW_YXTvBr9>Izwgm}#h&SA!}g zEK=7z;YEKwq}%T)QOtpN5eJhg<%WoH@C~wy;WIbXR>jp)v>KbMgr+6oFHF0&o4Yrd zySJM+)Nr*T6gFc$;ha%V+`p6|4mwh-Yj&SiUx#)raqvqTqo`=k6?A)cQE7&mlWd>VA)E1uBJXw%tPaVZTegq8O6040^(w;=NCJ^!FvC{nJRWsV= z6Ank1Ij@6)Qj$ov`%~`U$N9eUka_^r=rLGmwMcn6`y)tu9k{$PDyRv}EOPo0EjNYq zsx&MkB5~d!n@^+_F4`Px26t${*)5qKR3ies_d0xalMZWaqt-UptP>tx5j_;`O&&>m z?ttNW7_L&nnpFk(#dCPf`1)R@3LK=EB4Wa9?JFcL*P6J8N(2bF?mRyRcl#7zC}!y5 ze#=fF;=24b^<8MT(c&UW(`+m{>F&NSPL!NAhXC%;C1#yXvHdHV1Zkl^-Ir4rp|=Hm z@~)1Mr>*^ps3%9t*1soCvp3+4+&c#sDULBJ8gWQ5@Oe-rOM(dCTS{cT=Ow62yzBt< z7R{p#i;XpV)UI+~I$lp;x?8zBfLIpLyS-vLyoHPSN6VC`jSw#-CC|W(;iaSs7U?<4 z`3kx^EJW3`+XLjcpl_>*36RJL-;^8+8Zk-nQU{al)^Agf$1nen5cav|MdH7QU3b3) zWI;o|`BYU+1@uVKvoGyw_14bfu!wPpZtoqsh>=Q4$u^h9HYHhL_8LOT(2!X`I2%F` zza1gYaVUB^qGcouWs7gswWS?G{ocG_U2#vQVpNYQ8(-fKY1Tyj}wlhi*+#g*>R_^EZcwTSwz5Dlr{)1Gk% zc(EZXUBgZYVDvk{rhiCNOsLc6<^tR>W0$?4B`<}!MbDs-EeuLZx>QI5|8#?D*^nbo z#n>XDr?-VZ!r{o4{e41$ulAml0x2?ApC$N(JflAC5M><(QSm4;ft&1yM4Z*EARaw5 zrlnuX|J-M!gD{6+gC+lKE8gw12453RMevBm1Wr>$eR-ODe+hR3pyQ^_y>8UCz*pGR z7fq~pkGL62GGAKo=gGlQ`$maYZYpMbwK1#|OsZrJqX*LZw4!7|ge(J8R0^aMw@x(* z0ouD{wQbFYO62U4Fjv|ki$Ok_JS`yL;LQqSq7ks!YqGLau}DVNbN$Bd6xAY)eIbgg zcUk7pUMVVE_*AWSKf8wzXBIYYt%uyl;Gq1Ol$Q1@A@wW3TP}rJ2zWT1AH;-xu^kv% z!JwGns_c-%(&4^>r}7k&y6I5jFUCbuJGypx{7tUUDg3nF?S1VEMynxxvH#Z8+*Ai4(#RyJTCmt!0pocK zd@z0jJ~3S2FO)WBAnR(TYuLg;eU&>DI2kCBMjO_UIia{*-$yzkFjuiGB&F*5ax=}E z(`#)j0?w!fCfybgabUhf7(#=nEPjQFfj_yf$9{#!JfZ7ik9~ECO2g9VFZsr+pb}Un z7IEv)r%na%c_E-0=@7-$(dhRceE}Pd6^cpg2G0;nGv0K6H`=-qA2iMyZc^ue2%!9L z``VbY<_zsG`nmK<<~~2*vGgzCX#Mkh>*Lm!_a13Jf!AwUJP_zzUdZWN4tCC$zZ2j8 z9@XyoDRo__|K}I*vln?G4?dr+)c?+Z-`&W5{);{M&EFHgU?IQD!*|!MRQDz!w-kPx zd|&stKAmX>esR3deShe8-uZHyee;$(<*J)Qadt>wW(74*^4aVntPU+DzmpM;xQ#7{I@i{v5MaJ)>^vzvVM;;6t`8DK!GqO$(xah8BQ@g75E zx`w`D+=2d*-9>~ZyR7VxI=fJ1DB4L6xl84i9hzCYTv=&cw`5=##SrO6^$v`{hmXCQ zQJhJ7=RJv4Mmk>fk25atQir^h-*B{OGav>Ri6ZgK*OtT@vK+wYm>l7gR8%&5>N)a{_cI1^5#BvZ549I|3nS?^Tf ziEk8Ys7qSnkYW}?@RCHrSw*SOw>rkWBg=$a23+H^YUC*{oIH~qWea|CD`Tn(hg(0qVd2FZ+cKHv3cLVrJ$DmTepphTYs zLEW9@F6CCgk{TGqM9ZRY#Uj!w_j^)7R+1Q&n+2ZVfW_mYcQEFz|0%3J#OQz=L z?*4yKfd0Wr)TBLgulRHxCGtrm1j-QyAhn+cpVh+*cf}i0?JzgeBCYaDIp@Ym_gHBW z_=Fx-*^dBgrv=zMEP44dJ{enweYiR5x_K|@s5==!!X*#OWOgHzacx5DO|hxCvBy$Z zS@WuXQI&@!qd7DoIX*p-NL%wv?YIDwO7hE)|8{P1tz(CIHSOl3l8`M5D0yn{KVtOX zT~1C1oC}|#@h`A8J(53N?FS?OUPx}B^x7_5-EBOeEWUUWaucrkw&aXz;Ev@%6-^*FyETj#Q6i-%lmP@?y`pr)Gda; zoebZ~Lmqb?)k7}g#l)UwO$z;~dj6XwaBrz6mG8ch{pG{y`&7TZx2=QI~oaz~N;-w+^wCdO5als`%0^H{s&__qf zt~90J*r6d;@3zG85~^^ajY_byWwFxXNQ;RrNS56Ri6$~jxZd81z05NMkCB-I>Y2*&+FUJ z76UAW0DU)J0lQ`?*PJ3mH!{`=TIfxX=!+HgJAEq04v@F$rDG^NMAwcyiGW;5;B+8u zN=Gww^%}hYoiHmjqu zy{iMf>92pjTd!aN%tsnlObefJ;PZRC26TA$7MI3-XrpAIF_J*;Y*jnaw;(##ZVtj% zS>lGqQwIC(TM_E(2KJ?+O$lSo5Gc4&<8@q@9>=+OHXp!}8E=HlQm?5qyUz(1Rr2F9 zBn8<8RA;1AFx4Lb{gP?jhpIT4`*On++h5aeQuq=4jo*S9L@j59ZDjHqv-p5Zc|9it zkksCmzv`@)0|%Y1K6Bpa8Vi&_i@L8(4ZhM{+_;r?BL&?5>x@ScuRDkQbuCJwO5X1~ zD7V!#$o+Y_iX&s2s?D-Sc!88VB?E? zpdC)+0vucuE-_&)kB`U|PqrK>77&5-T4#XW|IBswMepV{6A9#aJ{ev2-F@8&dGvVx zAlTbs*7jKO{HNBR<+c#Ax`2V1iJrf6U+RDY@$awq!TDWp9)>r8dFW<0xFEP}f3Eva zXULJ?#;pRw_vF8yg7>*T-DpeI?a@BYp%F~uVDjnj)5xV_fr zgqfFUDUP5>S6^S%OdClmD^ex!=pMJ>+8cxV8i(x6j#U3_u{ey}U2zz4_J$|#luBX+ zRKNHwZ~oEVCerXpp#lpwBPdmZzhr=4hm>_ApyCYNp( zx=7g*taxQhBs01xlS3o4u`21RP=Ee50-eK#(Q%Cu9P!VNewu?*C&B~ukl9&fwTG)l|BtEnj;H#6|M)4A3T4YGjukSJ zJt~T0hLD||z4y+_<`Ci_JF+?U$liqPJx@AuaO`z{Pw(ID^ZWj8H>dGOr*k{!ysp>t zx~|9L{%9|ZdKnf_iK{Y>IFME`AirjOjqtoL)4XR(viJaXdpmDxie$A!5HQ$lv+QIA z)z%lC7mca|FybU!Rg;~bZ(#C8d*)T-S$33qnA%I8MMSFvJgr!$Ac4f{(mrqVA+o%Uc7Z3$TT$lTYW>xMJ{2RmuU0Cy7>IK>A|`q} zag#svOJ`-iSHw721#CAJ=H}9+!L0f6fM3se)0*yL_sC_A%B~i;;ubDr>@TP!!^%$e z?fuqk+cVE{{L_Zy*G+JiPLutGpvEWDVJfFrXg@|Czl%>|Dh#`gej~`;0}FlcnUNTb z70!tTc7^R^1%3WV|JiQ6;Q{s1ZizkffXRP%NO5dM2ZR*BFF zv;QimJC^vDYm)tW&{7BENo{M?e|Oo%NQK3VBV8X<>(MEB-a8F_xQ5S?A(ln*VDVhh zoW}5yD6=d1DyG04Z42K!^gm*gY*V@X({p07bft0e)4esB(GN-BzJxiy+D+cYH#~y) z|Bbz}y}HIx_#DmI-PjE@Z0cD$)kPx@u2Kt@T%zsIsFsGK=bqtYT<&s69Y~R*4++h3>>2&Q6oMX**pBE)b`}8r%E8r@0UtqpdIIbOcOKfVK z1g58pc-~C^i?u!YS4po7ByfA8`}Tc0(bQjMf8o8A;}8IGX5wa05)+0WzB{C(ibKsm}?~&BW0Al-J`8r@);lqI>#bM|UD$a>S=ndcG9-vi8NI z-lhLxP*nyXIXCO8mrX(9@rd*r-J*lKZrI*anhU_JN-L@ZLBKHSXBl(L^a48|P%mjp zW@m~Z6PHtSS9eA)N`Qzc9;f)kTjouG#AHw!Hd=)u_h7y^naloFr2x3wsDrsyR?nTAF;%#xZHa{ri537IMBcX99nua#H7Fs83qs64p~k?$Y-2s;~)_};Z9TIEhxddX4P;Fwf{&OJsHb!ySGv?t#BrEg#J zdyc!`b4<96_@*l}#jClY&>=U@7Rvyfort%i?-F0*ESR+0f9F88cMmCF&HZwrpZz!{ zV8q{-`_LN9+T^p@Ut2S8^#a0^94t}b3xhe5FiSfd53FQ@ZTe7zb!6tvcGmE!dzUZN zHH>+_bN;n`P0FU&56cM>AqXQNParJNO1AmIjoOH)DcTDRJT_u}_1f5eH=y=r@DR>u ztVh!gdfDn4i>ie&m-O#qV~N_SIn5^_$SRu1u2+J{N_eRym@r?nLqTi}usMVm7|3e( zUfwJ>C<87>I6U3a&ol7YKyWDHlK_RMQ~XA!<&!~&+o}5=xbe7hF>R*HMsbVgK}=(z z{3DKw3RF&8WmgG| zE4o<32r}BfemHFLJOF)JYPhW8*CQs}aMag>{DO0W1P2Mf^>fMI)(d-|2cBPdhg**r z%p;@hFE2AymURECpc{}4RLg0JOuR9*ICeYJld5&wdhsWf&rE{M=)lt2?Epsa1>9C7 zb|3#^$w_JJL6y%+vQ!@kQnwgK+{B*NVtMUP=XHI$&_2u-Y_u&Xp38enXXjFxwf-yg zXN$gLD5*OE+sh|CQm1rMd(0!d_SnKQCjN)EzXx!3*)l|sBmOx9!Xu$VfXw`M^u%^v?K^(GuBiN zucVG68P>j%r0*lKRg7zQ{ZM3?E-{AK0ULRrqU$=fF#&^w&)C%#PjdP#7Z}1aRbTSc zKoDtf3qb4ee66{MT25V>vd4p`O=`IBm6}nCasl07-V}oUj-J%=zW@?wp=By*0iR_O z%oK39HMH*evPF8Pufm%w7>u&rulmdDs$LpQy94qap!qPK-M^n0`p#-kP?vRS|;aT=EfkjWbaRL0Y&x%p*AV*-p%az4Q$?_HH#WZkuq>YHY z=eqHB8}P1K8slZGkaPnR5#y2IjLfZ}zmmulllRc#-q!}V?T3zZ=$O3|FL@3S#{~sC zc^b(Rwj7xknM7)~w5GonMVh`86^V~6qAJM^cr z@@7@~fyk(lY8j$812N;;Ksvqt;E!N5&WBI`ga>jl4RawG5*Lb-Iy1s=<)_DRrmIKW zMZ@C03n)P`QBYO+urjp|^g}hqo}OLzA=SeXKGSZO1F+0-h!N?utx*Hpy2(PUmdzxE zYt_oxA#>EejSwfSbGZWrjnK!;4|z#%OE%Og?ilHBl~TX|o4 zKcjR?33(cgA7nq>m2YrqY%xJBd`|sI{6QeH3wNr_5P9q1Tb{ z5wr~ou15i551@E&$`Sx4%UEhDx=!z@NNdx#t=R=qVvX3*P`7yu=PF1&U9PQ1R&DCugKh6I_iOoKL!<(MZ5qw@`tJ|ar!@HD2 z?%w|F8Yf2bc-z;9_-M!IWUlq}(Edc@<_AouP}7RaQk`Sa(y9O1;6OGIX9R&$W+W`hZ3 zQtdh;jeg70*D}QLzJr90=BQCH>>~?Z+&|*+xfjrSTr2exJlEphkUa|zDTDvtfGPr7 zhI#!x?LZ=5mzuN~{}WIdo-du4uTJl_UWH_Crd@T_V!+ryS(SC(%VyXR%ZW`{I&EB3 zB)62@RXCQb`Yhx>JXF5?>*65RA6~HJF=(RVSIIW1GeXje3AzaMKOgW|pp8l4c4`>j zZ|~tblhv5{{Y2xm& zI?PRp5xF*Y4cB?D-753GfM$5CI@%eu_N}Zuj+}vSnLZqo&!Z9=sJwq<`Z;^q^AM)E zogPrz!uV6#G*K=px{Vreg#P^^{I)IDP}4?o^VS}V)uUHAO$9%!|0=z%T2Rv>brNs^ z;vu6jhK&+Aw=Ya%4})%@bN{kK-zyf-4I|0T+N!zO_oE;bnAnvkbBT`e1?cZ+ZbXX_7eZVmkCI{DM=z`k73ij zcq&NVxO@&EN}c!oCpcBM^g%GwB#N+dhKLQM6vF{S-0|s$rqb7>4Na@7tDgo22I${Y zhvJ5?#W3~rBbPt4A#$X_h@;y^)JT+rW8f1&e5WgdmuKD6qu5W1=F(1e@^O(#%3m*p z7|XudcZ}rP*xe1NbFHVgU(5oc^`s*JPunDiB{8=YQkU2Y%=Q3Htq^e9t`0ej` zMvdhbBcT@R?=7MCHd42FqfGjYDhQlamux`S+2?Fb2-0H2Rne zwKXQ9?_k*Q)q$H?HgcIHY^Bfy2cj-(?UptR3o91%Ku^OzCLyz_`7b{$u1fQ2{~YFtPFWIce157I2*cTtVAHtgnPb_?}N zaaoehByIe>?1Sr}#iGPLs;Za! ze&`*Er^#AeT0a)9^F<9nZao!Xr~SKtUt@ro{omw8+uS)AvtAGs&{rTM&73RE*%qT? zK$$UPYWVVs-R5 zpv-w?fMtoUyP^M5BbxuK*>w>)8{RKvJh^YUhp^90fn1FEUlpAEz+R5*cc3pGO?oZv zZlZh+Zn7PuZ$)b;J>q3?PVK!C2Z;RrQb<9ekIe2bE_PVIPNqy9es&& zz3++UJ4-OYs^Z*pK!>o5NO-r|6IGfR;0E|#zaraA_cSq;-Vsjx){RI;3(=9!#vPYb z$v(%}GrJaa8E9!wuSnEvMJ2HcjL6yOEw=QV297aO3+ILglbQQ;{;Y2(|B$qyZwI91 zw^7r7%GG%&!90Km0rFpPNr{O5m*Oh=mG`S6yK{WcCiF>^UMhe3Akdbs?!K5#7Kpd{ zCZO!zB0)xJERWJx;rzT#!4p0(9ML%f0Gigy$>l`tCu_iU(15Y33Z ztE{XdA|bYM)pry8>GeY!=>~g`p`g=G9Uan}&bV2u9xvA%jmmNxg(Jya>XOzU_CjH% zRIukQ$&XJUjmoB5O4GT#Z>my;>U}Yku~J9ELZDimAyDF{CuH*tenGlZ_D*YOM0Wa( z!_jLdrSxWql|2=LU=_xlGA==q|FiWW9l1`IT%acYsGv4Tha0@djk;Q8g zoO&eX54N8-Ij)HcmFk06V*=c!!m>+|QvwR=#3V8mk8O(P2cV=uFjTJyl~*HvVruV) z)z9p`Y)qY-N9W<1wO*@Vdd`{&Wh8z=U$FI5ne*i)QB0Zs z+Q}?m)yzE;Q;bRZ%{1GtW&#pn38@^Ew-<8vAzV|qB4Z*4h^l4uD(>2hB$g&p=^kQR-MjEG2p ze|r4^DSNEsQF%%R>{A)|#GfCdK_q&NT0~J1@R_f+^%3&4oG|e$`i3Wil=u)TgXOM9 z9!KnzFJQe6%*+(p;FM^NF_*~XGXVK_YMl93ar?Wc&(2nq$oE+6g}rESD8Fk zmR72?!VmvOcva=w2b(>6S6cYzoN}9hG$)0eLzdu~ou1fwcl7lav2$eaEIf( zWRI;bs(Sb1r$`Hn#<=Q%fxE-QBf=sgD|yKVtEb3J3)q}_N?`=T@Kr&uAds}_M zm44wD7z3s?7z44M4hJ#vuH8}-%g=+8hY5Y_W>YfoPA8)3^k9+@sZz#r{aB|AOI0V- z8BvDUKGXo)P~f?cP_|Y$)f^*MYoE|f2zZvY+$|`YqSQ^RuD|Q>ALj*n3t}%P=o5rD zDy)S(#>rGLGiBZqnTPA@O?z8Ym@~G_)k3z6^}RXwIzN{|A3+QLOunxp>=x={OlpSY)S4Rh8v&52eGlb(^+FJ@$pO zx%gvPD6CL+Vy>rvew~J{u3UwZW&FcL*2HCWSD+X$?lwBvDl!n6#xq)Y8G543B;2&U{M; znTmK@0(fle){01q8^a?1UV9)bO#%HYUFqwP1v|bg0Hc=xDKzeg?Fe@9$Rg`*V)R-!^$CFo14~+Jwtk&w`ci!dU_IHLxGKuQO5Dx zPsrHaW?QSmA36$8P5@e!L|M76smWAb`YIf9D0 zi4jpHCCejJO@gg+blJ3Dd}v$!6W2BR7z1i;49H`~+^XG~-<&jwbwus;c>JpXkG-CH z%yb9QgyGP?|Ji@?sf})3Sw`I;j#U6ZEvwc`a#PxVJ8T)=8@0F&KF#a(7CZ*Gf{T5( zUtE4kvE^6LrlaH{j?@qM&51lBbI$NSx-j!U-iysZKk@F)G^C@1g!guIL#saLpvX#} z7A5-{@o(gO|_ zuEucoswl2-4$M8NdvE}?JX@AL^il#-WFaEAKYNp_B_~Z?Y&*Pf)RphV#1M-}N^YJ- zqx4!G(`Ss8b>! z+YV92SEL6WrHP98u)2!W5GunjqQC$vpwfJ0xg&l>O&}Wvf%bnOnEXLO!Z43KXe0EU z%M!OK)zs71bMkcR?g~;LMrS%WVuJ?=EKb}Wb(HtA(J7h_?yHgCXSnz3D5>K+>l zgcjoGgU@{abTFJ2;n zNw7F_F10HuxgSrmR}m}K;mqUnNk#ma&LUaMqvWe%!TJUs1+2XJcvYLe(}cmAP*UL& zov$f2dpeH5Rb~poRrXXw!t>|E1k11vt65uH+b4d1>bm?OmQ}0zdDnGtF8ai%OB2ig zO<<79d6OVpvCeHfMYq=82{WnGua>d~uAIt5E{cgjL=w=)1rd;(bb{5Ctkk~hBKC@8 zck#F-*}e6A;o`T-B?SA2@sio^uZ3T#J9dm`KeF{eLHxWTw#wG(miU0zz$Hd~SWByT zHsV%TKiSwRp8DoG!86L*Qs>Kxxp}WuVj+gsj%YDZ%+FaJQ_BlEfzr9i_WN9DQ9Q%) zq1Vl<(mw5;TrSW3iXKmt?ovO}cM-W)Q``K7&F~mfi=N-ya!^`ma*dpG-*Lc9a@#F7 zbRDJ%iHJ)Y^QTwN+5mwc*GN66R`woiw4NBzCBHzP%l?9JG7P`xzc$CdSWru5>_jPL@foqb zG*TyEGdD~Y8OE@j>0@{7h0}Uc#ltVv>-jgj2Mprl!S+#TXHc7Nv+U0I9m&@9Aawo6 zc&2Og^#^6rzI4LqpAnSvsY&i6FVj1o@v@Bs<9+p$ivO$c{+?$Zf$#uR3);RZOgDB2 z3j3Ui?L(fnv|cIr?AiO@$@9=4Jh&bTTFrrCEaJK6^g&YoTkFM-rSgOqQrNw_%ILEH z78q-^WPbblBTlZWjy@*+3M2Y^3s_9!>6yJJO1bi)e+v6W{u@;ozW{!A+wv&>y_(SK9^j;e2k#y>|KV9vqceFk#LN1RwUu-R6 z3&eUd!#&@fU3|xDKX%i%%=yy$&p6>e8xVGt z2c4|UmgZQCH7HL*EVy55$Av9wBIz{rD++6>ZP}uP?;ydMYdrKtPJGr517SGsRscPx z>Dk*olXQ>IKN|9_a&PsCa{h~^5@0^x6;bKHjM?c)Fz{Qu8_k-H;jm-~(`v zQ6*D}wN~_&brFcB4+#r{)cZ6*nFsCG=H?;oeA8pe`Rk6x!J`w{!Anp=?9RA5sbPU; zfJMHxW?~*$->XHD!pkfc2WN}LTEr8y@ruYO?1-O{OXeNAE2 zk@SNFVB7Tc^#L;rgck#8#W2rP4=`>@Ht@+v08N#Yn2E0av?gt63-gd#{G>|0M~UTZ zMuRQKJ{^*KvN64hJ}2+ST_`T2wfC8UTH%idlfaqv=~EscBq}Nz zRh5C|y+=DP#+w%6tjXmBt!rC`+;p*#QP!KfMtB|zqd!MwG3H`w3IFY!p5n8SD0}RJ zQ_-E&syCj{L3su{&%TphBI zJGGAw_~b1RN!gubRLoF>B&6D8)@CW!L#5S-sq0rCo;U~HbmgfHeDT- z{V#^`lt}W)zn!z?<}*a9){PH0Zk}Wv&m;e4U(bN{_#I56HV-p>qccy=M|Mr54vgML z(AHYWRBUo*p3mYqz-2CeE%`87GGGqUBx!huNSypuEDV-=u#2*%`(<9u7yr^?PUF$o z`%(u&OFeE2`(+ndJezwzaax@W2m{dK6_21yet+y+G8s=>NLJxUU4JYRedC(}5sr!l zhd=gQYVa;&>-t^8(TVddpgM}E_1Urg?|-nzP8hDQF^V8jSEseRU9I{*xy$y?TGepG z(=4vH1xuHUB>xTQg$b~K8Lvnw!|=nVMr;6PfHMgNEJH~{HQ9DL)#1AgfAh`ib*g4G!Af0|90ajHOCQmuV{j}N z{svd%=qH4xeiA&G9CefU@k0TGnP?3>*V5vQe_A6!`56W>5Y(Z((J>~~F%`o=8>_KU zzG!FJm?7NfAa`s(4lPkzIwaMbAd!hb@SSZ_(|E3-QPrg5<3 zM-rCgs!8~-VWhOuNf8#JDx~|e7rl1W?V&Q#%_Z-7lHr*d;JRYRkZ!Oc-wW9oMn!P)-bh$@V;L4$Ylf2S&J``vkO zhs+ujNc8}{2_?Z@Fvzh?GG6^$$<=qa&oU0H>EUAf8I}Tpj>ZR6UL)S6b7{R&fzs&~ z*vhiAk&hF;jzclhF*rFm^cq+Elu>g}3{m>lCURyVC_l!P!|uEaG4|s{ZkB++Kj*ZL z9Fxi>Q{CtA41FgzKU|N}BE>FO|OWc z0{vH*`#9oX9qNRahqvb%e^t%6ydsx<&%?2+zY9r|dsW;0>sjIN)VIp4>j|(XuHCG& z@7ErgETYHSm%r2}Zg`CF3~QHY*`QKg5oQRTs@c-Q+0Yu)){T!zI>kVxs|w=dra~Nw zla?+iGBH1H{rrn+*+E^*EnOY?5{>=8qo`Y%`IhfXwYVtDh!3t}ABqVNGEcnl-x#@s z072yg!$YFX!%Fnrh@Zj0iDCXN%Zq1|kJ2;K;{g)*T%Tk&^K{Aoov3p3OHb`bR^kr{ z=SMw2q|lqnRKcwds=B?Gz>io6Eu?p(d z9~UMaahe*frdLhn{W{2QK?Xvtv<>9bNf^jpn?mofpJkcoP817)H!FYJJLv}nShE-9 zw~KtP&K~T_OwCvOn)7==Xu(JB8^Ue*-@zxp`}wX_2CC1WPe%ASsST$Lk+2WYSi*9Y zs!itH`KS1J*`PN%Y*gi;)M}}5GNi0uSed6Ou$iL|OLDF9Y;_4E??fKfSmNInQpxHmV#~-K(Jx3-}6$=Hf><|>wmk$T3bwZ;wQ~mw`8#{1>)fDxPMfJI~x3%FC zMBXH(x;rK(I>c-u2MgvJ+Fb0lJStbLCP@Z_JpMZ) z7wk(1JT2+q4)3#mNpfQCzrl#H#coYGu1y|%S!&6=^qB>s{gZ#|iCZqO7_D41Q54uc z!%I~rGBO(J;CDB>L{~pLKI&^^C~x2QKnAy!Sl!}WW(hYo#}E>Pg#oiZ-sv}{u?PX^ zFZQ!vEA>PRxq=6Gyk$ziBLV~xjSIk#jhUq{C_Kn!|Ep|S8Gon^!sOxi%6j0mv@V1-exCxJ@IhN461T6>rgV|5Jy|5L0F&S`-j*(z#l!tUOh8&SHNQ zwd*K=WDaw6kcK522Kyr}N!#t+WckpOG6dE7qwC=+e2wRF)IVm%rse-jH!<{UIxZHn zPOUMM#IB2GU~@LFdu$*tx!H7ZLE)b9e)n)`UvTjx2~~Dc13+8PhjM&f+g?lwUs!$9#@150pPqFzQSQ7XO0(k(^fXAnq&0q>@pXQSEy>-Mw2N?qrgy2vlw9*#2PJrOFDIZFyDD|9A7(?jAO53QfbJlKHE-)m5#;;VC5bUIQ3UP8Zyp) zR}}1mljI1y-_!1Q)bWDsFTALT=}wf6DmfrD`Wf>0DF=ur2iwi$y#4lS8|FS1E_x3a zC+)t?^WG)bo6?+wW8h%?!z#3;z*^@;fLtOgEJp0pKR_?Ao-NJW_HMxON_ReJQ@5TPueCz4p-W$Nn_I^eh7`~s>3O32>9 z!K1EGrJHpVH&WseKwxGe*a^=q~!-pND&}I`Qj?d9DZq+Fr`ZC7o zeTmk^($$4nA3!u~^K-KT^p3a^{>2lehtRigGt6Y-!KYzwyQ}(eHE!RA$;b+x@Rn=t z_+y>}=z8dF$46c0n-RZV?`EV+xl?lui>2nXDXHaGeTCpKGN`SKXy}8rX!q6@4Tw2! zNQzl3we2$0A^&q94(zg`{5N!>arp5S&B?|D%=y2nD$09VxJ&jP))*rUpedT1gj2&J zW5O&W>itdRjJBlen=G%N45r|{GE2D)ue^u*M@T=C_#PrAcSJMG!J`S|VjyY1e~S_s1Wn2#?WDwhz&1r>-2)bU<>p^INH$E{o}ws`(4QyYD8 zw%x-f=fO>~{3^@a!}|5A>JHwYl@yno9QU;)dwSs@SOj1ACxy z!9pb=5d>O&4bNm`eD5+qFcip{R+k^~u5Kt3OMKcAhW=tGrvEq>^TfkFOf`l+va`|d;bhu#aBiQR zNGc_23wp_F&vZJ-{u%}WYJaFQkGyA$?tuR;!v6nc?$@5K~s4s?#BYu7h zBLz2q9`7`F+VC?&6Vel1@qS_tN&Mv?pDaU1?`(8p3ctL$86MLc#Pdvv^k;TrK3DFW zuKJfxd>S(R{(OQUa!_8Y%VajPGudh%ZQ1u>0!lQY85+d|A%g#OqXXig@3(tIecaAk`D4+-0Zzq?Xp`0&9`0r0gbyoM*`szE= zPNR;WM`|4J%vnHC=o`XePXXBCAn(7Q22!`@1f~OpV>lw!E~atiT(KrYIsV zYN`{V)Ir2_*N(R0&Tm(W+;b+e$+iKpuZq2qaES8T3cM!Q8d(Q~xO8aSYH{*9I{W9E zNNdCT)#dp++nbO2hE4G2{>s0w_@4ey8b{W$<~U}?r5k~ox<0iZ4e3_a^Bw$-#;Zc; zhhZplm|1im!2i&teg<>z zt?TRRzR`Nc#FjPh4*+mj847^IP7V(6as;YQ?@?V8$KF_Oy=>!zA6F|4SRu$g9j8`` zSz?%0g&!-a6TX*MgT>kCl8fk1RWvmill`@aJKqZ`S6&n$C9{J43kbhA-W9dw@`lp1 z#;?3nzA9z#{U9=>_&zJAPiUJ?&6jeh_TDc;>!`;n&P?><$AMV_*`EcvK^mPhP5L)P z7Mfsqco^^g5heOl>~nro?NI&*uE@Sha%*oOr;iSPO;44gLs(^6LQ&@Up1ro@x8%&P z5b$K-WX5C(oi_rWuNG{3YoCzRu*oy+zx%n&dvB$VP@SrW?}^9PbE6lWEI1zJ0eEtr z=+A31pZvxWg_U{Zdo6zCXB9!d6PAQmL)3f1n+oDN#^vvRS6jaE@nd6X3)O{(zcg0y?ENN zNVZ(l1lTg;wH^V9GQjsc8Nj}X^s|>vat`wh7h2)AO_)nJFJ{A;$FkdTx_l%pKq7Z^ z;>-67?>`l;3d`-3{Dx1s(w7bpqq_{nJ}sA0@wlXdZA0I=B~a%Us>&y9j&X|{a>-$$ z093e2alPvWBB{JwIN}$(jT~S#Q25S~atzrpL6ntg$BrGXNOU-`gB{GaYUH zUSuHY7Mhe2?<_OCq2zpb2yE>DS|Dg$j8LqE3G}IgUf>PQ_oA>izDdytpZ=AV2MK-m zUZ_RWlLG8@me|DjF}*Dt;_2|=GJT=n`)8}Ke50!<$=Y+zmJjFcYH;CqaGq8wdg-Ra z-r45yHSU-i?TKdyD6q@N$BOd&thk$HI4lBpZS-3-qW<-=MLdSMr7d2A0hn+Pi_=1D ziumI3K60Bo=aU&Reo=czyJzB!Oi{dh`)Ah94d;nTCT{$D3{v;%{Jz!FmoU0fyf#yP zo7BD;`@+w3Cd}xk=&nI~dgqcY%fcL|_?_4`)N+aD!?-xawq_G-Q7rMzi|PlrbZDhh zgJZOKn#+PwzIaQb2lo|(Q{EwnhAS6srhgMjl+W9E>|ObSX>MkNt>Yvt#9)P=J7vR} ziRH0vd^qo$m|DUyj3i#4ZLRg0&Zh>5qJp5>e$ykK{cp-~N)do>PW@D^xafHSm4zD7 zq<~BFNlLRjL|(m<14{RRqs|${x34%oS3~r(5XIgP134G*$kUy=*hg{(3h>%R?}j6z zxVbu2GB#-4NG`Wgy$*h1C0vE|N_@Yf)2?A=)Icp?*z zoFd-j1A=@%>d?0smPveQq)--VQLvo4E4M4Sc}Y;$FE+LmSf%MZ=rRhXfx=M`+bJaO z*COE2oWq`N`>;mi^~8~lH8gapJD4bhMoDgwfu$G3qCcy6+{eV~`SKy#jRTaX;5I0i z;*4JiO2~!m=i`+4tyS5ZNFzIj&+Wb6I>!-*eJRM0R}=A91r>L>)$K zICXh7&)Rxj?(j4;|6dzEQ*Ar2HNz2v0Q&m#|M$S8Kl}rCxzXM56=xSHB=O?RpU$PgF#zKl7|kKE zkL#QPvX4ss92BIp2u(20d*50*-t^;#KLnpm8nSv)K2G62(SUFi6cmUHOMn^bsxYe( ze^iW|iS~)Bv@~J?u#>=!NT5$dvSD}#XtqSfHz!NdPU6}n4{nlD7w<00*J1asPiFp3x!Tq8e*5Wq^a+E&wng!*eZq1hV z=%`GQywi}@fVR6$xQIE3%X>wGuW*2-P-q$rp$qKq(?}AE=Z+BA40zY%Uxg;BEk7pi zdCiP2+k&`y)$5GS2HI*kV=tn>GN_Z!AX0!{z>@CnhlvN6J|?_E=&vykdl63hp5R3- zF}WKE!bj2pIRTq9Hr+OoccB~M5Pt8G8iT6E(iu%%FShi$@5@2aWcja$i&Ng3X4j>t zY&Q01)oepP6rx9U?m8T(u}un;oczqW=ELO3y&Cze^L|f&C{XLcq&)xLgcHco_>Cwp zUih{4>QlYusxG=g`Gwb1MauBc4qmxqSJQj1lbpBzq=0F0HT)Z5v7*I9$6Gt8{WmM0 zTb#h5>e1XG{Wo4HM8D3K6Db;@s`ED&?haDKo$9YWCqU|Q+Ew2hBQ3n-#*CI4amr7C z&G;y*ewLccb~MOP@Vl3y_5`mJ`lOn8?4s=mQh$OiNFdaP_jVipS?Ts7kIUnDoskey zl-Gi`Y_Sj z$KkgzUc;TNl?+4&!0qxhi~ah1wB|{EGU?hClt2IsxTh}4bUo9{jI_Ar7B0&h_u|8*p44M}gQlR}NKIsN| ziCLANqoY^1Rr98CbN5Y0Il4)mcom4_aTk>#U=+cS?L~ptMrL=L8qV3$$3!i1wowP) z-Vm}zj6N|}+Z6urhknruz8iC(-?Qv>Yi>0ZH<98O1#-1*0JG4}A7K(9zQku;`I(Z& zk;dyo*vm6b3l0HBzd%UD z-kpZG1FHz8VKtbrw6)TdtBoK4ciQ4i5_!bR8WAX{+w#S;${UX5sSp{ zly0(vljuNj{FF|DjOCw3jT=Yl0n3tlbD}3IvfT!S4kZ22?EEV-FDQmhn4sc3m`_dj zS*JU1q4eLX1Y37d*T*O+lG4D~ja@6|ZAJrLgPCgiwpTvDExv3ki`P+2} z9QD9hC2~Lkj;Pj`)v%qh3!zEIJns9A3GpbaYI-D}8`BrYTfbNT1p>3$mNw`$ugbTo zk%?a{)EV?BqYa{6ucxw9BJJuFg;|8jO2#5&-l%Vi2*t#DUR3n(>ZsbjmSmuzZ*MWU zx{wqR$s$T`)lP~JYj~QIXKq7%OA>AQ|GOnD-0S%1Rke9>L5G&;nJQH$_kPrrX_&co z^QMc}J`TnErAl`9M;q$6%b8cfyw7dtcGd&dKG~3pnrrN?Xd_b?>C4}91sBfSb$oJU zzUt4$kW`fWebCm!qY2a;&>|zSg z`<@zlt;DxQ$;c&GB4a8(rUj&diL2c zT{g$_vGZgs+Wql#a8kMQ$7x=31T`(-CC=?P);=G8f)L%v62xjBz1M8%-9W{c`+vnX zIp*1eYGd*r^!?k|pm62>f2cakuqdOx+YjAHNl81DbT>%K(2Uej(mhD0C`w4j3?K|C z3>_jVDIrqQC5)sXEfR`io$YhZd7tb3s2}vY=HBh!p+wAx1YMu!gg3R=G` z1&UZfr6=?lFn? zv(FKw#}vXgyzQ!AcJ1ectlG;vvJ?-_S{gcV7#}Peb0f&8C z@z!;9BctQ^yKI*L@p0;|_I7`$BP@+T-gqvnY*3StghX9LlEXV0o}>($)>WAaXw8xi zMuz13eTxvxU$^mCyCNouA?(f{m0&NAX3T9ds*Jbh@Zfr zM)5p(h49+XSIaZO?Blf*%O*#W4}UUo{(k}QXxCEhG)A%6z~XJJZBX%Ie1Hcobm$i%Q)sj^{Z)3B6T z%mOgv?(o*`B#r;GmB`?ZWxvx$_R(v{OJD!wsd~>ZDCmukED3|*YNP%A)3r=j0LX2W zS9J1!#g#@6P?*4Sfu6f--}#enQt@m*HYNtB0*O8};7Tn_?T+nG;TJ}BOFZ(zWim-5Tz z7Q}fQ1JiijWE;tfBvf7s7Flg^p0R=^xXG#VJ4R! zFrL180rC!2;*L+Yx}hA8@7d|QpVFWf&uwSlH)}w91**B|%G;P^o-A%!wU`yMJ*)lt z?_nAl8(H0Nr{orYXWga$rpTy#-3HPa#N%DwrzqXH?4!^nUwO^o;yXv{BA9Z5(4Al< zJuoL5+bx-K`{Uv|v9!81G@{wN3Z@Jn%}k;$0zN+olWnuRb9V_I$p9nGo|(p}cUB#9 z&0ZX{*!m zmtN`8g-?dE+uc1b+Pwd;?7wqWwI8Ip8PZFg)uCO3>5`7%RHUXaC3=L~2z@u}!~b`l z8{$s*x)=~RdWw~ZuHR0O=t|<;Wy_z4f4G;I1xjnEL5Zi~-N1+blS4y8qABhLrw_wl zk<$Cg6i*3`KW)A3$&)QKxFO#oUs>aFdL+Gt@X_=$G*4uc%3*yzbGTpF7^sbClD7h{ z%k2Wzn&S|r5;Jp=d_(r`F%?sYu{&bq|+dwNItt-W&DTF1;5Ss3Vn{jzm=-9+fS>#wMrCP%{$;qE)#-ef096Pkw_1t1aubE2)opALI|01V{m;;Mm8U&U6%@_b=Cqg zwAz)gpawEn8ksJe;l`3lyC|DPX-$^F_~m2uA*P~%cftCO)^p9)cNzl$s0^*9eSxT1 zYVSA|hA#v-Jz1++sGDkWptw!O8=hg#$KS&0(e2Zo<@zp!JfW z(u01+Mr;hSqyG5Ln!cJ<#3AB^oKHTcfvNBQpo*K*>0+9Jmt;hnX4uU4_1reky#vM_ z<(T7r4C8%~w*qc+g80rme~zD0%TZS0(a{67=2J5WyMwTvJe{~~O79o>oaq|B!hJhe zIMB|lcB|TKt{!qFIiDHi{!)cTQH)(j^oBFMd+N=uTzSoCdu@i*^}_f3$g9VtXL*`h zMb#>`vlo3JRjx6yIJleKxcc|ew?9f(ZM4*b23mKG~yD!?LG}}b~pm*~F z{UguH?An9h61CqDmz8r~)%Wkg5>$r27qTx}x7K*ow@&?9EI9vpJ!ALFcA~gXB}{`U z;cDwX0@oI{tJ~rTe&>jQfgsgN_6U$KcxGuCxh2dFpG!=cevTc;)k;_@_<$~zr3}6v zRQI9*_-S65e3HmFWbQ6wk2q*6KL^ain$EX2$reeHVgk(t(tdmwxJy#u)Y^ zv!7=7I_XqL3P->~;IjX!GGtnw<#tc0tn7Up1!HQJ03*tG*&Q46cGca&xU_;mtHxoi&xg;dp#cqh(nxUHsp~XHWN*WR8D5}h@ zz)4ft;Ytfo!Z*v7>lTj|z0Ir=h|+kY0+mjWouiJcw^R?edEdWLXQ zzZNTTve=MYG;kI0fWYMdWQ(&5-5n9|Dl^wIpDP1 zx$?3$WKS!hIBAsd1c;Cxgb=HrdD!RYz{O{9sSk^ z&z;SY9n_em{M9taJn`D{r`I#9Go|9+j`(w;uaBCH-9|!Xc;Mx0hroW9B1_ z#stv;dO7+ovkJ+wWUdm9suXYJwMSjxrBqf+cP(vZN{+2p+MY?9@qew4au`qnm7h|0 zLgl&!8jRbiNp%jAd8i7(2Bu-VNM6A31reLytFkXo9&6XV^lB0r&V))TO8}8=!XD;z0M6f=jmHn zd12|)ltTzWIppp1P2nDg-}W+XJwsuRpizq*x^Edze#@;-S$m_DpJAM+FdXH?bo2>b zEjoD&W;`W}n!AcV3HFzRx97fI#5h}8N+0(%ctRKMC8nT-QIr=w?~<>z_FLbmo(W0o z^!31C8fXiVJKYe06aSDBBx{xhG?7mzAgPIKTO_4Vf>cXz^T)LX z4Mw-8J>0vb{C>WivhSmlxr-WlTxnT!D|*8m(vQT=n#n}XOE3AgP$#*2%fGF3C6!A?Rjf|oP4kAaqqFo?aXWg_q#2#(uSHASkxbRN~ro+g@C@#dh@bx zRX!uWX3(l^(Bt{xll~X;UHH#cEuyirMRnDSUO5;gJdCK8TUYI3Bq!1%r6v>Z1RkAbgWPTj zGW(bSf>-fcN@r&9((Ku=!V)ubYiy?MS4`#ZuJXfQv34Rd?_l;BpNQ;PI_)7Z7tbC* zuUI@y4Up}NjkGSnh*{35V=gm4hzK_eJ+P;!PC=n@GAl`Pd&Y>^&3L7ql3f( zJ4j7;KwOBlToVEl?aTerb(4iUfZbNj;U|YOie0i0Rgp+jh6FuCLLr;VE6l_vRW{tQ z=mkpM7TPVTo0mzKrD{I)yrWX__6OUiaBFd@r7mxqE0d|Z>=Dk^=YJwB&5vsI4!m)U zSs&(pD%=GIQWKrBGfF$`{2Dx1#IhE2PnO+R>~5Xb$G-R8i+|kdUHvreA&pMx(zRD@ z{4aA7VR_ha2R5djdna+?4K=qAS`=C~Kzsz-bz1tf4=PHV-#z*tyxb_f>c@j{9y$E~ z9X^T&64r%lTK4(=XGu#=8lRP2Hwa~t%=Fk^n08Om@pGzC88(may?UwAQmuCgw_#&} z;S6hMr)zt?=OMAT$_loG3V57K-kZtPv+KqXUL&uu8(KKP99u+pW>~;d?^$eD&5MU6 z2lvbmm#g36&(O?+-qar&HJD3z1H}_y?Y4Z(8wM$$QTzdNj__C$jxL>owCs8ZjQx1sg(U%xRPDia3W zjKL!r3x^kytKUUQ<{RmvvxL!|dU!7&0|6>lFp``sq?RJz%r=6UBff1=DH$KeEyJe^ zVL=HGVG4-CEFWc$Rkm1J(6A3aJwC@mh_VMkI45 z`&yd^ao@*+%65)JhDD0=Zwm*g+6B=nvPH-nE{tkMFXvihW2yVvpG|9y( zQhe>2St||dI7I2H;h8i7IWm{>0qVd$rX*RGH}#3vDDy`!42-Z# zvQ@;1>oI9RHX^JFLGlNtE8mClJhIkje_$sEswaACzd4wBcU&85%F-r**7r7ei@taf z_Q2n0RT}F#<|GNqQpQT(OFeLhH7#v_Ta!Y(ld!%kM+MrDLE8h~+eB^|e23P>03Xqa z*AgH5BF3lnKRwB!@0%Xy(ZscQNcS{^Ll44 z?Hc6!|15L%qk723QV2g>KNrfA3_p%F@W`k#FuhK(K%HevSf)f%w>W} zWamF9ouxq)Ys2AmqT7=6d&iPP-cIJbjjf9t8S~?}U0h20K9xf!+Gzca?X%es^ z)bZF=0Rxl;H*I$kKG)IFQ!;IYp0up6OYR#7vy5M7MbPYs%?f1I0r}I)k#mzJ5lQ<* z#!ufInH%jJGF=P>vdAgK5{0Q1_!SSjYCc8uxS6DN9=>mr>C(x?)qY87MTm;-#lRgWL;!?Ib8w z?8Io@`~=FD=Wk?o@5iYtUR&t~)yjB=2JDwA7v^`Cz)K)7PIeOZ!__`wQ#%pk31Wn{ zFB+;tl-dka??hLeMSpJ-PS1Jw3H~&f6*g=z8;j={>uZCDv75fdu3<(+SQl(}XYOJ? zI3_SncuIhRJ3Ohne@20L+QTR<#|1XcPA#}DN~7pmPtcemsaa&^JxWYkQpy<%6{IWs z%57)k8D|tLTsJ~7CjSVLmXj|%PiNye$w7QjAFbpaN9g6pc*qvc9ntAwC`XCHBoANH z*wfPOXWHN-&C+<&eG-W<@MK--eSXLq-|OthzNklD7o1ShVhnxKaQDnMx?zv!=~YNM zz^xi+5~`@)gP}6AiQLTaX^L4)vdXcKcRMnoc#WjyOZ_7cFS3T5xR+{2)CCbPaPbZQ zFrOugJlyo$S9Zhoxu>1GZ8haV&jt1frc<;Wx(c!8<6q61qNguQmycXt4tm0>ff(nd zN!wuAyYwQ*`GbQ$>)A&l)e$mB_FhirP7d7HEX2PcUHGpJ?(wpl_78u!f{dQLih^r+ zP|MPJ)bE9*SG~Ozx>9(!;bBxoLoC}QG2@99r;QAis&LAi!@AbDRk2^)2Hm=J_%U-f z?eePjs7k@fZ_-^!ZC+p0`GhA~UIuaNLU+PNTi;oaOU<_)t;A2-V0z0MtPg-?2$Gi$jqX+7 zYMacq)3rHi)UDcJ9>H!sM*|%c#SgO_#)6_XCwS5y50n>1=b+?;WvSzX;NVfWn}X$w zh&ooNoy>JfE_&vI^V=Cxgn82S3}j@KrRv@(SP#C$O_%U@g-W4er$bEO(+%WCuU4nK z$o-?+xR!ZyZS$oTyW|@#f6%x6r1OksbeP?EO%A?Q;{YUOX@FIvM89<1aCO=zj?&-) zIrP%_F5di%X13~m3p-v|hc9Ns@OWM4?|@#=$QC_k*}H;+ldYc20t=+5FkOZ(&`R3p!o zn|D)3Q;ITZq;%nYFm97X)h|qQ#dAl>T$mybHO0O_`Zmp+H~ky z)K+qTOF7QQLbF#++OAJ*eOF>HE|aEZsZ}1&HLQ5Y80fY`xFc*RaykF{`{7#P|J*z8 zv3~5=a4an4=;A zp7ERr;4-(u!VQ2;K`a%r+(zGlZa8d=DL))Kz5j#_?h+zftt*lT`CNG3Vh5^U2dLrR z3D17$wQ}ogY0ih^DJUuq)7tV_k1Z-?nTjWokE`4aEZp64P}*gVx0k-xrPF5u8JXG7 zu?)W!aPQJlqKvFb)Cx~9oGW$Kdbvowa60_|R4l5$_eg(JYnR5K>wi63Hz^eec6?Mp1 zIn2-VZ0_27=4=k_5+V=JGcK5RRq(2ByN@?Q`d}r^tKE68v*&H|SCp4e;VQuftZ445 zih0I3Ye6;<{z;r&XN_kq`F(cgR4U3HMGw1LnvS$H7uq9*-6{-*ThxQ__qy~E{UiMq zBX||Algf0{y-$Qg?t&m9>#gcVllb#2C)Mj3mCemklSW2)6T84ZcBS_nf2A+pfGarP z*c}+QUs?(4rfi0FWDyB4hRHyx>nqz1PKG5|8O3W+Y9>otE%))6qrUI48AH6(ht0fnq?$_Z6_oRwH!UNp zS7-z&6|qSA77YUC@#cTH*9Wqd!hFoqdQBMr+j&gb4lO#%+Uw>Sk$DDuJnHoCTg&LZ zQ-D&Brz+8dfIS+Fh@Ounmi1tYwpjmKs$Y|3TM2c}G0rv8P9y7sYQ#b_onhtRi?&8h zIW|jDxYBU=t$G!q`?qz{^q4S9>13}!{Guk~a~>ZILat$w4NZ)e+I=qr_g)JvWhrD* zVCA-089$A!YLUh42k}8x_3Z-JFQ1FrNW{(uvz$b0V&k{ICT=V#3em|dujj-@;oj6Y5yPd~uPWn1 zw9(kxIJ|l)MA2s^Njlz3d-nIKHnD0DKD@JVY$CQ)mEBv`{hYH7}$66A0Cjusf4<2MEr6?mX; zy>eham9?O6;p*16Wfm|;D*Hj}&d*=KQEb8pbTlWEpn96qsO_>Be*RJFxM09|N=y5+ zjSz**Tc3ejTAnyr=D8zHB5%5`)OBsHKjfE95dUWdSPlOQUd-|Wa*XpYY7rIV#S@?%+=gS49 z4{~^_NF{Zx3qDInx4%h1uLsjjc;N@W)R9oJc9O({m3AmSe@BrdtsNP65^>e39Vr&8 z6#m4B4)4_;#Oh0muLU!s=WBOE37+MP9JY$T#=Idt_8S@S`-b@Kj-#$yvgy2Swm^7R z3x(wxf})4*@7uBHom2aOYN|6$&2{~3Pp<0+1f%8(f}_oBXlR&&Y+}n`U)XR7bOhTsLpj%|ofzxXG%b$>|K# zcP*Zhvc_WI<+_rNTZS4`!F2Bj;)tvZ0_a_`f>6=n7Q?tp{IQ?*r3ovfKj3q^)^#Jt z%3bZq1ih1!-!ng-pZtTQ4c^?p%A}R2$YbK8HEA&XZcot<$3P3%*aI&YMZoqaE#9I6 zC>;|KhMWyJ7s<_w?W{S-T8qULBkR@Unw8_jKp2B(CWZI8Q{q|Cs)cUNialu;u^7~! z50=YNo-)%_VkkVT)ODQG>p3F;zxi(2E<+*7!CSRhD$j_e&V^ZbwbNslZzUr>j`W%| zIPP^hTI%QAkt5B>arZAdQ6#^)B(9ntgP!*&Z>5RnB?~t-G19C4Evk2B8&vYs!YlXZ z7s?R3JEg(jS505_OB5R95snH|VHLTJv6Rn+$=%9-#X~&@h8C_{E?Hg-_PNMD7l<_t z@3NC>Vb{*_4+whm;MT0}Xu`5R$#iWN&GPZ1T@9B9d)kbK4%2Jh z5E6auKZ2=)+FuKBfAa<-MVyZ>b1d7ZkMC{p`W|ghJtX0ifO_5%44;&c9|z5z0v3Gh zxPB*@J!Re*)>h*kdPr!GwSTbxXv2zQ&z;DCav*F#}Mr zv%6SlFbcvjTRoNJ)k(K9@bjRc!0GsAKCW}~=8N^+KR521EXjmqB-}%hMoT>2yk0Lc zwn5Xj)_b_W;(O1%favM(J&)0V4k#Jny%k*saF&?cXDDY_S`w-NdE{lvav3{Z(~56+ zK-6eR^Xk%z&ozZwPgmlDt(e7i&^rp})mS^7FE<{W-d);a<`)#mbOo%2og#&O^r(w* zm01qaT=hE`-9z-1MNmj>&5F{Ms#Zld`Ti7l@M2{35?g#)8|`ousW5KA=zZTMV6!|i zqKul3NWI-pG*AbHHL6SML)`QfM2JY^=BIu~y}v{~VUKQGWW5e)NG%CwSeTH?3}%f9 z#ItL<-@O~C*K^UR10@@i)bR`5yy$4#CAsyQn-(wNn)-8bO z^8+2YSnEwni33Yk1f0VI$C@%2zP336$*qkYVRb|k?*>brq=4P!Tq#<0)4WT;l_Ge8 zFg3{n1ew!|Q~K)HCy|&xdC~|kD122$1aw)*76x=GyIE(kiNu+RkRc$N?_BochF+yF zQ!WDBvjpEJun<==?Y4wC^w=l+HZ8)>^RdkJ9o^j@{_2!u3tI_lF90OD(8_pnhn57+ zjq`Zv?Gd6P*??yaxwKi2#%xM!mz|1!$d94f3vShY!m9@yl+F8DJ6i&}f-G4Q*p3ml zJgtufWhaVs^&@C4-5z+J_aPf{&O}bbw=#M(sEK4l!nrTv&g%S;*XRTBxBmkBM*LYo zJiIl<$wgtd_VN%r;mGXKnbyh3_!IcEx*i|<4mYgKTpH!h6WF|hI5wwi?B=;(_io#| z*OxbV@tCfi{P=|g&E-^5oG3K}OviOC;_~^uob(i}@kiY4V&aWr> z?#Ti7%V2bd$&aWv!z|j8BI4Esuk1lkClnNI@Y5;|wHDu4cQ4KxQYA2$nlj`%k|YiokD*3`#-LgWXSSui;iAY$Wn9B% z=StJ6g-^(h2FoQ|yL*BD!EwQ$ZMD-gOLYuIS&m&?CaUJx#i}lTz8g`_xTIjb9?!7V zT_T(esR;NFa{+wt7)vKHy~kA{HX&VlR$iJ~dV+>@kXKp_+Hg0I8wwRQRZj>(uAf4E zUR>8jhJnSIeC9kD&xe)$BKR^;Kn5F*84XLFFSXufuA_0$Mn@WcT35K^9Ty9uJ?k+K zBSHj`acO&BzpyP{_@TJ_?RIhBA7w&~hMsVIQ-ns&&OmQ1y)D<{vo%3Gf7ul>7MI`1pTA*JSCe$|Z2&n*%r4k{e?BC{5=v{~Rm>0taakE8Ns-s>ug z=ocLXPUDsY=(-Ux9UVGIP&pg2PC-yneM z7OiKIBXd;@r4<-?lg>4gm*aKmkhZP#QqaEZ(_ss02{qKd!N@qB1Z5&?Z9A#TCvF)C zAC72t>{@lI_fU-~6`(N68SXx0KLORdV^7RCm~>Hu_jlUgf|2Q*spWN~-Q0o*xwtOo z5eNJgiBPfxA52$L6Xohs?WmY%;vz^)WYI*GB#j_n__O&;iIR2@}W zi*Q(M9W?@yIRp_Dp+Qu?NmvX+@%>s8d-dPTXt7%DfwitUu)`F)H^+E5KNOAxhZeP; z@vk{;Hd!pbU_BYJq1d&ClSpnpN$XOkw;Kf%o{ySTcxc#lH&*&3^9(zJ4;jyY*h1BU zG%~UH5&U;0dEXdu)l-wXgsJbA5s<4jL z%=NE&7x$6O=!__sVfk?CH_ko9Or!=G1UjFubZD}uGPg~2CP~M?p0G++FN zgr&@0*m0635|T#lN+d={hZ)yoY+-g45ExWN#|M5sY?Gp+@8?d&UE-7(Xri07D0Ihs zJj$Mgac$W}FO%Z?K0#oxvl1&m*6rsX&%q$sa$&tXbVB`N6R9Hv>_XR&$xTg@na~g@n?HSVmM<=!Jj;rYFq69gFvp^zVu0x7 zP8PQlqCK!+?&aT!wW+Lpr}=5Xhi`urfhslU;U_ytA1qP5;TGbnzTGSUe9K>>b(J*-ybv_UHr~g?x|T71;h2kcWJ|!t}J13=XA%lx40u}Y-R|L%u=`lcZ} za*2w7JnkEQmYJ1bV(^G2*H>1Zy0-`rbT~voM~QqkUosZl__F3iXK0Gu4u6ZyeX0$~ zOJ~k|fr}RwcLq*@8l8)(P-G0%(Xt}8`K>^ZDFZ+!xGDgpv)tp5JqnlUsaYzm$v>+L ztNLlK=Q0@YxUsm*vg0z~1B`P_f-itE7cY7Q`EArDZ&C%;nyIkE|G2LC?Z`#J={{whassWj217Jo0vR>_MDwkJ2|Zya2IO zUuKU(jBKN_ySieHZgY>%N{}M2u~Y#%yp0>#b1m6>!7VwMdMCEKMwqw$&+19IvBR@x zM^Ad0=;RRFthvwV$Al}r%Rj&On7|6~20E$UoYAp*RjBpnX@k3s`FyapyY|BK6QvNG z$l$ayqmX(n6fUjd*h)_6;Cc3; zbVP3!{C&x;-I5GY=>fXcj+ZcaQ2Y!3->>WcwX?LZcZbf`(-eX$=xYpO52*%v3GL=BB^0av^F3s1dVgs^iOC z3ZbJQol@zAkl_V%V1t+#u+p{I(I4ElgCOY7cq#>Au?HUE&>4vniNsHP-xJVf@Bz);sBUd7QIc;d3@deDa5TD|jcoL)On<#^`o>5L#8sSH7Gy z!_)g%Q0^VOSG9cn-Y4|vfIN#|NUy1hOGqlo>4|0I@@T<5m5x3lSUISHH{xf|h9PpW z)$b}LM*kG#8q9Xyt-fZILTfkISR$?!kG!ThlWSJ6ubL74HR|tCZ{xs~FzxK)8sBfp zk*BJDo2>eJjUJrO$}{2$i&iTNva--*o?ONQF|ws9xJ#8_yQd>7Y5nn?BNkSvh0pf7 zhUZ9*9gGVssWu<7M`SV%L|iqXFK-^3)!j7Z;RR7DMsMDf4LWV6EiRai*vJ@LHk3KL zG#k&=M3?oIWD?Ze#Zv=w1CHM4sTiRE#5_I;X&_+D+typQ*zupK4|46dSI?{6(b-|{ zPoART@?7Jtk7{0RT&>^B&ykz}lj%gb0sq}G_<>7$+A}a-KkIvFOE|I8GQ#^L4|FHB ze$&LwSW;;&IiLPqu|p?_hNw{&1b6p&+%i}wv)@2Z>tO)&`uLsc@1ygLP$AX%BQ$OmGyA11serZ1VDzg7jQH6^7=g3iga^4m(jn$v-4puMoMLtyQCnPP=mWI_#V+m=0RP1tw6br zglD{jLKtG&Z|x&p+(Hx0^>I$+M%-~@%!nsK=ncZs((=RWzr^{eSdYIQ0J5qG+4#?K z9b8NA=db1n(+?#7+wo^R8$h@A>aQ!qKDpjMK6qbF{+|5tN+==AI6X_x;M_FT)4#F< z9+4S~mb=MKP<^_qhB69>eq4*TM*W%(k7En*+O{k5AKI$*WbaeSVK@ z|Ji%PS%6>}4Wqy6byv*K+!;7iq$D8M&w-`-X1ZpD_dAqV$r{o%LD!YuBQT|OPmPG6 z!G$!&NZ_}d601HSE|*UJ0baDuwvR5o8CUDTo;iLQTxUoh9nbWGp^TvemS?P`+2(oU zpke^a5{@WIabmVj7_bBJ+M~GK_qaAvzo1%sYBozV)67i-3gjt(?`+u?ZaychSxcCn zLA4O9Kc^Qvh2T%dGc=rQX|dB@Z@*9%eJf~;s>t0AAKglMjaDV@z8 zNS$QySb-IHam_(er*Bm!BmbdD=?k_oJi7A!K?jmfqoQWvaorThF5JsipZDh1qt-J& zk%i~M-3Aiu`B)Gb$zt-Vya_kJKFjkiL)h7$w1$_-)>&XWYryN$;JbGi-{$!~WOf)_ z`y%jCW3u6~58zvm*WLylbEuGRW`){&)tWYu((d-4tICgwY}b23EgSBMIwuE;v5;VP zW>95A8qr_G9j=El9So*kC{g%~M>!xuEqF#UHo9%6q*KhjCgN__AMdo+R>y`yN^-LR zhxL=bW7i})OIiYIJtsqze<)MU4cSO8~>Q_-(t|g#wxg(9>5B9lBOc&8cDnJ?P<|o56)8s8Ha}_jlqR zG?H?o_WqM(r@2f~{+=&DjB>h-p!PVvv*!EK!$Xq)@xgrih7rF{?!DJf{fz=Ssn8^y zDZQTgZ}NWs_s;8^0YW;Zo~HNOkT$R#O2IsUOnt4Jr7hUXZ|p^|3C`mP(X?D6KAJ2c??@)o@*jF55nlb;1lzQ)AA%gTtA7@no~@< zHZy!XW4msZ-nX!@AYgZr9kk{RZh62Iic3;-!j0$Vfx$0hIGy7Zd~my;W$Bk|m4#Uw z$s-EHteFF4@YKt^Zoo%BD?D^RztcA#@Yl+iq+GpiT)0GI;J#*jj=*4<_wdMZ<0af_!*K6~} zL#Mu2&rlN-X6pvOex^*v!gIqVkCcK%G@~Hfb##B3to@&Y4=idJ1D5~P_E7G!o7*+7 z_;_@hki1|BOEn^#-_?FB8{fIS+2h`0?+?O1psi;=vdvJx2lo;CauQXwZGrJ$(Pi1fxZ4BpVT*alypBD;5U>?KlzKagMAOFP#~%elT1}Fa zNm@5RT*$+knax4sR-@$&L`njM!Q|kER@1F<$=OmDOLG+CTBsF+g)h~QRH{o)b90)v zsMvLv^6fkW&B8D4MRxxUdK|a5D_wQrLVo@HJNviyuX3Sl_hFR#gN6HlgX|wJo#uaw zQaU<&FkJlSgj`G?u!`bPPv7h0P3mLHPD>M)mFcE{tZbI!z(vH z>RqVCVF$r#7X>mLP&^ywMeh@4W1)E&Bnol~=RLU6FAU-F?8LJ9G8=hD74ODbwCzi? zR;DbMg5~)YnZ9%aF}l_XK(OZYb5D0|>3DjLhks%sq?ZdXCa9`tZ~`k;5-`eEFH0fA zAx`(ifh1{2t8{X}JyyL8Ul4VT!z$juE$_% zK%AxIE<4s8CCoc6)l}LCZ4!5Us(vt0KS-s~y>O`#6L_&Wt1#T)`F{R7vMRWt*6Y!= zx2JS{?}BbsPnkAI;cgnZqfz6}zXUZ!A!*1ell+RuqXf=O4_D*) z0l%O|grG=z91uedn(Lyhs~u70f+p~hRR$3PwTEVnjd(uFW20fvklT36W)IlIp#`si>mVH ztW*AIzB+q(hO2AMVg_Sm3|~O85<=YH=;7ZAZNb;hXtHAe|Bm_ZmxYUMb0emIMk)#8 zZ>W8F^w;Tgw|J$u$oggIy`B3H51;-ReDtdpQS|HGncV#aP)SSh=tSn>0#mQl-o0L# zpO0VvRXq9KC&GAVXu?o!V(b0i7`4+I@?Gb1a}n#lKVM!`*?#mxYJL3g;p^`cKTjTt z{{9=+)PT$*GF3!tlpRW2<@#+oF4ZQNh|vZDEJvc^~xI+M7u3P z0{&l}+TKdqkdIzw;;(c#xg4dqyrc;AJx(ve1yY~me$NEzZ<7*Xco|XaPASjd1*UzH zLcK{KP!nVUZtMmaOk9VN2vgzMj+3w&_mSnDfnR!ROfB!qJruF0hz?2XGfLI!IHioyqZND_frN;Rtky&(6(z^rD$=6@)hu(L0M zhBx6V=DeOelN3_H<|kitQ|s9yx@Fmli<0a^a*|?=1d~}s=cDPP!*g82ZXC90E3F_p z+>>wnwTayvkxY>Q9f=lQBH)yRcgKPeiVzhXK&CgP%?rVK4L&U8%XHP0Qp84dbq)x* zJmz&_)r$9ah1T1~S^JjJH%WuGu@+h8-$&LqC)J16?@MCh15u=bVWl$K7!zb0rQ!JU zsf0U!B{ngGlzgUudx`?FM>^%lNV?kHJRdxCb%m<%%q3>`OJx*shiWV7$C<7`-R{j! z2eWgGG*cEr<;5TO~3p&+5fLP z{B2o$wZAUJ$qXG_s)91*xwJ&exP1lW#vEp)s3*d{;2Dp zo!MAty@(|GufO;%o2SE3>Ng9>7tUXg9{nyN6qF#-7IaanG;r*q^ zj3577bn_0G`*T&}@XYuF?-|=;0^EJVE?QD>b>zEL$9HQi{jt2bzyUQLF929{eX-s? z;Btdh)v%AMo_(jZ>d4?z(c)qq@otiKl`YP6hqo^g^E{W%9ud)dXpFIdoQ&?1A;oCB zdXKq0P;LlO>JTnoxLzhN85vK^cK4vozGjLqYyIVMC~|n?x@N)%2KX1GOp^K)3;0K1 zL-SrED26iLniFFErKGGWFHjeNgUh5sQl!;yhzPF1Zf)Em+y8z`$GQ+J?%lH_IswNs zDsAp$T~2v1XsF^Fl%(`?l`oBJ5V{i}3i-fW(5!0qE+T#0Hx1MeE!aXG|x) zfm0vx7bczs{~0YtEo@;Fvi;m_!f0hrv5xAsoZeJT%jx83UHl{EvWsAbsuQpsQ^w(*F0>-^J6$}BQ z3n~$|<9UFQ70!K?@per%^@H~&9(YuIf+yiiU6AW7k1UzX2?E;-aKuiHl41a}vaY|~ zbIo8=f`^@nFUY~EeGyKCc-3(DJ+)X$?Z5YP_u#pN&s#W;DS|%8qtmGHy1D4lcL;nv`Zynck*tQQN26iA4Qc9yBVvuuFX(<7vLj*yj zd&HQ5K~6%HR#K$91_Kc$Igw_-fB~b&m@r_By%+cMJooSYONGJbGxxpD>pYM12u9hR z=ayCj!7b^`5a_NjDgaxrzcuMdAd*9dG`48WEt5XEgUlW>Q+s!c`7gf~;eNWw9|3Ns zJV9g!bHj#lKMgXrCdgDK{1l`YBY9^vUP5W-vhDXmHoC+xN1;&=Z9fP^-XsR+18 zqPiz1f-2rQRA;)Hzx$>k8D$8(rb+tge>XCw6qCF6<Ne@62zx}BFssvpa&987xT?Da|W3jE0;=jJmoa|CJB=JEPHRs-J-^Z?Zl+Dmn>u4GCn4DTOTz??qQ@K(F#-$RAx(FunSq>BuH zoF4T7V_Yv=&J=fIbd$l`e_IgTn;hr+X&?HHtseJ3)*bq=T3pGA8gmEg$Es8*C6Qwi zlE>C23}$%DVl^Yjl-D12T>r=VJ;mSN>48~z=wBBlAWT`wZg=UYoMIR~SZv{k{@$!u z_5%$@VHWAk9U#@Y&ytX1uXgSB%$2bgiO7wbkf!R`w&Du*OX=LBjdm6*9uJC~@RcA0 zQ~qDsciB*%t$R(?hUUX{pT@jLMZEN#&L_CrdkPPBWJ0u_ewjJkcf&FEf=)#2NP)ev zPGSPPny&g+)TOLcEq1TJ)^L(&bp7sG37t6 zGt|d z0*_&=z}gGzy(ehRcnG3mN}o|mp03_2vS~A6Zt6RhyKUza)>?x1J~y%zUSJZLG|&xo zlIbcozuBO~YlLlSnBI_C<5njD#m`6B(}lI|SBu1V7YQaI>#y@8!fhx4rS%Xs<)wP`?ud;U}0Ds22v#oLb1WRQlZjhv!yXV@@9z#Mzb zW^HMr^FJ@~XAYZC7BIVqD~w^pTIl+e_a2VCd(>u=7y5~?rVNc+fRK1W4Dn2R%PHp1 zp%7>~&6&_mV6LLP0vd@%P+g$_CP+-L_bHsE?P;fD9e2aIwiB2u@3q)lOoF>}DeLv9 z?cb<$s>WWw`_yt(R$3IDxwaP$+t$Fu6>lY-S+@uoa*X4WL{8~55h1f&=(zSZL<_VB{j|(@&?|rR7P})>9EcZ|1QCaa!Zv3` zWE9e5zUVs|dIMrVPNoK3Gqc-%J`EDmwN%{D(;_eMA+u)u_}vtoR;=nv)k`-!47I2O z55iQElP-1ky?$L@4t_UTpmUa;KLw_Ia{AEuyQ-HB(ld#o)o$ZYLwrBaRVYNvNv3T%qf zmup#AWacX8;%AXmG`qeNo}!Dt9*jyR@9VyeoOgq96QVaccX^x;Sqsknmor`wPyIkDuRw^YAn4 z>(V#b3ni$Lw`A>|eile5ns+JQvA!XFqOAX=KUf47W#);5JG>7Ow2h824GVM(;v_Fr zWc~Jv{Hv;aZT8deW=k9DD6hK*Gm5^i(80g6>U((mwy!v~rtoT!ymOK9Q0&gQ|8P@< zbHz&+u8fM=EPH6OCkH12fQF9P*k>L~o6;Ta_Qgg)et{he3zFhk@h;NM^;-v}mnU5N z{`l};QN^NAD3EFDP-^<{kUFWa&&X}Ou66%zP*k*)wfQKT*RNCG)OG6YOH0e(d6hyR zcj-6h<;Wv0J>xD9^LP-g20@ntnuHo(zqVA1>iv{w&=ZfsJSHcrjej+{m94Xy=Mt-a{p9NSTfhEhe>sLBdhi?1#ZcRQzf#jeviMaBt(AD z`Oe-i^&e-{(pqN32$x)Wop1A03i2t@bnz-(IHgt>NXwoZ=GYR|=Ri2Bw+TPumf zVL;hOR&HFvZ%>?I4Buqg-7lO=AX7c)zj_2xGOb@%df|@T#-Lzp?jh%@$=!*9 z7jztW1ovXF>DO8I#$*EJF}vP2ITA+3CbyX_NCs_t6iL=LP18|Oy4Fq&72IVjre1}T z`Q_hJ`&dfk!jX%#y$3nvk^X3Us5_$*)*(Y5`wU)NI!Kk@Lm_{C4j#z8o=g&?Sqg5i zDYlBt%I_MbxBDb~;}~m{Cz*saD=R8pOVqi!wx&X0zQi%6{i*+Y-!WHYc3GI~7`kZ6 zSdv$Tlw!jj;s(lky%|@Bo$cd??H)X{wSieU$evo)%f#$O!8%g8H~~~h_vz4T>m) z*sUG|xlY{VCGlfUX=Tn=t`%RaK?CY#!}RoGEE|B`=P7m*@U;)Q`Z%Xifw%{w+0^T% z2Wna_1>|TY5I^>>0q4^I-|jb9efUNc9Zi{+)t9*z;I$V&BzR|f0O-k9nh%1q_LE3G zajmEbJe&?qCx$71{13Xybp2Ag-Yo_^S1n3U+#WKQjF&T&S?(Uxj_S>j17cjUQCUoTvK%pKV~llYPM)pdO*;j#x>Nlz+%KEJ>z7|fDwhSiH-2?7p)t!qWZXW zuK?fHmiK3B(RCb%k-Dc1z*Y9eVouw;e?E@VU^F`+nW-y%&Z_X|^h;SGi}Nf-?4~`w z^ZBRkd?!jrTuZ)Tz)c{j-BH%0v{3z=OB*8(H0LXYC<)e=hJ6t_+uu%2xQqH%Pp!TG-SoLdp13!nCKXGcMN;%4XCOwl&HRute?;x^o z_l=~q_MR&riQj(OyuS5?7)QJ_e{DTQ*$)TK8j*O5n;Og+3p}><(5wdfYv* zaa%tPGPU^e~1Q9=x+v&kvvm)c^_|wsG7DjvHu+7JGa>lsM zs}K)lD|wp>=8j=%rh#veR^ouE$a z^4idrwgJ95jofj^yoareV;nHd;WU$jkX0sfPY}VD&J-n2d1JQ5=_^QbJ@n_9y*KpT zX5>;tIzFAUHKB)Jsp1oqrZtUY-g3-iHV=rhe!&3+O4posnaDHlKsmhh z89~@IB`z0S%m*z>&mL2h*+_z;PB6-1xFx#5N?qzR>)DR>(B^PGutoOveF2;#x&i6; zSgmf1rnKc#c6RAre)U5S{LZ#5w)VaTh8OI@Hx!%_SdWubgUZRu#`#x4yn1bof}_c8 z_>zbyUfVuEF4dF13CQ%>zmH}ojk{?K$z_?To9TSf)7I0+aTh$RH=|BAAB667I74dT zLWVa2Ua^jT%RW=4GAaQKol4oG{<2;#7s{FnyfE|rWMA;lV5M36T6;sy?l~7j4<(xi zJI<40A8>*A2OZD3{ywfRvhzrrVC^wT$heU5tnB5-BTYGI)n9kNsYpK?zjd;u#OAtY z#o2EGB+rK5=fc`bEbUUcFYg$bzr6pL?d!ECR#)HNIM((7{pYOEPnGz=%Y&bw`3FO0 zD@{aKs*9X>wM0M9e}8xDvh;DEgopmp_#X}p7hcOOEejk{-6W3tXN>hp`2gF4IN%OpIF|Gmk5)=u$cAw(P=<*s_%8d&boF#cyFc2h^^6z)dF zv0u-O|HYf&K?(|3NmS0ypN=(5eO4Rk`60sESaT4)%Q{+A2U zOKW;Nix-5Da)~#9vwp=)487B!K z)h;okUSLN4SZp<&62EYx`;%$RmZ_o^ht#AJw0nzPx7A~Sy(eLZvT z|41Czayf-Y_uST_Ys?iJrcmQzH9|>nw;(7OM+kXayvLt@`JC=#(B9xxFrlH}6Sie` zAB1#+e#D0Qj7-#STr{eo{XMtzxRb^lAKF?k-kxmi7C$4uyJhi#g@B-Z_)L&y*ZHjP zzuQ6%NJWxi+dmk!nE6fujlgjcDPIi6o<>>c$rMwmko8ssB7YlD=shM}0 z2R9azB03#=M!+kN@g8ahx0^BZJx1E6e!05ZEIlQ)^zBSN{tA<$5B{z^Se3$3o%3)F%dybhYuP zOmA89LXM}}&je^C&51bOOW?A1x|cMUCH8Ee9@ptmZdX3~aOK5fot?=5*wuI=01h=# zX6;&IU08Zri@L%#8uG*=ty#s9Ul&%A&nx%1wW?_3@u{Ju+xbgi($c_J0?Vt#9EW+e zn7IslCtg9O2s)Ju!oI;{5QcP9-JgKCbtZ-L+hXM)WPS*60-)zP0de4 z8~yQLu+6D31DG0+no6xz1PNz-rQM2`!Ri?>x=ojGa4b` zsK)inONX&+&t- zZm<;iwLfqnNOHi>gVhfey+2ZKHUy0|dcU7-KNc|?yWIDAT@Yl^=i&XB14`y(Iw%9?ij*|{8cr((Q(n^V~2P=*h zu2nDk1pkEW5_Ib5+W#XLs~f#~DWZi``c1btKlBQKE3l@OAnzVGT#XWeG9?(&<;b{l zz_=LW)w=Uz;$U-z&a=lb{fEaJiOI}!n8g#>*Dg#_TDqZ!&9AmrBl=L3e9V>=y<#kV zM?=51@dwhF#Z>aZ+kIrFWh9kHEisnsnAVFwvD({W^jen5Z`Hxrqbx|Y_nqPf<~Ead zW-AIqy-C~nysy9E44ikVqUembToy!!Rk@>J<$BtxZ;%+bzwyir(o93iSvOagh5Z z9v~y}y_W9AKqLAAj1>Em%r%ptTMhln>TG(4R|anBCMN9bz#VgQ$Ljq*(;CSLG;!8n zQ+JwD`fmhl-k(tC%EPL>?p80XZ3vVSDN>&&r@)qq8gT+-=lsY?cx20Re&*epsUr{i z`Qo5!=Zo?wugd8ci0%!svqKf9IwW$aJpSbI*;)U_h#(ns6TlXznWEL?G22qhr*|It zswkg)j zz_R?Cu>JINM$t_1a(Cz#39YvhSJe|M3}Wl@KV==Sjw&(qm)5oDJIxQei)$olUn91} z9FQp3d+BubJE_|u>X|Y9&of1{<+Rx&4ese_%@v(FWG|s_FeimVDJb5VS{{@HZ)&<{ zT$v8z`qJ8WtM$kv8o%oCrbPm5xC>02>vCG3tEA0z0V5VK;INq`5KuL_xgaSsR@+%` z9mqxw!72w(Chqh^quR?u0pfvHAT_^{uVL;uqbZZ8(x8Z+8;jxHZY@=#WqDN(Z4Are!Vnc6=n6=qM?aIEyd=gdC z{*ySO9ce4F^wmG1#~f`4KiuGb>y=06k+M3|VzlM8L_M)#+b7lIo(SJ=@Nf(aRQ4w< zJw)bVNB{PhpcqP`fdE3Qh;qDH@z-W6pp1=$*y zte^aKaccYNH6#^?jU&Boe3Q@ydii~Ej$)Xcy;fV6#6tmgj}Dv62F{ zrDG+|2xu_6S}X%dTJbr*RgDy7y#8jK72A+%$uh)Y0GNYroO@9@y$Eo^jqv;>=b}N7 z`R80!&!6sT(xLtTw#4o7*{a$%uEQIx{K}7TPqz9CP){LO=>Y&{ncMRD**+4F*&;Qf z7Ni_YrQj>VpLb1|3xpXHM6;0vkR@0uyyHcXW<`bc*|KI`gtt#`bN1vWxXa?zdd? zu>ERd>4h+$Vs;bBv#XsNXlg_5vYa%5F@$`5CV0*&{D!Djck&JrAlySte*%`W5b706 zIm2v5{Aavk{v*>LcX4ie)2Y-0FAFOr$gm>lhVB}@lx3}@=t+Q=j`7TNq_Y}X3QWt8 zhMLLU#n;_(XOBzj8_&!<(=yQe(mlr~^Eo9g%?pqjF9SsIy>hj?H)+$=ZM;@j5wM_? z%6R$wxQAD(EQ^gH4e*ZES8kCNi>Gg1{ zaYMbFEVVE#qtQXHfXeBGSy5mJS1@$J7awD<*hw_f!?}6-fVrsDzR?uC6hx?|U0`)- zc=eSf>pJkS>Bz8`i%G(2Np3_tC3VvJ6rB-exda|x$Zg#(^V3^NipMMeeE3|cgjJS$Eu)KX6|3ch%0EDyy>QYg$sf|@R z-fiB(_SfcMhVP#fn*!}eK0SKD`jtk>^<%D2(;Tb9J}zqihuIHIiwua=`7yx|r7MrhJk+?x>SR>}%OCw^W?o zXt9o*j}37vjH4=OyR)Tm%@GT_5~XswK5IwoMN2vu#X{6_y>KD{56ow>0`6IJ%-@Ph z8p{-Rh&bF@A<}sxr(6=-X*aP^c0c{Ml4|d>}L#^TZ{I_D*oGI|5BR7?Hw>7&4`d$1l;K!qVCCs*8(~#4* zoBp2&wq`EH&SV984ZmtpN;)v<6+8V3L*<9Hl0qo;Uu2F?Y&727o3o)G+gp_1y?%yV zyj93tb|f2l6XTl-*0GGmYInfk$wsQGRQQu$5U6HM>8hLC~0Ku*^?=Ubv4=&t(ciNis|n?DzXd@+l~J zsPVlG{S#S3vUU3V4CT#jHwJdCWeuo_g49q&ssC`Kx+2ThO7}X?q+w zX+mAEw|7e$N>4w-g2uZ_u1^zh#1jr-1W&La@wB~ARX&;G;esJnq5LcJ+f@=@CA@(3 z`@WBD))PZL1@mhP_1^z!SjIt1Nm_M{*2hWY9M)4TD2FtlC#T}xLxQ(H0uNN6+x=0M zbHX?DaiyKn;|i;C@rnIu1SJ4_(l9bf$qIP=H|d+;^UyJ*O=xl~Lw5@blA0LB+6YDZ2zJMuC%&?@`TCF9#x zgfNKK_s^?uK)0Q?VE?la1Yp$oqqtVbXD7z%$CU2O{sTzm>^X5PfO=51h^2Tg>zYn& z(0M5nC^yK#*v_#A?_`VW9$=Rf`PmvC#zh_{Dk${I3PB~spJz4ta)*vRIDF~k*GSc4 z_(n&I6;s!0OZV!6{BT{P-jfF(50w@27Rg%_$ypT1^Dc&bT@0-9ZE*murjM8XfEj4? zc-7N}(UQi|4>J$Pzg8S5_I#c)WSAb&yu^`vvd8(znFi{~myeGxedUz`-b@<_<3$OY zjDc`!F4w-9tj3x2vI*ly_~T0uCrx3Q@MC=oe8oP0WI5mM4FJqo-N)M>4^l$ZhjZ{p z@V;Bk-%?c+PrS+Oy6F%XtCe8%u5Loh>|-u_ZP(wEZ*!bM*4Z;(-|o#ol?LZO&pVz1 znkF&(^F(t4m(ASjcu*I~I~;up=M~c;gH04jJVQ51{SwuVosL1&GiZ~cKBXD04-o$LJTBbDtpYz<(_wvCpC zT{%*E(TQETSpn*Jn&rFoP;rueZC&FWB~Ba?vi@ZwP_5zo$k)1}g?a(rw8X%Ay9V}m zMDS0g-ZZzQBM;%(^TLA7lfx@j%YGJ%D{@)uv?tP4=TEaLAB`x}j8Hsjcu=1}tUvvX zKT%dEJjKkQfn&Hav+&C3i}&RR;rcIbsU^kD3dw%T;dvlgKt1W! zbo$`odiK4KAf)hj-9EPI14gpah82j|}3D);B^{b+^N=|QT9P!C z4zm})=qoVEbLewCF@_Hl;+h8YHOn8R6hTCBqW1@Y;o;E|C0-WL&_5bTd-;7yxvuei zS&sG0!-~P_eq#{J-4+yf$=q=vC~t&!`K7G7sZpP5MbLrw&uM`&FZFYI2F*R=-=K9x z@?uIM1Tt0q{XojCr1pNWYlPR&$wgL!XqMG`AHq`37(foF_l<;V zY4XFAl%7J9W3rE#vA@Wmh_rot#(s`Zsh92pxBRnw!BNiEQ0HM!pYbUK{%<9J%caT+ zU9g5drAwGT5SPtvKJXwzBP^y4Z~N5^oE{L|%t;dUW+6Wms5rQiZPQ7#s~F_Y){5`% z)}zL5+joe_Xg;h7xuktFNA1<=$qtR5S2Gtc%h`ek=YEOpd=NXXs`8dXAj zebJfwPL>ANk}KwZx}B4v7w1{)VlzzbP>Kg9$Yu|?U)ls%A8GtaVj>Tf+v zf+Tk*t@uTFuR~VTarfG8{d@CV-oJ3H_#W-{#2KfgSdn8^GBf%UK{~Nz5Ni(~G-!`L z+W)j%PPMae{f-Y`ap>MR0lmr*o*@A|(KrI4kDXH|spc!nD~fl5G=tfNK5?)#&4|zV z;T+k^9s}4+x#!C2r7kR7A>HwPT#8=-PKcZV>EqGYe(!`vh`F>+yd@d>d@KK|3>6cl zPO#mO%JW^VJAF6pj`#`xYnr#t4d>L~(_B?@er5XkS`x0x$+jdOc!e9rURZ#RE6AMa zD4Y2=$kV}HGz5Ykc0;?}uHsaZetQ!+MzciT_OElb9xBY%>DWvyNw4O2m4B!w7T>33 zI`-wGqoP`ZK^Bi%>~#IB7Y)F9d1U2^-{UA>&Q!7aUmhU=VU-EDa1vtYb&{TV`XJtn zDWw(D3)30L;-2vTH`IcdL`%!hzq($wThm)*qvOZYgz<6ZJ~CQ2x3#sU%R&ZpQg=p7 z>PuOYs#1>Ad|mXcSFO9g~c_Qr5spGHh9OIv^r4@1Ij~*4!K1>=p3KOERg>6#GOpdmyuwCtc_ImpkoxKY(Hd$l*%fL>|sA z={Vt$|Dvdx)yEir3jZ}IKT@pw1|P^pd2CUh@9gqD?2$m8hR)5hTNmErMK}TkxWA*! zdH}V^TTHFJ*XJ6D9wrt%t7JDzsVm~~cy8x$x3AKt%8|<+_z!$57mAo|c=?2+YNzl( zIa~d%byE02@)7-{XWXt?aRufdtSIqKJl`)Xu~6s@Q&*_kvBRuAAP^z zdwPhbFstchdrYvv5l}T>M?N0c3UsxEYsH3gxnUwt`_2J>;Go`%6Dxi{AMu-lHR(ye zuWrtdG!N*rANVbckY_bJuvf-1Re)$a?)tVHeafj`;5Rj8#6^sFMI4Btv~1FFk{x`h z+&}7aoJ1`Eb4&AYXy$B68Aokd&HUN)_gl;RD(fFV&Do4IKWR#~s!7Q>!-D=4u_rEx z==R>LH@g+jr6U%*QigZ)eDkb+WIq8E{|>n6)bHtHgs;3LC^Tk#?8@EZ{iGVTgev`b z0e@iFrAmQSrOKE)Gt1gU8=>?@)HCe{PK!Ot&=aO&+>z0=JAX8ld$DS2aWOpiGZ%m? zm6RW{J&Dkxv`u~z(mt_nX`g_OBM?ELno>Yo&{e4wgO*_l-J(-{=q#O^{gXU_8hsU@ zlbO2bVa#cBXy_(fgR3IO_v!V-mlk#>k<;mn-GeO9|H-XrXfS5;8?mSk32a!BF;-@o zw5i+tw{RXLK1oE#FP+5f+lE^A303~3fg23yr5{_p(h!2`{WGJVb#fZLn0rU8vq@sH zF|+zr7xvD<)E@Jy$D%z}m#7OXmtrO#rk`Nl^m%%JMu&|>N<^N0`y5Nb(L?vlwJ%;i zP7+DtW@em!uEUahjzv*JzCr>0kt|~Ny;isMjkvCn#|Msw-x;*i%TIVx4wFQ@E(n3# z&}v=KpF7q^ex{mreCNSaYoH{+BdozT-u;1d+QnX31;K~B4UJw@uOrV8T8(7zk+ zT~RB6e#z29Lqq>kInFxn8>_X59MdI~j_*5af-eJe7a+*vSw8#a%_*_YKY7i8VPAQr zRUzeGKt*H7nbDo}B~++W@XHlj*z>emy-v09ZU`Acn$D8sfwGOyHd8 zILei531DwirPf|g*szW_{@HP=-?h7FbbZvhn7US4qB!K+ZEx;H?{Qt7sPFbs$|eWN zC3izp6$Xb^fuDLK*Bz_W!wT$c^@;d-Ni0Y=Hc6^-{qFaP z#j)w|%ET5|x)y)N*d@soU(+nDSdQ$kOG;=ip31F)+1l%JSdy}gSHQb|eLd)^49zf+OQ$SlEbCR4Ymfa66+7;faYtR%*O+Fry2jjU zAPYRK5b1GK;xKcBy!Z3}cLW?#XMq!w6qm*vuq=98R+q3d1ejF4F?=Jyor|z(8#XxT zEA4e_X=CDY)RRl-MqK?t-#`9`d_Xhygr-#Pd9Cip4}>&(v}P)nSZ!mm z$(l3bO)lmS0=>;N8O{mE;E^oditl+v#_Qab<(6)n08oYXJS}IUBkLE38~V5Tr~5zR z=Mpv9rg)BM>AT~N|JH&t_*v~NnsAeLQJ7{bAo3RMA)Xl+#!pYCr=)-_PJ0A|&rXy5 zg2;;_`z$%<(YhGA*r21om%w>V6gqZkOisw@*2#muVWpGP~KO3!ALNVVGY zXo)FdpimowA%*^LO76Ypf5$q@>~ADq|BqY-?&ogqOv4!+dW(CSa<5vRWnQX3;2KH0 z=vpy+edgHynx;3C4IJvy5ileb%}%KP-H5w&E~C7x>HS;j!rOBFdssxANKEZD$1aiv zxB$?`W%|F<)-E-{_?!zbe064B@;3PRLO9~|(I;-n?~0rbNPu$kiT+~Og8e|Dp<$mu zSPPm4ct&!8>FWHXOS(q34^Lk*brLl@ul2g+{qN22oIHb`IN(qh`|*Wz!N7x)8=IhqW(9(?d?~q_hHgL!3`BKVhR)lk3a>2YOtrVxX0`CPfRLYxZ%Yn%q=L;gw z&yJ}teQZnA4A1rVS-HegD7a?6`DwmXHM27Idxm$KNR~V)Pk{-tzDDdjvZTJ`{4EyI zJ^T?^Uhwyr)m3HxsQL-F&{MZH5rDj7taUdX%M(LUAkY=>P)xV(~=h>>1Yvq8f z$xTGslvlWSQfmB7AzI@1I!LYAe3G-Gbig(9?W>0mKTteqJyyXr`tR<&FjT9i0Wcu@ zh>4Sv^Zfj|g;Wt;5m9B;0$^S#Qua|cRB5It&V16A`=OU4&EN@1Eko-?jA)^6^>{2c zAhml_vWYl^{`f(-^hmiIZM0rjR1#A~R?84)Wxb?z%IOO2tVGJGg-NYHfwTvv1u9oU z(sV#*No34XM4IjWf3mtp>yJ2}MkWM_XuWNgXN`gDkA7T~qRqafu|h>FYfnz{RT#cH z^njDAUt)k(i9&Y_41Bt70t@&#yXb`}HcV@M3Y66+RrK-IaG9oF4mFEud05BT zvu5d-ez>82(=_Jf`ULr2iFY(eLNM=iS79gn*4wyzh|n~5u86Ibw|({C?RPKEG8q6+ z=8#!t9Lf_*B=vK<9LgEoZ5Vz}Jr+P#Wv#1^?sgDf*nX_`6sRgw`T%UEaRTJLzc?Aj zDOqMa&vXAl2+*LBX}(=nL$j%mE10_d}5-TQTC+ArcN0D0= zA<_STY)!Q*2piZi1&G63)^N()9C)~0tJ%&>OacS(r?Q_prg-<&UMR*EYCU&vCVf

Qj#nOfQewMUTTxjRm6W5?Zu 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%0D}XWQlo^LCns0}YaTQa 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 Date: Tue, 16 Sep 2025 22:28:57 -0400 Subject: [PATCH 37/40] Formatted --- flutter_local_notifications/example/lib/main.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flutter_local_notifications/example/lib/main.dart b/flutter_local_notifications/example/lib/main.dart index 60907083d..cef457a34 100644 --- a/flutter_local_notifications/example/lib/main.dart +++ b/flutter_local_notifications/example/lib/main.dart @@ -20,8 +20,7 @@ import 'package:universal_platform/universal_platform.dart'; import 'padded_button.dart'; import 'plugin.dart'; import 'repeating.dart' as repeating; -import 'web_stub.dart' - if (dart.library.js_interop) 'web.dart'; +import 'web_stub.dart' if (dart.library.js_interop) 'web.dart'; import 'windows.dart' as windows; From dd4f491043e62f93efcac2676e9a6c647e83fee4 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 22:44:05 -0400 Subject: [PATCH 38/40] Added version to example --- flutter_local_notifications/example/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/flutter_local_notifications/example/pubspec.yaml b/flutter_local_notifications/example/pubspec.yaml index 21edacde6..f8f86216e 100644 --- a/flutter_local_notifications/example/pubspec.yaml +++ b/flutter_local_notifications/example/pubspec.yaml @@ -1,6 +1,7 @@ name: flutter_local_notifications_example description: Demonstrates how to use the flutter_local_notifications plugin. publish_to: none +version: 1.0.0+0 dependencies: cupertino_icons: ^1.0.8 From 621a747b02303a75569bf2797d24f03822e3c5a7 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 22:51:58 -0400 Subject: [PATCH 39/40] Updated reamde again --- flutter_local_notifications/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flutter_local_notifications/README.md b/flutter_local_notifications/README.md index f606595d7..1ae90ffc0 100644 --- a/flutter_local_notifications/README.md +++ b/flutter_local_notifications/README.md @@ -169,8 +169,8 @@ The `onDidReceiveNotificationResponse` callback runs on the main isolate of the ### Web limitations - If you are debugging with `flutter run -d chrome`, you will see notifications but they will not respond to being clicked! This is due to the private debugging window that Flutter opens, and they will respond properly in release builds. To test notification handlers, make sure to use `flutter run -d web-server`. If you find that hot reload is broken with `-d web-server`, try to test as much as possible with `-d chrome`. -- ***\*****You must request notification permissions before showing notifications -- but only in response to a user interaction.*****\*** If you try to request permissions automatically, like on loading a page, not only may your request be automatically denied, but the browser may deem your site as abusive and no longer show any more prompts to the user, and just block everything going forward. -- Notification actions are supported by Chrome and Edge, but not Firefox or Safari. They may catch up soon, but text input fields use a standards *_**proposal**_*, not an accepted standard, and so may only work on Chrome for a while. +- **You must request notification permissions before showing notifications -- but only in response to a user interaction.** If you try to request permissions automatically, like on loading a page, not only may your request be automatically denied, but the browser may deem your site as abusive and no longer show any more prompts to the user, and just block everything going forward. +- Notification actions are supported by Chrome and Edge, but not Firefox or Safari. They may catch up soon, but text input fields use a standards _proposal_, not an accepted standard, and so may only work on Chrome for a while. - Browsers don't support scheduled or repeating notifications, and browsers on Android do not support custom vibration. @@ -187,7 +187,7 @@ Due to some limitations on iOS with how it treats null values in dictionaries, a | macOS | | | Linux | | | Windows | | -| Web | | +| Web | | ## 👏 Acknowledgements From 63b329647b22342b81d799f6a4d141747d3c0bf1 Mon Sep 17 00:00:00 2001 From: Levi Lesches Date: Tue, 16 Sep 2025 23:05:30 -0400 Subject: [PATCH 40/40] Pubspec description --- flutter_local_notifications_web/pubspec.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/flutter_local_notifications_web/pubspec.yaml b/flutter_local_notifications_web/pubspec.yaml index 9613fa4ed..87dc4f783 100644 --- a/flutter_local_notifications_web/pubspec.yaml +++ b/flutter_local_notifications_web/pubspec.yaml @@ -1,7 +1,8 @@ name: flutter_local_notifications_web -description: "A new Flutter plugin project." +description: Web implementation of the flutter_local_notifications plugin version: 1.0.0 -homepage: +homepage: https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications_web +issue_tracker: https://github.com/MaikuB/flutter_local_notifications/issues environment: sdk: ^3.4.0