From 4d107f978c3d5fc48140d753fb92637c043ec5a9 Mon Sep 17 00:00:00 2001 From: Jan-Philipp Benecke Date: Tue, 12 Nov 2024 11:59:29 +0100 Subject: [PATCH] Add download snapshot button to camera more info dialog (#22704) * Add take snapshot button to camera more info dialog * Change to download * Use camera proxy * Remove filename to have right extension * Add error handling and process indication * Update src/dialogs/more-info/controls/more-info-camera.ts Co-authored-by: Petar Petrov * Run prettier --------- Co-authored-by: Petar Petrov --- .../more-info/controls/more-info-camera.ts | 66 ++++++++++++++++++- src/translations/en.json | 4 ++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/dialogs/more-info/controls/more-info-camera.ts b/src/dialogs/more-info/controls/more-info-camera.ts index d532b5861c..7b339db519 100644 --- a/src/dialogs/more-info/controls/more-info-camera.ts +++ b/src/dialogs/more-info/controls/more-info-camera.ts @@ -4,14 +4,20 @@ import { property, state } from "lit/decorators"; import "../../../components/ha-camera-stream"; import type { CameraEntity } from "../../../data/camera"; import type { HomeAssistant } from "../../../types"; +import "../../../components/buttons/ha-progress-button"; +import { UNAVAILABLE } from "../../../data/entity"; +import { fileDownload } from "../../../util/file_download"; +import { showToast } from "../../../util/toast"; class MoreInfoCamera extends LitElement { - @property({ attribute: false }) public hass?: HomeAssistant; + @property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public stateObj?: CameraEntity; @state() private _attached = false; + @state() private _waiting = false; + public connectedCallback() { super.connectedCallback(); this._attached = true; @@ -23,7 +29,7 @@ class MoreInfoCamera extends LitElement { } protected render() { - if (!this._attached || !this.hass || !this.stateObj) { + if (!this._attached || !this.stateObj) { return nothing; } @@ -34,14 +40,70 @@ class MoreInfoCamera extends LitElement { allow-exoplayer controls > + +
+ + ${this.hass.localize( + "ui.dialogs.more_info_control.camera.download_snapshot" + )} + +
`; } + private async _downloadSnapshot(ev: CustomEvent) { + const button = ev.currentTarget as any; + this._waiting = true; + + try { + const result: Response | undefined = await this.hass.callApiRaw( + "GET", + `camera_proxy/${this.stateObj!.entity_id}` + ); + + if (!result) { + throw new Error("No response from API"); + } + + const blob = await result.blob(); + const url = window.URL.createObjectURL(blob); + fileDownload(url); + } catch (err) { + this._waiting = false; + button.actionError(); + showToast(this, { + message: this.hass.localize( + "ui.dialogs.more_info_control.camera.failed_to_download" + ), + }); + return; + } + + this._waiting = false; + button.actionSuccess(); + } + static get styles(): CSSResultGroup { return css` :host { display: block; } + + .actions { + width: 100%; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-end; + box-sizing: border-box; + padding: 12px; + z-index: 1; + gap: 8px; + } `; } } diff --git a/src/translations/en.json b/src/translations/en.json index d5d68728d1..26c602f546 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1339,6 +1339,10 @@ "button": "[%key:ui::dialogs::more_info_control::cover::switch_mode::button%]", "position": "[%key:ui::dialogs::more_info_control::cover::switch_mode::position%]" } + }, + "camera": { + "download_snapshot": "Download snapshot", + "failed_to_download": "Failed to download snapshot. Please check the logs for more information." } }, "entity_registry": {