Show users if room knows them

Also selects the current room in the rooms list
This commit is contained in:
Joscha 2022-02-27 00:16:36 +01:00
parent ccf6a59f39
commit f34bf63be4
7 changed files with 104 additions and 27 deletions

View file

@ -8,7 +8,7 @@ use crate::macros::id_alias;
// TODO Use base64 representation instead // TODO Use base64 representation instead
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
struct Id(#[serde(with = "hex")] [u8; 32]); struct Id(#[serde(with = "hex")] [u8; 32]);
impl Id { impl Id {

View file

@ -3,7 +3,7 @@
macro_rules! id_alias { macro_rules! id_alias {
($name:ident) => { ($name:ident) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct $name(Id); pub struct $name(Id);
impl $name { impl $name {

View file

@ -36,9 +36,9 @@ struct Connected {
} }
/// State for when a client has fully joined a room. /// State for when a client has fully joined a room.
struct Present { pub struct Present {
session: Session, pub session: Session,
others: HashMap<SessionId, Session>, pub others: HashMap<SessionId, Session>,
} }
enum Status { enum Status {
@ -95,6 +95,10 @@ impl Room {
room room
} }
pub fn present(&self) -> Option<&Present> {
self.present.as_ref()
}
async fn bg_task(room: Arc<Mutex<Room>>, config: &'static Config) { async fn bg_task(room: Arc<Mutex<Room>>, config: &'static Config) {
let mut room_verified = false; let mut room_verified = false;
loop { loop {

View file

@ -237,10 +237,18 @@ impl Ui {
let users_pane_border = areas[3]; let users_pane_border = areas[3];
let users_pane_area = areas[4]; let users_pane_area = areas[4];
// Rooms pane // Main pane and users pane
frame.render_widget(Rooms::new(&self.rooms), rooms_pane_area); if let Some(room) = &mut self.room {
room.render_main(frame, main_pane_area).await;
room.render_users(frame, users_pane_area).await;
}
// TODO Main pane and users pane // Rooms pane
let mut rooms = Rooms::new(&self.rooms);
if let Some(room) = &self.room {
rooms = rooms.select(room.name());
}
frame.render_widget(rooms, rooms_pane_area);
// Pane borders and width // Pane borders and width
self.rooms_pane.restrict_width(rooms_pane_area.width); self.rooms_pane.restrict_width(rooms_pane_area.width);
@ -248,7 +256,7 @@ impl Ui {
self.users_pane.restrict_width(users_pane_area.width); self.users_pane.restrict_width(users_pane_area.width);
frame.render_widget(self.users_pane.border(), users_pane_border); frame.render_widget(self.users_pane.border(), users_pane_border);
// Overlays // Overlay
if let Some(overlay) = &mut self.overlay { if let Some(overlay) = &mut self.overlay {
match overlay { match overlay {
Overlay::JoinRoom(state) => { Overlay::JoinRoom(state) => {

View file

@ -1,12 +1,17 @@
mod users;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tui::backend::Backend; use tui::backend::Backend;
use tui::layout::Rect; use tui::layout::Rect;
use tui::widgets::{Block, BorderType, Borders};
use tui::Frame; use tui::Frame;
use crate::room::Room; use crate::room::Room;
use self::users::Users;
pub struct RoomInfo { pub struct RoomInfo {
name: String, name: String,
room: Arc<Mutex<Room>>, room: Arc<Mutex<Room>>,
@ -21,11 +26,24 @@ impl RoomInfo {
&self.name &self.name
} }
pub async fn render_messages<B: Backend>(&mut self, frame: &mut Frame<'_, B>, area: Rect) { pub async fn render_main<B: Backend>(&mut self, frame: &mut Frame<'_, B>, area: Rect) {
// TODO Implement // TODO Implement
frame.render_widget(
Block::default()
.borders(Borders::TOP)
.border_type(BorderType::Double),
Rect {
x: area.x,
y: area.y + 1,
width: area.width,
height: 1,
},
);
} }
pub async fn render_users<B: Backend>(&mut self, frame: &mut Frame<'_, B>, area: Rect) { pub async fn render_users<B: Backend>(&mut self, frame: &mut Frame<'_, B>, area: Rect) {
// TODO Implement if let Some(present) = self.room.lock().await.present() {
frame.render_widget(Users::new(present), area);
}
} }
} }

View file

@ -0,0 +1,63 @@
use std::collections::HashSet;
use std::iter;
use cove_core::{Identity, Session};
use tui::buffer::Buffer;
use tui::layout::Rect;
use tui::style::{Modifier, Style};
use tui::text::{Span, Spans};
use tui::widgets::{Paragraph, Widget};
use crate::room::Present;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct UserInfo {
nick: String,
identity: Identity,
}
impl From<&Session> for UserInfo {
fn from(s: &Session) -> Self {
UserInfo {
nick: s.nick.clone(),
identity: s.identity,
}
}
}
pub struct Users {
users: Vec<UserInfo>,
}
impl Users {
pub fn new(present: &Present) -> Self {
let mut users: Vec<UserInfo> = iter::once(&present.session)
.chain(present.others.values())
.map(<&Session as Into<UserInfo>>::into)
.collect();
users.sort();
Self { users }
}
}
impl Widget for Users {
fn render(self, area: Rect, buf: &mut Buffer) {
let title_style = Style::default().add_modifier(Modifier::BOLD);
let sessions = self.users.len();
let identities = self
.users
.iter()
.map(|i| i.identity)
.collect::<HashSet<_>>()
.len();
let title = format!("Users ({identities}/{sessions})");
let mut lines = vec![Spans::from(Span::styled(title, title_style))];
for user in self.users {
// TODO Colour users based on identity
lines.push(Spans::from(Span::from(user.nick)));
}
Paragraph::new(lines).render(area, buf);
}
}

View file

@ -41,22 +41,6 @@ impl Rooms {
} }
self 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")
}
} }
impl Widget for Rooms { impl Widget for Rooms {