1
mirror of https://github.com/home-assistant/frontend synced 2024-09-25 09:39:00 +02:00
ha-frontend/src/components/ha-push-notifications-toggle.ts

157 lines
4.3 KiB
TypeScript
Raw Normal View History

import { LitElement, TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import { getAppKey } from "../data/notify_html5";
import { showPromptDialog } from "../dialogs/generic/show-dialog-box";
import { HaSwitch } from "./ha-switch";
import { HomeAssistant } from "../types";
import { fireEvent } from "../common/dom/fire_event";
export const pushSupported =
"serviceWorker" in navigator &&
"PushManager" in window &&
(document.location.protocol === "https:" ||
document.location.hostname === "localhost" ||
document.location.hostname === "127.0.0.1");
@customElement("ha-push-notifications-toggle")
class HaPushNotificationsToggle extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public disabled!: boolean;
@state() private _pushChecked: boolean =
"Notification" in window && Notification.permission === "granted";
@state() private _loading: boolean = true;
protected render(): TemplateResult {
Polymer 3 modulize (#1154) * Version bump to 20180510.1 * Fix hass util * Fix translations * Bye paper-time-input * Add webpack config * Add webpack to package.json * Fix translation import * Disable web animations polyfill bad import * Disable importHref import * Update webpack config to build authorize.js * Build translations json * Build frontend correctly * Run eslint --fix * Load markdown JS on demand (#1155) * Add HTML imports (#1160) * Fix localize (#1161) * Fix Roboto in build (#1162) * Load web animations polyfill (#1163) * P3: Fix chart js (#1164) * P3: Fix Chart JS * Update timeline package * P3: panel resolver (#1165) * WIP * Initial importing of panels * Fix panel resolver * Fix automation and script editor (#1166) * Expose Polymer and Polymer.Element on window (#1167) * Remove unused import * eslint --fix * Es5 build (#1168) * Build for ES5 * Fix build_frontend * Remove stale comment * Migrate to use paper-material-styles (#1170) * Send parsed date to history/logbook (#1171) * Fork app storage behavior (#1172) * Add paper input with type time (#1173) * Fix authorize * Lint * Sort imports * Lint * Remove eslint-html * Do not lint authorize.html * Fix polymer lint * Try chrome 62 for wct * P3: Add patched iconset (#1175) * Add patched iconset * Lint * Test with latest Chrome again * Use less window.hassUtil * Teporarily use my fecha fork * Import correct intl.messageFormat * Update wct-browser-legacy to 1.0.0 * Include polyfill in right place * Fix IntlMessageFormat * Fix test not having a global scope * Rollup <_< * Fork app-localize-behavior * Disable wct tests * Lint
2018-05-15 19:31:47 +02:00
return html`
<ha-switch
.disabled=${this.disabled || this._loading}
.checked=${this._pushChecked}
@change=${this._handlePushChange}
></ha-switch>
`;
Polymer 3 modulize (#1154) * Version bump to 20180510.1 * Fix hass util * Fix translations * Bye paper-time-input * Add webpack config * Add webpack to package.json * Fix translation import * Disable web animations polyfill bad import * Disable importHref import * Update webpack config to build authorize.js * Build translations json * Build frontend correctly * Run eslint --fix * Load markdown JS on demand (#1155) * Add HTML imports (#1160) * Fix localize (#1161) * Fix Roboto in build (#1162) * Load web animations polyfill (#1163) * P3: Fix chart js (#1164) * P3: Fix Chart JS * Update timeline package * P3: panel resolver (#1165) * WIP * Initial importing of panels * Fix panel resolver * Fix automation and script editor (#1166) * Expose Polymer and Polymer.Element on window (#1167) * Remove unused import * eslint --fix * Es5 build (#1168) * Build for ES5 * Fix build_frontend * Remove stale comment * Migrate to use paper-material-styles (#1170) * Send parsed date to history/logbook (#1171) * Fork app storage behavior (#1172) * Add paper input with type time (#1173) * Fix authorize * Lint * Sort imports * Lint * Remove eslint-html * Do not lint authorize.html * Fix polymer lint * Try chrome 62 for wct * P3: Add patched iconset (#1175) * Add patched iconset * Lint * Test with latest Chrome again * Use less window.hassUtil * Teporarily use my fecha fork * Import correct intl.messageFormat * Update wct-browser-legacy to 1.0.0 * Include polyfill in right place * Fix IntlMessageFormat * Fix test not having a global scope * Rollup <_< * Fork app-localize-behavior * Disable wct tests * Lint
2018-05-15 19:31:47 +02:00
}
async connectedCallback() {
super.connectedCallback();
2018-08-31 11:17:57 +02:00
if (!pushSupported) return;
try {
const reg = await navigator.serviceWorker.ready;
2018-08-31 11:17:57 +02:00
if (!reg.pushManager) {
return;
}
reg.pushManager.getSubscription().then((subscription) => {
this._loading = false;
this._pushChecked = !!subscription;
});
} catch (err) {
// We don't set loading to `false` so we remain disabled
}
}
2018-08-20 11:49:13 +02:00
private _handlePushChange(ev: Event) {
2018-08-31 11:17:57 +02:00
// Somehow this is triggered on Safari on page load causing
// it to get into a loop and crash the page.
if (!pushSupported) return;
const pushnotifications = (ev.target as HaSwitch).checked;
if (pushnotifications) {
this._subscribePushNotifications();
} else {
this._unsubscribePushNotifications();
}
}
2018-08-20 11:49:13 +02:00
private async _subscribePushNotifications() {
2018-08-20 11:49:13 +02:00
const reg = await navigator.serviceWorker.ready;
let sub;
2018-08-20 11:49:13 +02:00
try {
let browserName: string;
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
browserName = "firefox";
2018-08-20 11:49:13 +02:00
} else {
browserName = "chrome";
2018-08-20 11:49:13 +02:00
}
const name = await showPromptDialog(this, {
title: this.hass.localize(
"ui.panel.profile.push_notifications.add_device_prompt.title"
),
inputLabel: this.hass.localize(
"ui.panel.profile.push_notifications.add_device_prompt.input_label"
),
});
if (name == null) {
this._pushChecked = false;
return;
}
let applicationServerKey: Uint8Array | null;
try {
applicationServerKey = await getAppKey(this.hass);
} catch (ex) {
applicationServerKey = null;
}
if (applicationServerKey) {
sub = await reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey,
});
} else {
sub = await reg.pushManager.subscribe({ userVisibleOnly: true });
}
await this.hass.callApi("POST", "notify.html5", {
2018-08-20 11:49:13 +02:00
subscription: sub,
browser: browserName,
name,
});
} catch (err: any) {
const message = err.message || "Notification registration failed.";
if (sub) {
await sub.unsubscribe();
}
2018-08-20 11:49:13 +02:00
// eslint-disable-next-line
console.error(err);
fireEvent(this, "hass-notification", { message });
this._pushChecked = false;
2018-08-20 11:49:13 +02:00
}
}
private async _unsubscribePushNotifications() {
2018-08-20 11:49:13 +02:00
const reg = await navigator.serviceWorker.ready;
try {
const sub = await reg.pushManager.getSubscription();
if (!sub) return;
await this.hass.callApi("DELETE", "notify.html5", { subscription: sub });
2018-08-20 11:49:13 +02:00
await sub.unsubscribe();
} catch (err: any) {
const message =
err.message || "Failed unsubscribing for push notifications.";
2018-08-20 11:49:13 +02:00
// eslint-disable-next-line
console.error("Error in unsub push", err);
2018-08-20 11:49:13 +02:00
fireEvent(this, "hass-notification", { message });
this._pushChecked = true;
2018-08-20 11:49:13 +02:00
}
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-push-notifications-toggle": HaPushNotificationsToggle;
}
}