Show users if room knows them
Also selects the current room in the rooms list
This commit is contained in:
parent
ccf6a59f39
commit
f34bf63be4
7 changed files with 104 additions and 27 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
63
cove-tui/src/ui/room/users.rs
Normal file
63
cove-tui/src/ui/room/users.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue