mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Migrate push notification toggle from Polymer to Lit (#18565)
This commit is contained in:
parent
3da7025d78
commit
1d2dc37f75
@ -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) {
|
|
||||||
return disabled || loading;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define(
|
declare global {
|
||||||
"ha-push-notifications-toggle",
|
interface HTMLElementTagNameMap {
|
||||||
HaPushNotificationsToggle
|
"ha-push-notifications-toggle": HaPushNotificationsToggle;
|
||||||
);
|
}
|
||||||
|
}
|
@ -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);
|
|
72
src/panels/profile/ha-push-notifications-row.ts
Normal file
72
src/panels/profile/ha-push-notifications-row.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user