fix(tui): make browse retry work and de-jargon the copy
- Retry actually retries: 'r' in the browse popup re-requests a timed-out user (previously the 'Press b to retry' hint did nothing — b wasn't handled inside the popup). BrowseTabs::retry_active is unit-tested. - Friendlier timeout copy that explains the likely cause: "Couldn't reach <user>. They may be offline, or their connection can't be reached (both of you may be behind a router/firewall). Press r to try again." - Replace protocol terminology in user-facing labels: 'Peer slots' -> 'Free slots', 'Peer upload speed' -> 'Upload speed'.
This commit is contained in:
@@ -371,6 +371,20 @@ impl BrowseTabs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retry the active tab if it timed out: reset it to loading and return the
|
||||||
|
/// username so the caller can re-issue the request. Returns `None` if the
|
||||||
|
/// active tab isn't in a retryable (timed-out) state.
|
||||||
|
pub fn retry_active(&mut self) -> Option<String> {
|
||||||
|
let tab = self.tabs.get_mut(self.active)?;
|
||||||
|
if tab.status == BrowseStatus::TimedOut {
|
||||||
|
let username = tab.username.clone();
|
||||||
|
*tab = BrowseState::loading(username.clone());
|
||||||
|
Some(username)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Close the active tab, returning `false` when no tabs remain.
|
/// Close the active tab, returning `false` when no tabs remain.
|
||||||
pub fn close_active(&mut self) -> bool {
|
pub fn close_active(&mut self) -> bool {
|
||||||
if self.active < self.tabs.len() {
|
if self.active < self.tabs.len() {
|
||||||
@@ -545,6 +559,20 @@ mod tests {
|
|||||||
assert_eq!(tabs.active_tab().unwrap().status, BrowseStatus::Loading);
|
assert_eq!(tabs.active_tab().unwrap().status, BrowseStatus::Loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn browse_tabs_retry_active_only_when_timed_out() {
|
||||||
|
let mut tabs = BrowseTabs::new();
|
||||||
|
tabs.open("alice");
|
||||||
|
// Loading tab isn't retryable.
|
||||||
|
assert_eq!(tabs.retry_active(), None);
|
||||||
|
tabs.active_tab_mut().unwrap().status = BrowseStatus::TimedOut;
|
||||||
|
// Timed-out tab retries and resets to loading.
|
||||||
|
assert_eq!(tabs.retry_active().as_deref(), Some("alice"));
|
||||||
|
assert_eq!(tabs.active_tab().unwrap().status, BrowseStatus::Loading);
|
||||||
|
// Now loading again, no further retry.
|
||||||
|
assert_eq!(tabs.retry_active(), None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn browse_state_load_auto_expands_top_level() {
|
fn browse_state_load_auto_expands_top_level() {
|
||||||
let mut state = BrowseState::loading("bob".to_string());
|
let mut state = BrowseState::loading("bob".to_string());
|
||||||
|
|||||||
@@ -388,6 +388,7 @@ impl MainTui {
|
|||||||
("Enter", "open/download"),
|
("Enter", "open/download"),
|
||||||
("d", "download folder"),
|
("d", "download folder"),
|
||||||
("Tab", "switch user"),
|
("Tab", "switch user"),
|
||||||
|
("r", "retry"),
|
||||||
("w", "close tab"),
|
("w", "close tab"),
|
||||||
("Esc", "hide"),
|
("Esc", "hide"),
|
||||||
]
|
]
|
||||||
@@ -631,6 +632,13 @@ impl MainTui {
|
|||||||
self.sync_browse_selection();
|
self.sync_browse_selection();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
KeyCode::Char('r') => {
|
||||||
|
// Retry a timed-out browse.
|
||||||
|
if let Some(username) = self.state.browse.retry_active() {
|
||||||
|
let _ = self.client.browse_user(&username);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,10 +90,18 @@ fn render_browse_one(
|
|||||||
frame.render_widget(Paragraph::new(text).block(block), area);
|
frame.render_widget(Paragraph::new(text).block(block), area);
|
||||||
}
|
}
|
||||||
BrowseStatus::TimedOut => {
|
BrowseStatus::TimedOut => {
|
||||||
let text = Line::styled(
|
let text = vec![
|
||||||
"Timed out waiting for the file list. Press b to retry.",
|
Line::styled(
|
||||||
error_style(),
|
format!("Couldn't reach {}.", browse.username),
|
||||||
);
|
error_style(),
|
||||||
|
),
|
||||||
|
Line::raw(""),
|
||||||
|
Line::raw(
|
||||||
|
"They may be offline, or their connection can't be \
|
||||||
|
reached (both of you may be behind a router/firewall).",
|
||||||
|
),
|
||||||
|
Line::raw("Press r to try again."),
|
||||||
|
];
|
||||||
frame.render_widget(Paragraph::new(text).block(block), area);
|
frame.render_widget(Paragraph::new(text).block(block), area);
|
||||||
}
|
}
|
||||||
BrowseStatus::Loaded => {
|
BrowseStatus::Loaded => {
|
||||||
|
|||||||
@@ -104,12 +104,12 @@ fn build_info_lines(
|
|||||||
} else {
|
} else {
|
||||||
"all busy".to_string()
|
"all busy".to_string()
|
||||||
};
|
};
|
||||||
lines.push(label_value("Peer slots", &slot_text));
|
lines.push(label_value("Free slots", &slot_text));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(speed) = download.metadata.peer_upload_speed {
|
if let Some(speed) = download.metadata.peer_upload_speed {
|
||||||
lines.push(label_value(
|
lines.push(label_value(
|
||||||
"Peer upload speed",
|
"Upload speed",
|
||||||
&format_speed(f64::from(speed)),
|
&format_speed(f64::from(speed)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user