Clamp the progress gauge ratio
The player position can overrun a stale or wrong duration (streams, hand-written track files), and ratatui's LineGauge asserts its ratio into 0..=1 — the TUI died with "ratio should be between 0 and 1" mid-playback. Clamp instead, with render regression tests for both the overrun and the zero-duration case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
955c7ea5b4
commit
8bb653ab3e
|
|
@ -142,10 +142,16 @@ impl NowPlaying {
|
||||||
.constraints([Constraint::Min(10), Constraint::Max(completion_size)])
|
.constraints([Constraint::Min(10), Constraint::Max(completion_size)])
|
||||||
.split(now_playing_layout[1]);
|
.split(now_playing_layout[1]);
|
||||||
|
|
||||||
|
// Clamped: the player's position can overrun a stale or wrong
|
||||||
|
// duration (streams, hand-written track files), and
|
||||||
|
// `LineGauge` panics on ratios outside 0..=1.
|
||||||
let ratio = if duration.is_zero() {
|
let ratio = if duration.is_zero() {
|
||||||
0.0
|
0.0
|
||||||
} else {
|
} else {
|
||||||
position.as_secs_f64().div(duration.as_secs_f64())
|
position
|
||||||
|
.as_secs_f64()
|
||||||
|
.div(duration.as_secs_f64())
|
||||||
|
.clamp(0.0, 1.0)
|
||||||
};
|
};
|
||||||
|
|
||||||
let progress = LineGauge::default()
|
let progress = LineGauge::default()
|
||||||
|
|
@ -180,3 +186,48 @@ impl NowPlaying {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use ratatui::{backend::TestBackend, Terminal};
|
||||||
|
|
||||||
|
/// A now-playing pane mid-track, built directly (no `update_track`,
|
||||||
|
/// which fires a desktop notification).
|
||||||
|
fn now_playing(position_ms: u32, duration_ms: u32) -> NowPlaying {
|
||||||
|
NowPlaying {
|
||||||
|
play_state: PlayState::Playing,
|
||||||
|
duration: Some(Duration::from_millis(duration_ms.into())),
|
||||||
|
modifiers: QueueModifiers::default(),
|
||||||
|
position: Some(Duration::from_millis(position_ms.into())),
|
||||||
|
track: Some(Track {
|
||||||
|
path: "/fs/radio.cbd-track.toml".to_string(),
|
||||||
|
artist: "artist".to_string(),
|
||||||
|
title: "title".to_string(),
|
||||||
|
duration: None,
|
||||||
|
album: None,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(pane: &NowPlaying) {
|
||||||
|
let backend = TestBackend::new(60, 12);
|
||||||
|
let mut terminal = Terminal::new(backend).expect("test terminal");
|
||||||
|
terminal
|
||||||
|
.draw(|f| pane.render(f, f.area()))
|
||||||
|
.expect("draw must not panic");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The position can overrun a stale or wrong duration (streams,
|
||||||
|
/// hand-written track files); the gauge must clamp instead of hitting
|
||||||
|
/// ratatui's `ratio should be between 0 and 1` panic.
|
||||||
|
#[test]
|
||||||
|
fn progress_gauge_survives_position_past_duration() {
|
||||||
|
render(&now_playing(90_000, 60_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn progress_gauge_survives_a_zero_duration() {
|
||||||
|
render(&now_playing(5_000, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue