Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 45 additions & 17 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -40,6 +39,20 @@ class _MyAppState extends State<MyApp> {
@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":
Expand Down Expand Up @@ -115,15 +128,11 @@ class _MyAppState extends State<MyApp> {
}

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":
Expand Down Expand Up @@ -190,10 +199,32 @@ class _MyAppState extends State<MyApp> {
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(
Expand All @@ -203,7 +234,6 @@ class _MyAppState extends State<MyApp> {
},
child: const Text("Test Notification"),
),
const SizedBox(width: 4),
ElevatedButton(
onPressed: () {
_dismissBasicNotification();
Expand All @@ -212,19 +242,18 @@ class _MyAppState extends State<MyApp> {
),
],
),
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(
Expand All @@ -233,7 +262,6 @@ class _MyAppState extends State<MyApp> {
},
child: const Text("Expect the unexpected."),
),
const SizedBox(width: 4),
ElevatedButton(
onPressed: () {
_sendGrievous();
Expand Down Expand Up @@ -390,7 +418,7 @@ class _MyAppState extends State<MyApp> {
}

void openNewWindow(String url) {
html.window.open(url, "", 'noopener,noreferrer');
web.window.open(url, "", 'noopener,noreferrer');
}

Future<void> _showTimerNotification() {
Expand Down
5 changes: 4 additions & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions example/web/js_notifications-sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
25 changes: 19 additions & 6 deletions lib/interop/notifications_api/notification_api.dart
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -11,16 +11,19 @@ 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<bool> requestPermission() async {
try {
if (!isSupported) {
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);
Expand All @@ -30,12 +33,22 @@ 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);
printDebug(e);
return false;
}
}

String? get permission {
try {
return web.Notification.permission;
} catch (e) {
printDebug("Failed to query notifications permission", tag: tag);
printDebug(e);
return null;
}
}
}
3 changes: 3 additions & 0 deletions lib/js_notifications_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 4 additions & 0 deletions lib/method_channel/js_notifications_method_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'.
Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions test/js_notifications_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down