feat: add download info pane to TUI

Splits the downloads area 60/40 with a new info pane that adapts to the
selected download's status: header (filename, user, size, status, save
path, bitrate, length) plus queued-specific fields (queue position, peer
slots, peer upload speed) or live progress/speed/ETA when transferring.

Plumbs queue position via a new ClientOperation::PlaceInQueueUpdate so
PlaceInQueueResponse messages from peers reach DownloadStore, and threads
search-time metadata (bitrate, length, peer slots/speed) onto Download
through a new download_with_metadata entry point.
This commit is contained in:
michel
2026-04-26 17:19:26 +02:00
parent fa962a0dea
commit 574833bf61
12 changed files with 454 additions and 29 deletions
+33
View File
@@ -50,6 +50,19 @@ impl DownloadStore {
}
}
pub fn update_queue_position(
&mut self,
username: &str,
filename: &str,
position: u32,
) -> bool {
let Some(download) = self.get_by_file_mut(username, filename) else {
return false;
};
download.queue_position = Some(position);
true
}
pub fn remove_queued_by_file(
&mut self,
username: &str,
@@ -150,6 +163,8 @@ mod tests {
download_directory: "test".to_string(),
status,
sender: mpsc::channel().0,
queue_position: None,
metadata: Default::default(),
}
}
@@ -167,6 +182,24 @@ mod tests {
assert!(store.list().is_empty());
}
#[test]
fn update_queue_position_sets_field_when_match() {
let mut store = DownloadStore::new();
let mut download = make_download(1, DownloadStatus::Queued);
download.username = "peer".to_string();
download.filename = "song.mp3".to_string();
store.add(download);
assert!(store.update_queue_position("peer", "song.mp3", 42));
assert_eq!(
store.get_by_token(1).unwrap().queue_position,
Some(42)
);
assert!(!store.update_queue_position("peer", "missing.mp3", 1));
assert!(!store.update_queue_position("other", "song.mp3", 1));
}
#[test]
fn pause_then_resume_in_progress_download() {
let mut store = DownloadStore::new();