angular/aio/src/app/sw-updates/sw-update-notifications.service.ts

95 lines
2.7 KiB
TypeScript

import { Inject, Injectable } from '@angular/core';
import { MdSnackBar, MdSnackBarConfig, MdSnackBarRef } from '@angular/material';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/filter';
import { Global } from './global.value';
import { SwUpdatesService } from './sw-updates.service';
/**
* SwUpdateNotificationsService
*
* @description
* Once enabled:
* 1. Subscribes to ServiceWorker updates and prompts the user to update.
* 2. When the user confirms, it activates the update and reloads the page upon activation success.
* 3. Continues to listen for available ServiceWorker updates.
*
* @method
* `disable()` {() => void} - Dismiss any open notifications and stop listening for ServiceWorker
* updates.
*
* @method
* `enable()` {() => void} - Start listening for ServiceWorker updates.
*/
@Injectable()
export class SwUpdateNotificationsService {
private onDisable = new Subject();
private snackBars: MdSnackBarRef<any>[] = [];
private enabled = false;
constructor(@Inject(Global) private global: any,
private snackBarService: MdSnackBar,
private swUpdates: SwUpdatesService) {
this.onDisable.subscribe(() => this.snackBars.forEach(sb => sb.dismiss()));
}
disable() {
if (this.enabled) {
this.enabled = false;
this.onDisable.next();
}
}
enable() {
if (!this.enabled) {
this.enabled = true;
this.swUpdates.isUpdateAvailable
.filter(v => v)
.takeUntil(this.onDisable)
.subscribe(() => this.notifyForUpdate());
}
}
private activateUpdate() {
this.swUpdates.activateUpdate().then(success => {
if (success) {
this.onActivateSuccess();
} else {
this.onActivateFailure();
}
});
}
private notifyForUpdate() {
this.openSnackBar('New update for angular.io is available.', 'Update now')
.onAction().subscribe(() => this.activateUpdate());
}
private onActivateFailure() {
const snackBar = this.openSnackBar('Update activation failed :(', 'Dismiss', {duration: 5000});
snackBar.onAction().subscribe(() => snackBar.dismiss());
}
private onActivateSuccess() {
this.reloadPage();
}
private openSnackBar(message: string, action?: string, config?: MdSnackBarConfig): MdSnackBarRef<any> {
const snackBar = this.snackBarService.open(message, action, config);
snackBar.afterDismissed().subscribe(() => this.snackBars = this.snackBars.filter(sb => sb !== snackBar));
this.snackBars.push(snackBar);
return snackBar;
}
private reloadPage() {
const location = this.global && (this.global as Window).location;
if (location && location.reload) {
location.reload();
}
}
}