Migrate push notification toggle from Polymer to Lit (#18565)

This commit is contained in:
Simon Lamon 2023-11-24 15:47:09 +01:00 committed by GitHub
parent 3da7025d78
commit 1d2dc37f75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 115 additions and 148 deletions

View File

@ -1,10 +1,10 @@
import { html } from "@polymer/polymer/lib/utils/html-tag"; import { LitElement, TemplateResult, html } from "lit";
/* eslint-plugin-disable lit */ import { customElement, property, state } from "lit/decorators";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { getAppKey } from "../data/notify_html5"; import { getAppKey } from "../data/notify_html5";
import { showPromptDialog } from "../dialogs/generic/show-dialog-box"; import { showPromptDialog } from "../dialogs/generic/show-dialog-box";
import { EventsMixin } from "../mixins/events-mixin"; import { HaSwitch } from "./ha-switch";
import "./ha-switch"; import { HomeAssistant } from "../types";
import { fireEvent } from "../common/dom/fire_event";
export const pushSupported = export const pushSupported =
"serviceWorker" in navigator && "serviceWorker" in navigator &&
@ -13,39 +13,27 @@ export const pushSupported =
document.location.hostname === "localhost" || document.location.hostname === "localhost" ||
document.location.hostname === "127.0.0.1"); document.location.hostname === "127.0.0.1");
/* @customElement("ha-push-notifications-toggle")
* @appliesMixin EventsMixin class HaPushNotificationsToggle extends LitElement {
*/ @property({ attribute: false }) public hass!: HomeAssistant;
class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
static get template() { @state() private _disabled: boolean = false;
@state() private _pushChecked: boolean =
"Notification" in window && Notification.permission === "granted";
@state() private _loading: boolean = true;
protected render(): TemplateResult {
return html` return html`
<ha-switch <ha-switch
disabled="[[_compDisabled(disabled, loading)]]" .disabled=${this._disabled || this._loading}
checked="{{pushChecked}}" .checked=${this._pushChecked}
on-change="handlePushChange" @change=${this._handlePushChange}
></ha-switch> ></ha-switch>
`; `;
} }
static get properties() {
return {
hass: { type: Object, value: null },
disabled: {
type: Boolean,
value: false,
},
pushChecked: {
type: Boolean,
value:
"Notification" in window && Notification.permission === "granted",
},
loading: {
type: Boolean,
value: true,
},
};
}
async connectedCallback() { async connectedCallback() {
super.connectedCallback(); super.connectedCallback();
@ -57,32 +45,33 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
return; return;
} }
reg.pushManager.getSubscription().then((subscription) => { reg.pushManager.getSubscription().then((subscription) => {
this.loading = false; this._loading = false;
this.pushChecked = !!subscription; this._pushChecked = !!subscription;
}); });
} catch (err) { } catch (err) {
// We don't set loading to `false` so we remain disabled // We don't set loading to `false` so we remain disabled
} }
} }
handlePushChange(event) { private _handlePushChange(ev: Event) {
// Somehow this is triggered on Safari on page load causing // Somehow this is triggered on Safari on page load causing
// it to get into a loop and crash the page. // it to get into a loop and crash the page.
if (!pushSupported) return; if (!pushSupported) return;
if (event.target.checked) { const pushnotifications = (ev.target as HaSwitch).checked;
this.subscribePushNotifications(); if (pushnotifications) {
this._subscribePushNotifications();
} else { } else {
this.unsubscribePushNotifications(); this._unsubscribePushNotifications();
} }
} }
async subscribePushNotifications() { private async _subscribePushNotifications() {
const reg = await navigator.serviceWorker.ready; const reg = await navigator.serviceWorker.ready;
let sub; let sub;
try { try {
let browserName; let browserName: string;
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) { if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
browserName = "firefox"; browserName = "firefox";
} else { } else {
@ -98,11 +87,11 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
), ),
}); });
if (name == null) { if (name == null) {
this.pushChecked = false; this._pushChecked = false;
return; return;
} }
let applicationServerKey; let applicationServerKey: Uint8Array | null;
try { try {
applicationServerKey = await getAppKey(this.hass); applicationServerKey = await getAppKey(this.hass);
} catch (ex) { } catch (ex) {
@ -123,7 +112,7 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
browser: browserName, browser: browserName,
name, name,
}); });
} catch (err) { } catch (err: any) {
const message = err.message || "Notification registration failed."; const message = err.message || "Notification registration failed.";
if (sub) { if (sub) {
await sub.unsubscribe(); await sub.unsubscribe();
@ -132,12 +121,12 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
// eslint-disable-next-line // eslint-disable-next-line
console.error(err); console.error(err);
this.fire("hass-notification", { message }); fireEvent(this, "hass-notification", { message });
this.pushChecked = false; this._pushChecked = false;
} }
} }
async unsubscribePushNotifications() { private async _unsubscribePushNotifications() {
const reg = await navigator.serviceWorker.ready; const reg = await navigator.serviceWorker.ready;
try { try {
@ -147,24 +136,21 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
await this.hass.callApi("DELETE", "notify.html5", { subscription: sub }); await this.hass.callApi("DELETE", "notify.html5", { subscription: sub });
await sub.unsubscribe(); await sub.unsubscribe();
} catch (err) { } catch (err: any) {
const message = const message =
err.message || "Failed unsubscribing for push notifications."; err.message || "Failed unsubscribing for push notifications.";
// eslint-disable-next-line // eslint-disable-next-line
console.error("Error in unsub push", err); console.error("Error in unsub push", err);
this.fire("hass-notification", { message }); fireEvent(this, "hass-notification", { message });
this.pushChecked = true; this._pushChecked = true;
}
} }
} }
_compDisabled(disabled, loading) { declare global {
return disabled || loading; interface HTMLElementTagNameMap {
"ha-push-notifications-toggle": HaPushNotificationsToggle;
} }
} }
customElements.define(
"ha-push-notifications-toggle",
HaPushNotificationsToggle
);

