Skip to content

Commit e0ea35d

Browse files
committed
Basic Support
- Check if the browser supports Notifcations - Request Permission to send notifications - Create a notification with Options. - Provide a default example - Provide IServiceCollectionExtension
1 parent 28dccba commit e0ea35d

24 files changed

+500
-144
lines changed

README.md

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,46 @@
1-
# Notifications
1+
# Notifications
2+
Implementation of the [Notification API](https://developer.mozilla.org/en-US/docs/Web/API/notification) in C# for [Blazor](https://github.com/aspnet/Blazor) via Interop.
3+
4+
## Demo
5+
There is a sample application in /tests/ folder
6+
For some other references of what the API does see the example [demo](https://web-push-book.gauntface.com/demos/notification-examples/)
7+
8+
## Installation
9+
10+
Coming Soon (waiting on the nuspec/ci)
11+
12+
## Usage
13+
14+
### Add INotificationService via DI
15+
> Scoped by default.
16+
```csharp
17+
public void ConfigureServices(IServiceCollection services)
18+
{
19+
services.AddNotifications();
20+
}
21+
```
22+
23+
### Inject into component/pages
24+
```csharp
25+
@using Blazor.Extensions
26+
@inject INotificationService NotificationService
27+
```
28+
29+
### Create a notification
30+
```csharp
31+
NotificationOptions options = new NotificationOptions
32+
{
33+
Body = body,
34+
Icon = icon,
35+
};
36+
37+
await NotificationService.CreateAsync(title, options);
38+
```
39+
### Browser Support
40+
```csharp
41+
bool IsSupportedByBrowser = NotificationService.IsSupportedByBrowserAsync;
42+
```
43+
### Request Permission
44+
```csharp
45+
PermissionType permission = await NotificationService.RequestPermissionAsync();
46+
```

src/Blazor.Extensions.Notifications.JS/Blazor.Extensions.Notifications.JS.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
</ItemGroup>
2222

2323
<ItemGroup>
24-
<WebpackInputs Remove="src\BlazorTypes.ts" />
25-
<WebpackInputs Remove="src\GlobalExports.ts" />
24+
<WebpackInputs Remove="src\NotificationService.ts" />
2625
</ItemGroup>
2726

2827
<Target Name="EnsureNpmRestored" Condition="!Exists('node_modules')">

src/Blazor.Extensions.Notifications.JS/dist/blazor.extensions.notifications.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Blazor.Extensions.Notifications.JS/src/BlazorTypes.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/Blazor.Extensions.Notifications.JS/src/GlobalExports.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
1-
import './GlobalExports';
1+
import { NotificationsManager } from './NotificationService';
22

3-
// import { HubConnectionManager } from './HubConnectionManager';
3+
namespace Notifications {
4+
const blazorExtensions: string = 'BlazorExtensions';
5+
// define what this extension adds to the window object inside BlazorExtensions
6+
const extensionObject = {
7+
Notifications: new NotificationsManager()
8+
};
49

5-
// "use strict";
6-
// HubConnectionManager.initialize();
10+
export function initialize(): void {
11+
if (typeof window !== 'undefined' && !window[blazorExtensions]) {
12+
// when the library is loaded in a browser via a <script> element, make the
13+
// following APIs available in global scope for invocation from JS
14+
window[blazorExtensions] = {
15+
...extensionObject
16+
};
17+
} else {
18+
window[blazorExtensions] = {
19+
...window[blazorExtensions],
20+
...extensionObject
21+
};
22+
}
23+
}
24+
}
725

8-
//TODO: Import all your .TS here and initialize it. This script will be called when the package is referenced and app start.
26+
Notifications.initialize();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
interface INotificationsManager {
2+
IsSupported(): boolean;
3+
RequestPermission(): Promise<string>;
4+
Create(title: string, options: object): object;
5+
}
6+
7+
8+
export class NotificationsManager implements INotificationsManager {
9+
RequestPermission(): Promise<string> {
10+
return new Promise((resolve, reject) => {
11+
Notification.requestPermission((permission) => {
12+
resolve(permission);
13+
});
14+
});
15+
}
16+
IsSupported(): boolean {
17+
if (("Notification" in window))
18+
return true;
19+
return false;
20+
}
21+
Create(title: string, options: object): object {
22+
var note = new Notification(title, options);
23+
return note;
24+
}
25+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Threading.Tasks;
2+
3+
namespace Blazor.Extensions
4+
{
5+
public interface INotificationService
6+
{
7+
/// <summary>
8+
/// Checks if the Notifications' API is Support by the browser.
9+
/// </summary>
10+
/// <returns></returns>
11+
Task<bool> IsSupportedByBrowserAsync();
12+
/// <summary>
13+
/// Request the user for his permission to send notifications.
14+
/// </summary>
15+
/// <returns></returns>
16+
Task<PermissionType> RequestPermissionAsync();
17+
/// <summary>
18+
/// Create a Notification with <seealso cref="NotificationOptions"/>
19+
/// </summary>
20+
/// <param name="title"></param>
21+
/// <param name="options"></param>
22+
/// <returns></returns>
23+
Task CreateAsync(string title, NotificationOptions options);
24+
Task CreateAsync(string title, string description, string iconUrl);
25+
}
26+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Blazor.Extensions
6+
{
7+
/// <summary>
8+
/// A notification is an abstract representation of something that happened, such as the delivery of a message.
9+
/// </summary>
10+
public class Notification
11+
{
12+
#region Properties
13+
/// <summary>
14+
/// Defines a title for the notification, which will be shown at the top of the notification window when it is fired.
15+
/// </summary>
16+
public Guid Id { get; set; } = Guid.NewGuid();
17+
public string Title { get; private set; }
18+
#endregion
19+
20+
#region Options
21+
/// <summary>
22+
/// A <see cref="DateTime"/> representing the time, in milliseconds since 00:00:00 UTC on 1 January 1970, of the event for which the notification was created.
23+
/// </summary>
24+
public DateTime? TimeStamp { get; private set; } = DateTime.UtcNow;
25+
26+
/// <summary>
27+
/// The direction in which to display the notification. It defaults to auto, which just adopts the browser's language setting behavior, but you can override that behaviour by setting values of ltr and rtl (although most browsers seem to ignore these settings.)
28+
/// </summary>
29+
public string Dir { get; private set; }
30+
/// <summary>
31+
/// The notification's language, as specified using a DOMString representing a BCP 47 language tag. See the Sitepoint ISO 2 letter language codes page for a simple reference.
32+
/// </summary>
33+
public string Lang { get; private set; }
34+
/// <summary>
35+
/// a <see cref="string"/> containing the URL of the image used to represent the notification when there is not enough space to display the notification itself.
36+
/// </summary>
37+
public string Badge { get; private set; }
38+
/// <summary>
39+
/// A <see cref="string"/> representing the body text of the notification, which will be displayed below the title.
40+
/// </summary>
41+
public string Body { get; private set; }
42+
/// <summary>
43+
/// A <see cref="string"/> representing an identifying tag for the notification.
44+
/// </summary>
45+
public string Tag { get; private set; }
46+
/// <summary>
47+
/// A <see cref="string"/> containing the URL of an icon to be displayed in the notification.
48+
/// </summary>
49+
public string Icon { get; private set; }
50+
/// <summary>
51+
/// A <see cref="string"/> containing the URL of an image to be displayed in the notification.
52+
/// </summary>
53+
public string Image { get; set; }
54+
/// <summary>
55+
/// An <see cref="object"/> with arbitrary data that you want associated with the notification. This can be of any data type.
56+
/// </summary>
57+
public object Data { get; private set; }
58+
public bool? Renotify { get; private set; }
59+
/// <summary>
60+
/// Indicates that a notification should remain active until the user clicks or dismisses it, rather than closing automatically. The default value is false.
61+
/// </summary>
62+
public bool? RequireInteraction { get; private set; }
63+
public bool? Silent { get; private set; }
64+
/// <summary>
65+
/// A <see cref="string"/> containing the URL of an audio file to be played when the notification fires.
66+
/// </summary>
67+
public string Sound { get; private set; }
68+
/// <summary>
69+
/// noscreen: A Boolean specifying whether the notification firing should enable the device's screen or not.
70+
/// The default is false, which means it will enable the screen.
71+
/// </summary>
72+
public bool? NoScreen { get; private set; }
73+
/// <summary>
74+
/// sticky: A Boolean specifying whether the notification should be 'sticky', i.e. not easily clearable by the user.
75+
/// The default is false, which means it won't be sticky.
76+
/// </summary>
77+
public bool? Sticky { get; private set; }
78+
/// <summary>
79+
/// The amount of seconds until the notifciation is closed. Default is 5 seconds
80+
/// </summary>
81+
public int TimeOut { get; private set; } = 5;
82+
#endregion
83+
84+
#region Constructors
85+
public Notification(string title, NotificationOptions options = null)
86+
{
87+
if (string.IsNullOrWhiteSpace(title))
88+
throw new ArgumentNullException($"{nameof(title)}, cannot be null or empty.");
89+
90+
this.Title = title;
91+
92+
if (options == null)
93+
return;
94+
95+
this.TimeStamp = options.TimeStamp;
96+
this.Dir = options.Dir;
97+
this.Lang = options.Lang;
98+
this.Badge = options.Badge;
99+
this.Body = options.Body; ;
100+
this.Tag = options.Tag;
101+
this.Icon = options.Icon;
102+
this.Image = options.Image;
103+
this.Data = options.Data;
104+
this.Renotify = options.Renotify;
105+
this.RequireInteraction = options.RequireInteraction;
106+
this.Silent = options.Silent;
107+
this.Sound = options.Sound;
108+
this.NoScreen = options.NoScreen;
109+
this.Sticky = options.Sticky;
110+
this.TimeOut = options.TimeOut ?? this.TimeOut;
111+
}
112+
#endregion
113+
}
114+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Blazor.Extensions
6+
{
7+
public class NotificationOptions
8+
{
9+
#region Properties
10+
/// <summary>
11+
/// A <see cref="DateTime"/> representing the time, in milliseconds since 00:00:00 UTC on 1 January 1970, of the event for which the notification was created.
12+
/// </summary>
13+
public DateTime? TimeStamp { get; set; } = DateTime.UtcNow;
14+
/// <summary>
15+
/// The direction in which to display the notification. It defaults to auto, which just adopts the browser's language setting behavior, but you can override that behaviour by setting values of ltr and rtl (although most browsers seem to ignore these settings.)
16+
/// </summary>
17+
public string Dir { get; set; } = "auto";
18+
/// <summary>
19+
/// The notification's language, as specified using a <see cref="string"/> representing a BCP 47 language tag. See the Sitepoint ISO 2 letter language codes page for a simple reference.
20+
/// </summary>
21+
public string Lang { get; set; } = "en";
22+
/// <summary>
23+
/// a <see cref="string"/> containing the URL of the image used to represent the notification when there is not enough space to display the notification itself.
24+
/// </summary>
25+
public string Badge { get; set; }
26+
/// <summary>
27+
/// A <see cref="string"/> representing the body text of the notification, which will be displayed below the title.
28+
/// </summary>
29+
public string Body { get; set; }
30+
/// <summary>
31+
/// A <see cref="string"/> representing an identifying tag for the notification.
32+
/// </summary>
33+
public string Tag { get; set; }
34+
/// <summary>
35+
/// A <see cref="string"/> containing the URL of an icon to be displayed in the notification.
36+
/// </summary>
37+
public string Icon { get; set; }
38+
/// <summary>
39+
/// A <see cref="string"/> containing the URL of an image to be displayed in the notification.
40+
/// </summary>
41+
public string Image { get; set; }
42+
/// <summary>
43+
/// An <see cref="object"/> with arbitrary data that you want associated with the notification. This can be of any data type.
44+
/// </summary>
45+
public object Data { get; set; }
46+
/// <summary>
47+
/// A <see cref="bool"/> specifying whether the user should be notified after a new notification replaces an old one. The default is false, which means they won't be notified.
48+
/// </summary>
49+
public bool? Renotify { get; set; }
50+
/// <summary>
51+
/// Indicates that a notification should remain active until the user clicks or dismisses it, rather than closing automatically. The default value is false.
52+
/// </summary>
53+
public bool? RequireInteraction { get; set; }
54+
/// <summary>
55+
/// A <see cref="bool"/> specifying whether the notification should be silent, i.e. no sounds or vibrations should be issued, regardless of the device settings.
56+
/// The default is false, which means it won't be silent.
57+
/// </summary>
58+
public bool? Silent { get; set; }
59+
/// <summary>
60+
/// A <see cref="string"/> containing the URL of an audio file to be played when the notification fires.
61+
/// </summary>
62+
public string Sound { get; set; }
63+
/// <summary>
64+
/// A <see cref="bool"/> specifying whether the notification firing should enable the device's screen or not.
65+
/// The default is false, which means it will enable the screen.
66+
/// </summary>
67+
public bool? NoScreen { get; set; }
68+
/// <summary>
69+
/// A <see cref="bool"/> specifying whether the notification should be 'sticky', i.e. not easily clearable by the user.
70+
/// The default is false, which means it won't be sticky.
71+
/// </summary>
72+
public bool? Sticky { get; set; }
73+
/// <summary>
74+
/// The amount of seconds until the notifciation is closed.
75+
/// </summary>
76+
public int? TimeOut { get; set; } = 5;
77+
#endregion
78+
}
79+
}

0 commit comments

Comments
 (0)