feat(ui): add Join Video button — joins call and auto-starts camera
Blue FAB alongside Join Voice; click handler connects then calls startCamera() so video is active from the moment the call starts. Cam button inside drawer still toggles camera after joining either way. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,12 +43,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Voice join FAB -->
|
||||
<!-- Voice / Video join FABs -->
|
||||
<div class="lobby-fab-row">
|
||||
<button id="join-voice-btn" class="fab" title="Join Voice Chat">
|
||||
<span class="fab-icon">🎧</span>
|
||||
<span class="fab-label">Join Voice</span>
|
||||
</button>
|
||||
<button id="join-video-btn" class="fab fab-video" title="Join with Video">
|
||||
<span class="fab-icon">📹</span>
|
||||
<span class="fab-label">Join Video</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Incoming call banner -->
|
||||
|
||||
@@ -62,6 +62,7 @@ const lobbyFp = document.getElementById("lobby-fp")!;
|
||||
const lobbyUserList = document.getElementById("lobby-user-list")!;
|
||||
const lobbyUserCount = document.getElementById("lobby-user-count")!;
|
||||
const joinVoiceBtn = document.getElementById("join-voice-btn")!;
|
||||
const joinVideoBtn = document.getElementById("join-video-btn")!;
|
||||
const incomingBanner = document.getElementById("incoming-call-banner")!;
|
||||
const incomingCallerName = document.getElementById("incoming-caller-name")!;
|
||||
const incomingIdenticon = document.getElementById("incoming-identicon")!;
|
||||
@@ -396,10 +397,40 @@ joinVoiceBtn.addEventListener("click", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
joinVideoBtn.addEventListener("click", async () => {
|
||||
if (inVoice || connectPending) return;
|
||||
const relay = getRelay();
|
||||
const s = loadSettings();
|
||||
if (!relay) { showToast("No relay configured"); return; }
|
||||
connectPending = true;
|
||||
const origText = joinVideoBtn.textContent;
|
||||
joinVideoBtn.textContent = "Connecting…";
|
||||
(joinVideoBtn as HTMLButtonElement).disabled = true;
|
||||
try {
|
||||
await connectWithTimeout({
|
||||
relay: relay.address,
|
||||
room: s.room || "general",
|
||||
alias: s.alias || "",
|
||||
osAec: s.osAec,
|
||||
quality: s.quality || "auto",
|
||||
});
|
||||
enterVoice(false);
|
||||
startCamera();
|
||||
} catch (e: any) {
|
||||
console.error("connect failed:", e);
|
||||
showToast(`Join failed: ${errorMessage(e)}`);
|
||||
} finally {
|
||||
connectPending = false;
|
||||
joinVideoBtn.textContent = origText;
|
||||
(joinVideoBtn as HTMLButtonElement).disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
function enterVoice(isDirect: boolean) {
|
||||
inVoice = true;
|
||||
const s = loadSettings();
|
||||
joinVoiceBtn.classList.add("hidden");
|
||||
joinVideoBtn.classList.add("hidden");
|
||||
voiceDrawer.classList.remove("hidden");
|
||||
vdRoom.textContent = isDirect && directCallPeer
|
||||
? (directCallPeer.alias || directCallPeer.fingerprint.substring(0, 16))
|
||||
@@ -429,6 +460,7 @@ function leaveVoice() {
|
||||
pendingCallId = null;
|
||||
voiceDrawer.classList.add("hidden");
|
||||
joinVoiceBtn.classList.remove("hidden");
|
||||
joinVideoBtn.classList.remove("hidden");
|
||||
vdLevelBar.style.width = "0%";
|
||||
if (statusInterval) { clearInterval(statusInterval); statusInterval = null; }
|
||||
stopCamera();
|
||||
|
||||
@@ -204,6 +204,16 @@ body {
|
||||
padding: 12px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.fab-video {
|
||||
background: #3b82f6;
|
||||
box-shadow: 0 4px 16px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.fab-video:hover {
|
||||
box-shadow: 0 6px 20px rgba(59, 130, 246, 0.4);
|
||||
}
|
||||
|
||||
.fab {
|
||||
|
||||
Reference in New Issue
Block a user