Shuffle and Repeat now go to the CLOUD whenever connected (renderer OR controller),
gating on transport_connected like Tauri's v2_toggle_shuffle / v2_set_repeat_mode,
instead of the old peer-active gate that fell through to a LOCAL reshuffle when QBZ
was the active renderer — that did nothing visible AND risked a divergent local
order. QBZ sends only the seed + pivot; the cloud owns the order; the toggle reads
the cloud-authoritative queue.shuffle_mode. The local shuffle path is now reachable
only when NOT connected.
- shuffle/repeat button reflects the cloud queue flag (queue.shuffle_mode for the
controller branch, core queue state via refresh_transport_modes for the renderer
branch), not the per-renderer field the cloud never populates for a peer — fixes
the iOS-reflects / WebPlayer-doesn't asymmetry.
- pause/play to a peer renderer: send a BARE SetPlayerState (playing_state only).
iOS reports current_queue_item_id=null while playing, so resolving the qid landed
on queue_item_id 0 — the protocol's "unknown" placeholder — and iOS could not
anchor the pause, auto-resuming. A bare transport toggle is spec-sanctioned: the
renderer pauses/resumes its own current item in place.
- skip_serializing_if on the SetPlayerState request structs so a None field is
OMITTED, not serialized as null; and the mapper now treats a null current_queue_item
as absent. Without this the bare command failed to encode and was never sent.
- log the outbound SetPlayerState payload for controller diagnostics.
cc