downloading 93% done

This commit is contained in:
2026-02-16 15:13:31 -06:00
parent 82437cbc4f
commit f466775cc4

View File

@@ -2411,26 +2411,24 @@ fn render_downloads_panel(frame: &mut Frame, app: &App, area: Rect) {
DownloadStatus::Failed(_) => "failed",
};
// Always mark the active (front) item with ▶ like before
let active_prefix = if i == 0 { "" } else { " " };
let prog = if matches!(it.status, DownloadStatus::Downloading) {
format!(" {}B", it.bytes_downloaded)
// If downloading, show "NN% (ETA)" BEFORE the title
let prog_prefix = if matches!(it.status, DownloadStatus::Downloading) {
format_download_pct_eta(it.bytes_downloaded, it.bytes_total, it.added_at)
} else {
String::new()
};
rows.push(ListItem::new(format!(
"{active_prefix}{status}: {}{prog}",
"{active_prefix}{status}: {prog_prefix}{}",
it.title
)));
}
// Optional footer message (only if we still have room)
if let Some(msg) = &st.last_message {
if rows.len() < max_rows {
rows.push(ListItem::new(format!("{msg}")));
}
}
// NOTE: intentionally removed the footer "— {msg}" line
// because you said its unnecessary.
}
}
Err(_) => rows.push(ListItem::new("(downloads lock poisoned)")),
@@ -2451,10 +2449,9 @@ fn render_downloads_panel(frame: &mut Frame, app: &App, area: Rect) {
.highlight_symbol(">> ")
.highlight_style(Style::default().add_modifier(Modifier::REVERSED));
// THIS is the missing piece: selection state for the list
let mut state = ListState::default();
// clamp selection so it never goes out of bounds
// Clamp selection so it never goes out of bounds
let len = app
.downloads
.as_ref()
@@ -2471,6 +2468,39 @@ fn render_downloads_panel(frame: &mut Frame, app: &App, area: Rect) {
frame.render_stateful_widget(list, area, &mut state);
}
// Returns e.g. "56% (4:32) "
// If total is unknown, returns "--% (--:--) "
fn format_download_pct_eta(downloaded: u64, total: Option<u64>, added_at: Instant) -> String {
// Percent
let pct_str = match total {
Some(t) if t > 0 => {
let pct = (downloaded as f64 / t as f64) * 100.0;
format!("{:0.0}%", pct.clamp(0.0, 100.0))
}
_ => "--%".to_string(),
};
// ETA from average speed since added_at (good enough for UI)
let elapsed = added_at.elapsed().as_secs_f64();
let speed = if elapsed > 0.0 {
downloaded as f64 / elapsed
} else {
0.0
};
let eta_str = match (total, speed) {
(Some(t), s) if t > downloaded && s > 1.0 => {
let remaining = (t - downloaded) as f64;
let eta_secs = remaining / s;
fmt_hms(eta_secs)
}
_ => "--:--".to_string(),
};
format!("{pct_str} ({eta_str}) ")
}
fn render_mpv_panel(frame: &mut Frame, app: &App, area: Rect) {
// Make the bar exactly 1 row and don't depend on bordered blocks.
let [c0, c1, c2, c3, c4, c5] = Layout::vertical([