feat(casting): implement casting functionality with auto-mute and UI controls

This commit is contained in:
2026-03-14 02:38:54 +01:00
parent 953366ed63
commit 0bdf7104a9
4 changed files with 112 additions and 1 deletions

View File

@@ -14,9 +14,10 @@ import {
} from "./components";
import type { SubtitleTrack } from "./components/video-player";
import type { LogoPosition } from "@/lib/types";
import { Maximize2, Minimize2, Volume1, Volume2, VolumeX } from "lucide-react";
import { Cast, Maximize2, Minimize2, Volume1, Volume2, VolumeX } from "lucide-react";
import { useAuthContext } from "@/context/auth-context";
import { useChannels, useCurrentBroadcast, useEpg } from "@/hooks/use-channels";
import { useCast } from "@/hooks/use-cast";
import {
useStreamUrl,
fmtTime,
@@ -166,6 +167,20 @@ function TvPageContent() {
const toggleMute = useCallback(() => setIsMuted((m) => !m), []);
const VolumeIcon = isMuted || volume === 0 ? VolumeX : volume < 0.5 ? Volume1 : Volume2;
const { castAvailable, isCasting, castDeviceName, requestCast, stopCasting } = useCast();
// Auto-mute local video while casting, restore on cast end
const prevMutedRef = useRef(false);
useEffect(() => {
if (isCasting) {
prevMutedRef.current = isMuted;
setIsMuted(true);
} else {
setIsMuted(prevMutedRef.current);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isCasting]);
// Channel jump by number (e.g. press "1","4" → jump to ch 14 after 1.5 s)
const [channelInput, setChannelInput] = useState("");
const channelInputTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -654,6 +669,18 @@ function TvPageContent() {
: <Maximize2 className="h-4 w-4" />}
</button>
{castAvailable && (
<button
className={`pointer-events-auto rounded-md bg-black/50 p-1.5 backdrop-blur transition-colors hover:bg-black/70 hover:text-white ${
isCasting ? "text-blue-400" : "text-zinc-400"
}`}
onClick={() => isCasting ? stopCasting() : streamUrl && requestCast(streamUrl)}
title={isCasting ? `Stop casting to ${castDeviceName ?? "TV"}` : "Cast to TV"}
>
<Cast className="h-4 w-4" />
</button>
)}
<button
className="pointer-events-auto rounded-md bg-black/50 px-3 py-1.5 text-xs text-zinc-400 backdrop-blur transition-colors hover:bg-black/70 hover:text-white"
onClick={toggleSchedule}
@@ -708,6 +735,13 @@ function TvPageContent() {
</div>
</div>
{/* Casting indicator */}
{isCasting && castDeviceName && (
<div className="pointer-events-none absolute left-4 top-4 z-10 rounded-md bg-black/60 px-3 py-1.5 text-xs text-blue-300 backdrop-blur">
Casting to {castDeviceName}
</div>
)}
{/* Channel number input overlay */}
{channelInput && (
<div className="pointer-events-none absolute left-1/2 top-1/2 z-30 -translate-x-1/2 -translate-y-1/2 rounded-xl bg-black/80 px-8 py-5 text-center backdrop-blur">