Skip to content

Commit

Permalink
Basic Support
Browse files Browse the repository at this point in the history
- Check if the browser supports Notifcations
- Request Permission to send notifications
- Create a notification with Options.
- Provide a default example
- Provide IServiceCollectionExtension
  • Loading branch information
vertonghenb committed Oct 29, 2018
1 parent 28dccba commit e0ea35d
Show file tree
Hide file tree
Showing 24 changed files with 500 additions and 144 deletions.
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,46 @@
# Notifications
# Notifications
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.

## Demo
There is a sample application in /tests/ folder
For some other references of what the API does see the example [demo](https://web-push-book.gauntface.com/demos/notification-examples/)

## Installation

Coming Soon (waiting on the nuspec/ci)

## Usage

### Add INotificationService via DI
> Scoped by default.
```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddNotifications();
}
```

### Inject into component/pages
```csharp
@using Blazor.Extensions
@inject INotificationService NotificationService
```

### Create a notification
```csharp
NotificationOptions options = new NotificationOptions
{
Body = body,
Icon = icon,
};

await NotificationService.CreateAsync(title, options);
```
### Browser Support
```csharp
bool IsSupportedByBrowser = NotificationService.IsSupportedByBrowserAsync;
```
### Request Permission
```csharp
PermissionType permission = await NotificationService.RequestPermissionAsync();
```
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
</ItemGroup>

<ItemGroup>
<WebpackInputs Remove="src\BlazorTypes.ts" />
<WebpackInputs Remove="src\GlobalExports.ts" />
<WebpackInputs Remove="src\NotificationService.ts" />
</ItemGroup>

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

Large diffs are not rendered by default.

12 changes: 0 additions & 12 deletions src/Blazor.Extensions.Notifications.JS/src/BlazorTypes.ts

This file was deleted.

6 changes: 0 additions & 6 deletions src/Blazor.Extensions.Notifications.JS/src/GlobalExports.ts

This file was deleted.

28 changes: 23 additions & 5 deletions src/Blazor.Extensions.Notifications.JS/src/Initialize.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
import './GlobalExports';
import { NotificationsManager } from './NotificationService';

// import { HubConnectionManager } from './HubConnectionManager';
namespace Notifications {
const blazorExtensions: string = 'BlazorExtensions';
// define what this extension adds to the window object inside BlazorExtensions
const extensionObject = {
Notifications: new NotificationsManager()
};

// "use strict";
// HubConnectionManager.initialize();
export function initialize(): void {
if (typeof window !== 'undefined' && !window[blazorExtensions]) {
// when the library is loaded in a browser via a <script> element, make the
// following APIs available in global scope for invocation from JS
window[blazorExtensions] = {
...extensionObject
};
} else {
window[blazorExtensions] = {
...window[blazorExtensions],
...extensionObject
};
}
}
}

//TODO: Import all your .TS here and initialize it. This script will be called when the package is referenced and app start.
Notifications.initialize();
25 changes: 25 additions & 0 deletions src/Blazor.Extensions.Notifications.JS/src/NotificationService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
interface INotificationsManager {
IsSupported(): boolean;
RequestPermission(): Promise<string>;
Create(title: string, options: object): object;
}


export class NotificationsManager implements INotificationsManager {
RequestPermission(): Promise<string> {
return new Promise((resolve, reject) => {
Notification.requestPermission((permission) => {
resolve(permission);
});
});
}
IsSupported(): boolean {
if (("Notification" in window))
return true;
return false;
}
Create(title: string, options: object): object {
var note = new Notification(title, options);
return note;
}
}
26 changes: 26 additions & 0 deletions src/Blazor.Extensions.Notifications/INotificationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Threading.Tasks;

namespace Blazor.Extensions
{
public interface INotificationService
{
/// <summary>
/// Checks if the Notifications' API is Support by the browser.
/// </summary>
/// <returns></returns>
Task<bool> IsSupportedByBrowserAsync();
/// <summary>
/// Request the user for his permission to send notifications.
/// </summary>
/// <returns></returns>
Task<PermissionType> RequestPermissionAsync();
/// <summary>
/// Create a Notification with <seealso cref="NotificationOptions"/>
/// </summary>
/// <param name="title"></param>
/// <param name="options"></param>
/// <returns></returns>
Task CreateAsync(string title, NotificationOptions options);
Task CreateAsync(string title, string description, string iconUrl);
}
}
114 changes: 114 additions & 0 deletions src/Blazor.Extensions.Notifications/Notification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Blazor.Extensions
{
/// <summary>
/// A notification is an abstract representation of something that happened, such as the delivery of a message.
/// </summary>
public class Notification
{
#region Properties
/// <summary>
/// Defines a title for the notification, which will be shown at the top of the notification window when it is fired.
/// </summary>
public Guid Id { get; set; } = Guid.NewGuid();
public string Title { get; private set; }
#endregion

#region Options
/// <summary>
/// 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.
/// </summary>
public DateTime? TimeStamp { get; private set; } = DateTime.UtcNow;

/// <summary>
/// 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.)
/// </summary>
public string Dir { get; private set; }
/// <summary>
/// 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.
/// </summary>
public string Lang { get; private set; }
/// <summary>
/// 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.
/// </summary>
public string Badge { get; private set; }
/// <summary>
/// A <see cref="string"/> representing the body text of the notification, which will be displayed below the title.
/// </summary>
public string Body { get; private set; }
/// <summary>
/// A <see cref="string"/> representing an identifying tag for the notification.
/// </summary>
public string Tag { get; private set; }
/// <summary>
/// A <see cref="string"/> containing the URL of an icon to be displayed in the notification.
/// </summary>
public string Icon { get; private set; }
/// <summary>
/// A <see cref="string"/> containing the URL of an image to be displayed in the notification.
/// </summary>
public string Image { get; set; }
/// <summary>
/// An <see cref="object"/> with arbitrary data that you want associated with the notification. This can be of any data type.
/// </summary>
public object Data { get; private set; }
public bool? Renotify { get; private set; }
/// <summary>
/// Indicates that a notification should remain active until the user clicks or dismisses it, rather than closing automatically. The default value is false.
/// </summary>
public bool? RequireInteraction { get; private set; }
public bool? Silent { get; private set; }
/// <summary>
/// A <see cref="string"/> containing the URL of an audio file to be played when the notification fires.
/// </summary>
public string Sound { get; private set; }
/// <summary>
/// noscreen: A Boolean specifying whether the notification firing should enable the device's screen or not.
/// The default is false, which means it will enable the screen.
/// </summary>
public bool? NoScreen { get; private set; }
/// <summary>
/// sticky: A Boolean specifying whether the notification should be 'sticky', i.e. not easily clearable by the user.
/// The default is false, which means it won't be sticky.
/// </summary>
public bool? Sticky { get; private set; }
/// <summary>
/// The amount of seconds until the notifciation is closed. Default is 5 seconds
/// </summary>
public int TimeOut { get; private set; } = 5;
#endregion

#region Constructors
public Notification(string title, NotificationOptions options = null)
{
if (string.IsNullOrWhiteSpace(title))
throw new ArgumentNullException($"{nameof(title)}, cannot be null or empty.");

this.Title = title;

if (options == null)
return;

this.TimeStamp = options.TimeStamp;
this.Dir = options.Dir;
this.Lang = options.Lang;
this.Badge = options.Badge;
this.Body = options.Body; ;
this.Tag = options.Tag;
this.Icon = options.Icon;
this.Image = options.Image;
this.Data = options.Data;
this.Renotify = options.Renotify;
this.RequireInteraction = options.RequireInteraction;
this.Silent = options.Silent;
this.Sound = options.Sound;
this.NoScreen = options.NoScreen;
this.Sticky = options.Sticky;
this.TimeOut = options.TimeOut ?? this.TimeOut;
}
#endregion
}
}
79 changes: 79 additions & 0 deletions src/Blazor.Extensions.Notifications/NotificationOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Blazor.Extensions
{
public class NotificationOptions
{
#region Properties
/// <summary>
/// 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.
/// </summary>
public DateTime? TimeStamp { get; set; } = DateTime.UtcNow;
/// <summary>
/// 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.)
/// </summary>
public string Dir { get; set; } = "auto";
/// <summary>
/// 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.
/// </summary>
public string Lang { get; set; } = "en";
/// <summary>
/// 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.
/// </summary>
public string Badge { get; set; }
/// <summary>
/// A <see cref="string"/> representing the body text of the notification, which will be displayed below the title.
/// </summary>
public string Body { get; set; }
/// <summary>
/// A <see cref="string"/> representing an identifying tag for the notification.
/// </summary>
public string Tag { get; set; }
/// <summary>
/// A <see cref="string"/> containing the URL of an icon to be displayed in the notification.
/// </summary>
public string Icon { get; set; }
/// <summary>
/// A <see cref="string"/> containing the URL of an image to be displayed in the notification.
/// </summary>
public string Image { get; set; }
/// <summary>
/// An <see cref="object"/> with arbitrary data that you want associated with the notification. This can be of any data type.
/// </summary>
public object Data { get; set; }
/// <summary>
/// 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.
/// </summary>
public bool? Renotify { get; set; }
/// <summary>
/// Indicates that a notification should remain active until the user clicks or dismisses it, rather than closing automatically. The default value is false.
/// </summary>
public bool? RequireInteraction { get; set; }
/// <summary>
/// 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.
/// The default is false, which means it won't be silent.
/// </summary>
public bool? Silent { get; set; }
/// <summary>
/// A <see cref="string"/> containing the URL of an audio file to be played when the notification fires.
/// </summary>
public string Sound { get; set; }
/// <summary>
/// A <see cref="bool"/> specifying whether the notification firing should enable the device's screen or not.
/// The default is false, which means it will enable the screen.
/// </summary>
public bool? NoScreen { get; set; }
/// <summary>
/// A <see cref="bool"/> specifying whether the notification should be 'sticky', i.e. not easily clearable by the user.
/// The default is false, which means it won't be sticky.
/// </summary>
public bool? Sticky { get; set; }
/// <summary>
/// The amount of seconds until the notifciation is closed.
/// </summary>
public int? TimeOut { get; set; } = 5;
#endregion
}
}
Loading

0 comments on commit e0ea35d

Please sign in to comment.