Connected Devices: added remote control

This commit is contained in:
Ultradesu
2026-07-24 04:49:48 +03:00
parent 389eacd388
commit b14781f5a4
4 changed files with 203 additions and 87 deletions
+25
View File
@@ -409,6 +409,31 @@ pub(crate) fn become_active_device(state: &mut AppState, runtime: &mut Runtime,
publish_playback_snapshot(state, runtime);
}
pub(crate) fn transfer_active_to_this_device(state: &mut AppState, runtime: &mut Runtime) {
if state.device_playback.role == state::DevicePlaybackRole::Active {
publish_playback_snapshot(state, runtime);
request_urgent_device_sync(runtime);
return;
}
let should_start = state.player.current.is_some() || !state.player.queue.is_empty();
if state.player.current.is_none() && !state.player.queue.is_empty() {
state.player.current = state.player.queue.get(state.player.queue_pos).cloned();
state.player.position_secs = 0.0;
}
if state.player.current.is_some() {
state.player.playing = true;
state.player.paused = false;
}
become_active_device(state, runtime, false);
if should_start && state.player.current.is_some() {
start_current_audio(state, runtime, state.player.position_secs, false);
push_media_metadata(state, runtime);
push_media_update(state, runtime, true);
}
publish_playback_snapshot(state, runtime);
request_urgent_device_sync(runtime);
}
fn record_control_playback_state(state: &mut AppState, runtime: &Runtime) {
if !state.device_playback.is_control() {
return;
+8 -13
View File
@@ -23,7 +23,6 @@ pub(crate) struct ConnectedDevicePopupRow {
pub name: String,
pub is_self: bool,
pub online: bool,
pub revoked: bool,
pub section: DevicePresenceSection,
pub active: bool,
pub playing: bool,
@@ -49,7 +48,6 @@ pub(crate) fn connected_device_rows(state: &AppState) -> Vec<ConnectedDevicePopu
name: state::device_display_name(device),
is_self,
online,
revoked: device.revoked,
section,
active: state::device_status_active(state, &device.device_id),
playing: if is_self {
@@ -83,7 +81,6 @@ pub(crate) fn connected_device_rows(state: &AppState) -> Vec<ConnectedDevicePopu
name: state.device_playback.self_device_name.clone(),
is_self: true,
online: true,
revoked: false,
section: DevicePresenceSection::Online,
active: state.device_playback.role == crate::app::state::DevicePlaybackRole::Active,
playing: state.player.playing,
@@ -173,7 +170,9 @@ fn handle_connected_devices(
key: KeyEvent,
) {
let rows = connected_device_rows(state);
let last = rows.len().saturating_sub(1);
let other_rows: Vec<_> = rows.iter().filter(|row| !row.is_self).cloned().collect();
let last = other_rows.len();
let cursor = cursor.min(last);
match key.code {
KeyCode::Esc | KeyCode::Char('q') => {}
KeyCode::Up | KeyCode::Char('k') => {
@@ -187,15 +186,11 @@ fn handle_connected_devices(
});
}
KeyCode::Enter => {
if let Some(row) = rows.get(cursor.min(last)) {
if row.revoked {
state.status_message = Some("revoked device cannot be controlled".into());
} else if row.is_self {
super::become_active_device(state, runtime, true);
state.status_message = Some("active playback moved to this device".into());
} else if let Some(snapshot) =
state.device_playback.remote.get(&row.device_id).cloned()
{
if cursor == 0 {
super::transfer_active_to_this_device(state, runtime);
state.status_message = Some("active playback moved to this device".into());
} else if let Some(row) = other_rows.get(cursor.saturating_sub(1).min(last)) {
if let Some(snapshot) = state.device_playback.remote.get(&row.device_id).cloned() {
super::become_control_device(state, runtime, snapshot);
} else {
state.status_message = Some("device has no playback snapshot yet".into());
+5 -2
View File
@@ -1204,7 +1204,7 @@ fn queue_add(state: &mut AppState, next: bool) -> Option<Effect> {
} else {
format!("queued: {count} tracks")
});
return None;
return Some(Effect::PlaybackQueueChanged);
}
if let Some(id) = selected_release_id(state) {
return Some(Effect::EnqueueRelease { id, next });
@@ -3119,7 +3119,10 @@ mod tests {
update(&mut state, Action::ToggleTrackSelection);
update(&mut state, Action::MoveDown);
assert_eq!(update(&mut state, Action::QueueAddLast), None,);
assert_eq!(
update(&mut state, Action::QueueAddLast),
Some(Effect::PlaybackQueueChanged),
);
let queued: Vec<i64> = state.player.queue.iter().map(|track| track.id).collect();
assert_eq!(queued, vec![1, 2]);
assert!(!state.track_selection.is_active());