diff --git a/README.md b/README.md index 8891b1d3..f5d2a47d 100644 --- a/README.md +++ b/README.md @@ -433,7 +433,7 @@ Scan mode tracks Home Assistant state *changes* -- when the card is first starte | - | - | - | - | | `enabled` | `false` | :white_check_mark: | Whether to enable scan mode. | | `filter_selected_camera` | `false` | :white_check_mark: | If set to `true` will only trigger on the currently selected camera.| -| `show_trigger_status` | `true` | :white_check_mark: | Whether or not the card should show a visual indication that it is triggered (a pulsing border around the card edge). | +| `show_trigger_status` | `true` | :white_check_mark: | Whether or not the `live` view should show a visual indication that it is triggered (a pulsing border around the camera edge). | | `untrigger_seconds` | `0` | :white_check_mark: | The number of seconds to wait after all entities are inactive before untriggering. | | `actions` | | :white_check_mark: | The actions to take when scan mode triggers (see below). | diff --git a/src/card.ts b/src/card.ts index 527b710a..550067c8 100644 --- a/src/card.ts +++ b/src/card.ts @@ -238,11 +238,6 @@ class FrigateCard extends LitElement { const cardStyle = { 'aspect-ratio': this._controller.getStyleManager().getAspectRatioStyle(), }; - const cardClasses = { - triggered: - !!this._controller.getTriggersManager().isTriggered() && - !!this._config?.view.scan.show_trigger_status, - }; const mainClasses = { main: true, 'curve-top': @@ -264,7 +259,6 @@ class FrigateCard extends LitElement { hasHold: frigateCardHasAction(actions.hold_action), hasDoubleClick: frigateCardHasAction(actions.double_tap_action), })} - class="${classMap(cardClasses)}" style="${styleMap(cardStyle)}" @frigate-card:message=${(ev: CustomEvent) => this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)} @@ -313,6 +307,9 @@ class FrigateCard extends LitElement { ?.getEpoch()} .hide=${!!this._controller.getMessageManager().hasMessage()} .microphoneStream=${this._controller.getMicrophoneManager()?.getStream()} + .triggeredCameraIDs=${this._config?.view.scan.show_trigger_status + ? this._controller.getTriggersManager().getTriggeredCameraIDs() + : undefined} >`} ${ // Keep message rendering to last to show messages that may have been diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 23d58d7c..f69a04aa 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -31,6 +31,7 @@ import { import { localize } from '../../localize/localize.js'; import basicBlockStyle from '../../scss/basic-block.scss'; import liveCarouselStyle from '../../scss/live-carousel.scss'; +import liveGridStyle from '../../scss/live-grid.scss'; import liveProviderStyle from '../../scss/live-provider.scss'; import { ExtendedHomeAssistant, @@ -114,6 +115,9 @@ export class FrigateCardLive extends LitElement { @property({ attribute: false }) public microphoneStream?: MediaStream; + @property({ attribute: false }) + public triggeredCameraIDs?: Set; + // Whether or not the live view is currently in the background (i.e. preloaded // but not visible) @state() @@ -219,6 +223,7 @@ export class FrigateCardLive extends LitElement { .cardWideConfig=${this.cardWideConfig} .cameraManager=${this.cameraManager} .microphoneStream=${this.microphoneStream} + .triggeredCameraIDs=${this.triggeredCameraIDs} @frigate-card:message=${(ev: CustomEvent) => { this._renderKey++; this._messageReceivedPostRender = true; @@ -283,7 +288,12 @@ export class FrigateCardLiveGrid extends LitElement { @property({ attribute: false }) public microphoneStream?: MediaStream; + @property({ attribute: false }) + public triggeredCameraIDs?: Set; + protected _renderCarousel(cameraID?: string): TemplateResult { + const triggeredCameraID = cameraID ?? this.view?.camera; + return html` `; @@ -351,7 +363,7 @@ export class FrigateCardLiveGrid extends LitElement { } static get styles(): CSSResultGroup { - return unsafeCSS(basicBlockStyle); + return unsafeCSS(liveGridStyle); } } diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index 3237464e..52e81acd 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -43,6 +43,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { public fadeThumbnails = false; protected _thumbnailSlides: TemplateResult[] = []; + protected _plugins = [AutoSize()]; protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('config')) { @@ -137,7 +138,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { return html` diff --git a/src/components/views.ts b/src/components/views.ts index 8fbf9af8..de9bb490 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -62,6 +62,9 @@ export class FrigateCardViews extends LitElement { @property({ attribute: false }) public microphoneStream?: MediaStream; + @property({ attribute: false }) + public triggeredCameraIDs?: Set; + protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('view') || changedProps.has('config')) { if (this.view?.is('live') || this._shouldLivePreload()) { @@ -239,6 +242,7 @@ export class FrigateCardViews extends LitElement { .cameraManager=${this.cameraManager} .cardWideConfig=${this.cardWideConfig} .microphoneStream=${this.microphoneStream} + .triggeredCameraIDs=${this.triggeredCameraIDs} class="${classMap(liveClasses)}" > diff --git a/src/scss/card.scss b/src/scss/card.scss index 7a489571..0ed212a9 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -21,7 +21,7 @@ // The standard HA header is 56 pixels tall, so that much off the top (header) // and bottom (to maintain center), before doing the calculation of // max-height. This matters on small mobile devices in landscape orientation. - --frigate-card-expand-max-height: calc( ( 100vh - (2 * 56px) ) * 0.85 ); + --frigate-card-expand-max-height: calc((100vh - (2 * 56px)) * 0.85); --frigate-card-expand-max-width: 85vw; --frigate-card-expand-width: none; --frigate-card-expand-height: none; @@ -52,10 +52,6 @@ div.main { // Necessary to get Safari to show border-radius correctly. transform: translateZ(0); - // Include the borders in the sizing (to keep the triggered warning pulse - // visible in fullscreen). - box-sizing: border-box; - // Hide scrollbar: Firefox scrollbar-width: none; // Hide scrollbar: IE and Edge @@ -112,20 +108,6 @@ ha-card { position: static; color: var(--secondary-text-color, white); } -ha-card.triggered { - @keyframes warning-pulse { - 0% { - border: solid 2px rgba(0, 0, 0, 0); - } - 50% { - border: solid 2px var(--warning-color); - } - 100% { - border: solid 2px rgba(0, 0, 0, 0); - } - } - animation: warning-pulse 5s infinite; -} /************ * Fullscreen diff --git a/src/scss/live-carousel.scss b/src/scss/live-carousel.scss index 81c26c13..79c460f2 100644 --- a/src/scss/live-carousel.scss +++ b/src/scss/live-carousel.scss @@ -1,4 +1,5 @@ :host { + display: block; --video-max-height: none; } diff --git a/src/scss/live-grid.scss b/src/scss/live-grid.scss new file mode 100644 index 00000000..8e860304 --- /dev/null +++ b/src/scss/live-grid.scss @@ -0,0 +1,20 @@ +@use 'basic-block.scss'; + +@keyframes warning-pulse { + 0% { + border: solid 2px var(--frigate-card-triggered-color-1, rgba(0, 0, 0, 0)); + } + 50% { + border: solid 2px var(--frigate-card-triggered-color-2, var(--warning-color)); + } + 100% { + border: solid 2px var(--frigate-card-triggered-color-1, rgba(0, 0, 0, 0)); + } +} + +frigate-card-live-carousel[triggered] { + animation: warning-pulse 5s infinite; +} +frigate-card-live-carousel[selected] { + --frigate-card-triggered-color-1: var(--primary-color); +}