diff --git a/cove-tui/src/ui.rs b/cove-tui/src/ui.rs index 18e5c83..00edff1 100644 --- a/cove-tui/src/ui.rs +++ b/cove-tui/src/ui.rs @@ -1,16 +1,21 @@ mod rooms; +use std::collections::HashMap; use std::io::Stdout; +use std::sync::Arc; use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, MouseEvent, MouseEventKind}; use futures::StreamExt; use tokio::sync::mpsc::error::TryRecvError; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; +use tokio::sync::Mutex; use tui::backend::CrosstermBackend; use tui::layout::{Constraint, Direction, Layout}; use tui::widgets::Paragraph; use tui::{Frame, Terminal}; +use crate::room::Room; + use self::rooms::{Rooms, RoomsState}; pub type Backend = CrosstermBackend; @@ -28,6 +33,7 @@ enum EventHandleResult { pub struct Ui { event_tx: UnboundedSender, + rooms: HashMap>>, rooms_state: RoomsState, log: Vec, } @@ -36,6 +42,7 @@ impl Ui { fn new(event_tx: UnboundedSender) -> Self { Self { event_tx, + rooms: HashMap::new(), rooms_state: RoomsState::default(), log: vec!["Hello world!".to_string()], } @@ -155,7 +162,8 @@ impl Ui { ]) .split(frame.size()); - frame.render_stateful_widget(Rooms::new(), outer[0], &mut self.rooms_state); + // frame.render_stateful_widget(Rooms::new(&self.rooms), outer[0], &mut self.rooms_state); + frame.render_stateful_widget(Rooms::dummy(), outer[0], &mut self.rooms_state); let scroll = if self.log.len() as u16 > outer[1].height { self.log.len() as u16 - outer[1].height diff --git a/cove-tui/src/ui/rooms.rs b/cove-tui/src/ui/rooms.rs index f0b1a99..1396fc6 100644 --- a/cove-tui/src/ui/rooms.rs +++ b/cove-tui/src/ui/rooms.rs @@ -1,15 +1,62 @@ use std::cmp; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::Mutex; use tui::buffer::Buffer; use tui::layout::Rect; -use tui::style::{Modifier, Style}; -use tui::widgets::{Block, Borders, StatefulWidget, Widget}; +use tui::style::{Color, Modifier, Style}; +use tui::text::{Span, Spans}; +use tui::widgets::{Block, Borders, Paragraph, StatefulWidget, Widget}; -pub struct Rooms {} +use crate::room::Room; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +struct RoomInfo { + name: String, +} + +pub struct Rooms { + rooms: Vec, + selected: Option, +} impl Rooms { - pub fn new() -> Self { - Self {} + pub fn new(rooms: &HashMap>>) -> Self { + let mut rooms = rooms + .iter() + .map(|(name, _room)| RoomInfo { name: name.clone() }) + .collect::>(); + rooms.sort(); + Self { + rooms, + selected: None, + } + } + + pub fn select(mut self, name: &str) -> Self { + for (i, room) in self.rooms.iter().enumerate() { + if room.name == name { + self.selected = Some(i); + } + } + self + } + + pub fn dummy() -> Self { + fn r(s: &str) -> RoomInfo { + RoomInfo { + name: s.to_string(), + } + } + + let mut rooms = vec![r("xkcd"), r("test"), r("welcome"), r("music")]; + rooms.sort(); + Rooms { + rooms, + selected: None, + } + .select("welcome") } } @@ -17,12 +64,44 @@ impl StatefulWidget for Rooms { type State = RoomsState; fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) { + let title_style = Style::default().add_modifier(Modifier::BOLD); + let empty_style = Style::default() + .fg(Color::Gray) + .add_modifier(Modifier::ITALIC); + let room_style = Style::default().fg(Color::LightBlue); + let selected_room_style = room_style.add_modifier(Modifier::BOLD); + state.width = cmp::min(state.width, area.width); - // let left = Rect { - // width: area.width - 1, - // ..area - // }; + // Actual room names + let left = Rect { + width: area.width - 1, + ..area + }; + let mut lines = vec![Spans::from(Span::styled("Rooms", title_style))]; + if self.rooms.is_empty() { + lines.push(Spans::from(vec![ + Span::raw("\r\n"), + Span::styled("none", empty_style), + ])); + } + for (i, room) in self.rooms.iter().enumerate() { + let name = format!("&{}", room.name); + if Some(i) == self.selected { + lines.push(Spans::from(vec![ + Span::raw("\n>"), + Span::styled(name, selected_room_style), + ])); + } else { + lines.push(Spans::from(vec![ + Span::raw("\n "), + Span::styled(name, room_style), + ])); + } + } + Paragraph::new(lines).render(left, buf); + + // The panel's border let right = Rect { x: area.right() - 1, width: 1, @@ -40,10 +119,10 @@ impl StatefulWidget for Rooms { } } +// TODO Figure out some sort of scroll offset solution #[derive(Debug)] pub struct RoomsState { width: u16, - offset: u16, hovering: bool, dragging: bool, } @@ -52,7 +131,6 @@ impl Default for RoomsState { fn default() -> Self { Self { width: 24, - offset: 0, hovering: false, dragging: false, } @@ -72,10 +150,6 @@ impl RoomsState { self.dragging = active; } - pub fn dragging(&self) -> bool { - self.dragging - } - pub fn drag_to(&mut self, width: u16) { if self.dragging { self.width = width;