import {Track} from "livekit-client" import {MediaQuery} from "svelte/reactivity" import {derived, get, writable} from "svelte/store" import {currentVoiceSession, VoiceState, type VoiceSession, voiceState} from "@app/call/stores" import {pushToast} from "@app/util/toast" export enum VideoCallLayout { Chat = "chat", Video = "video", Split = "split", } export const isDesktopLayout = new MediaQuery("min-width: 768px", false) export enum ViewportSize { Desktop = "desktop", Mobile = "mobile", } export const videoCallViewportSync = { previousLayout: undefined as ViewportSize | undefined, } export const videoCallLayout = writable(VideoCallLayout.Split) export const resetVideoCallLayout = () => { videoCallViewportSync.previousLayout = undefined videoCallLayout.set(VideoCallLayout.Chat) } export const videoPrimaryTileKey = writable(undefined) export const toggleVideoPrimaryTile = (key: string) => { videoPrimaryTileKey.update(k => (k === key ? undefined : key)) } const VISUAL_SOURCES = [Track.Source.Camera, Track.Source.ScreenShare] as const const countLiveVisualFeeds = (session: VoiceSession): number => { const room = session.room let n = 0 const lp = room.localParticipant if (session.cameraOn) { const pub = lp.getTrackPublication(Track.Source.Camera) if (pub?.track) n += 1 } if (session.screenShareOn) { const pub = lp.getTrackPublication(Track.Source.ScreenShare) if (pub?.track) n += 1 } for (const rp of room.remoteParticipants.values()) { for (const source of VISUAL_SOURCES) { const pub = rp.getTrackPublication(source) if (pub?.isSubscribed && pub.track) n += 1 } } return n } export const triggerVideoFeedCount = () => { currentVoiceSession.update(s => (s ? {...s} : s)) } export const videoTileCount = derived([currentVoiceSession, voiceState], ([$session, $state]) => { if ($state !== VoiceState.Connected || !$session) return 0 return countLiveVisualFeeds($session) }) export const toggleCamera = async () => { const session = get(currentVoiceSession) if (!session) return const cameraOn = !session.cameraOn try { await session.room.localParticipant.setCameraEnabled(cameraOn) currentVoiceSession.set({...session, cameraOn}) } catch { pushToast({ theme: "error", message: cameraOn ? "Could not access camera" : "Could not turn off camera", }) } } export const toggleScreenShare = async () => { const session = get(currentVoiceSession) if (!session) return const screenShareOn = !session.screenShareOn try { await session.room.localParticipant.setScreenShareEnabled(screenShareOn) currentVoiceSession.set({...session, screenShareOn}) } catch { pushToast({ theme: "error", message: screenShareOn ? "Could not start screen sharing" : "Could not stop screen sharing", }) } }