Cleanup remaining files
This commit is contained in:
@@ -47,7 +47,6 @@ export const isParticipantSpeaking = derived(
|
||||
$participants.some(sp => participantKey(sp) === participantKey(p)),
|
||||
)
|
||||
|
||||
/** True when the local user is in LiveKit’s active-speakers list (currently talking). */
|
||||
export const isLocalSpeaking = derived(
|
||||
[currentVoiceSession, speakingParticipants],
|
||||
([$session, $speaking]) => {
|
||||
|
||||
+12
-18
@@ -71,17 +71,14 @@ export const toggleCamera = async () => {
|
||||
if (!session) return
|
||||
|
||||
const cameraOn = !session.cameraOn
|
||||
if (!cameraOn) {
|
||||
session.room.localParticipant.setCameraEnabled(false)
|
||||
currentVoiceSession.set({...session, cameraOn})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await session.room.localParticipant.setCameraEnabled(true)
|
||||
await session.room.localParticipant.setCameraEnabled(cameraOn)
|
||||
currentVoiceSession.set({...session, cameraOn})
|
||||
} catch (e) {
|
||||
pushToast({theme: "error", message: "Could not access camera"})
|
||||
} catch {
|
||||
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
|
||||
|
||||
const screenShareOn = !session.screenShareOn
|
||||
if (!screenShareOn) {
|
||||
session.room.localParticipant.setScreenShareEnabled(false)
|
||||
currentVoiceSession.set({...session, screenShareOn})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await session.room.localParticipant.setScreenShareEnabled(true)
|
||||
await session.room.localParticipant.setScreenShareEnabled(screenShareOn)
|
||||
currentVoiceSession.set({...session, screenShareOn})
|
||||
} catch (e) {
|
||||
pushToast({theme: "error", message: "Could not start screen sharing"})
|
||||
} catch {
|
||||
pushToast({
|
||||
theme: "error",
|
||||
message: screenShareOn ? "Could not start screen sharing" : "Could not stop screen sharing",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ export const leaveVoiceRoom = async () => {
|
||||
try {
|
||||
await session.room.localParticipant.setCameraEnabled(false)
|
||||
} catch {
|
||||
/* pass */
|
||||
pushToast({theme: "error", message: "Error turning off camera."})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ export const leaveVoiceRoom = async () => {
|
||||
try {
|
||||
await session.room.localParticipant.setScreenShareEnabled(false)
|
||||
} catch {
|
||||
/* pass */
|
||||
pushToast({theme: "error", message: "Error turning off screen sharing."})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Icon from "@lib/components/Icon.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 {get} from "svelte/store"
|
||||
import {
|
||||
@@ -28,11 +28,11 @@
|
||||
class?: string
|
||||
}
|
||||
|
||||
type VideoTile = {
|
||||
type VideoTileData = {
|
||||
identity: string
|
||||
isLocal: boolean
|
||||
trackSid: string
|
||||
attachable: Track | undefined
|
||||
track: Track | undefined
|
||||
source: Track.Source.Camera | Track.Source.ScreenShare
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
}
|
||||
|
||||
const room = session.room
|
||||
const videoTiles: VideoTile[] = []
|
||||
const videoTiles: VideoTileData[] = []
|
||||
const user = room.localParticipant
|
||||
|
||||
if (session.cameraOn) {
|
||||
@@ -84,7 +84,7 @@
|
||||
identity: user.identity,
|
||||
isLocal: true,
|
||||
trackSid: localPub?.trackSid ?? "local-camera",
|
||||
attachable: localPub?.track,
|
||||
track: localPub?.track,
|
||||
source: Track.Source.Camera,
|
||||
})
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
identity: user.identity,
|
||||
isLocal: true,
|
||||
trackSid: localPub?.trackSid ?? "local-screen",
|
||||
attachable: localPub?.track,
|
||||
track: localPub?.track,
|
||||
source: Track.Source.ScreenShare,
|
||||
})
|
||||
}
|
||||
@@ -107,7 +107,7 @@
|
||||
identity: rp.identity,
|
||||
isLocal: false,
|
||||
trackSid: camPub.trackSid,
|
||||
attachable: camPub.track,
|
||||
track: camPub.track,
|
||||
source: Track.Source.Camera,
|
||||
})
|
||||
}
|
||||
@@ -117,7 +117,7 @@
|
||||
identity: rp.identity,
|
||||
isLocal: false,
|
||||
trackSid: screenPub.trackSid,
|
||||
attachable: screenPub.track,
|
||||
track: screenPub.track,
|
||||
source: Track.Source.ScreenShare,
|
||||
})
|
||||
}
|
||||
@@ -127,7 +127,7 @@
|
||||
})
|
||||
|
||||
/** 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 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 name = pk ? displayProfileByPubkey(pk) : "Unknown"
|
||||
return source === Track.Source.ScreenShare ? `${name} · screen` : name
|
||||
@@ -183,7 +183,7 @@
|
||||
)
|
||||
</script>
|
||||
|
||||
{#snippet videoTile(tile: VideoTile, layout: TileLayout)}
|
||||
{#snippet videoTile(tile: VideoTileData, layout: TileLayout)}
|
||||
<div
|
||||
class={cx(
|
||||
"relative isolate overflow-hidden rounded-box shadow-sm",
|
||||
@@ -192,9 +192,9 @@
|
||||
layout === "strip" && "aspect-video w-44 shrink-0",
|
||||
tile.source === Track.Source.ScreenShare ? "bg-black" : "bg-base-100",
|
||||
)}>
|
||||
{#if tile.attachable}
|
||||
<VideoCallVideo
|
||||
track={tile.attachable}
|
||||
{#if tile.track}
|
||||
<VideoCallTile
|
||||
track={tile.track}
|
||||
muted={tile.isLocal}
|
||||
fit={tile.source === Track.Source.ScreenShare ? "contain" : "cover"}
|
||||
class="pointer-events-none absolute inset-0" />
|
||||
|
||||
@@ -11,21 +11,21 @@
|
||||
|
||||
const {track, muted = true, fit = "cover", class: className = ""}: Props = $props()
|
||||
|
||||
let el = $state<HTMLVideoElement | undefined>()
|
||||
let videoElement = $state<HTMLVideoElement | undefined>()
|
||||
|
||||
$effect(() => {
|
||||
const v = el
|
||||
const t = track
|
||||
if (!v) return
|
||||
t.attach(v)
|
||||
const element = videoElement
|
||||
const activeTrack = track
|
||||
if (!element) return
|
||||
activeTrack.attach(element)
|
||||
return () => {
|
||||
t.detach(v)
|
||||
activeTrack.detach(element)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<video
|
||||
bind:this={el}
|
||||
bind:this={videoElement}
|
||||
class={cx("h-full w-full", fit === "contain" ? "object-contain" : "object-cover", className)}
|
||||
playsinline
|
||||
{muted}></video>
|
||||
@@ -41,16 +41,9 @@
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
void loadDevices()
|
||||
const md = navigator.mediaDevices
|
||||
if (!md?.addEventListener) return
|
||||
const onDeviceChange = () => {
|
||||
void loadDevices()
|
||||
}
|
||||
md.addEventListener("devicechange", onDeviceChange)
|
||||
return () => {
|
||||
md.removeEventListener("devicechange", onDeviceChange)
|
||||
}
|
||||
loadDevices()
|
||||
navigator.mediaDevices?.addEventListener?.("devicechange", loadDevices)
|
||||
return () => navigator.mediaDevices?.removeEventListener?.("devicechange", loadDevices)
|
||||
})
|
||||
|
||||
$effect(() => {
|
||||
|
||||
@@ -53,6 +53,14 @@
|
||||
)
|
||||
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 => {
|
||||
if ($voiceState === VoiceState.Joining || $voiceState === VoiceState.Connected) {
|
||||
return $currentVoiceRoom
|
||||
@@ -90,26 +98,17 @@
|
||||
pushModal(VoiceCallAudioSettingsDialog)
|
||||
}
|
||||
|
||||
const showVoiceLayoutToggle = $derived(
|
||||
$voiceState === VoiceState.Connected &&
|
||||
targetRoom !== undefined &&
|
||||
getRoomType(targetRoom) === RoomType.Voice &&
|
||||
typeof h === "string" &&
|
||||
relay !== undefined &&
|
||||
decodeRelay(relay) === targetRoom.url &&
|
||||
h === targetRoom.h,
|
||||
)
|
||||
const showChatButton = $derived($voiceState === VoiceState.Connected && isViewingCurrentVoiceRoom)
|
||||
|
||||
const isChatPanelActive = $derived(
|
||||
showVoiceLayoutToggle &&
|
||||
((!isDesktopLayout.current &&
|
||||
($videoCallLayout === VideoCallLayout.Chat ||
|
||||
$videoCallLayout === VideoCallLayout.Split)) ||
|
||||
(isDesktopLayout.current && $videoCallLayout === VideoCallLayout.Split)),
|
||||
showChatButton &&
|
||||
(isDesktopLayout.current
|
||||
? $videoCallLayout === VideoCallLayout.Split
|
||||
: $videoCallLayout === VideoCallLayout.Chat),
|
||||
)
|
||||
|
||||
const onChatToggle = () => {
|
||||
if (!showVoiceLayoutToggle) return
|
||||
if (!showChatButton) return
|
||||
if (isDesktopLayout.current) {
|
||||
videoCallLayout.update(p =>
|
||||
p === VideoCallLayout.Split ? VideoCallLayout.Video : VideoCallLayout.Split,
|
||||
@@ -128,17 +127,6 @@
|
||||
const mediaToggleClass = "center tooltip tooltip-top btn btn-sm btn-square btn-ghost"
|
||||
</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}
|
||||
<div
|
||||
in:fly={{y: 60, duration: 350}}
|
||||
@@ -163,7 +151,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
{#if showVoiceLayoutToggle}
|
||||
{#if showChatButton}
|
||||
<Button
|
||||
data-tip="Toggle Chat"
|
||||
class={cx(
|
||||
@@ -206,7 +194,15 @@
|
||||
onclick={toggleMute}>
|
||||
<span class="relative inline-flex items-center justify-center overflow-visible">
|
||||
<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>
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user