Skip to content

Commit

Permalink
fix: Render media correctly in rtl languages (#1757)
Browse files Browse the repository at this point in the history
  • Loading branch information
dermotduffy authored Dec 14, 2024
1 parent dc5de02 commit cebd4b2
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 96 deletions.
6 changes: 4 additions & 2 deletions src/components/carousel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
CarouselController,
CarouselDirection,
} from '../utils/embla/carousel-controller';
import { getTextDirection } from '../utils/text-direction';

export type EmblaCarouselPlugins = CreatePluginType<
LoosePluginType,
Expand Down Expand Up @@ -85,13 +86,13 @@ export class FrigateCardCarousel extends LitElement {

protected render(): TemplateResult | void {
return html` <div class="embla">
<slot name="previous"></slot>
<slot name="left"></slot>
<div ${ref(this._refRoot)} class="embla__viewport">
<div class="embla__container">
<slot ${ref(this._refParent)}></slot>
</div>
</div>
<slot name="next"></slot>
<slot name="right"></slot>
</div>`;
}

Expand All @@ -108,6 +109,7 @@ export class FrigateCardCarousel extends LitElement {
transitionEffect: this.transitionEffect,
loop: this.loop,
plugins: this.plugins,
textDirection: getTextDirection(this),
},
);
} else if (changedProps.has('selected')) {
Expand Down
117 changes: 71 additions & 46 deletions src/components/live/carousel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { customElement, property, state } from 'lit/decorators.js';
import { guard } from 'lit/directives/guard.js';
import { createRef, Ref, ref } from 'lit/directives/ref.js';
import { CameraManager } from '../../camera-manager/manager.js';
import { CameraManagerCameraMetadata } from '../../camera-manager/types.js';
import {
ConditionsManagerEpoch,
getOverriddenConfig,
Expand Down Expand Up @@ -37,6 +38,7 @@ import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy
import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js';
import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js';
import { getStreamCameraID } from '../../utils/substream.js';
import { getTextDirection } from '../../utils/text-direction.js';
import { View } from '../../view/view.js';
import '../carousel';
import { EmblaCarouselPlugins } from '../carousel.js';
Expand All @@ -49,6 +51,16 @@ import { FrigateCardLiveProvider } from './provider.js';

const FRIGATE_CARD_LIVE_PROVIDER = 'frigate-card-live-provider';

interface CameraNeighbor {
id: string;
metadata?: CameraManagerCameraMetadata | null;
}

interface CameraNeighbors {
previous?: CameraNeighbor;
next?: CameraNeighbor;
}

@customElement('frigate-card-live-carousel')
export class FrigateCardLiveCarousel extends LitElement {
@property({ attribute: false })
Expand Down Expand Up @@ -315,31 +327,74 @@ export class FrigateCardLiveCarousel extends LitElement {
`;
}

protected _getCameraIDsOfNeighbors(): [string | null, string | null] {
protected _getSubstreamCameraID(cameraID: string, view?: View | null): string {
return view?.context?.live?.overrides?.get(cameraID) ?? cameraID;
}

protected _getCameraNeighbors(): CameraNeighbors | null {
const cameraIDs = this.cameraManager
? [...this.cameraManager?.getStore().getCameraIDsWithCapability('live')]
: [];
const view = this.viewManagerEpoch?.manager.getView();

if (this.viewFilterCameraID || cameraIDs.length <= 1 || !view || !this.hass) {
return [null, null];
return {};
}

const cameraID = this.viewFilterCameraID ?? view.camera;
const currentIndex = cameraIDs.indexOf(cameraID);

if (currentIndex < 0) {
return [null, null];
return {};
}

return [
cameraIDs[currentIndex > 0 ? currentIndex - 1 : cameraIDs.length - 1],
cameraIDs[currentIndex + 1 < cameraIDs.length ? currentIndex + 1 : 0],
];
const prevID = cameraIDs[currentIndex > 0 ? currentIndex - 1 : cameraIDs.length - 1];
const nextID = cameraIDs[currentIndex + 1 < cameraIDs.length ? currentIndex + 1 : 0];

return {
previous: {
id: prevID,
metadata: prevID
? this.cameraManager?.getCameraMetadata(
this._getSubstreamCameraID(prevID, view),
)
: null,
},
next: {
id: nextID,
metadata: nextID
? this.cameraManager?.getCameraMetadata(
this._getSubstreamCameraID(nextID, view),
)
: null,
},
};
}

protected _getSubstreamCameraID(cameraID: string, view?: View | null): string {
return view?.context?.live?.overrides?.get(cameraID) ?? cameraID;
protected _renderNextPrevious(
side: 'left' | 'right',
neighbors: CameraNeighbors | null,
): TemplateResult {
const textDirection = getTextDirection(this);
const neighbor =
(textDirection === 'ltr' && side === 'left') ||
(textDirection === 'rtl' && side === 'right')
? neighbors?.previous
: neighbors?.next;

return html`<frigate-card-next-previous-control
slot=${side}
.hass=${this.hass}
.side=${side}
.controlConfig=${this.overriddenLiveConfig?.controls.next_previous}
.label=${neighbor?.metadata?.title ?? ''}
.icon=${neighbor?.metadata?.icon}
?disabled=${!neighbor}
@click=${(ev) => {
this._setViewCameraID(neighbor?.id);
stopEventFromActivatingCardWideActions(ev);
}}
>
</frigate-card-next-previous-control>`;
}

protected render(): TemplateResult | void {
Expand All @@ -355,14 +410,8 @@ export class FrigateCardLiveCarousel extends LitElement {
}

const hasMultipleCameras = slides.length > 1;
const [prevID, nextID] = this._getCameraIDsOfNeighbors();

const cameraMetadataPrevious = prevID
? this.cameraManager.getCameraMetadata(this._getSubstreamCameraID(prevID, view))
: null;
const cameraMetadataNext = nextID
? this.cameraManager.getCameraMetadata(this._getSubstreamCameraID(nextID, view))
: null;
const neighbors = this._getCameraNeighbors();

const forcePTZVisibility =
!this._mediaHasLoaded ||
(!!this.viewFilterCameraID && this.viewFilterCameraID !== view.camera) ||
Expand Down Expand Up @@ -393,35 +442,11 @@ export class FrigateCardLiveCarousel extends LitElement {
this._mediaHasLoaded = false;
}}
>
<frigate-card-next-previous-control
slot="previous"
.hass=${this.hass}
.direction=${'previous'}
.controlConfig=${this.overriddenLiveConfig.controls.next_previous}
.label=${cameraMetadataPrevious?.title ?? ''}
.icon=${cameraMetadataPrevious?.icon}
?disabled=${prevID === null}
@click=${(ev) => {
this._setViewCameraID(prevID);
stopEventFromActivatingCardWideActions(ev);
}}
>
</frigate-card-next-previous-control>
${this._renderNextPrevious('left', neighbors)}
<!-- -->
${slides}
<frigate-card-next-previous-control
slot="next"
.hass=${this.hass}
.direction=${'next'}
.controlConfig=${this.overriddenLiveConfig.controls.next_previous}
.label=${cameraMetadataNext?.title ?? ''}
.icon=${cameraMetadataNext?.icon}
?disabled=${nextID === null}
@click=${(ev) => {
this._setViewCameraID(nextID);
stopEventFromActivatingCardWideActions(ev);
}}
>
</frigate-card-next-previous-control>
<!-- -->
${this._renderNextPrevious('right', neighbors)}
</frigate-card-carousel>
<frigate-card-ptz
.config=${this.overriddenLiveConfig.controls.ptz}
Expand Down
8 changes: 4 additions & 4 deletions src/components/next-prev-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { createFetchThumbnailTask } from '../utils/thumbnail.js';
@customElement('frigate-card-next-previous-control')
export class FrigateCardNextPreviousControl extends LitElement {
@property({ attribute: false })
public direction?: 'next' | 'previous';
public side?: 'left' | 'right';

set controlConfig(controlConfig: NextPreviousControlConfig | undefined) {
if (controlConfig?.size) {
Expand Down Expand Up @@ -53,8 +53,8 @@ export class FrigateCardNextPreviousControl extends LitElement {

const classes = {
controls: true,
left: this.direction === 'previous',
right: this.direction === 'next',
left: this.side === 'left',
right: this.side === 'right',
thumbnails: !renderIcon,
icons: renderIcon,
button: renderIcon,
Expand All @@ -63,7 +63,7 @@ export class FrigateCardNextPreviousControl extends LitElement {
if (renderIcon) {
const icon =
!this.thumbnail || !this.icon || this._controlConfig.style === 'chevrons'
? this.direction === 'previous'
? this.side === 'left'
? 'mdi:chevron-left'
: 'mdi:chevron-right'
: this.icon;
Expand Down
83 changes: 41 additions & 42 deletions src/components/viewer/carousel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy
import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js';
import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js';
import { ResolvedMediaCache } from '../../utils/ha/resolved-media.js';
import { getTextDirection } from '../../utils/text-direction.js';
import { ViewMedia } from '../../view/media.js';
import '../carousel';
import type { EmblaCarouselPlugins } from '../carousel.js';
Expand Down Expand Up @@ -306,6 +307,44 @@ export class FrigateCardViewerCarousel extends LitElement {
}
}

protected _renderNextPrevious(
side: 'left' | 'right',
neighbors?: MediaNeighbors | null,
): TemplateResult {
const scroll = (direction: 'previous' | 'next'): void => {
if (!neighbors || !this._media) {
return;
}
const newIndex =
(direction === 'previous' ? neighbors.previous?.index : neighbors.next?.index) ??
null;
if (newIndex !== null) {
this._setViewSelectedIndex(newIndex);
}
};

const textDirection = getTextDirection(this);
const scrollDirection =
(textDirection === 'ltr' && side === 'left') ||
(textDirection === 'rtl' && side === 'right')
? 'previous'
: 'next';

return html` <frigate-card-next-previous-control
slot=${side}
.hass=${this.hass}
.side=${side}
.controlConfig=${this.viewerConfig?.controls.next_previous}
.thumbnail=${neighbors?.[scrollDirection]?.media.getThumbnail() ?? undefined}
.label=${neighbors?.[scrollDirection]?.media.getTitle() ?? ''}
?disabled=${!neighbors?.[scrollDirection]}
@click=${(ev: Event) => {
scroll(scrollDirection);
stopEventFromActivatingCardWideActions(ev);
}}
></frigate-card-next-previous-control>`;
}

protected render(): TemplateResult | void {
const mediaCount = this._media?.length ?? 0;
if (!this._media || !mediaCount) {
Expand All @@ -324,18 +363,6 @@ export class FrigateCardViewerCarousel extends LitElement {
}

const neighbors = this._getMediaNeighbors();
const scroll = (direction: 'previous' | 'next'): void => {
if (!neighbors || !this._media) {
return;
}
const newIndex =
(direction === 'previous' ? neighbors.previous?.index : neighbors.next?.index) ??
null;
if (newIndex !== null) {
this._setViewSelectedIndex(newIndex);
}
};

const view = this.viewManagerEpoch?.manager.getView();

return html`
Expand All @@ -356,37 +383,9 @@ export class FrigateCardViewerCarousel extends LitElement {
this._player = null;
}}
>
${this.showControls
? html` <frigate-card-next-previous-control
slot="previous"
.hass=${this.hass}
.direction=${'previous'}
.controlConfig=${this.viewerConfig?.controls.next_previous}
.thumbnail=${neighbors?.previous?.media.getThumbnail() ?? undefined}
.label=${neighbors?.previous?.media.getTitle() ?? ''}
?disabled=${!neighbors?.previous}
@click=${(ev: Event) => {
scroll('previous');
stopEventFromActivatingCardWideActions(ev);
}}
></frigate-card-next-previous-control>`
: ''}
${this.showControls ? this._renderNextPrevious('left', neighbors) : ''}
${guard([this._media, view], () => this._getSlides())}
${this.showControls
? html` <frigate-card-next-previous-control
slot="next"
.hass=${this.hass}
.direction=${'next'}
.controlConfig=${this.viewerConfig?.controls.next_previous}
.thumbnail=${neighbors?.next?.media.getThumbnail() ?? undefined}
.label=${neighbors?.next?.media.getTitle() ?? ''}
?disabled=${!neighbors?.next}
@click=${(ev: Event) => {
scroll('next');
stopEventFromActivatingCardWideActions(ev);
}}
></frigate-card-next-previous-control>`
: ''}
${this.showControls ? this._renderNextPrevious('right', neighbors) : ''}
</frigate-card-carousel>
${view
? html` <frigate-card-ptz
Expand Down
4 changes: 2 additions & 2 deletions src/scss/next-previous-control.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@
top: calc(50% - (var(--frigate-card-next-prev-size-hover) / 2));
}

.controls.previous.thumbnails:hover {
.controls.left.thumbnails:hover {
left: calc(
var(--frigate-card-left-position) -
(var(--frigate-card-next-prev-size-hover) - var(--frigate-card-next-prev-size)) / 2
);
}

.controls.next.thumbnails:hover {
.controls.right.thumbnails:hover {
right: calc(
var(--frigate-card-right-position) -
(var(--frigate-card-next-prev-size-hover) - var(--frigate-card-next-prev-size)) / 2
Expand Down
Loading

0 comments on commit cebd4b2

Please sign in to comment.