Cleanup remaining files

This commit is contained in:
mplorentz
2026-04-08 11:09:52 -04:00
committed by hodlbod
parent 11fa8fd720
commit 81ab03311a
7 changed files with 62 additions and 80 deletions
-1
View File
@@ -47,7 +47,6 @@ export const isParticipantSpeaking = derived(
$participants.some(sp => participantKey(sp) === participantKey(p)), $participants.some(sp => participantKey(sp) === participantKey(p)),
) )
/** True when the local user is in LiveKits active-speakers list (currently talking). */
export const isLocalSpeaking = derived( export const isLocalSpeaking = derived(
[currentVoiceSession, speakingParticipants], [currentVoiceSession, speakingParticipants],
([$session, $speaking]) => { ([$session, $speaking]) => {
+12 -18
View File
@@ -71,17 +71,14 @@ export const toggleCamera = async () => {
if (!session) return if (!session) return
const cameraOn = !session.cameraOn const cameraOn = !session.cameraOn
if (!cameraOn) {
session.room.localParticipant.setCameraEnabled(false)
currentVoiceSession.set({...session, cameraOn})
return
}
try { try {
await session.room.localParticipant.setCameraEnabled(true) await session.room.localParticipant.setCameraEnabled(cameraOn)
currentVoiceSession.set({...session, cameraOn}) currentVoiceSession.set({...session, cameraOn})
} catch (e) { } catch {
pushToast({theme: "error", message: "Could not access camera"}) pushToast({
theme: "error",
message: cameraOn ? "Could not access camera" : "Could not turn off camera",
})
} }
} }
@@ -90,16 +87,13 @@ export const toggleScreenShare = async () => {
if (!session) return if (!session) return
const screenShareOn = !session.screenShareOn const screenShareOn = !session.screenShareOn
if (!screenShareOn) {
session.room.localParticipant.setScreenShareEnabled(false)
currentVoiceSession.set({...session, screenShareOn})
return
}
try { try {
await session.room.localParticipant.setScreenShareEnabled(true) await session.room.localParticipant.setScreenShareEnabled(screenShareOn)
currentVoiceSession.set({...session, screenShareOn}) currentVoiceSession.set({...session, screenShareOn})
} catch (e) { } catch {
pushToast({theme: "error", message: "Could not start screen sharing"}) pushToast({
theme: "error",
message: screenShareOn ? "Could not start screen sharing" : "Could not stop screen sharing",
})
} }
} }
+2 -2
View File
@@ -325,7 +325,7 @@ export const leaveVoiceRoom = async () => {
try { try {
await session.room.localParticipant.setCameraEnabled(false) await session.room.localParticipant.setCameraEnabled(false)
} catch { } catch {
/* pass */ pushToast({theme: "error", message: "Error turning off camera."})
} }
} }
@@ -333,7 +333,7 @@ export const leaveVoiceRoom = async () => {
try { try {
await session.room.localParticipant.setScreenShareEnabled(false) await session.room.localParticipant.setScreenShareEnabled(false)
} catch { } catch {
/* pass */ pushToast({theme: "error", message: "Error turning off screen sharing."})
} }
} }
+14 -14
View File
@@ -6,7 +6,7 @@
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import ProfileCircle from "@app/components/ProfileCircle.svelte" import ProfileCircle from "@app/components/ProfileCircle.svelte"
import VideoCallVideo from "@app/components/VideoCallVideo.svelte" import VideoCallTile from "@app/components/VideoCallTile.svelte"
import VoiceWidget from "@app/components/VoiceWidget.svelte" import VoiceWidget from "@app/components/VoiceWidget.svelte"
import {get} from "svelte/store" import {get} from "svelte/store"
import { import {
@@ -28,11 +28,11 @@
class?: string class?: string
} }
type VideoTile = { type VideoTileData = {
identity: string identity: string
isLocal: boolean isLocal: boolean
trackSid: string trackSid: string
attachable: Track | undefined track: Track | undefined
source: Track.Source.Camera | Track.Source.ScreenShare source: Track.Source.Camera | Track.Source.ScreenShare
} }
@@ -75,7 +75,7 @@
} }
const room = session.room const room = session.room
const videoTiles: VideoTile[] = [] const videoTiles: VideoTileData[] = []
const user = room.localParticipant const user = room.localParticipant
if (session.cameraOn) { if (session.cameraOn) {
@@ -84,7 +84,7 @@
identity: user.identity, identity: user.identity,
isLocal: true, isLocal: true,
trackSid: localPub?.trackSid ?? "local-camera", trackSid: localPub?.trackSid ?? "local-camera",
attachable: localPub?.track, track: localPub?.track,
source: Track.Source.Camera, source: Track.Source.Camera,
}) })
} }
@@ -95,7 +95,7 @@
identity: user.identity, identity: user.identity,
isLocal: true, isLocal: true,
trackSid: localPub?.trackSid ?? "local-screen", trackSid: localPub?.trackSid ?? "local-screen",
attachable: localPub?.track, track: localPub?.track,
source: Track.Source.ScreenShare, source: Track.Source.ScreenShare,
}) })
} }
@@ -107,7 +107,7 @@
identity: rp.identity, identity: rp.identity,
isLocal: false, isLocal: false,
trackSid: camPub.trackSid, trackSid: camPub.trackSid,
attachable: camPub.track, track: camPub.track,
source: Track.Source.Camera, source: Track.Source.Camera,
}) })
} }
@@ -117,7 +117,7 @@
identity: rp.identity, identity: rp.identity,
isLocal: false, isLocal: false,
trackSid: screenPub.trackSid, trackSid: screenPub.trackSid,
attachable: screenPub.track, track: screenPub.track,
source: Track.Source.ScreenShare, source: Track.Source.ScreenShare,
}) })
} }
@@ -127,7 +127,7 @@
}) })
/** Identity + source only — LiveKit can change trackSid after publish, which broke spotlight + stale-key effect. */ /** Identity + source only — LiveKit can change trackSid after publish, which broke spotlight + stale-key effect. */
const tileKey = (t: VideoTile) => `${t.identity}\x1f${t.source}` const tileKey = (t: VideoTileData) => `${t.identity}\x1f${t.source}`
const primaryTile = $derived.by(() => { const primaryTile = $derived.by(() => {
const k = $videoPrimaryTileKey const k = $videoPrimaryTileKey
@@ -160,7 +160,7 @@
} }
}) })
const labelFor = (identity: string, source: VideoTile["source"]) => { const labelFor = (identity: string, source: VideoTileData["source"]) => {
const pk = pubkeyFromLiveKitIdentity(identity) const pk = pubkeyFromLiveKitIdentity(identity)
const name = pk ? displayProfileByPubkey(pk) : "Unknown" const name = pk ? displayProfileByPubkey(pk) : "Unknown"
return source === Track.Source.ScreenShare ? `${name} · screen` : name return source === Track.Source.ScreenShare ? `${name} · screen` : name
@@ -183,7 +183,7 @@
) )
</script> </script>
{#snippet videoTile(tile: VideoTile, layout: TileLayout)} {#snippet videoTile(tile: VideoTileData, layout: TileLayout)}
<div <div
class={cx( class={cx(
"relative isolate overflow-hidden rounded-box shadow-sm", "relative isolate overflow-hidden rounded-box shadow-sm",
@@ -192,9 +192,9 @@
layout === "strip" && "aspect-video w-44 shrink-0", layout === "strip" && "aspect-video w-44 shrink-0",
tile.source === Track.Source.ScreenShare ? "bg-black" : "bg-base-100", tile.source === Track.Source.ScreenShare ? "bg-black" : "bg-base-100",
)}> )}>
{#if tile.attachable} {#if tile.track}
<VideoCallVideo <VideoCallTile
track={tile.attachable} track={tile.track}
muted={tile.isLocal} muted={tile.isLocal}
fit={tile.source === Track.Source.ScreenShare ? "contain" : "cover"} fit={tile.source === Track.Source.ScreenShare ? "contain" : "cover"}
class="pointer-events-none absolute inset-0" /> class="pointer-events-none absolute inset-0" />
@@ -11,21 +11,21 @@
const {track, muted = true, fit = "cover", class: className = ""}: Props = $props() const {track, muted = true, fit = "cover", class: className = ""}: Props = $props()
let el = $state<HTMLVideoElement | undefined>() let videoElement = $state<HTMLVideoElement | undefined>()
$effect(() => { $effect(() => {
const v = el const element = videoElement
const t = track const activeTrack = track
if (!v) return if (!element) return
t.attach(v) activeTrack.attach(element)
return () => { return () => {
t.detach(v) activeTrack.detach(element)
} }
}) })
</script> </script>
<video <video
bind:this={el} bind:this={videoElement}
class={cx("h-full w-full", fit === "contain" ? "object-contain" : "object-cover", className)} class={cx("h-full w-full", fit === "contain" ? "object-contain" : "object-cover", className)}
playsinline playsinline
{muted}></video> {muted}></video>
@@ -41,16 +41,9 @@
} }
$effect(() => { $effect(() => {
void loadDevices() loadDevices()
const md = navigator.mediaDevices navigator.mediaDevices?.addEventListener?.("devicechange", loadDevices)
if (!md?.addEventListener) return return () => navigator.mediaDevices?.removeEventListener?.("devicechange", loadDevices)
const onDeviceChange = () => {
void loadDevices()
}
md.addEventListener("devicechange", onDeviceChange)
return () => {
md.removeEventListener("devicechange", onDeviceChange)
}
}) })
$effect(() => { $effect(() => {
+24 -28
View File
@@ -53,6 +53,14 @@
) )
const routeDisplayedRoom = $derived($displayedRoomStore) const routeDisplayedRoom = $derived($displayedRoomStore)
const isViewingCurrentVoiceRoom = $derived(
$currentVoiceRoom !== undefined &&
url !== undefined &&
typeof h === "string" &&
$currentVoiceRoom.url === url &&
$currentVoiceRoom.h === h,
)
const targetRoom = $derived.by((): Room | undefined => { const targetRoom = $derived.by((): Room | undefined => {
if ($voiceState === VoiceState.Joining || $voiceState === VoiceState.Connected) { if ($voiceState === VoiceState.Joining || $voiceState === VoiceState.Connected) {
return $currentVoiceRoom return $currentVoiceRoom
@@ -90,26 +98,17 @@
pushModal(VoiceCallAudioSettingsDialog) pushModal(VoiceCallAudioSettingsDialog)
} }
const showVoiceLayoutToggle = $derived( const showChatButton = $derived($voiceState === VoiceState.Connected && isViewingCurrentVoiceRoom)
$voiceState === VoiceState.Connected &&
targetRoom !== undefined &&
getRoomType(targetRoom) === RoomType.Voice &&
typeof h === "string" &&
relay !== undefined &&
decodeRelay(relay) === targetRoom.url &&
h === targetRoom.h,
)
const isChatPanelActive = $derived( const isChatPanelActive = $derived(
showVoiceLayoutToggle && showChatButton &&
((!isDesktopLayout.current && (isDesktopLayout.current
($videoCallLayout === VideoCallLayout.Chat || ? $videoCallLayout === VideoCallLayout.Split
$videoCallLayout === VideoCallLayout.Split)) || : $videoCallLayout === VideoCallLayout.Chat),
(isDesktopLayout.current && $videoCallLayout === VideoCallLayout.Split)),
) )
const onChatToggle = () => { const onChatToggle = () => {
if (!showVoiceLayoutToggle) return if (!showChatButton) return
if (isDesktopLayout.current) { if (isDesktopLayout.current) {
videoCallLayout.update(p => videoCallLayout.update(p =>
p === VideoCallLayout.Split ? VideoCallLayout.Video : VideoCallLayout.Split, p === VideoCallLayout.Split ? VideoCallLayout.Video : VideoCallLayout.Split,
@@ -128,17 +127,6 @@
const mediaToggleClass = "center tooltip tooltip-top btn btn-sm btn-square btn-ghost" const mediaToggleClass = "center tooltip tooltip-top btn btn-sm btn-square btn-ghost"
</script> </script>
{#snippet mutedSlash(show: boolean)}
{#if show}
<span
class="pointer-events-none absolute inset-0 flex items-center justify-center overflow-visible"
aria-hidden="true">
<span class="h-[1.3px] w-[150%] max-w-none shrink-0 -rotate-45 rounded-full bg-current"
></span>
</span>
{/if}
{/snippet}
{#if targetRoom} {#if targetRoom}
<div <div
in:fly={{y: 60, duration: 350}} in:fly={{y: 60, duration: 350}}
@@ -163,7 +151,7 @@
</span> </span>
</div> </div>
</button> </button>
{#if showVoiceLayoutToggle} {#if showChatButton}
<Button <Button
data-tip="Toggle Chat" data-tip="Toggle Chat"
class={cx( class={cx(
@@ -206,7 +194,15 @@
onclick={toggleMute}> onclick={toggleMute}>
<span class="relative inline-flex items-center justify-center overflow-visible"> <span class="relative inline-flex items-center justify-center overflow-visible">
<Icon icon={Microphone} size={4} /> <Icon icon={Microphone} size={4} />
{@render mutedSlash($currentVoiceSession.muted)} {#if $currentVoiceSession.muted}
<span
class="pointer-events-none absolute inset-0 flex items-center justify-center overflow-visible"
aria-hidden="true">
<span
class="h-[1.3px] w-[150%] max-w-none shrink-0 -rotate-45 rounded-full bg-current"
></span>
</span>
{/if}
</span> </span>
</Button> </Button>
<Button <Button