fix(qconnect): badge clear, multi-track enqueue, shuffle WS-authoritative, cursor/history/pause
- badge: gate is-remote on transport_connected so it clears on every session-end path (transport drop / watchdog / reconnect-exhausted), not only toggle-off - multi-track: route a whole album/playlist/favorites enqueue to the peer in one QueueAddTracks/QueueInsertTracks (all-or-nothing admission), not single-track only - shuffle inbound: SetShuffleMode renderer arm is flag-only (set_shuffle_flag) so the renderer never invents a local order; the cloud's echoed order is authoritative - shuffle outbound: send shuffle_seed + shuffle_pivot_queue_item_id (the cloud needs the seed to build the order); hoist resolve_qconnect_shuffle_pivot to qconnect-app - start index: resolve_remote_start_index validates the track_id before trusting a qid, so a freshly-pushed album no longer inherits a stale cursor (wrong NowPlayingBar track) - history: play_index records history only when actually moving, so the current track is no longer duplicated in the History tab - pause-to-peer: resolve current_queue_item from the core-aligned cursor instead of the stale renderer snapshot, so pausing an iOS renderer (reports null qid) is accepted cc
This commit is contained in:
10 files changed
+499
-49
No files matched your search
@@ -1,6 +1,7 @@
|
||||
use tauri::State;
|
||||
|
||||
use qbz_models::{QueueState, QueueTrack as CoreQueueTrack, RepeatMode};
|
||||
use qconnect_app::queue_resolution::resolve_qconnect_shuffle_pivot;
|
||||
use qconnect_app::QueueCommandType;
|
||||
use qconnect_app::{QConnectQueueState, QConnectRendererState};
|
||||
|
||||
@@ -273,43 +274,15 @@ fn qconnect_loop_mode_from_repeat_mode(mode: RepeatMode) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_qconnect_shuffle_pivot(
|
||||
queue: &QConnectQueueState,
|
||||
renderer: &QConnectRendererState,
|
||||
) -> Option<u64> {
|
||||
let Some(current_track) = renderer.current_track.as_ref() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if queue
|
||||
.queue_items
|
||||
.iter()
|
||||
.position(|item| item.queue_item_id == current_track.queue_item_id)
|
||||
.is_some()
|
||||
{
|
||||
return Some(current_track.queue_item_id);
|
||||
}
|
||||
|
||||
if let Some((_, item)) = queue
|
||||
.queue_items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, item)| item.track_id == current_track.track_id)
|
||||
{
|
||||
return Some(item.queue_item_id);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
build_qconnect_remove_upcoming_payload, build_qconnect_reorder_payload,
|
||||
qconnect_loop_mode_from_repeat_mode, resolve_qconnect_shuffle_pivot,
|
||||
qconnect_loop_mode_from_repeat_mode,
|
||||
};
|
||||
use crate::qconnect::QconnectVisibleQueueProjection;
|
||||
use qbz_models::RepeatMode;
|
||||
use qconnect_app::queue_resolution::resolve_qconnect_shuffle_pivot;
|
||||
use qconnect_app::{QConnectQueueState, QConnectRendererState};
|
||||
use qconnect_core::QueueItem;
|
||||
use serde_json::json;
|
||||
|
||||
@@ -310,6 +310,9 @@ impl QconnectRendererEngine for CoreBridge {
|
||||
async fn set_shuffle(&self, enabled: bool) {
|
||||
CoreBridge::set_shuffle(self, enabled).await
|
||||
}
|
||||
async fn set_shuffle_flag(&self, enabled: bool) {
|
||||
CoreBridge::set_shuffle_with_order(self, enabled, None).await
|
||||
}
|
||||
async fn get_all_queue_tracks(&self) -> (Vec<QueueTrack>, Option<usize>) {
|
||||
CoreBridge::get_all_queue_tracks(self).await
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user