diff --git a/cove-tui/src/backend/cove/conn.rs b/cove-tui/src/backend/cove/conn.rs index 91b33fb..532d48f 100644 --- a/cove-tui/src/backend/cove/conn.rs +++ b/cove-tui/src/backend/cove/conn.rs @@ -10,7 +10,7 @@ use cove_core::packets::{ use cove_core::replies::Replies; use cove_core::{replies, Session, SessionId}; use tokio::sync::mpsc::UnboundedSender; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, MutexGuard}; // TODO Split into "interacting" and "maintenance" parts? #[derive(Debug, thiserror::Error)] @@ -121,6 +121,10 @@ impl Connected { status: Status::ChoosingRoom, } } + + pub fn present(&self) -> Option<&Present> { + self.status.present() + } } // The warning about enum variant sizes shouldn't matter since a connection will @@ -147,6 +151,10 @@ impl State { Self::Connecting | Self::Stopped => None, } } + + pub fn present(&self) -> Option<&Present> { + self.connected()?.present() + } } #[derive(Clone)] @@ -156,6 +164,11 @@ pub struct CoveConn { } impl CoveConn { + // TODO Disallow modification via this MutexGuard + pub async fn state(&self) -> MutexGuard<'_, State> { + self.state.lock().await + } + async fn cmd(&self, cmd: C) -> Result where C: Into, diff --git a/cove-tui/src/backend/cove/room.rs b/cove-tui/src/backend/cove/room.rs index f6253d9..44a897b 100644 --- a/cove-tui/src/backend/cove/room.rs +++ b/cove-tui/src/backend/cove/room.rs @@ -3,7 +3,7 @@ use std::time::Duration; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio::sync::oneshot::{self, Sender}; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, MutexGuard}; use crate::config::Config; use crate::never::Never; @@ -31,6 +31,7 @@ impl ConnConfig { } pub struct CoveRoom { + name: String, conn: Arc>, /// Once this is dropped, all other room-related tasks, connections and /// values are cleaned up. It is never used to send actual values. @@ -60,6 +61,7 @@ impl CoveRoom { let (conn, mt) = conf.new_conn().await; let room = Self { + name: name.clone(), conn: Arc::new(Mutex::new(conn)), dead_mans_switch: tx, }; @@ -76,6 +78,15 @@ impl CoveRoom { room } + pub fn name(&self) -> &str { + &self.name + } + + // TODO Disallow modification via this MutexGuard + pub async fn conn(&self) -> MutexGuard<'_, CoveConn> { + self.conn.lock().await + } + async fn shovel_events( mut ev_rx: UnboundedReceiver, ev_tx: UnboundedSender, diff --git a/cove-tui/src/ui/cove.rs b/cove-tui/src/ui/cove.rs index 7ce6cb7..159d353 100644 --- a/cove-tui/src/ui/cove.rs +++ b/cove-tui/src/ui/cove.rs @@ -1,11 +1,17 @@ mod users; use tui::backend::Backend; -use tui::layout::Rect; +use tui::layout::{Alignment, Constraint, Direction, Layout, Rect}; +use tui::text::Span; +use tui::widgets::{Block, BorderType, Borders, Paragraph}; use tui::Frame; use crate::backend::cove::room::CoveRoom; +use self::users::CoveUsers; + +use super::styles; + pub struct CoveUi { room: CoveRoom, } @@ -15,11 +21,52 @@ impl CoveUi { Self { room } } + fn name(&self) -> &str { + self.room.name() + } + pub async fn render_main(&mut self, frame: &mut Frame<'_, B>, area: Rect) { + let areas = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(1), + Constraint::Length(1), + Constraint::Min(0), + ]) + .split(area); + let room_name_area = areas[0]; + let separator_area = areas[1]; + let main_area = areas[2]; + + self.render_banner(frame, room_name_area).await; + self.render_separator(frame, separator_area).await; + self.render_main_inner(frame, main_area).await; + } + + async fn render_banner(&mut self, frame: &mut Frame<'_, B>, area: Rect) { + // TODO Show current nick as well, if applicable + let room_name = Paragraph::new(Span::styled( + format!("&{}", self.name()), + styles::selected_room(), + )) + .alignment(Alignment::Center); + frame.render_widget(room_name, area); + } + + async fn render_separator(&mut self, frame: &mut Frame<'_, B>, area: Rect) { + let separator = Block::default() + .borders(Borders::BOTTOM) + .border_type(BorderType::Double); + frame.render_widget(separator, area); + } + + async fn render_main_inner(&mut self, frame: &mut Frame<'_, B>, area: Rect) { // TODO Implement } pub async fn render_users(&mut self, frame: &mut Frame<'_, B>, area: Rect) { - // TODO Implement + if let Some(present) = self.room.conn().await.state().await.present() { + frame.render_widget(CoveUsers::new(present), area); + } } }