View File

@ -1,91 +0,0 @@
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { pushSupported } from "../../components/ha-push-notifications-toggle";
import "../../components/ha-settings-row";
import LocalizeMixin from "../../mixins/localize-mixin";
import { documentationUrl } from "../../util/documentation-url";
/*
* @appliesMixin LocalizeMixin
*/
class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style>
a {
color: var(--primary-color);
}
</style>
<ha-settings-row narrow="[[narrow]]">
<span slot="heading"
>[[localize('ui.panel.profile.push_notifications.header')]]</span
>
<span slot="description">
[[localize(_descrLocalizeKey)]]
<a
href="[[_computeDocumentationUrl(hass)]]"
target="_blank"
rel="noreferrer"
>[[localize('ui.panel.profile.push_notifications.link_promo')]]</a
>
</span>
<ha-push-notifications-toggle
hass="[[hass]]"
disabled="[[_error]]"
></ha-push-notifications-toggle>
</ha-settings-row>
`;
}
static get properties() {
return {
hass: Object,
narrow: Boolean,
_descrLocalizeKey: {
type: String,
computed: "_descriptionKey(_platformLoaded, _pushSupported)",
},
_platformLoaded: {
type: Boolean,
computed: "_compPlatformLoaded(hass)",
},
_pushSupported: {
type: Boolean,
value: pushSupported,
},
_error: {
type: Boolean,
computed: "_compError(_platformLoaded, _pushSupported)",
},
};
}
_computeDocumentationUrl(hass) {
return documentationUrl(hass, "/integrations/html5");
}
_compPlatformLoaded(hass) {
return isComponentLoaded(hass, "notify.html5");
}
_compError(platformLoaded, pushSupported_) {
return !platformLoaded || !pushSupported_;
}
_descriptionKey(platformLoaded, pushSupported_) {
let key;
if (!pushSupported_) {
key = "error_use_https";
} else if (!platformLoaded) {
key = "error_load_platform";
} else {
key = "description";
}
return `ui.panel.profile.push_notifications.${key}`;
}
}
customElements.define("ha-push-notifications-row", HaPushNotificationsRow);

View File

@ -0,0 +1,72 @@
import { LitElement, TemplateResult, css, html } from "lit";
import { customElement, property } from "lit/decorators";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { pushSupported } from "../../components/ha-push-notifications-toggle";
import "../../components/ha-settings-row";
import { documentationUrl } from "../../util/documentation-url";
import { HomeAssistant } from "../../types";
@customElement("ha-push-notifications-row")
class HaPushNotificationsRow extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public narrow!: boolean;
protected render(): TemplateResult {
const platformLoaded = isComponentLoaded(this.hass, "notify.html5");
let descriptionKey:
| "error_use_https"
| "error_load_platform"
| "description";
if (!pushSupported) {
descriptionKey = "error_use_https";
} else if (!platformLoaded) {
descriptionKey = "error_load_platform";
} else {
descriptionKey = "description";
}
const isDisabled = !platformLoaded || !pushSupported;
return html`
<ha-settings-row .narrow=${this.narrow}>
<span slot="heading"
>${this.hass.localize(
"ui.panel.profile.push_notifications.header"
)}</span
>
<span slot="description">
${this.hass.localize(
`ui.panel.profile.push_notifications.${descriptionKey}`
)}
<a
href=${documentationUrl(this.hass, "/integrations/html5")}
target="_blank"
rel="noreferrer"
>${this.hass.localize(
"ui.panel.profile.push_notifications.link_promo"
)}</a
>
</span>
<ha-push-notifications-toggle
.hass=${this.hass}
.disabled=${isDisabled}
></ha-push-notifications-toggle>
</ha-settings-row>
`;
}
static get styles() {
return css`
a {
color: var(--primary-color);
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-push-notifications-row": HaPushNotificationsRow;
}
}