Bump prettier to v3 and format all files
This commit is contained in:
@@ -87,8 +87,8 @@ export const getViewMediaFromBrowseMediaArray = (
|
||||
browseMediaItem.media_class === MEDIA_CLASS_VIDEO
|
||||
? 'clip'
|
||||
: browseMediaItem.media_class === MEDIA_CLASS_IMAGE
|
||||
? 'snapshot'
|
||||
: null;
|
||||
? 'snapshot'
|
||||
: null;
|
||||
|
||||
if (!mediaType) {
|
||||
continue;
|
||||
|
||||
@@ -1034,19 +1034,19 @@ export class FrigateCameraManagerEngine
|
||||
options?.phase === 'stop'
|
||||
? 'stop'
|
||||
: action === 'zoom_in' || action === 'zoom_out'
|
||||
? 'zoom'
|
||||
: action === 'preset'
|
||||
? 'preset'
|
||||
: 'move',
|
||||
? 'zoom'
|
||||
: action === 'preset'
|
||||
? 'preset'
|
||||
: 'move',
|
||||
...(options?.phase !== 'stop' && {
|
||||
argument:
|
||||
action === 'zoom_in'
|
||||
? 'in'
|
||||
: action === 'zoom_out'
|
||||
? 'out'
|
||||
: action === 'preset'
|
||||
? options?.preset
|
||||
: action,
|
||||
? 'out'
|
||||
: action === 'preset'
|
||||
? options?.preset
|
||||
: action,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
+10
-10
@@ -65,19 +65,19 @@ export interface RecordingSegment {
|
||||
export type QueryReturnType<QT> = QT extends EventQuery
|
||||
? EventQueryResults
|
||||
: QT extends RecordingQuery
|
||||
? RecordingQueryResults
|
||||
: QT extends RecordingSegmentsQuery
|
||||
? RecordingSegmentsQueryResults
|
||||
: QT extends MediaMetadataQuery
|
||||
? MediaMetadataQueryResults
|
||||
: never;
|
||||
? RecordingQueryResults
|
||||
: QT extends RecordingSegmentsQuery
|
||||
? RecordingSegmentsQueryResults
|
||||
: QT extends MediaMetadataQuery
|
||||
? MediaMetadataQueryResults
|
||||
: never;
|
||||
export type PartialQueryConcreteType<PQT> = PQT extends PartialEventQuery
|
||||
? EventQuery
|
||||
: PQT extends PartialRecordingQuery
|
||||
? RecordingQuery
|
||||
: PQT extends PartialRecordingSegmentsQuery
|
||||
? RecordingSegmentsQuery
|
||||
: never;
|
||||
? RecordingQuery
|
||||
: PQT extends PartialRecordingSegmentsQuery
|
||||
? RecordingSegmentsQuery
|
||||
: never;
|
||||
|
||||
export type ResultsMap<QT> = Map<QT, QueryReturnType<QT>>;
|
||||
export type EventQueryResultsMap = ResultsMap<EventQuery>;
|
||||
|
||||
@@ -100,20 +100,20 @@ export class PTZDigitalAction extends FrigateCardAction<PTZDigitialActionConfig>
|
||||
this._action.ptz_action === 'zoom_in'
|
||||
? STEP_ZOOM
|
||||
: this._action.ptz_action === 'zoom_out'
|
||||
? -STEP_ZOOM
|
||||
: 0;
|
||||
? -STEP_ZOOM
|
||||
: 0;
|
||||
const xDelta =
|
||||
this._action.ptz_action === 'left'
|
||||
? -STEP_PAN
|
||||
: this._action.ptz_action === 'right'
|
||||
? STEP_PAN
|
||||
: 0;
|
||||
? STEP_PAN
|
||||
: 0;
|
||||
const yDelta =
|
||||
this._action.ptz_action === 'up'
|
||||
? -STEP_PAN
|
||||
: this._action.ptz_action === 'down'
|
||||
? STEP_PAN
|
||||
: 0;
|
||||
? STEP_PAN
|
||||
: 0;
|
||||
|
||||
return {
|
||||
zoom: clamp(zoom + zoomDelta, ZOOM_MIN, ZOOM_MAX),
|
||||
|
||||
@@ -39,10 +39,7 @@ export class PTZAction extends FrigateCardAction<PTZActionConfig> {
|
||||
?.targetID ??
|
||||
null;
|
||||
const ptzCapabilities = ptzCameraID
|
||||
? api
|
||||
.getCameraManager()
|
||||
.getCameraCapabilities(ptzCameraID)
|
||||
?.getPTZCapabilities()
|
||||
? api.getCameraManager().getCameraCapabilities(ptzCameraID)?.getPTZCapabilities()
|
||||
: null;
|
||||
const ptzConfiguration = ptzCameraID
|
||||
? api.getCameraManager().getStore().getCameraConfig(ptzCameraID)?.ptz
|
||||
|
||||
@@ -4,6 +4,6 @@ import { FrigateCardAction } from './base';
|
||||
|
||||
export class SubstreamOffAction extends FrigateCardAction<GeneralActionConfig> {
|
||||
public async execute(api: CardActionsAPI): Promise<void> {
|
||||
api.getViewManager().setViewWithoutSubstream();
|
||||
api.getViewManager().setViewWithoutSubstream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ActionType } from "../../config/types";
|
||||
import { CardActionsAPI } from "../types";
|
||||
import { ActionType } from '../../config/types';
|
||||
import { CardActionsAPI } from '../types';
|
||||
|
||||
export interface AuxillaryActionConfig {
|
||||
camera_image?: string;
|
||||
|
||||
@@ -15,8 +15,7 @@ export class AutoUpdateManager {
|
||||
*/
|
||||
public startDefaultViewTimer(): void {
|
||||
this._timer.stop();
|
||||
const updateSeconds = this._api.getConfigManager().getConfig()
|
||||
?.view.update_seconds;
|
||||
const updateSeconds = this._api.getConfigManager().getConfig()?.view.update_seconds;
|
||||
if (updateSeconds) {
|
||||
this._timer.start(updateSeconds, () => {
|
||||
if (this._isAutomatedUpdateAllowed()) {
|
||||
|
||||
@@ -9,7 +9,10 @@ import { ActionExecutionRequestEventTarget } from './actions/utils/execution-req
|
||||
export type ScrollCallback = () => void;
|
||||
export type MenuToggleCallback = () => void;
|
||||
|
||||
export type CardHTMLElement = LitElement & ReactiveControllerHost & ActionEventTarget & ActionExecutionRequestEventTarget;
|
||||
export type CardHTMLElement = LitElement &
|
||||
ReactiveControllerHost &
|
||||
ActionEventTarget &
|
||||
ActionExecutionRequestEventTarget;
|
||||
|
||||
export class CardElementManager {
|
||||
protected _api: CardElementAPI;
|
||||
@@ -70,7 +73,7 @@ export class CardElementManager {
|
||||
setOrRemoveAttribute(this._element, true, 'tabindex', '0');
|
||||
|
||||
this._api.getFullscreenManager().connect();
|
||||
|
||||
|
||||
this._element.addEventListener(
|
||||
'mousemove',
|
||||
this._api.getInteractionManager().reportInteraction,
|
||||
|
||||
@@ -66,7 +66,7 @@ export class HASSManager {
|
||||
}
|
||||
|
||||
if (this._api.getConditionsManager().hasHAStateConditions()) {
|
||||
this._api.getConditionsManager().setState({
|
||||
this._api.getConditionsManager().setState({
|
||||
state: this._hass.states,
|
||||
user: this._hass.user,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { FrigateCardError, MESSAGE_TYPE_PRIORITIES, Message, MessageType } from '../types';
|
||||
import {
|
||||
FrigateCardError,
|
||||
MESSAGE_TYPE_PRIORITIES,
|
||||
Message,
|
||||
MessageType,
|
||||
} from '../types';
|
||||
import { errorToConsole } from '../utils/basic';
|
||||
import { CardMessageAPI } from './types';
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export interface CardActionsAPI {
|
||||
getCameraManager(): CameraManager;
|
||||
getCameraURLManager(): CameraURLManager;
|
||||
getCardElementManager(): CardElementManager;
|
||||
getConditionsManager(): ConditionsManager;
|
||||
getConditionsManager(): ConditionsManager;
|
||||
getConfigManager(): ConfigManager;
|
||||
getDownloadManager(): DownloadManager;
|
||||
getExpandManager(): ExpandManager;
|
||||
@@ -256,7 +256,7 @@ export interface KeysState {
|
||||
shift: boolean;
|
||||
alt: boolean;
|
||||
meta: boolean;
|
||||
}
|
||||
};
|
||||
}
|
||||
interface TaggedAutomation extends Automation {
|
||||
tag?: unknown;
|
||||
|
||||
+95
-89
@@ -258,99 +258,105 @@ class FrigateCard extends LitElement {
|
||||
|
||||
// Caution: Keep the main div and the menu next to one another in order to
|
||||
// ensure the hover menu styling continues to work.
|
||||
return this._renderInDialogIfNecessary(html` <ha-card
|
||||
id="ha-card"
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: frigateCardHasAction(actions.hold_action),
|
||||
hasDoubleClick: frigateCardHasAction(actions.double_tap_action),
|
||||
})}
|
||||
style="${styleMap(this._controller.getStyleManager().getAspectRatioStyle())}"
|
||||
@frigate-card:message=${(ev: CustomEvent<Message>) =>
|
||||
this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)}
|
||||
@frigate-card:view:change=${(ev: CustomEvent<View>) =>
|
||||
this._controller.getViewManager().setView(ev.detail)}
|
||||
@frigate-card:view:change-context=${(ev: CustomEvent<ViewContext | null>) =>
|
||||
this._controller.getViewManager().setViewWithMergedContext(ev.detail)}
|
||||
@frigate-card:media:loaded=${(ev: CustomEvent<MediaLoadedInfo>) =>
|
||||
this._controller.getMediaLoadedInfoManager().set(ev.detail)}
|
||||
@frigate-card:media:unloaded=${() =>
|
||||
this._controller.getMediaLoadedInfoManager().clear()}
|
||||
@frigate-card:media:volumechange=${
|
||||
() => this.requestUpdate() /* Refresh mute menu button */
|
||||
}
|
||||
@frigate-card:media:play=${
|
||||
() => this.requestUpdate() /* Refresh play/pause menu button */
|
||||
}
|
||||
@frigate-card:media:pause=${
|
||||
() => this.requestUpdate() /* Refresh play/pause menu button */
|
||||
}
|
||||
@frigate-card:focus=${() => this.focus()}
|
||||
>
|
||||
${renderMenuAbove ? this._renderMenu() : ''}
|
||||
<div ${ref(this._refMain)} class="${classMap(mainClasses)}">
|
||||
${!cameraManager.isInitialized() &&
|
||||
!this._controller.getMessageManager().hasMessage()
|
||||
? renderProgressIndicator({
|
||||
cardWideConfig: this._controller.getConfigManager().getCardWideConfig(),
|
||||
})
|
||||
: // Always want to render <frigate-card-views> even if there's a message, to
|
||||
// ensure live preload is always present (even if not displayed).
|
||||
html`<frigate-card-views
|
||||
${ref(this._refViews)}
|
||||
return this._renderInDialogIfNecessary(
|
||||
html` <ha-card
|
||||
id="ha-card"
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: frigateCardHasAction(actions.hold_action),
|
||||
hasDoubleClick: frigateCardHasAction(actions.double_tap_action),
|
||||
})}
|
||||
style="${styleMap(this._controller.getStyleManager().getAspectRatioStyle())}"
|
||||
@frigate-card:message=${(ev: CustomEvent<Message>) =>
|
||||
this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)}
|
||||
@frigate-card:view:change=${(ev: CustomEvent<View>) =>
|
||||
this._controller.getViewManager().setView(ev.detail)}
|
||||
@frigate-card:view:change-context=${(ev: CustomEvent<ViewContext | null>) =>
|
||||
this._controller.getViewManager().setViewWithMergedContext(ev.detail)}
|
||||
@frigate-card:media:loaded=${(ev: CustomEvent<MediaLoadedInfo>) =>
|
||||
this._controller.getMediaLoadedInfoManager().set(ev.detail)}
|
||||
@frigate-card:media:unloaded=${() =>
|
||||
this._controller.getMediaLoadedInfoManager().clear()}
|
||||
@frigate-card:media:volumechange=${
|
||||
() => this.requestUpdate() /* Refresh mute menu button */
|
||||
}
|
||||
@frigate-card:media:play=${
|
||||
() => this.requestUpdate() /* Refresh play/pause menu button */
|
||||
}
|
||||
@frigate-card:media:pause=${
|
||||
() => this.requestUpdate() /* Refresh play/pause menu button */
|
||||
}
|
||||
@frigate-card:focus=${() => this.focus()}
|
||||
>
|
||||
${renderMenuAbove ? this._renderMenu() : ''}
|
||||
<div ${ref(this._refMain)} class="${classMap(mainClasses)}">
|
||||
${!cameraManager.isInitialized() &&
|
||||
!this._controller.getMessageManager().hasMessage()
|
||||
? renderProgressIndicator({
|
||||
cardWideConfig: this._controller.getConfigManager().getCardWideConfig(),
|
||||
})
|
||||
: // Always want to render <frigate-card-views> even if there's a message, to
|
||||
// ensure live preload is always present (even if not displayed).
|
||||
html`<frigate-card-views
|
||||
${ref(this._refViews)}
|
||||
.hass=${this._hass}
|
||||
.view=${this._controller.getViewManager().getView()}
|
||||
.cameraManager=${cameraManager}
|
||||
.resolvedMediaCache=${this._controller.getResolvedMediaCache()}
|
||||
.nonOverriddenConfig=${this._controller
|
||||
.getConfigManager()
|
||||
.getNonOverriddenConfig()}
|
||||
.overriddenConfig=${this._controller.getConfigManager().getConfig()}
|
||||
.cardWideConfig=${this._controller
|
||||
.getConfigManager()
|
||||
.getCardWideConfig()}
|
||||
.rawConfig=${this._controller.getConfigManager().getRawConfig()}
|
||||
.configManager=${this._controller.getConfigManager()}
|
||||
.conditionsManagerEpoch=${this._controller
|
||||
.getConditionsManager()
|
||||
?.getEpoch()}
|
||||
.hide=${!!this._controller.getMessageManager().hasMessage()}
|
||||
.microphoneManager=${this._controller.getMicrophoneManager()}
|
||||
.triggeredCameraIDs=${this._config?.view.triggers.show_trigger_status
|
||||
? this._controller.getTriggersManager().getTriggeredCameraIDs()
|
||||
: undefined}
|
||||
></frigate-card-views>`}
|
||||
${
|
||||
// Keep message rendering to last to show messages that may have been
|
||||
// generated during the render.
|
||||
renderMessage(this._controller.getMessageManager().getMessage())
|
||||
}
|
||||
</div>
|
||||
${!renderMenuAbove ? this._renderMenu() : ''}
|
||||
${this._config?.elements
|
||||
? // Elements need to render after the main views so it can render 'on
|
||||
// top'.
|
||||
html` <frigate-card-elements
|
||||
${ref(this._refElements)}
|
||||
.hass=${this._hass}
|
||||
.view=${this._controller.getViewManager().getView()}
|
||||
.cameraManager=${cameraManager}
|
||||
.resolvedMediaCache=${this._controller.getResolvedMediaCache()}
|
||||
.nonOverriddenConfig=${this._controller
|
||||
.getConfigManager()
|
||||
.getNonOverriddenConfig()}
|
||||
.overriddenConfig=${this._controller.getConfigManager().getConfig()}
|
||||
.cardWideConfig=${this._controller.getConfigManager().getCardWideConfig()}
|
||||
.rawConfig=${this._controller.getConfigManager().getRawConfig()}
|
||||
.configManager=${this._controller.getConfigManager()}
|
||||
.elements=${this._config?.elements}
|
||||
.conditionsManagerEpoch=${this._controller
|
||||
.getConditionsManager()
|
||||
?.getEpoch()}
|
||||
.hide=${!!this._controller.getMessageManager().hasMessage()}
|
||||
.microphoneManager=${this._controller.getMicrophoneManager()}
|
||||
.triggeredCameraIDs=${this._config?.view.triggers.show_trigger_status
|
||||
? this._controller.getTriggersManager().getTriggeredCameraIDs()
|
||||
: undefined}
|
||||
></frigate-card-views>`}
|
||||
${
|
||||
// Keep message rendering to last to show messages that may have been
|
||||
// generated during the render.
|
||||
renderMessage(this._controller.getMessageManager().getMessage())
|
||||
}
|
||||
</div>
|
||||
${!renderMenuAbove ? this._renderMenu() : ''}
|
||||
${this._config?.elements
|
||||
? // Elements need to render after the main views so it can render 'on
|
||||
// top'.
|
||||
html` <frigate-card-elements
|
||||
${ref(this._refElements)}
|
||||
.hass=${this._hass}
|
||||
.elements=${this._config?.elements}
|
||||
.conditionsManagerEpoch=${this._controller
|
||||
.getConditionsManager()
|
||||
?.getEpoch()}
|
||||
@frigate-card:menu-add=${(ev: CustomEvent<MenuItem>) => {
|
||||
this._menuButtonController.addDynamicMenuButton(ev.detail);
|
||||
this.requestUpdate();
|
||||
}}
|
||||
@frigate-card:menu-remove=${(ev: CustomEvent<MenuItem>) => {
|
||||
this._menuButtonController.removeDynamicMenuButton(ev.detail);
|
||||
this.requestUpdate();
|
||||
}}
|
||||
@frigate-card:conditions:evaluate=${(ev: ConditionsEvaluateRequestEvent) => {
|
||||
ev.evaluation = this._controller
|
||||
.getConditionsManager()
|
||||
?.evaluateConditions(ev.conditions);
|
||||
}}
|
||||
>
|
||||
</frigate-card-elements>`
|
||||
: ``}
|
||||
</ha-card>`);
|
||||
@frigate-card:menu-add=${(ev: CustomEvent<MenuItem>) => {
|
||||
this._menuButtonController.addDynamicMenuButton(ev.detail);
|
||||
this.requestUpdate();
|
||||
}}
|
||||
@frigate-card:menu-remove=${(ev: CustomEvent<MenuItem>) => {
|
||||
this._menuButtonController.removeDynamicMenuButton(ev.detail);
|
||||
this.requestUpdate();
|
||||
}}
|
||||
@frigate-card:conditions:evaluate=${(
|
||||
ev: ConditionsEvaluateRequestEvent,
|
||||
) => {
|
||||
ev.evaluation = this._controller
|
||||
.getConditionsManager()
|
||||
?.evaluateConditions(ev.conditions);
|
||||
}}
|
||||
>
|
||||
</frigate-card-elements>`
|
||||
: ``}
|
||||
</ha-card>`,
|
||||
);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -343,8 +343,8 @@ export class MediaFilterController {
|
||||
mediaType = !!hasClips[0]
|
||||
? MediaFilterMediaType.Clips
|
||||
: !!hasSnapshots[0]
|
||||
? MediaFilterMediaType.Snapshots
|
||||
: undefined;
|
||||
? MediaFilterMediaType.Snapshots
|
||||
: undefined;
|
||||
}
|
||||
|
||||
const whatSets = uniqWith(
|
||||
@@ -460,8 +460,8 @@ export class MediaFilterController {
|
||||
favorites: events
|
||||
? managerCapabilities?.has('favorite-events')
|
||||
: recordings
|
||||
? managerCapabilities?.has('favorite-recordings')
|
||||
: false,
|
||||
? managerCapabilities?.has('favorite-recordings')
|
||||
: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -377,8 +377,8 @@ export class MenuButtonController {
|
||||
icon: forbidden
|
||||
? 'mdi:microphone-message-off'
|
||||
: muted
|
||||
? 'mdi:microphone-off'
|
||||
: 'mdi:microphone',
|
||||
? 'mdi:microphone-off'
|
||||
: 'mdi:microphone',
|
||||
...config.menu.buttons.microphone,
|
||||
type: 'custom:frigate-card-menu-icon',
|
||||
title: localize('config.menu.buttons.microphone'),
|
||||
@@ -570,8 +570,8 @@ export class MenuButtonController {
|
||||
const ptzConfig = view.is('live')
|
||||
? config.live.controls.ptz
|
||||
: view.isViewerView()
|
||||
? config.media_viewer.controls.ptz
|
||||
: null;
|
||||
? config.media_viewer.controls.ptz
|
||||
: null;
|
||||
|
||||
if (!ptzConfig || ptzConfig.mode === 'off') {
|
||||
return null;
|
||||
|
||||
@@ -96,9 +96,11 @@ export class PTZController {
|
||||
return this._forceVisibility !== undefined
|
||||
? this._forceVisibility
|
||||
: this._config?.mode === 'auto'
|
||||
? !!this._cameraID &&
|
||||
!!this._cameraManager?.getCameraCapabilities(this._cameraID)?.hasPTZCapability()
|
||||
: this._config?.mode === 'on';
|
||||
? !!this._cameraID &&
|
||||
!!this._cameraManager
|
||||
?.getCameraCapabilities(this._cameraID)
|
||||
?.hasPTZCapability()
|
||||
: this._config?.mode === 'on';
|
||||
}
|
||||
|
||||
public getPTZActions(): PTZActionNameToMultiAction {
|
||||
|
||||
@@ -30,7 +30,7 @@ export class FrigateCardDatePicker extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
const changed = () => {
|
||||
const value = this._refInput.value?.value;
|
||||
|
||||
|
||||
dispatchFrigateCardEvent<DatePickerEvent>(this, 'date-picker:change', {
|
||||
date: value ? new Date(value) : null,
|
||||
});
|
||||
|
||||
@@ -90,8 +90,8 @@ export class FrigateCardGallery extends LitElement {
|
||||
const eventsMediaType = this.view.is('snapshots')
|
||||
? 'snapshots'
|
||||
: this.view.is('clips')
|
||||
? 'clips'
|
||||
: null;
|
||||
? 'clips'
|
||||
: null;
|
||||
changeViewToRecentEventsForCameraAndDependents(
|
||||
this,
|
||||
this.cameraManager,
|
||||
@@ -358,8 +358,8 @@ export class FrigateCardGalleryCore extends LitElement {
|
||||
const newMediaQueries = MediaQueriesClassifier.areEventQueries(query)
|
||||
? new EventMediaQueries(extension.queries as EventQuery[])
|
||||
: MediaQueriesClassifier.areRecordingQueries(query)
|
||||
? new RecordingMediaQueries(extension.queries as RecordingQuery[])
|
||||
: null;
|
||||
? new RecordingMediaQueries(extension.queries as RecordingQuery[])
|
||||
: null;
|
||||
|
||||
if (newMediaQueries) {
|
||||
this.view
|
||||
|
||||
+36
-36
@@ -947,42 +947,42 @@ export class FrigateCardLiveProvider
|
||||
>
|
||||
</frigate-card-live-ha>`
|
||||
: provider === 'go2rtc'
|
||||
? html`<frigate-card-live-go2rtc
|
||||
${ref(this._refProvider)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
.cameraEndpoints=${this.cameraEndpoints}
|
||||
.microphoneStream=${this.microphoneStream}
|
||||
.microphoneConfig=${this.liveConfig.microphone}
|
||||
?controls=${this.liveConfig.controls.builtin}
|
||||
@frigate-card:media:loaded=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-go2rtc>`
|
||||
: provider === 'webrtc-card'
|
||||
? html`<frigate-card-live-webrtc-card
|
||||
${ref(this._refProvider)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
.cameraEndpoints=${this.cameraEndpoints}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
?controls=${this.liveConfig.controls.builtin}
|
||||
@frigate-card:media:loaded=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-webrtc-card>`
|
||||
: provider === 'jsmpeg'
|
||||
? html` <frigate-card-live-jsmpeg
|
||||
${ref(this._refProvider)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
.cameraEndpoints=${this.cameraEndpoints}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
@frigate-card:media:loaded=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-jsmpeg>`
|
||||
: html``}
|
||||
? html`<frigate-card-live-go2rtc
|
||||
${ref(this._refProvider)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
.cameraEndpoints=${this.cameraEndpoints}
|
||||
.microphoneStream=${this.microphoneStream}
|
||||
.microphoneConfig=${this.liveConfig.microphone}
|
||||
?controls=${this.liveConfig.controls.builtin}
|
||||
@frigate-card:media:loaded=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-go2rtc>`
|
||||
: provider === 'webrtc-card'
|
||||
? html`<frigate-card-live-webrtc-card
|
||||
${ref(this._refProvider)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
.cameraEndpoints=${this.cameraEndpoints}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
?controls=${this.liveConfig.controls.builtin}
|
||||
@frigate-card:media:loaded=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-webrtc-card>`
|
||||
: provider === 'jsmpeg'
|
||||
? html` <frigate-card-live-jsmpeg
|
||||
${ref(this._refProvider)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
.cameraEndpoints=${this.cameraEndpoints}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
@frigate-card:media:loaded=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-jsmpeg>`
|
||||
: html``}
|
||||
`)}
|
||||
${showImageDuringLoading && !this._isVideoMediaLoaded
|
||||
? html`<ha-icon
|
||||
|
||||
@@ -204,10 +204,7 @@ export function dispatchFrigateCardErrorEvent(
|
||||
export interface FrigateCardMessageEventTarget extends EventTarget {
|
||||
addEventListener(
|
||||
event: 'frigate-card:message',
|
||||
listener: (
|
||||
this: FrigateCardMessageEventTarget,
|
||||
ev: CustomEvent<Message>,
|
||||
) => void,
|
||||
listener: (this: FrigateCardMessageEventTarget, ev: CustomEvent<Message>) => void,
|
||||
options?: AddEventListenerOptions | boolean,
|
||||
): void;
|
||||
addEventListener(
|
||||
@@ -217,10 +214,7 @@ export interface FrigateCardMessageEventTarget extends EventTarget {
|
||||
): void;
|
||||
removeEventListener(
|
||||
event: 'frigate-card:message',
|
||||
listener: (
|
||||
this: FrigateCardMessageEventTarget,
|
||||
ev: CustomEvent<Message>,
|
||||
) => void,
|
||||
listener: (this: FrigateCardMessageEventTarget, ev: CustomEvent<Message>) => void,
|
||||
options?: boolean | EventListenerOptions,
|
||||
): void;
|
||||
removeEventListener(
|
||||
|
||||
@@ -92,31 +92,33 @@ export class FrigateCardThumbnailCarousel extends LitElement {
|
||||
'slide-selected': selectedIndex === index,
|
||||
};
|
||||
|
||||
slides.push(html` <frigate-card-thumbnail
|
||||
class="${classMap(classes)}"
|
||||
.cameraManager=${this.cameraManager}
|
||||
.hass=${this.hass}
|
||||
.media=${media}
|
||||
.view=${this.view}
|
||||
.seek=${seekTarget && media.includesTime(seekTarget) ? seekTarget : undefined}
|
||||
?details=${!!this.config?.show_details}
|
||||
?show_favorite_control=${this.config?.show_favorite_control}
|
||||
?show_timeline_control=${this.config?.show_timeline_control}
|
||||
?show_download_control=${this.config?.show_download_control}
|
||||
@click=${(ev: Event) => {
|
||||
if (this.view && this.view.queryResults) {
|
||||
dispatchFrigateCardEvent<ThumbnailCarouselTap>(
|
||||
this,
|
||||
'thumbnail-carousel:tap',
|
||||
{
|
||||
queryResults: this.view.queryResults.clone().selectIndex(index),
|
||||
},
|
||||
);
|
||||
}
|
||||
stopEventFromActivatingCardWideActions(ev);
|
||||
}}
|
||||
>
|
||||
</frigate-card-thumbnail>`);
|
||||
slides.push(
|
||||
html` <frigate-card-thumbnail
|
||||
class="${classMap(classes)}"
|
||||
.cameraManager=${this.cameraManager}
|
||||
.hass=${this.hass}
|
||||
.media=${media}
|
||||
.view=${this.view}
|
||||
.seek=${seekTarget && media.includesTime(seekTarget) ? seekTarget : undefined}
|
||||
?details=${!!this.config?.show_details}
|
||||
?show_favorite_control=${this.config?.show_favorite_control}
|
||||
?show_timeline_control=${this.config?.show_timeline_control}
|
||||
?show_download_control=${this.config?.show_download_control}
|
||||
@click=${(ev: Event) => {
|
||||
if (this.view && this.view.queryResults) {
|
||||
dispatchFrigateCardEvent<ThumbnailCarouselTap>(
|
||||
this,
|
||||
'thumbnail-carousel:tap',
|
||||
{
|
||||
queryResults: this.view.queryResults.clone().selectIndex(index),
|
||||
},
|
||||
);
|
||||
}
|
||||
stopEventFromActivatingCardWideActions(ev);
|
||||
}}
|
||||
>
|
||||
</frigate-card-thumbnail>`,
|
||||
);
|
||||
}
|
||||
return slides;
|
||||
}
|
||||
|
||||
+13
-13
@@ -418,13 +418,13 @@ export class FrigateCardThumbnail extends LitElement {
|
||||
.thumbnail=${thumbnail ?? undefined}
|
||||
></frigate-card-thumbnail-feature-event>`
|
||||
: ViewMediaClassifier.isRecording(this.media)
|
||||
? html`<frigate-card-thumbnail-feature-recording
|
||||
aria-label="${title ?? ''}"
|
||||
title="${title ?? ''}"
|
||||
.cameraTitle=${this.details ? undefined : cameraTitle}
|
||||
.date=${this.media.getStartTime() ?? undefined}
|
||||
></frigate-card-thumbnail-feature-recording>`
|
||||
: html``}
|
||||
? html`<frigate-card-thumbnail-feature-recording
|
||||
aria-label="${title ?? ''}"
|
||||
title="${title ?? ''}"
|
||||
.cameraTitle=${this.details ? undefined : cameraTitle}
|
||||
.date=${this.media.getStartTime() ?? undefined}
|
||||
></frigate-card-thumbnail-feature-recording>`
|
||||
: html``}
|
||||
${shouldShowFavoriteControl
|
||||
? html` <ha-icon
|
||||
class="${classMap(starClasses)}"
|
||||
@@ -454,12 +454,12 @@ export class FrigateCardThumbnail extends LitElement {
|
||||
.seek=${this.seek}
|
||||
></frigate-card-thumbnail-details-event>`
|
||||
: this.details && ViewMediaClassifier.isRecording(this.media)
|
||||
? html`<frigate-card-thumbnail-details-recording
|
||||
.media=${this.media ?? undefined}
|
||||
.cameraTitle=${cameraTitle}
|
||||
.seek=${this.seek}
|
||||
></frigate-card-thumbnail-details-recording>`
|
||||
: html``}
|
||||
? html`<frigate-card-thumbnail-details-recording
|
||||
.media=${this.media ?? undefined}
|
||||
.cameraTitle=${cameraTitle}
|
||||
.seek=${this.seek}
|
||||
></frigate-card-thumbnail-details-recording>`
|
||||
: html``}
|
||||
${shouldShowTimelineControl
|
||||
? html`<ha-icon
|
||||
class="timeline"
|
||||
|
||||
@@ -283,18 +283,18 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
panMode === 'pan'
|
||||
? localize('config.common.controls.timeline.pan_modes.pan')
|
||||
: panMode === 'seek'
|
||||
? localize('config.common.controls.timeline.pan_modes.seek')
|
||||
: panMode === 'seek-in-media'
|
||||
? localize('config.common.controls.timeline.pan_modes.seek-in-media')
|
||||
: localize('config.common.controls.timeline.pan_modes.seek-in-camera');
|
||||
? localize('config.common.controls.timeline.pan_modes.seek')
|
||||
: panMode === 'seek-in-media'
|
||||
? localize('config.common.controls.timeline.pan_modes.seek-in-media')
|
||||
: localize('config.common.controls.timeline.pan_modes.seek-in-camera');
|
||||
const panIcon =
|
||||
panMode === 'pan'
|
||||
? 'mdi:pan-horizontal'
|
||||
: panMode === 'seek'
|
||||
? 'mdi:filmstrip-box-multiple'
|
||||
: panMode === 'seek-in-media'
|
||||
? 'mdi:play-box-lock'
|
||||
: 'mdi:camera-lock';
|
||||
? 'mdi:filmstrip-box-multiple'
|
||||
: panMode === 'seek-in-media'
|
||||
? 'mdi:play-box-lock'
|
||||
: 'mdi:camera-lock';
|
||||
|
||||
return html` <div
|
||||
@frigate-card:timeline:thumbnail-data-request=${this._handleThumbnailDataRequest.bind(
|
||||
@@ -312,10 +312,10 @@ export class FrigateCardTimelineCore extends LitElement {
|
||||
panMode === 'pan'
|
||||
? 'seek'
|
||||
: panMode === 'seek'
|
||||
? 'seek-in-media'
|
||||
: panMode === 'seek-in-media'
|
||||
? 'seek-in-camera'
|
||||
: 'pan';
|
||||
? 'seek-in-media'
|
||||
: panMode === 'seek-in-media'
|
||||
? 'seek-in-camera'
|
||||
: 'pan';
|
||||
}}
|
||||
aria-label="${panTitle}"
|
||||
title="${panTitle}"
|
||||
|
||||
@@ -141,16 +141,16 @@ export class FrigateCardViews extends LitElement {
|
||||
const thumbnailConfig = this.view?.is('live')
|
||||
? this.overriddenConfig.live.controls.thumbnails
|
||||
: this.view?.isViewerView()
|
||||
? this.overriddenConfig.media_viewer.controls.thumbnails
|
||||
: this.view?.is('timeline')
|
||||
? this.overriddenConfig.timeline.controls.thumbnails
|
||||
: undefined;
|
||||
? this.overriddenConfig.media_viewer.controls.thumbnails
|
||||
: this.view?.is('timeline')
|
||||
? this.overriddenConfig.timeline.controls.thumbnails
|
||||
: undefined;
|
||||
|
||||
const miniTimelineConfig = this.view?.is('live')
|
||||
? this.overriddenConfig.live.controls.timeline
|
||||
: this.view?.isViewerView()
|
||||
? this.overriddenConfig.media_viewer.controls.timeline
|
||||
: undefined;
|
||||
? this.overriddenConfig.media_viewer.controls.timeline
|
||||
: undefined;
|
||||
|
||||
const cameraConfig = this.view
|
||||
? this.cameraManager?.getStore().getCameraConfig(this.view.camera) ?? null
|
||||
|
||||
@@ -34,7 +34,6 @@ export const keyboardShortcutsSchema = z.object({
|
||||
});
|
||||
export type KeyboardShortcuts = z.infer<typeof keyboardShortcutsSchema>;
|
||||
|
||||
|
||||
const KEYBOARD_SHORTCUT_PTZ_NAMES = [
|
||||
'ptz_down',
|
||||
'ptz_home',
|
||||
|
||||
@@ -722,8 +722,8 @@ const UPGRADES = [
|
||||
data === 'all'
|
||||
? ['selected', 'visible', 'microphone']
|
||||
: data === 'never'
|
||||
? null
|
||||
: arrayify(data),
|
||||
? null
|
||||
: arrayify(data),
|
||||
),
|
||||
upgradeWithOverrides('media_viewer.auto_play', (data) =>
|
||||
data === 'all' ? null : data === 'never' ? [] : arrayify(data),
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import { getConfigValue, setConfigValue } from '../management.js';
|
||||
import {
|
||||
ProfileType,
|
||||
RawFrigateCardConfig,
|
||||
frigateCardConfigSchema,
|
||||
} from '../types.js';
|
||||
import { ProfileType, RawFrigateCardConfig, frigateCardConfigSchema } from '../types.js';
|
||||
import { deepRemoveDefaults } from '../../utils/zod.js';
|
||||
import { LOW_PERFORMANCE_PROFILE } from './low-performance.js';
|
||||
import { SCRUBBING_PROFILE } from './scrubbing.js';
|
||||
|
||||
const PROFILES = {
|
||||
'low-performance': LOW_PERFORMANCE_PROFILE,
|
||||
'scrubbing': SCRUBBING_PROFILE,
|
||||
scrubbing: SCRUBBING_PROFILE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+9
-11
@@ -737,9 +737,7 @@ const ptzCameraConfigDefaults = {
|
||||
// service data as actions for each PTZ action, and it will be preprocessed
|
||||
// into the full form. This also provides compatability with the AlexIT/WebRTC
|
||||
// PTZ configuration.
|
||||
const dataPTZFormatToFullFormat = function (
|
||||
suffix: string,
|
||||
): (data: unknown) => unknown {
|
||||
const dataPTZFormatToFullFormat = function (suffix: string): (data: unknown) => unknown {
|
||||
return (data) => {
|
||||
if (!data || typeof data !== 'object' || !data['service']) {
|
||||
return data;
|
||||
@@ -1545,9 +1543,7 @@ export const menuConfigSchema = z
|
||||
camera_ui: visibleButtonSchema.default(menuConfigDefault.buttons.camera_ui),
|
||||
cameras: visibleButtonSchema.default(menuConfigDefault.buttons.cameras),
|
||||
clips: visibleButtonSchema.default(menuConfigDefault.buttons.clips),
|
||||
ptz_home: hiddenButtonSchema.default(
|
||||
menuConfigDefault.buttons.ptz_home,
|
||||
),
|
||||
ptz_home: hiddenButtonSchema.default(menuConfigDefault.buttons.ptz_home),
|
||||
display_mode: visibleButtonSchema.default(
|
||||
menuConfigDefault.buttons.display_mode,
|
||||
),
|
||||
@@ -1608,7 +1604,7 @@ const viewerConfigDefault = {
|
||||
ptz: {
|
||||
...ptzControlsDefaults,
|
||||
mode: 'off' as const,
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1658,10 +1654,12 @@ const viewerConfigSchema = z
|
||||
next_previous: viewerNextPreviousControlConfigSchema.default(
|
||||
viewerConfigDefault.controls.next_previous,
|
||||
),
|
||||
ptz: ptzControlsConfigSchema.extend({
|
||||
// The media_viewer ptz has no 'auto' mode.
|
||||
mode: z.enum(['off', 'on']).default(viewerConfigDefault.controls.ptz.mode),
|
||||
}).default(viewerConfigDefault.controls.ptz),
|
||||
ptz: ptzControlsConfigSchema
|
||||
.extend({
|
||||
// The media_viewer ptz has no 'auto' mode.
|
||||
mode: z.enum(['off', 'on']).default(viewerConfigDefault.controls.ptz.mode),
|
||||
})
|
||||
.default(viewerConfigDefault.controls.ptz),
|
||||
thumbnails: thumbnailsControlSchema.default(
|
||||
viewerConfigDefault.controls.thumbnails,
|
||||
),
|
||||
|
||||
+11
-6
@@ -1123,10 +1123,15 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
);
|
||||
}
|
||||
|
||||
protected _renderKeyAssigner(configPath: string, defaultValue: KeyboardShortcut): TemplateResult {
|
||||
protected _renderKeyAssigner(
|
||||
configPath: string,
|
||||
defaultValue: KeyboardShortcut,
|
||||
): TemplateResult {
|
||||
return html` <frigate-card-key-assigner
|
||||
.label=${localize(`config.${configPath}`)}
|
||||
.value=${this._config ? getConfigValue(this._config, configPath, defaultValue) : null}
|
||||
.value=${this._config
|
||||
? getConfigValue(this._config, configPath, defaultValue)
|
||||
: null}
|
||||
@value-changed=${(ev) => this._valueChangedHandler(configPath, ev)}
|
||||
></frigate-card-key-assigner>`;
|
||||
}
|
||||
@@ -1279,10 +1284,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
${icon.name
|
||||
? html` <ha-icon .icon=${icon.name}></ha-icon> `
|
||||
: icon.path
|
||||
? html`
|
||||
<ha-svg-icon .viewBox=${icon.viewBox} .path="${icon.path}"></ha-svg-icon>
|
||||
`
|
||||
: ``}
|
||||
? html`
|
||||
<ha-svg-icon .viewBox=${icon.viewBox} .path="${icon.path}"></ha-svg-icon>
|
||||
`
|
||||
: ``}
|
||||
<span>${localize(labelPath)}</span>
|
||||
</div>
|
||||
${selected ? html`<div class="values">${template}</div>` : ''}
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
|
||||
**Image Formatting Process**:
|
||||
|
||||
* Horizontal mirror (to face the opposite direction)
|
||||
* Cropped for 16:9
|
||||
* Scaled down to 492x277
|
||||
* Quality @ 85%
|
||||
- Horizontal mirror (to face the opposite direction)
|
||||
- Cropped for 16:9
|
||||
- Scaled down to 492x277
|
||||
- Quality @ 85%
|
||||
|
||||
```sh
|
||||
$ convert -extent 2048x1152 -flop -gravity center 47543120431_b285c45ac8_k.jpg frigate-bird-in-sky.jpg
|
||||
|
||||
@@ -645,4 +645,4 @@
|
||||
"timeline": {
|
||||
"select_date": "Escolliu la data"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,4 +652,4 @@
|
||||
"timeline": {
|
||||
"select_date": "Choose date"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,4 +645,4 @@
|
||||
"timeline": {
|
||||
"select_date": "Choisir une date"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,4 +645,4 @@
|
||||
"timeline": {
|
||||
"select_date": "Scegli la data"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,4 +645,4 @@
|
||||
"timeline": {
|
||||
"select_date": "Escolha a data"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,4 +645,4 @@
|
||||
"timeline": {
|
||||
"select_date": "Selecionar a data"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ customElements.whenDefined('ha-camera-stream').then(() => {
|
||||
public isPaused(): boolean {
|
||||
return this._player?.isPaused() ?? true;
|
||||
}
|
||||
|
||||
|
||||
public async getScreenshotURL(): Promise<string | null> {
|
||||
return this._player ? await this._player.getScreenshotURL() : null;
|
||||
}
|
||||
|
||||
@@ -21,10 +21,12 @@ import {
|
||||
dispatchMediaLoadedEvent,
|
||||
dispatchMediaPauseEvent,
|
||||
dispatchMediaPlayEvent,
|
||||
dispatchMediaVolumeChangeEvent
|
||||
dispatchMediaVolumeChangeEvent,
|
||||
} from '../utils/media-info.js';
|
||||
import {
|
||||
hideMediaControlsTemporarily, MEDIA_LOAD_CONTROLS_HIDE_SECONDS, setControlsOnVideo
|
||||
hideMediaControlsTemporarily,
|
||||
MEDIA_LOAD_CONTROLS_HIDE_SECONDS,
|
||||
setControlsOnVideo,
|
||||
} from '../utils/media.js';
|
||||
import { screenshotMedia } from '../utils/screenshot.js';
|
||||
|
||||
|
||||
@@ -21,12 +21,12 @@ import {
|
||||
dispatchMediaLoadedEvent,
|
||||
dispatchMediaPauseEvent,
|
||||
dispatchMediaPlayEvent,
|
||||
dispatchMediaVolumeChangeEvent
|
||||
dispatchMediaVolumeChangeEvent,
|
||||
} from '../utils/media-info.js';
|
||||
import {
|
||||
hideMediaControlsTemporarily,
|
||||
MEDIA_LOAD_CONTROLS_HIDE_SECONDS,
|
||||
setControlsOnVideo
|
||||
setControlsOnVideo,
|
||||
} from '../utils/media.js';
|
||||
|
||||
customElements.whenDefined('ha-web-rtc-player').then(() => {
|
||||
|
||||
+37
-37
@@ -27,71 +27,71 @@ ha-icon-button.button {
|
||||
}
|
||||
|
||||
@mixin state-icon($element) {
|
||||
#{$element}[data-domain="alert"][data-state="on"],
|
||||
#{$element}[data-domain="automation"][data-state="on"],
|
||||
#{$element}[data-domain="binary_sensor"][data-state="on"],
|
||||
#{$element}[data-domain="calendar"][data-state="on"],
|
||||
#{$element}[data-domain="camera"][data-state="streaming"],
|
||||
#{$element}[data-domain="cover"][data-state="open"],
|
||||
#{$element}[data-domain="fan"][data-state="on"],
|
||||
#{$element}[data-domain="humidifier"][data-state="on"],
|
||||
#{$element}[data-domain="light"][data-state="on"],
|
||||
#{$element}[data-domain="input_boolean"][data-state="on"],
|
||||
#{$element}[data-domain="lock"][data-state="unlocked"],
|
||||
#{$element}[data-domain="media_player"][data-state="on"],
|
||||
#{$element}[data-domain="media_player"][data-state="paused"],
|
||||
#{$element}[data-domain="media_player"][data-state="playing"],
|
||||
#{$element}[data-domain="script"][data-state="on"],
|
||||
#{$element}[data-domain="sun"][data-state="above_horizon"],
|
||||
#{$element}[data-domain="switch"][data-state="on"],
|
||||
#{$element}[data-domain="timer"][data-state="active"],
|
||||
#{$element}[data-domain="vacuum"][data-state="cleaning"],
|
||||
#{$element}[data-domain="group"][data-state="on"],
|
||||
#{$element}[data-domain="group"][data-state="home"],
|
||||
#{$element}[data-domain="group"][data-state="open"],
|
||||
#{$element}[data-domain="group"][data-state="locked"],
|
||||
#{$element}[data-domain="group"][data-state="problem"] {
|
||||
#{$element}[data-domain='alert'][data-state='on'],
|
||||
#{$element}[data-domain='automation'][data-state='on'],
|
||||
#{$element}[data-domain='binary_sensor'][data-state='on'],
|
||||
#{$element}[data-domain='calendar'][data-state='on'],
|
||||
#{$element}[data-domain='camera'][data-state='streaming'],
|
||||
#{$element}[data-domain='cover'][data-state='open'],
|
||||
#{$element}[data-domain='fan'][data-state='on'],
|
||||
#{$element}[data-domain='humidifier'][data-state='on'],
|
||||
#{$element}[data-domain='light'][data-state='on'],
|
||||
#{$element}[data-domain='input_boolean'][data-state='on'],
|
||||
#{$element}[data-domain='lock'][data-state='unlocked'],
|
||||
#{$element}[data-domain='media_player'][data-state='on'],
|
||||
#{$element}[data-domain='media_player'][data-state='paused'],
|
||||
#{$element}[data-domain='media_player'][data-state='playing'],
|
||||
#{$element}[data-domain='script'][data-state='on'],
|
||||
#{$element}[data-domain='sun'][data-state='above_horizon'],
|
||||
#{$element}[data-domain='switch'][data-state='on'],
|
||||
#{$element}[data-domain='timer'][data-state='active'],
|
||||
#{$element}[data-domain='vacuum'][data-state='cleaning'],
|
||||
#{$element}[data-domain='group'][data-state='on'],
|
||||
#{$element}[data-domain='group'][data-state='home'],
|
||||
#{$element}[data-domain='group'][data-state='open'],
|
||||
#{$element}[data-domain='group'][data-state='locked'],
|
||||
#{$element}[data-domain='group'][data-state='problem'] {
|
||||
color: var(--paper-item-icon-active-color, #fdd835);
|
||||
}
|
||||
|
||||
#{$element}[data-domain="climate"][data-state="cooling"] {
|
||||
#{$element}[data-domain='climate'][data-state='cooling'] {
|
||||
color: var(--cool-color, var(--state-climate-cool-color));
|
||||
}
|
||||
|
||||
#{$element}[data-domain="climate"][data-state="heating"] {
|
||||
#{$element}[data-domain='climate'][data-state='heating'] {
|
||||
color: var(--heat-color, var(--state-climate-heat-color));
|
||||
}
|
||||
|
||||
#{$element}[data-domain="climate"][data-state="drying"] {
|
||||
#{$element}[data-domain='climate'][data-state='drying'] {
|
||||
color: var(--dry-color, var(--state-climate-dry-color));
|
||||
}
|
||||
|
||||
#{$element}[data-domain="alarm_control_panel"] {
|
||||
#{$element}[data-domain='alarm_control_panel'] {
|
||||
color: var(--alarm-color-armed, var(--label-badge-red));
|
||||
}
|
||||
#{$element}[data-domain="alarm_control_panel"][data-state="disarmed"] {
|
||||
#{$element}[data-domain='alarm_control_panel'][data-state='disarmed'] {
|
||||
color: var(--alarm-color-disarmed, var(--label-badge-green));
|
||||
}
|
||||
#{$element}[data-domain="alarm_control_panel"][data-state="pending"],
|
||||
#{$element}[data-domain="alarm_control_panel"][data-state="arming"] {
|
||||
#{$element}[data-domain='alarm_control_panel'][data-state='pending'],
|
||||
#{$element}[data-domain='alarm_control_panel'][data-state='arming'] {
|
||||
color: var(--alarm-color-pending, var(--label-badge-yellow));
|
||||
animation: pulse 1s infinite;
|
||||
}
|
||||
#{$element}[data-domain="alarm_control_panel"][data-state="triggered"] {
|
||||
#{$element}[data-domain='alarm_control_panel'][data-state='triggered'] {
|
||||
color: var(--alarm-color-triggered, var(--label-badge-red));
|
||||
animation: pulse 1s infinite;
|
||||
}
|
||||
|
||||
#{$element}[data-domain="plant"][data-state="problem"],
|
||||
#{$element}[data-domain="zwave"][data-state="dead"] {
|
||||
#{$element}[data-domain='plant'][data-state='problem'],
|
||||
#{$element}[data-domain='zwave'][data-state='dead'] {
|
||||
color: var(--state-icon-error-color);
|
||||
}
|
||||
|
||||
/* Color the icon if unavailable */
|
||||
#{$element}[data-state="unavailable"] {
|
||||
#{$element}[data-state='unavailable'] {
|
||||
color: var(--state-unavailable-color);
|
||||
}
|
||||
}
|
||||
|
||||
@include state-icon("ha-icon");
|
||||
@include state-icon("ha-icon-button");
|
||||
@include state-icon('ha-icon');
|
||||
@include state-icon('ha-icon-button');
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@
|
||||
--frigate-card-thumbnail-details-width: calc(
|
||||
var(--frigate-card-thumbnail-size) + 200px
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,12 @@ div.control-surround {
|
||||
}
|
||||
right: 100%;
|
||||
}
|
||||
:host([empty]), :host([empty]) > * {
|
||||
:host([empty]),
|
||||
:host([empty]) > * {
|
||||
visibility: hidden;
|
||||
}
|
||||
:host(:not([empty])), :host(:not([empty])) > * {
|
||||
:host(:not([empty])),
|
||||
:host(:not([empty])) > * {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -47,7 +49,8 @@ ha-icon.control {
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
:host([open]) ha-icon.control, ha-icon.control:hover {
|
||||
:host([open]) ha-icon.control,
|
||||
ha-icon.control:hover {
|
||||
// When the drawer is open or hovered make the button to close it more
|
||||
// prominent.
|
||||
opacity: 1;
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
hui-error-card.element {
|
||||
inset: 0px;
|
||||
transform: unset;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@ img {
|
||||
display: block;
|
||||
|
||||
@include media-layout.media-layout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,4 +76,4 @@ div.key + div.key:before {
|
||||
margin-right: 5px;
|
||||
|
||||
content: ' + ';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@use 'media-layout.scss';
|
||||
@use 'media-layout.scss';
|
||||
|
||||
img, video {
|
||||
img,
|
||||
video {
|
||||
@include media-layout.media-layout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,4 +44,4 @@ div.when frigate-card-date-picker.selected {
|
||||
}
|
||||
div.when frigate-card-date-picker.hidden {
|
||||
width: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ div.opposing {
|
||||
********************************************/
|
||||
|
||||
:host([data-style='overlay']),
|
||||
:host([data-style*=hover]),
|
||||
:host([data-style*='hover']),
|
||||
:host([data-style='hidden']) {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
mwc-list-item {
|
||||
mwc-list-item {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ img {
|
||||
}
|
||||
|
||||
img,
|
||||
ha-icon {
|
||||
ha-icon {
|
||||
// Safari will occasionally not load thumbnails correctly with display block.
|
||||
display: inline-block;
|
||||
|
||||
@@ -22,7 +22,10 @@ ha-icon {
|
||||
vertical-align: top;
|
||||
margin: 0;
|
||||
|
||||
border-radius: var(--frigate-card-css-border-radius, var(--ha-card-border-radius, 4px));
|
||||
border-radius: var(
|
||||
--frigate-card-css-border-radius,
|
||||
var(--ha-card-border-radius, 4px)
|
||||
);
|
||||
|
||||
max-width: var(--frigate-card-thumbnail-size);
|
||||
max-height: 100%;
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
|
||||
border: 1px solid var(--secondary-color);
|
||||
background-color: var(--secondary-background-color);
|
||||
border-radius: var(--frigate-card-css-border-radius, var(--ha-card-border-radius, 4px));
|
||||
border-radius: var(
|
||||
--frigate-card-css-border-radius,
|
||||
var(--ha-card-border-radius, 4px)
|
||||
);
|
||||
box-sizing: border-box;
|
||||
|
||||
color: var(--primary-text-color);
|
||||
|
||||
+11
-5
@@ -16,7 +16,10 @@
|
||||
|
||||
:host([details]) {
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: var(--frigate-card-css-border-radius, var(--ha-card-border-radius, 4px));
|
||||
border-radius: var(
|
||||
--frigate-card-css-border-radius,
|
||||
var(--ha-card-border-radius, 4px)
|
||||
);
|
||||
padding: 2px;
|
||||
|
||||
// When details are enabled, use a background color so that the details have
|
||||
@@ -36,10 +39,12 @@ ha-icon {
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
transition: opacity 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
transition:
|
||||
opacity 0.2s ease-in-out,
|
||||
color 0.2s ease-in-out;
|
||||
}
|
||||
ha-icon:hover {
|
||||
opacity: 1.0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ha-icon.star {
|
||||
@@ -60,6 +65,7 @@ ha-icon.download {
|
||||
bottom: 3px;
|
||||
}
|
||||
|
||||
frigate-card-thumbnail-details-event, frigate-card-thumbnail-details-recording {
|
||||
frigate-card-thumbnail-details-event,
|
||||
frigate-card-thumbnail-details-recording {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,9 @@ div.timeline {
|
||||
color: var(--primary-text-color);
|
||||
background-color: var(--primary-color);
|
||||
|
||||
transition: background-color ease-in-out 1s, border-color ease-in-out 1s,
|
||||
transition:
|
||||
background-color ease-in-out 1s,
|
||||
border-color ease-in-out 1s,
|
||||
box-shadow ease-in-out 1s;
|
||||
}
|
||||
.vis-item.vis-selected {
|
||||
|
||||
@@ -19,4 +19,4 @@ frigate-card-ha-hls-player {
|
||||
frigate-card-progress-indicator {
|
||||
padding: 30px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
frigate-card-viewer-carousel {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { HomeAssistant } from "@dermotduffy/custom-card-helpers";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { CameraConfig } from "../config/types.js";
|
||||
import { dispatchErrorMessageEvent } from "../components/message.js";
|
||||
import { localize } from "../localize/localize.js";
|
||||
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
|
||||
import { HassEntity } from 'home-assistant-js-websocket';
|
||||
import { CameraConfig } from '../config/types.js';
|
||||
import { dispatchErrorMessageEvent } from '../components/message.js';
|
||||
import { localize } from '../localize/localize.js';
|
||||
|
||||
/**
|
||||
* Get the state object or dispatch an error. Used in `ha` and `image` live
|
||||
|
||||
@@ -6,7 +6,7 @@ const deviceSchema = z.object({
|
||||
model: z.string().nullable(),
|
||||
config_entries: z.string().array(),
|
||||
manufacturer: z.string().nullable(),
|
||||
})
|
||||
});
|
||||
const deviceListSchema = deviceSchema.array();
|
||||
export type DeviceList = z.infer<typeof deviceListSchema>;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
HassEntity,
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase
|
||||
HassEntity,
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
} from 'home-assistant-js-websocket';
|
||||
|
||||
const UPDATE_SUPPORT_PROGRESS = 4;
|
||||
|
||||
@@ -4,4 +4,4 @@ These entity icon mappings are copied (with slight tweaks to work with this
|
||||
card), from the [Lovelace Mushroom
|
||||
Card](https://github.com/piitaya/lovelace-mushroom/tree/main/src/utils/icons), which are in turn copied from [the Home Assistant frontend](https://github.com/home-assistant/frontend/tree/dev/src/common/entity) in order to
|
||||
replace the out of date entity icons in
|
||||
[custom-card-helpers](https://github.com/custom-cards/custom-card-helpers).
|
||||
[custom-card-helpers](https://github.com/custom-cards/custom-card-helpers).
|
||||
|
||||
@@ -52,7 +52,12 @@ const FIXED_DOMAIN_ICONS = {
|
||||
zone: 'mdi:map-marker-radius',
|
||||
};
|
||||
|
||||
export function domainIcon(domain: string, entity?: HassEntity, state?: string, defaultIcon?: string): string {
|
||||
export function domainIcon(
|
||||
domain: string,
|
||||
entity?: HassEntity,
|
||||
state?: string,
|
||||
defaultIcon?: string,
|
||||
): string {
|
||||
switch (domain) {
|
||||
case 'alarm_control_panel':
|
||||
return alarmPanelIcon(state);
|
||||
|
||||
@@ -70,10 +70,7 @@ const batteryStateIcon = (
|
||||
return batteryIcon(battery, batteryCharging);
|
||||
};
|
||||
|
||||
const batteryIcon = (
|
||||
batteryState: number | string,
|
||||
batteryCharging?: boolean,
|
||||
) => {
|
||||
const batteryIcon = (batteryState: number | string, batteryCharging?: boolean) => {
|
||||
const batteryValue = Number(batteryState);
|
||||
if (isNaN(batteryValue)) {
|
||||
if (batteryState === 'off') {
|
||||
|
||||
@@ -62,7 +62,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async (
|
||||
targetView: options?.targetView,
|
||||
select: options?.select,
|
||||
useCache: options?.useCache,
|
||||
viewContext: options?.viewContext
|
||||
viewContext: options?.viewContext,
|
||||
},
|
||||
)
|
||||
)?.dispatchChangeEvent(element);
|
||||
@@ -201,7 +201,7 @@ export const executeMediaQueryForView = async (
|
||||
camera: cameraID,
|
||||
})
|
||||
.mergeInContext(options?.viewContext)
|
||||
.mergeInContext(viewerContext)
|
||||
.mergeInContext(viewerContext);
|
||||
};
|
||||
|
||||
export const executeMediaQueryForViewWithErrorDispatching = async (
|
||||
|
||||
@@ -18,7 +18,7 @@ export class MediaQueriesClassifier {
|
||||
return this.areEventQueries(queries)
|
||||
? 'event'
|
||||
: this.areRecordingQueries(queries)
|
||||
? 'recording'
|
||||
: null;
|
||||
? 'recording'
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,8 +246,8 @@ export class MediaQueriesResults {
|
||||
return criteria?.allCameras
|
||||
? this.getCameraIDs()
|
||||
: criteria?.cameraID
|
||||
? new Set([criteria.cameraID])
|
||||
: null;
|
||||
? new Set([criteria.cameraID])
|
||||
: null;
|
||||
}
|
||||
|
||||
public selectResultIfFound(
|
||||
|
||||
@@ -26,10 +26,10 @@ export const getCameraIDsForViewName = (
|
||||
viewName === 'clip'
|
||||
? 'clips'
|
||||
: viewName === 'snapshot'
|
||||
? 'snapshots'
|
||||
: viewName === 'recording'
|
||||
? 'recordings'
|
||||
: viewName;
|
||||
? 'snapshots'
|
||||
: viewName === 'recording'
|
||||
? 'recordings'
|
||||
: viewName;
|
||||
return cameraID
|
||||
? cameraManager.getStore().getAllDependentCameras(cameraID, capability)
|
||||
: cameraManager.getStore().getCameraIDsWithCapability(capability);
|
||||
|
||||
+3
-3
@@ -64,7 +64,7 @@ export class View {
|
||||
}
|
||||
|
||||
public static adoptFromViewIfAppropriate(next: View, curr?: View | null): void {
|
||||
if (!curr) {
|
||||
if (!curr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,8 +121,8 @@ export class View {
|
||||
currentQueriesView === 'clips'
|
||||
? 'clip'
|
||||
: currentQueriesView === 'snapshots'
|
||||
? 'snapshot'
|
||||
: 'recording';
|
||||
? 'snapshot'
|
||||
: 'recording';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user