mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-19 10:57:19 +00:00

* Update ts-eslint * Remove comments * Remove unused ts-ignore * Add undefined generic type instead of unknown * Remove unused undefined type * Fix type issues * Use undefined instead of void for subscribed return type
281 lines
8.2 KiB
TypeScript
281 lines
8.2 KiB
TypeScript
import "@material/mwc-button/mwc-button";
|
|
import "@material/mwc-list/mwc-list";
|
|
import type { ActionDetail } from "@material/mwc-list/mwc-list";
|
|
import { mdiCast, mdiCastConnected, mdiViewDashboard } from "@mdi/js";
|
|
import type { Auth, Connection } from "home-assistant-js-websocket";
|
|
import type { CSSResultGroup, TemplateResult } from "lit";
|
|
import { LitElement, css, html } from "lit";
|
|
import { customElement, property, state } from "lit/decorators";
|
|
import type { CastManager } from "../../../../src/cast/cast_manager";
|
|
import {
|
|
castSendShowLovelaceView,
|
|
ensureConnectedCastSession,
|
|
} from "../../../../src/cast/receiver_messages";
|
|
import {
|
|
askWrite,
|
|
enableWrite,
|
|
saveTokens,
|
|
} from "../../../../src/common/auth/token_storage";
|
|
import { atLeastVersion } from "../../../../src/common/config/version";
|
|
import { toggleAttribute } from "../../../../src/common/dom/toggle_attribute";
|
|
import "../../../../src/components/ha-icon";
|
|
import "../../../../src/components/ha-svg-icon";
|
|
import {
|
|
getLegacyLovelaceCollection,
|
|
getLovelaceCollection,
|
|
} from "../../../../src/data/lovelace";
|
|
import { isStrategyDashboard } from "../../../../src/data/lovelace/config/types";
|
|
import type { LovelaceViewConfig } from "../../../../src/data/lovelace/config/view";
|
|
import "../../../../src/layouts/hass-loading-screen";
|
|
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
|
import "./hc-layout";
|
|
import "../../../../src/components/ha-list-item";
|
|
|
|
@customElement("hc-cast")
|
|
class HcCast extends LitElement {
|
|
@property({ attribute: false }) public auth!: Auth;
|
|
|
|
@property({ attribute: false }) public connection!: Connection;
|
|
|
|
@property({ attribute: false }) public castManager!: CastManager;
|
|
|
|
@state() private askWrite = false;
|
|
|
|
@state() private lovelaceViews?: LovelaceViewConfig[] | null;
|
|
|
|
protected render(): TemplateResult {
|
|
if (this.lovelaceViews === undefined) {
|
|
return html`<hass-loading-screen no-toolbar></hass-loading-screen>`;
|
|
}
|
|
|
|
const error =
|
|
this.castManager.castState === "NO_DEVICES_AVAILABLE"
|
|
? html`
|
|
<p>There were no suitable Chromecast devices to cast to found.</p>
|
|
`
|
|
: undefined;
|
|
|
|
return html`
|
|
<hc-layout .auth=${this.auth} .connection=${this.connection}>
|
|
${this.askWrite
|
|
? html`
|
|
<p class="question action-item">
|
|
Stay logged in?
|
|
<span>
|
|
<mwc-button @click=${this._handleSaveTokens}>
|
|
YES
|
|
</mwc-button>
|
|
<mwc-button @click=${this._handleSkipSaveTokens}>
|
|
NO
|
|
</mwc-button>
|
|
</span>
|
|
</p>
|
|
`
|
|
: ""}
|
|
${error
|
|
? html` <div class="card-content">${error}</div> `
|
|
: !this.castManager.status
|
|
? html`
|
|
<p class="center-item">
|
|
<mwc-button raised @click=${this._handleLaunch}>
|
|
<ha-svg-icon .path=${mdiCast}></ha-svg-icon>
|
|
Start Casting
|
|
</mwc-button>
|
|
</p>
|
|
`
|
|
: html`
|
|
<div class="section-header">PICK A VIEW</div>
|
|
<mwc-list @action=${this._handlePickView} activatable>
|
|
${(
|
|
this.lovelaceViews ?? [
|
|
generateDefaultViewConfig({}, {}, {}, {}, () => ""),
|
|
]
|
|
).map(
|
|
(view, idx) => html`
|
|
<ha-list-item
|
|
graphic="avatar"
|
|
.activated=${this.castManager.status?.lovelacePath ===
|
|
(view.path ?? idx)}
|
|
.selected=${this.castManager.status?.lovelacePath ===
|
|
(view.path ?? idx)}
|
|
>
|
|
${view.title || view.path || "Unnamed view"}
|
|
${view.icon
|
|
? html`
|
|
<ha-icon
|
|
.icon=${view.icon}
|
|
slot="graphic"
|
|
></ha-icon>
|
|
`
|
|
: html`<ha-svg-icon
|
|
slot="item-icon"
|
|
.path=${mdiViewDashboard}
|
|
></ha-svg-icon>`}
|
|
</ha-list-item>
|
|
`
|
|
)}</mwc-list
|
|
>
|
|
`}
|
|
|
|
<div class="card-actions">
|
|
${this.castManager.status
|
|
? html`
|
|
<mwc-button @click=${this._handleLaunch}>
|
|
<ha-svg-icon .path=${mdiCastConnected}></ha-svg-icon>
|
|
Manage
|
|
</mwc-button>
|
|
`
|
|
: ""}
|
|
<div class="spacer"></div>
|
|
<mwc-button @click=${this._handleLogout}>Log out</mwc-button>
|
|
</div>
|
|
</hc-layout>
|
|
`;
|
|
}
|
|
|
|
protected firstUpdated(changedProps) {
|
|
super.firstUpdated(changedProps);
|
|
|
|
const llColl = atLeastVersion(this.connection.haVersion, 0, 107)
|
|
? getLovelaceCollection(this.connection)
|
|
: getLegacyLovelaceCollection(this.connection);
|
|
// We first do a single refresh because we need to check if there is LL
|
|
// configuration.
|
|
llColl.refresh().then(
|
|
() => {
|
|
llColl.subscribe((config) => {
|
|
if (isStrategyDashboard(config)) {
|
|
this.lovelaceViews = null;
|
|
} else {
|
|
this.lovelaceViews = config.views;
|
|
}
|
|
});
|
|
},
|
|
async () => {
|
|
this.lovelaceViews = null;
|
|
}
|
|
);
|
|
|
|
this.askWrite = askWrite();
|
|
|
|
this.castManager.addEventListener("state-changed", () => {
|
|
this.requestUpdate();
|
|
});
|
|
this.castManager.addEventListener("connection-changed", () => {
|
|
this.requestUpdate();
|
|
});
|
|
}
|
|
|
|
protected updated(changedProps) {
|
|
super.updated(changedProps);
|
|
toggleAttribute(
|
|
this,
|
|
"hide-icons",
|
|
this.lovelaceViews ? !this.lovelaceViews.some((view) => view.icon) : true
|
|
);
|
|
}
|
|
|
|
private async _handleSkipSaveTokens() {
|
|
this.askWrite = false;
|
|
}
|
|
|
|
private async _handleSaveTokens() {
|
|
enableWrite();
|
|
this.askWrite = false;
|
|
}
|
|
|
|
private _handleLaunch() {
|
|
this.castManager.requestSession();
|
|
}
|
|
|
|
private async _handlePickView(ev: CustomEvent<ActionDetail>) {
|
|
const path = this.lovelaceViews![ev.detail.index].path ?? ev.detail.index;
|
|
await ensureConnectedCastSession(this.castManager!, this.auth!);
|
|
castSendShowLovelaceView(this.castManager, this.auth.data.hassUrl, path);
|
|
}
|
|
|
|
private async _handleLogout() {
|
|
try {
|
|
await this.auth.revoke();
|
|
saveTokens(null);
|
|
if (this.castManager.castSession) {
|
|
this.castManager.castContext.endCurrentSession(true);
|
|
}
|
|
this.connection.close();
|
|
location.reload();
|
|
} catch (_err: any) {
|
|
alert("Unable to log out!");
|
|
}
|
|
}
|
|
|
|
static get styles(): CSSResultGroup {
|
|
return css`
|
|
.center-item {
|
|
display: flex;
|
|
justify-content: space-around;
|
|
}
|
|
|
|
.action-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.question {
|
|
position: relative;
|
|
padding: 8px 16px;
|
|
}
|
|
|
|
.question:before {
|
|
border-radius: 4px;
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
pointer-events: none;
|
|
content: "";
|
|
background-color: var(--primary-color);
|
|
opacity: 0.12;
|
|
will-change: opacity;
|
|
}
|
|
|
|
.connection,
|
|
.connection a {
|
|
color: var(--secondary-text-color);
|
|
}
|
|
|
|
mwc-button ha-svg-icon {
|
|
margin-right: 8px;
|
|
margin-inline-end: 8px;
|
|
margin-inline-start: initial;
|
|
height: 18px;
|
|
}
|
|
|
|
ha-list-item ha-icon,
|
|
ha-list-item ha-svg-icon {
|
|
padding: 12px;
|
|
color: var(--secondary-text-color);
|
|
}
|
|
|
|
:host([hide-icons]) ha-icon {
|
|
display: none;
|
|
}
|
|
|
|
.spacer {
|
|
flex: 1;
|
|
}
|
|
|
|
.card-content a {
|
|
color: var(--primary-color);
|
|
}
|
|
`;
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
"hc-cast": HcCast;
|
|
}
|
|
}
|