mirror of
https://git.sdf.org/epl692/tui-mqtt-chat.git
synced 2025-12-08 13:58:49 -05:00
feat: implement automatic scrolling
This commit is contained in:
18
src/main.rs
18
src/main.rs
@@ -1,5 +1,5 @@
|
|||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, EventStream},
|
event::{DisableMouseCapture, EnableMouseCapture, Event, KeyCode, EventStream},
|
||||||
execute,
|
execute,
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
};
|
};
|
||||||
@@ -22,6 +22,7 @@ struct App {
|
|||||||
input: String,
|
input: String,
|
||||||
username: String,
|
username: String,
|
||||||
current_room: String,
|
current_room: String,
|
||||||
|
messages_state: ListState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
@@ -31,11 +32,14 @@ impl App {
|
|||||||
messages.push(("System".to_string(), format!("Welcome to the chat, {}!", username)));
|
messages.push(("System".to_string(), format!("Welcome to the chat, {}!", username)));
|
||||||
messages.push(("System".to_string(), "To change your username, type /nick <new_username>".to_string()));
|
messages.push(("System".to_string(), "To change your username, type /nick <new_username>".to_string()));
|
||||||
messages.push(("System".to_string(), format!("You are currently in room: {}. To change room, type /join <new_room_name>", default_room)));
|
messages.push(("System".to_string(), format!("You are currently in room: {}. To change room, type /join <new_room_name>", default_room)));
|
||||||
|
let mut messages_state = ListState::default();
|
||||||
|
messages_state.select(Some(messages.len().saturating_sub(1)));
|
||||||
App {
|
App {
|
||||||
messages,
|
messages,
|
||||||
input: String::new(),
|
input: String::new(),
|
||||||
username,
|
username,
|
||||||
current_room: default_room,
|
current_room: default_room,
|
||||||
|
messages_state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +121,7 @@ async fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Re
|
|||||||
let mut reader = EventStream::new();
|
let mut reader = EventStream::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
terminal.draw(|f| ui(f, &app))?;
|
terminal.draw(|f| ui(f, &mut app))?;
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
Some(Ok(event)) = reader.next() => {
|
Some(Ok(event)) = reader.next() => {
|
||||||
@@ -130,6 +134,7 @@ async fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Re
|
|||||||
let new_username = message_text.split_whitespace().nth(1).unwrap_or(&app.username).to_string();
|
let new_username = message_text.split_whitespace().nth(1).unwrap_or(&app.username).to_string();
|
||||||
app.username = new_username.clone();
|
app.username = new_username.clone();
|
||||||
app.messages.push(("System".to_string(), format!("Username changed to: {}", app.username)));
|
app.messages.push(("System".to_string(), format!("Username changed to: {}", app.username)));
|
||||||
|
app.messages_state.select(Some(app.messages.len().saturating_sub(1)));
|
||||||
|
|
||||||
let chat_message = ChatMessage {
|
let chat_message = ChatMessage {
|
||||||
username: old_username,
|
username: old_username,
|
||||||
@@ -156,6 +161,7 @@ async fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Re
|
|||||||
client_clone.subscribe(&format!("chat/{}", new_room), QoS::AtMostOnce).await.unwrap();
|
client_clone.subscribe(&format!("chat/{}", new_room), QoS::AtMostOnce).await.unwrap();
|
||||||
app.current_room = new_room.clone();
|
app.current_room = new_room.clone();
|
||||||
app.messages.push(("System".to_string(), format!("Changed room to: {}", new_room)));
|
app.messages.push(("System".to_string(), format!("Changed room to: {}", new_room)));
|
||||||
|
app.messages_state.select(Some(app.messages.len().saturating_sub(1)));
|
||||||
|
|
||||||
// Send joining message to new room
|
// Send joining message to new room
|
||||||
let joining_message = ChatMessage {
|
let joining_message = ChatMessage {
|
||||||
@@ -166,6 +172,7 @@ async fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Re
|
|||||||
client_clone.publish(&format!("chat/{}", new_room), QoS::AtMostOnce, false, joining_payload.as_bytes()).await.unwrap();
|
client_clone.publish(&format!("chat/{}", new_room), QoS::AtMostOnce, false, joining_payload.as_bytes()).await.unwrap();
|
||||||
} else {
|
} else {
|
||||||
app.messages.push(("System".to_string(), format!("Already in room: {}", new_room)));
|
app.messages.push(("System".to_string(), format!("Already in room: {}", new_room)));
|
||||||
|
app.messages_state.select(Some(app.messages.len().saturating_sub(1)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let chat_message = ChatMessage {
|
let chat_message = ChatMessage {
|
||||||
@@ -194,6 +201,7 @@ async fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Re
|
|||||||
}
|
}
|
||||||
Some((username, message)) = rx.recv() => {
|
Some((username, message)) = rx.recv() => {
|
||||||
app.messages.push((username, message));
|
app.messages.push((username, message));
|
||||||
|
app.messages_state.select(Some(app.messages.len().saturating_sub(1)));
|
||||||
}
|
}
|
||||||
else => {
|
else => {
|
||||||
break;
|
break;
|
||||||
@@ -204,7 +212,7 @@ async fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Re
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui(f: &mut Frame, app: &App) {
|
fn ui(f: &mut Frame, app: &mut App) {
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.margin(1)
|
.margin(1)
|
||||||
@@ -216,9 +224,9 @@ fn ui(f: &mut Frame, app: &App) {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(username, message)| ListItem::new(format!("{}: {}", username, message)))
|
.map(|(username, message)| ListItem::new(format!("{}: {}", username, message)))
|
||||||
.collect();
|
.collect();
|
||||||
let messages = List::new(messages)
|
let messages_list = List::new(messages)
|
||||||
.block(Block::default().borders(Borders::ALL).title("Messages"));
|
.block(Block::default().borders(Borders::ALL).title("Messages"));
|
||||||
f.render_widget(messages, chunks[0]);
|
f.render_stateful_widget(messages_list, chunks[0], &mut app.messages_state);
|
||||||
|
|
||||||
let input = Paragraph::new(app.input.as_str())
|
let input = Paragraph::new(app.input.as_str())
|
||||||
.style(Style::default())
|
.style(Style::default())
|
||||||
|
|||||||
Reference in New Issue
Block a user