diff --git a/example/lib/main.dart b/example/lib/main.dart index 67894a6..f885d36 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,5 @@ import 'dart:async'; -//ignore: avoid_web_libraries_in_flutter -import 'dart:html' as html; +import 'package:web/web.dart' as web; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -40,6 +39,20 @@ class _MyAppState extends State { @override void initState() { super.initState(); + + //Callback on taps + _jsNotificationsPlugin.tapStream.listen((event) { + switch (event.action) { + default: + if (event.tag == "rick_roll") { + openNewWindow("https://www.youtube.com/watch?v=dQw4w9WgXcQ"); + } else if (event.tag == "star_wars_channel") { + openNewWindow("https://www.youtube.com/@StarWars"); + } + } + }); + + //Callback on actions _jsNotificationsPlugin.actionStream.listen((event) { switch (event.action) { case "unexpected": @@ -115,15 +128,11 @@ class _MyAppState extends State { } default: - { - if (event.tag == "rick_roll") { - openNewWindow("https://www.youtube.com/watch?v=dQw4w9WgXcQ"); - } else if (event.tag == "star_wars_channel") { - openNewWindow("https://www.youtube.com/@StarWars"); - } - } + {} } }); + + //Callback on dismiss _jsNotificationsPlugin.dismissStream.listen((event) { switch (event.tag) { case "data-notification": @@ -190,10 +199,32 @@ class _MyAppState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ Column( + spacing: 12, children: [ - Text("Test Notification", style: _boldTextStyle), + Text("Notification permission", style: _boldTextStyle), + Text( + "Permission status: ${_jsNotificationsPlugin.permission ?? "null"}"), + ElevatedButton( + onPressed: () async { + //requestPermissions() will only show modal if permission is + // "default". + //The three states are important regarding feedback to + //users: + //1. default = show request button + //2. granted = ready to show + //3. denied = blocked, you have to show instructions on how + //to manually turn on notifications. + await _jsNotificationsPlugin.requestPermissions(); + + //Update permission text after request was sent + setState(() {}); + }, + child: const Text("Request permission"), + ), const SizedBox(height: 8), + Text("Test Notification", style: _boldTextStyle), Row( + spacing: 8, mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( @@ -203,7 +234,6 @@ class _MyAppState extends State { }, child: const Text("Test Notification"), ), - const SizedBox(width: 4), ElevatedButton( onPressed: () { _dismissBasicNotification(); @@ -212,19 +242,18 @@ class _MyAppState extends State { ), ], ), - const SizedBox(height: 24), - Text("Data Notification", style: _boldTextStyle), const SizedBox(height: 8), + Text("Data Notification", style: _boldTextStyle), ElevatedButton( onPressed: () { _sendDataNotification(); }, child: const Text("Data Notification"), ), - const SizedBox(height: 24), - Text("Custom Notifications", style: _boldTextStyle), const SizedBox(height: 8), + Text("Custom Notifications", style: _boldTextStyle), Row( + spacing: 8, mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( @@ -233,7 +262,6 @@ class _MyAppState extends State { }, child: const Text("Expect the unexpected."), ), - const SizedBox(width: 4), ElevatedButton( onPressed: () { _sendGrievous(); @@ -390,7 +418,7 @@ class _MyAppState extends State { } void openNewWindow(String url) { - html.window.open(url, "", 'noopener,noreferrer'); + web.window.open(url, "", 'noopener,noreferrer'); } Future _showTimerNotification() { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 06bd713..9c8578b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -28,7 +28,10 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.6 - stop_watch_timer: ^3.2.1 + stop_watch_timer: ^3.2.2 + + # For window.open support + web: ^1.1.1 dev_dependencies: integration_test: diff --git a/example/web/js_notifications-sw.js b/example/web/js_notifications-sw.js index 7a30eaf..29d0dc5 100644 --- a/example/web/js_notifications-sw.js +++ b/example/web/js_notifications-sw.js @@ -83,6 +83,8 @@ const getClients = () => self.clients.matchAll(matchOptions); const hasPermissions = () => Notification.permission === 'granted'; +const permission = () => Notification.permission; + // function showNotification(title, options, timer) { const showNotification = async (title, options) => { if (!hasPermissions()) { diff --git a/lib/interop/notifications_api/notification_api.dart b/lib/interop/notifications_api/notification_api.dart index 06aa03e..165cd92 100644 --- a/lib/interop/notifications_api/notification_api.dart +++ b/lib/interop/notifications_api/notification_api.dart @@ -1,5 +1,5 @@ -import 'dart:html'; - +import 'package:web/web.dart' as web; +import 'dart:js_interop'; //For .toDart support on JSPromise import 'package:simple_print/simple_print.dart'; class NotificationsAPI { @@ -11,7 +11,10 @@ class NotificationsAPI { static NotificationsAPI get instance => _instance; - bool get isSupported => Notification.supported; + //package:web/web.dart do not have the supported value as dart:html + //https://api.dart.dev/dart-html/Notification/supported.html + //If permission has any value, it is "supported" + bool get isSupported => web.Notification.permission.isNotEmpty; Future requestPermission() async { try { @@ -19,8 +22,8 @@ class NotificationsAPI { printDebug("Notifications not supported", tag: tag); return false; } - final perm = await Notification.requestPermission(); - return (perm == "granted"); + final perm = await web.Notification.requestPermission().toDart; + return (perm.toString() == "granted"); } catch (e) { printDebug("Failed to request notifications permission", tag: tag); printDebug(e); @@ -30,7 +33,7 @@ class NotificationsAPI { bool get hasPermission { try { - final perm = Notification.permission; + final perm = web.Notification.permission; return (perm == "granted"); } catch (e) { printDebug("Failed to query notifications permission", tag: tag); @@ -38,4 +41,14 @@ class NotificationsAPI { return false; } } + + String? get permission { + try { + return web.Notification.permission; + } catch (e) { + printDebug("Failed to query notifications permission", tag: tag); + printDebug(e); + return null; + } + } } diff --git a/lib/js_notifications_web.dart b/lib/js_notifications_web.dart index bee46bb..d5b0064 100644 --- a/lib/js_notifications_web.dart +++ b/lib/js_notifications_web.dart @@ -115,6 +115,9 @@ class JsNotificationsWeb extends JsNotificationsPlatform { @override bool get hasPermissions => notificationsAPI.hasPermission; + @override + String? get permission => notificationsAPI.permission; + @override bool get isSupported => notificationsAPI.isSupported; diff --git a/lib/method_channel/js_notifications_method_channel.dart b/lib/method_channel/js_notifications_method_channel.dart index 92ac647..e1190e2 100644 --- a/lib/method_channel/js_notifications_method_channel.dart +++ b/lib/method_channel/js_notifications_method_channel.dart @@ -39,6 +39,10 @@ class MethodChannelJsNotifications extends JsNotificationsPlatform { // TODO: implement hasPermissions bool get hasPermissions => throw UnimplementedError(); + @override + // TODO: implement permissions + String? get permission => throw UnimplementedError(); + @override // TODO: implement isSupported bool get isSupported => throw UnimplementedError(); diff --git a/lib/platform_interface/js_notifications_platform_interface.dart b/lib/platform_interface/js_notifications_platform_interface.dart index 3538a6b..1f5b331 100644 --- a/lib/platform_interface/js_notifications_platform_interface.dart +++ b/lib/platform_interface/js_notifications_platform_interface.dart @@ -40,6 +40,14 @@ abstract class JsNotificationsPlatform extends PlatformInterface { /// See: https://developer.mozilla.org/en-US/docs/Web/API/Notification/permission_static bool get hasPermissions; + /// Convenience method for checking browser notification raw status + /// wrapper for Dart's native JS notification [Notification.permission] + /// + /// Return values: granted, denied, default or [null] + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/Notification/permission_static + String? get permission; + /// Convenience method checking browser notification support, /// wrapper for Dart's native JS notification [Notification.requestPermission()]. /// Returns [true] if response matches 'granted'. diff --git a/pubspec.yaml b/pubspec.yaml index 489f24b..6fa2beb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: js_notifications description: "An extended NotificationsAPI for Dart managing web notifications." -version: 0.0.5 +version: 0.0.6 homepage: https://github.com/cybex-dev/js_notifications platforms: web: @@ -19,7 +19,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - web: ^1.1.0 + web: ^1.1.1 plugin_platform_interface: ^2.1.8 uuid: ^4.5.1 simple_print: ^0.0.1+2 diff --git a/test/js_notifications_test.dart b/test/js_notifications_test.dart index 8c5b661..78c5461 100644 --- a/test/js_notifications_test.dart +++ b/test/js_notifications_test.dart @@ -54,6 +54,10 @@ class MockJsNotificationsPlatform // TODO: implement hasPermissions bool get hasPermissions => throw UnimplementedError(); + @override + // TODO: implement permission + String? get permission => throw UnimplementedError(); + @override // TODO: implement isSupported bool get isSupported => throw UnimplementedError();