fix(cast): update play button status and add disconnect handoff
1. Play button fix: After resuming on cast device, update playerStore.isPlaying so the UI shows the correct playing state immediately. 2. Disconnect handoff: When disconnecting from Chromecast/DLNA while playing: - Captures current track and position from cast state - Shows confirm dialog asking if user wants to continue locally - If yes, starts local playback and seeks to saved position - If no, just resets player state This provides seamless transitions in both directions: - Local → Cast: auto-resumes with position - Cast → Local: asks user, then resumes with position
This commit is contained in:
1 parent
d52ebeac20
commit
685efcfd76
2 files changed
+87
-2
No files matched your search
@@ -60,6 +60,10 @@ let onCastTrackEnded: (() => Promise<void>) | null = null;
|
||||
// Callback for when cast disconnects (to reset player state)
|
||||
let onCastDisconnected: (() => void) | null = null;
|
||||
|
||||
// Callback for asking user if they want to continue locally after disconnect
|
||||
// Returns true if user wants to continue, false otherwise
|
||||
let onAskContinueLocally: ((track: PlayingTrack, position: number) => Promise<boolean>) | null = null;
|
||||
|
||||
// Track end detection state
|
||||
let lastTransportState: string = '';
|
||||
let trackEndDetected = false;
|
||||
@@ -175,6 +179,9 @@ export async function connectToDevice(device: CastDevice, protocol: CastProtocol
|
||||
durationSecs: currentTrack.duration
|
||||
});
|
||||
|
||||
// Update playerStore to reflect playing state (fixes play button UI)
|
||||
setIsPlaying(true);
|
||||
|
||||
// Try to seek to the saved position (if significant)
|
||||
if (currentPosition > 5) {
|
||||
console.log('[CastStore] Seeking to saved position:', currentPosition);
|
||||
@@ -200,16 +207,30 @@ export async function connectToDevice(device: CastDevice, protocol: CastProtocol
|
||||
|
||||
/**
|
||||
* Disconnect from current device
|
||||
*
|
||||
* If a track was playing, asks user if they want to continue locally.
|
||||
*/
|
||||
export async function disconnect(): Promise<void> {
|
||||
if (!state.isConnected || !state.protocol) return;
|
||||
|
||||
// Capture current state BEFORE disconnecting
|
||||
const wasPlaying = state.isPlaying;
|
||||
const currentTrack = getCurrentTrack();
|
||||
const currentPosition = state.positionSecs;
|
||||
const savedProtocol = state.protocol;
|
||||
|
||||
console.log('[CastStore] Disconnecting, current state:', {
|
||||
wasPlaying,
|
||||
trackId: currentTrack?.id,
|
||||
position: currentPosition
|
||||
});
|
||||
|
||||
// Stop position polling first
|
||||
stopPositionPolling();
|
||||
|
||||
try {
|
||||
await castStop();
|
||||
switch (state.protocol) {
|
||||
switch (savedProtocol) {
|
||||
case 'chromecast':
|
||||
await invoke('cast_disconnect');
|
||||
break;
|
||||
@@ -235,11 +256,35 @@ export async function disconnect(): Promise<void> {
|
||||
};
|
||||
notifyListeners();
|
||||
|
||||
// If there was a track playing, ask user if they want to continue locally
|
||||
if (wasPlaying && currentTrack && !currentTrack.isLocal && onAskContinueLocally) {
|
||||
console.log('[CastStore] Asking user if they want to continue locally...');
|
||||
try {
|
||||
const continueLocally = await onAskContinueLocally(currentTrack, currentPosition);
|
||||
if (continueLocally) {
|
||||
console.log('[CastStore] User wants to continue locally, starting playback...');
|
||||
// Start local playback - the callback handler will do this
|
||||
// since it has access to playbackService
|
||||
} else {
|
||||
console.log('[CastStore] User declined to continue locally');
|
||||
// Just notify that cast disconnected
|
||||
if (onCastDisconnected) {
|
||||
onCastDisconnected();
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[CastStore] Failed to handle continue locally:', err);
|
||||
if (onCastDisconnected) {
|
||||
onCastDisconnected();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Notify player to reset its state
|
||||
if (onCastDisconnected) {
|
||||
onCastDisconnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set callback for when cast disconnects
|
||||
@@ -248,6 +293,14 @@ export function setOnCastDisconnected(callback: () => void): void {
|
||||
onCastDisconnected = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set callback for asking user if they want to continue locally after disconnect
|
||||
* The callback receives the track and position, and should return true if user wants to continue
|
||||
*/
|
||||
export function setOnAskContinueLocally(callback: (track: PlayingTrack, position: number) => Promise<boolean>): void {
|
||||
onAskContinueLocally = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a track to the connected device
|
||||
*/
|
||||
|
||||
+33
-1
@@ -262,7 +262,8 @@
|
||||
import {
|
||||
subscribe as subscribeCast,
|
||||
getCastState,
|
||||
isCasting
|
||||
isCasting,
|
||||
setOnAskContinueLocally
|
||||
} from '$lib/stores/castStore';
|
||||
|
||||
// Components
|
||||
@@ -2255,6 +2256,37 @@
|
||||
// Ignore storage errors
|
||||
}
|
||||
|
||||
// Set up callback for cast disconnect handoff
|
||||
setOnAskContinueLocally(async (track, position) => {
|
||||
// Ask user if they want to continue locally
|
||||
const continueLocally = window.confirm(
|
||||
`Continue playing "${track.title}" on this device?`
|
||||
);
|
||||
|
||||
if (continueLocally) {
|
||||
try {
|
||||
// Start local playback
|
||||
await playTrack(track, { showLoadingToast: false });
|
||||
|
||||
// Seek to saved position after a short delay
|
||||
if (position > 5) {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await playerSeek(position);
|
||||
console.log('[CastHandoff] Seeked to position:', position);
|
||||
} catch (seekErr) {
|
||||
console.log('[CastHandoff] Could not restore position:', seekErr);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[CastHandoff] Failed to resume local playback:', err);
|
||||
}
|
||||
}
|
||||
|
||||
return continueLocally;
|
||||
});
|
||||
|
||||
// Note: loadFavorites() is called in handleLoginSuccess after login is confirmed
|
||||
// This prevents API calls before authentication is complete
|
||||
|
||||
|
||||
Reference in new issue
Block a user