diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json index 9e923ee0..71fb1d78 100644 --- a/src/assets/locales/en.json +++ b/src/assets/locales/en.json @@ -94,6 +94,9 @@ "failure": "Error occurred" } }, + "casting": { + "enabled": "Casting to device..." + }, "playbackError": { "badge": "Playback error", "title": "Failed to play video!", diff --git a/src/components/player/atoms/CastingNotification.tsx b/src/components/player/atoms/CastingNotification.tsx new file mode 100644 index 00000000..9c4e423b --- /dev/null +++ b/src/components/player/atoms/CastingNotification.tsx @@ -0,0 +1,22 @@ +import { useTranslation } from "react-i18next"; + +import { Icon, Icons } from "@/components/Icon"; +import { usePlayerStore } from "@/stores/player/store"; + +export function CastingNotification() { + const { t } = useTranslation(); + const isLoading = usePlayerStore((s) => s.mediaPlaying.isLoading); + const display = usePlayerStore((s) => s.display); + const isCasting = display?.getType() === "casting"; + + if (isLoading || !isCasting) return null; + + return ( +
+
+ +
+

{t("player.casting.enabled")}

+
+ ); +} diff --git a/src/components/player/atoms/index.ts b/src/components/player/atoms/index.ts index 111703d5..3caf8154 100644 --- a/src/components/player/atoms/index.ts +++ b/src/components/player/atoms/index.ts @@ -15,3 +15,4 @@ export * from "./Airplay"; export * from "./VolumeChangedPopout"; export * from "./NextEpisodeButton"; export * from "./Chromecast"; +export * from "./CastingNotification"; diff --git a/src/components/player/base/SubtitleView.tsx b/src/components/player/base/SubtitleView.tsx index c3f16a78..38520cac 100644 --- a/src/components/player/base/SubtitleView.tsx +++ b/src/components/player/base/SubtitleView.tsx @@ -107,8 +107,10 @@ export function SubtitleRenderer() { export function SubtitleView(props: { controlsShown: boolean }) { const caption = usePlayerStore((s) => s.caption.selected); const captionAsTrack = usePlayerStore((s) => s.caption.asTrack); + const display = usePlayerStore((s) => s.display); + const isCasting = display?.getType() === "casting"; - if (captionAsTrack || !caption) return null; + if (captionAsTrack || !caption || isCasting) return null; return ( { destroyVideoElement(); fscreen.removeEventListener("fullscreenchange", fullscreenChange); diff --git a/src/components/player/display/chromecast.ts b/src/components/player/display/chromecast.ts index c8bfc3c7..401fc6f8 100644 --- a/src/components/player/display/chromecast.ts +++ b/src/components/player/display/chromecast.ts @@ -158,6 +158,9 @@ export function makeChromecastDisplayInterface( return { on, off, + getType() { + return "casting"; + }, destroy: () => { stopListening(); destroyVideoElement(); diff --git a/src/components/player/display/displayInterface.ts b/src/components/player/display/displayInterface.ts index 0b76fd79..b7a3e09d 100644 --- a/src/components/player/display/displayInterface.ts +++ b/src/components/player/display/displayInterface.ts @@ -46,6 +46,8 @@ export interface DisplayCaption { url?: string; } +export type DisplayType = "web" | "casting"; + export interface DisplayInterface extends Listener { play(): void; pause(): void; @@ -66,4 +68,5 @@ export interface DisplayInterface extends Listener { setPlaybackRate(rate: number): void; setMeta(meta: DisplayMeta): void; setCaption(caption: DisplayCaption | null): void; + getType(): DisplayType; } diff --git a/src/pages/parts/player/PlayerPart.tsx b/src/pages/parts/player/PlayerPart.tsx index 14df6f31..48a25094 100644 --- a/src/pages/parts/player/PlayerPart.tsx +++ b/src/pages/parts/player/PlayerPart.tsx @@ -31,10 +31,15 @@ export function PlayerPart(props: PlayerPartProps) { {status === playerStatus.PLAYING ? ( - - - - + <> + + + + + + + + ) : null}