Added JAM feature
This commit is contained in:
Generated
+1
-1
@@ -1566,7 +1566,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "furumi_tui"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"blake3",
|
||||
|
||||
+15
-4
@@ -2784,6 +2784,12 @@ fn handle_device_playback_snapshot(
|
||||
runtime: &mut Runtime,
|
||||
snapshot: crate::devices::PlaybackSnapshot,
|
||||
) {
|
||||
// Personal-device reconciliation must never change Jam ownership. Jam
|
||||
// has its own authority and lifecycle even when the same TUI also belongs
|
||||
// to a trusted-device group.
|
||||
if state.device_playback.role == state::DevicePlaybackRole::Jam {
|
||||
return;
|
||||
}
|
||||
if snapshot.device_id == state.device_playback.self_device_id {
|
||||
return;
|
||||
}
|
||||
@@ -2813,7 +2819,7 @@ fn handle_device_playback_snapshot(
|
||||
return;
|
||||
}
|
||||
let lease_expired = active_idle_lease_expired(&snapshot, now);
|
||||
let already_controls_this_device = state.device_playback.is_control()
|
||||
let already_controls_this_device = state.device_playback.is_personal_control()
|
||||
&& state.device_playback.active_device_id.as_deref() == Some(snapshot.device_id.as_str());
|
||||
if !lease_expired || already_controls_this_device {
|
||||
let was_active = state.device_playback.is_audio_owner();
|
||||
@@ -2828,7 +2834,7 @@ fn handle_device_playback_snapshot(
|
||||
return;
|
||||
}
|
||||
|
||||
if state.device_playback.is_control() {
|
||||
if state.device_playback.is_personal_control() {
|
||||
return;
|
||||
}
|
||||
become_active_device(state, runtime, false);
|
||||
@@ -2942,7 +2948,7 @@ fn handle_app_event(state: &mut AppState, runtime: &mut Runtime, event: AppEvent
|
||||
})
|
||||
.unwrap_or(1)
|
||||
.max(1);
|
||||
let active_revoked = state.device_playback.is_control()
|
||||
let active_revoked = state.device_playback.is_personal_control()
|
||||
&& state
|
||||
.device_playback
|
||||
.active_device_id
|
||||
@@ -2960,7 +2966,7 @@ fn handle_app_event(state: &mut AppState, runtime: &mut Runtime, event: AppEvent
|
||||
})
|
||||
.is_some_and(|device| device.revoked)
|
||||
});
|
||||
let active_missing = state.device_playback.is_control()
|
||||
let active_missing = state.device_playback.is_personal_control()
|
||||
&& state
|
||||
.device_playback
|
||||
.active_device_id
|
||||
@@ -3022,6 +3028,11 @@ fn handle_app_event(state: &mut AppState, runtime: &mut Runtime, event: AppEvent
|
||||
AppEvent::DevicePlayback(snapshot) => {
|
||||
handle_device_playback_snapshot(state, runtime, snapshot);
|
||||
}
|
||||
AppEvent::PlaybackCommand(_)
|
||||
if state.device_playback.role == state::DevicePlaybackRole::Jam =>
|
||||
{
|
||||
tracing::debug!("ignored personal-device playback command while Jam is active");
|
||||
}
|
||||
AppEvent::PlaybackCommand(command) => {
|
||||
handle_playback_command(state, runtime, command);
|
||||
}
|
||||
|
||||
@@ -423,6 +423,12 @@ fn handle_connected_devices(
|
||||
});
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
if state.device_playback.role == crate::app::state::DevicePlaybackRole::Jam {
|
||||
state.status_message =
|
||||
Some("leave the current Jam before switching personal devices".into());
|
||||
state.popup = Some(Popup::ConnectedDevices { cursor });
|
||||
return;
|
||||
}
|
||||
if cursor == 0 {
|
||||
super::transfer_active_to_this_device(state, runtime);
|
||||
state.status_message = Some("active playback moved to this device".into());
|
||||
|
||||
@@ -1248,6 +1248,10 @@ impl DevicePlaybackState {
|
||||
|| (self.role == DevicePlaybackRole::Jam && !self.jam_host)
|
||||
}
|
||||
|
||||
pub fn is_personal_control(&self) -> bool {
|
||||
self.role == DevicePlaybackRole::Control
|
||||
}
|
||||
|
||||
pub fn is_audio_owner(&self) -> bool {
|
||||
self.role == DevicePlaybackRole::Active
|
||||
|| (self.role == DevicePlaybackRole::Jam && self.jam_host)
|
||||
|
||||
+1
-1
@@ -555,7 +555,7 @@ fn draw_connected_devices(frame: &mut Frame, state: &AppState, cursor: usize) {
|
||||
);
|
||||
}
|
||||
|
||||
render_subtitle(frame, other_area, state, "Other devices");
|
||||
render_subtitle(frame, other_area, state, "My devices");
|
||||
let list_area = Rect {
|
||||
x: other_area.x,
|
||||
y: other_area.y + 1,
|
||||
|
||||
+12
-19
@@ -38,15 +38,10 @@ pub fn selection() -> Style {
|
||||
}
|
||||
|
||||
pub fn selection_for(state: &AppState) -> Style {
|
||||
if state.device_playback.is_control() {
|
||||
let background = if state.device_playback.role == DevicePlaybackRole::Jam {
|
||||
Color::Rgb(80, 24, 96)
|
||||
} else {
|
||||
Color::Rgb(92, 72, 0)
|
||||
};
|
||||
Style::new().fg(Color::White).bg(background)
|
||||
} else {
|
||||
selection()
|
||||
match state.device_playback.role {
|
||||
DevicePlaybackRole::Jam => Style::new().fg(Color::White).bg(Color::Rgb(80, 24, 96)),
|
||||
DevicePlaybackRole::Control => Style::new().fg(Color::White).bg(Color::Rgb(92, 72, 0)),
|
||||
DevicePlaybackRole::Active => selection(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,10 +50,10 @@ pub fn header_for(state: &AppState) -> Style {
|
||||
}
|
||||
|
||||
pub fn border_for(state: &AppState) -> Style {
|
||||
if state.device_playback.is_control() {
|
||||
Style::new().fg(CONTROL_ACCENT)
|
||||
} else {
|
||||
dim()
|
||||
match state.device_playback.role {
|
||||
DevicePlaybackRole::Jam => Style::new().fg(JAM_ACCENT),
|
||||
DevicePlaybackRole::Control => Style::new().fg(CONTROL_ACCENT),
|
||||
DevicePlaybackRole::Active => dim(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,11 +74,9 @@ pub fn role_pill(role: DevicePlaybackRole) -> Style {
|
||||
}
|
||||
|
||||
fn accent_color_for(state: &AppState) -> Color {
|
||||
if state.device_playback.role == DevicePlaybackRole::Jam {
|
||||
JAM_ACCENT
|
||||
} else if state.device_playback.is_control() {
|
||||
CONTROL_ACCENT
|
||||
} else {
|
||||
ACCENT
|
||||
match state.device_playback.role {
|
||||
DevicePlaybackRole::Jam => JAM_ACCENT,
|
||||
DevicePlaybackRole::Control => CONTROL_ACCENT,
|
||||
DevicePlaybackRole::Active => ACCENT,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user