From e75b045470a22ea9d355657d523d767820ea0d73 Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Sat, 11 Apr 2026 18:41:26 +0400 Subject: [PATCH] fix(ui): auto-dismiss call screen when peer hangs up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously: peer hangs up → Rust emits signal-event {type:hangup} → JS clears callStatusText + hides incoming panel, but the call screen stays on with a dangling Hangup button the user has to press to acknowledge a call that's already over. Dead UX. Now: the hangup event handler tears down our side of the media engine via `invoke("disconnect")` and transitions back to the connect screen when we're currently in the call screen. Incoming-call panel still hides as before. `userDisconnected = true` is set so the existing call-event "disconnected" auto-reconnect path (which fires on transport drop) doesn't kick in — the peer-hangup signal is an intentional end-of-call, not a transport blip worth retrying. Also documented: "not connected" errors from the `disconnect` command are silently swallowed because they happen when there's no engine to tear down (e.g. incoming call that was never answered — caller bailed), which is the correct outcome there. Co-Authored-By: Claude Opus 4.6 (1M context) --- desktop/src/main.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/desktop/src/main.ts b/desktop/src/main.ts index 87c43a2..3de5e8f 100644 --- a/desktop/src/main.ts +++ b/desktop/src/main.ts @@ -1261,8 +1261,34 @@ listen("signal-event", (event: any) => { })(); break; case "hangup": + // Peer (or the relay) ended the call. Tear down OUR side + // of the media engine and return to the connect screen + // automatically — the user shouldn't have to hit End Call + // on a call that's already over. + // + // Scenarios this handles: + // * active direct call, peer hung up → disconnect + back + // to connect screen + // * incoming call was ringing but caller bailed → hide + // incoming panel (no engine to disconnect) + // * setup failure mid-handshake → same as above callStatusText.textContent = ""; incomingCallPanel.classList.add("hidden"); + (async () => { + try { + // disconnect errors out with "not connected" if there's + // no active engine — safe to ignore, we just want to + // make sure any engine IS torn down. + await invoke("disconnect"); + } catch {} + // Suppress the call-event "disconnected" auto-reconnect + // path since this was a peer-initiated hangup, not a + // transport drop. + userDisconnected = true; + if (!callScreen.classList.contains("hidden")) { + showConnectScreen(); + } + })(); break; case "reconnecting": // Signal supervisor is retrying the relay connection. Show