feat: settings popup and uploads in the transfers pane

Press 'o' for a settings popup: edit the download folder, add/remove
share paths (applied live via a rescan and persisted to config.toml),
and force a re-index with 'r' for files changed on disk. The state
machine is unit-tested; feedback shows the shared file/folder counts.

The downloads pane is now Downloads/Uploads: uploads being served are
listed after downloads with an up-arrow marker, live progress, and
status; 'x' cancels an in-progress upload. Client::shared_counts exposes
the index size for the status line.
This commit is contained in:
michel
2026-07-20 20:56:39 +02:00
parent 4936d4dd2a
commit 724796c1eb
10 changed files with 533 additions and 19 deletions
+77 -1
View File
@@ -134,6 +134,7 @@ impl MainTui {
frame,
downloads_chunks[0],
&self.state.downloads,
&self.state.uploads,
&mut self.state.downloads_table_state,
self.state.focused_pane == FocusedPane::Downloads,
);
@@ -170,6 +171,11 @@ impl MainTui {
);
}
// Settings popup overlays everything when open.
if self.state.settings.is_some() {
self.render_settings_popup(frame);
}
// Chat rooms overlay everything when open.
if self.state.show_rooms {
let area = centered_rect(85, 80, frame.area());
@@ -183,6 +189,67 @@ impl MainTui {
}
}
fn render_settings_popup(&self, frame: &mut Frame) {
use crate::models::SettingsMode;
let Some(settings) = self.state.settings.as_ref() else {
return;
};
let area = centered_rect(70, 60, frame.area());
frame.render_widget(ratatui::widgets::Clear, area);
let mut lines: Vec<ratatui::text::Line> = Vec::new();
let marker = |selected: bool| if selected { "> " } else { " " };
let download_line = if settings.mode == SettingsMode::EditingDownloadDir
{
format!("> Download folder: {}▏", settings.input)
} else {
format!(
"{}Download folder: {}",
marker(settings.selected == 0),
settings.download_dir
)
};
lines.push(ratatui::text::Line::from(download_line));
lines.push(ratatui::text::Line::from(""));
lines.push(ratatui::text::Line::from(format!(
"Shared folders ({}):",
settings.share_dirs.len()
)));
for (i, dir) in settings.share_dirs.iter().enumerate() {
lines.push(ratatui::text::Line::from(format!(
"{}{}",
marker(settings.selected == i + 1),
dir
)));
}
if settings.share_dirs.is_empty() {
lines.push(ratatui::text::Line::from(
" (nothing shared — press 'a' to add a folder)",
));
}
if settings.mode == SettingsMode::AddingShare {
lines.push(ratatui::text::Line::from(format!(
" Add share: {}▏",
settings.input
)));
}
if let Some(status) = &settings.status {
lines.push(ratatui::text::Line::from(""));
lines.push(ratatui::text::Line::from(status.clone()));
}
let block = ratatui::widgets::Block::default()
.borders(ratatui::widgets::Borders::ALL)
.title(" Settings ");
frame.render_widget(
ratatui::widgets::Paragraph::new(lines)
.block(block)
.wrap(ratatui::widgets::Wrap { trim: false }),
area,
);
}
fn render_messages_popup(&self, frame: &mut Frame) {
let area = centered_rect(70, 60, frame.area());
@@ -273,7 +340,16 @@ impl MainTui {
"chat".to_string()
};
let shortcuts = if self.state.show_rooms {
let shortcuts = if self.state.settings.is_some() {
vec![
("↑↓", "move"),
("Enter/e", "edit download dir"),
("a", "add share"),
("d", "remove share"),
("r", "re-index"),
("Esc", "close"),
]
} else if self.state.show_rooms {
self.rooms_shortcuts()
} else if self.state.show_browse {
vec![