Layout and search fix
🏗️ Build and Test JellyTau / Run Tests (push) Failing after 2m4s
🏗️ Build and Test JellyTau / Android Compile Check (push) Has been skipped
Traceability Validation / Check Requirement Traces (push) Successful in 23s
Build & Release / Run Tests (push) Failing after 2m45s
Build & Release / Build Linux (push) Has been skipped
Build & Release / Build Android (push) Has been skipped
Build & Release / Create Release (push) Has been skipped

This commit is contained in:
2026-07-11 19:55:55 +02:00
parent a2cd9978f0
commit 2a1f1689b4
20 changed files with 991 additions and 995 deletions
+33 -1
View File
@@ -48,12 +48,16 @@ function createPlaybackModeStore() {
async function refreshMode(): Promise<void> {
try {
const rustMode = (await commands.playbackModeGetCurrent()) as RustPlaybackMode;
const remoteSessionId = rustMode.type === "remote" ? rustMode.session_id || null : null;
update((s) => ({
...s,
mode: rustMode.type,
remoteSessionId: rustMode.type === "remote" ? rustMode.session_id || null : null,
remoteSessionId,
}));
// Keep the selected session aligned so the merged UI stores follow the
// authoritative mode.
sessions.selectSession(remoteSessionId);
} catch (error) {
console.error("Failed to get playback mode:", error);
}
@@ -135,6 +139,10 @@ function createPlaybackModeStore() {
throw error;
} finally {
currentTransferAbort = null;
// Snap back to whatever the Rust manager actually settled on. If any step
// above threw mid-transfer, the optimistic update may not match reality;
// Rust is authoritative, so reconcile to it.
await refreshMode();
}
}
@@ -263,6 +271,9 @@ function createPlaybackModeStore() {
console.warn("[PlaybackMode] Failed to clear transferring flag:", e);
}
currentTransferAbort = null;
// Reconcile to the authoritative Rust mode in case a step above threw and
// left our optimistic state inconsistent (see transferToRemote).
await refreshMode();
}
}
@@ -288,6 +299,27 @@ function createPlaybackModeStore() {
console.error("[PlaybackMode] Lockscreen-triggered transfer failed:", e),
);
}
return;
}
// The Rust PlaybackModeManager is the single source of truth for routing.
// Reconcile our mirror store to it whenever it changes, so the UI and the
// event filter in playerEvents.ts can't drift and start routing controls to
// the wrong device. We deliberately do NOT reconcile while a transfer is in
// flight: transfers emit intermediate mode changes (and briefly hold the
// transferring flag), and the transfer functions own the final state.
if (event.payload.type === "playback_mode_changed") {
const currentState = get({ subscribe });
if (currentState.isTransferring) {
return;
}
const mode = event.payload.mode as PlaybackMode;
const remoteSessionId =
mode === "remote" ? event.payload.session_id ?? null : null;
console.log("[PlaybackMode] Backend mode changed →", mode, remoteSessionId);
update((s) => ({ ...s, mode, remoteSessionId }));
// Keep the selected session in step so the merged UI stores follow.
sessions.selectSession(remoteSessionId);
}
});