feat(tui): scroll long names in every list and page through popups and chat

The sideways keys the results had (h/l, arrows, 0 and $) now scroll a
transfer's file name and a query too, each list on its own. The browse tree
and the room list take Home/End, PgUp/PgDn and the vim jumps like the main
lists, and a chat log, room or private, pages back through its history and
holds its place while new messages arrive; what arrives meanwhile counts as
unread until the reader returns to the end.
This commit is contained in:
Michel de Graaf
2026-09-07 08:16:20 +00:00
parent da8ab45303
commit 478d976776
18 changed files with 841 additions and 175 deletions
+15 -1
View File
@@ -1,6 +1,7 @@
use super::MainTui;
use super::input::{jumped, list_jump};
use crate::models::{BrowseStatus, files_under, find_node};
use ratatui::crossterm::event::{KeyCode, KeyEvent};
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use std::{thread, time::Duration};
/// How long to wait for a browse response before showing a timeout notice.
@@ -12,6 +13,11 @@ impl MainTui {
self.state.show_browse = false;
return;
}
let jump = list_jump(key, self.popup_page());
// Control combinations are only ever jumps: ctrl-d pages, d downloads.
if jump.is_none() && key.modifiers.contains(KeyModifiers::CONTROL) {
return;
}
// Tab management: switch between browsed users or close the active tab.
match key.code {
@@ -60,6 +66,14 @@ impl MainTui {
(rows, sel, row)
};
if let Some(jump) = jump {
if let Some(browse) = self.state.browse.active_tab_mut() {
browse.selected_row = jumped(sel, rows.len(), jump);
}
self.sync_browse_selection();
return;
}
// Downloads need `&self.client` free of the browse borrow.
match key.code {
KeyCode::Enter if !row.is_folder => {