feat(tui): browse or PM a user from a chat room's member list
The member list in an open room is now selectable with the arrow keys. Press 'b' to browse the highlighted user's shared files (opens the browse tree) or 'm' to send them a private message (opens the compose bar pre-filled with the recipient). Selection resets when switching rooms; RoomsState navigation is unit-tested.
This commit is contained in:
@@ -356,11 +356,13 @@ impl MainTui {
|
||||
}
|
||||
}
|
||||
RoomsView::Chat => vec![
|
||||
("Enter", "type message"),
|
||||
("Enter", "say"),
|
||||
("↑↓", "pick user"),
|
||||
("b", "browse user"),
|
||||
("m", "message user"),
|
||||
("Tab", "switch room"),
|
||||
("l", "room list"),
|
||||
("l", "rooms"),
|
||||
("x", "leave"),
|
||||
("q", "close"),
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -840,6 +842,15 @@ impl MainTui {
|
||||
KeyCode::Tab => self.state.rooms.next_tab(),
|
||||
KeyCode::BackTab => self.state.rooms.prev_tab(),
|
||||
KeyCode::Char('x') => self.leave_active_room(),
|
||||
KeyCode::Up | KeyCode::Char('k') => {
|
||||
self.state.rooms.select_user_up();
|
||||
}
|
||||
KeyCode::Down | KeyCode::Char('j') => {
|
||||
self.state.rooms.select_user_down();
|
||||
}
|
||||
// Act on the highlighted member of the room.
|
||||
KeyCode::Char('b') => self.browse_selected_room_user(),
|
||||
KeyCode::Char('m') => self.message_selected_room_user(),
|
||||
KeyCode::Enter if self.state.rooms.active_room().is_some() => {
|
||||
self.state.rooms.composing = true;
|
||||
}
|
||||
@@ -847,6 +858,29 @@ impl MainTui {
|
||||
}
|
||||
}
|
||||
|
||||
/// Browse the shares of the member highlighted in the active room. Closes
|
||||
/// the rooms popup so the browse tree is the sole overlay.
|
||||
fn browse_selected_room_user(&mut self) {
|
||||
if let Some(user) = self.state.rooms.selected_user() {
|
||||
self.state.show_rooms = false;
|
||||
self.start_browse(user);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compose a private message to the member highlighted in the active room.
|
||||
/// Closes the rooms popup and opens the message command bar pre-filled with
|
||||
/// the recipient.
|
||||
fn message_selected_room_user(&mut self) {
|
||||
if let Some(user) = self.state.rooms.selected_user() {
|
||||
self.state.show_rooms = false;
|
||||
self.state.command_bar_active = true;
|
||||
self.state.command_bar_mode = CommandBarMode::Message;
|
||||
self.state.command_bar_input = format!("{user} ");
|
||||
self.state.command_bar_cursor_position =
|
||||
self.state.command_bar_input.len();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_room_compose_input(&mut self, key: KeyEvent) {
|
||||
match key.code {
|
||||
KeyCode::Enter => self.send_room_message(),
|
||||
|
||||
@@ -132,7 +132,7 @@ fn render_chat(frame: &mut Frame, area: Rect, rooms: &RoomsState) {
|
||||
.split(chunks[1]);
|
||||
|
||||
render_messages(frame, body[0], active.lines.as_slice());
|
||||
render_users(frame, body[1], &active.users);
|
||||
render_users(frame, body[1], &active.users, rooms.user_selected);
|
||||
|
||||
// Compose line or hint.
|
||||
if rooms.composing {
|
||||
@@ -200,7 +200,12 @@ fn render_messages(
|
||||
frame.render_widget(Paragraph::new(rendered), area);
|
||||
}
|
||||
|
||||
fn render_users(frame: &mut Frame, area: Rect, users: &[String]) {
|
||||
fn render_users(
|
||||
frame: &mut Frame,
|
||||
area: Rect,
|
||||
users: &[String],
|
||||
selected: usize,
|
||||
) {
|
||||
let block = Block::default()
|
||||
.borders(Borders::LEFT)
|
||||
.border_style(dimmed_style())
|
||||
@@ -209,10 +214,20 @@ fn render_users(frame: &mut Frame, area: Rect, users: &[String]) {
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let height = inner.height as usize;
|
||||
// Keep the highlighted user in view by scrolling the window to it.
|
||||
let start = selected.saturating_sub(height.saturating_sub(1));
|
||||
let shown: Vec<Line> = users
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(start)
|
||||
.take(height)
|
||||
.map(|u| Line::from(Span::styled(u.clone(), primary_style())))
|
||||
.map(|(i, u)| {
|
||||
if i == selected {
|
||||
Line::from(Span::styled(format!("▸ {u}"), highlight_style()))
|
||||
} else {
|
||||
Line::from(Span::styled(format!(" {u}"), primary_style()))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
frame.render_widget(Paragraph::new(shown), inner);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user