Show unseen message count in room list

This commit is contained in:
Joscha 2022-08-08 23:14:58 +02:00
parent e00ce4ebba
commit 888870b779
5 changed files with 92 additions and 18 deletions

View file

@ -139,6 +139,10 @@ impl MsgStore<LogMsg> for Logger {
None None
} }
async fn unseen_msgs_count(&self) -> usize {
0
}
async fn set_seen(&self, _id: &usize, _seen: bool) {} async fn set_seen(&self, _id: &usize, _seen: bool) {}
async fn set_older_seen(&self, _id: &usize, _seen: bool) {} async fn set_older_seen(&self, _id: &usize, _seen: bool) {}

View file

@ -133,6 +133,7 @@ pub trait MsgStore<M: Msg> {
async fn newest_unseen_msg_id(&self) -> Option<M::Id>; async fn newest_unseen_msg_id(&self) -> Option<M::Id>;
async fn older_unseen_msg_id(&self, id: &M::Id) -> Option<M::Id>; async fn older_unseen_msg_id(&self, id: &M::Id) -> Option<M::Id>;
async fn newer_unseen_msg_id(&self, id: &M::Id) -> Option<M::Id>; async fn newer_unseen_msg_id(&self, id: &M::Id) -> Option<M::Id>;
async fn unseen_msgs_count(&self) -> usize;
async fn set_seen(&self, id: &M::Id, seen: bool); async fn set_seen(&self, id: &M::Id, seen: bool);
async fn set_older_seen(&self, id: &M::Id, seen: bool); async fn set_older_seen(&self, id: &M::Id, seen: bool);
} }

View file

@ -11,6 +11,7 @@ use toss::terminal::Terminal;
use crate::euph::api::{SessionType, SessionView, Snowflake}; use crate::euph::api::{SessionType, SessionView, Snowflake};
use crate::euph::{self, Joined, Status}; use crate::euph::{self, Joined, Status};
use crate::store::MsgStore;
use crate::vault::EuphVault; use crate::vault::EuphVault;
use super::chat::{ChatState, Reaction}; use super::chat::{ChatState, Reaction};
@ -36,6 +37,7 @@ enum State {
pub struct EuphRoom { pub struct EuphRoom {
ui_event_tx: mpsc::UnboundedSender<UiEvent>, ui_event_tx: mpsc::UnboundedSender<UiEvent>,
vault: EuphVault,
room: Option<euph::Room>, room: Option<euph::Room>,
state: State, state: State,
@ -50,6 +52,7 @@ impl EuphRoom {
pub fn new(vault: EuphVault, ui_event_tx: mpsc::UnboundedSender<UiEvent>) -> Self { pub fn new(vault: EuphVault, ui_event_tx: mpsc::UnboundedSender<UiEvent>) -> Self {
Self { Self {
ui_event_tx, ui_event_tx,
vault: vault.clone(),
room: None, room: None,
state: State::Normal, state: State::Normal,
chat: ChatState::new(vault), chat: ChatState::new(vault),
@ -91,6 +94,10 @@ impl EuphRoom {
} }
} }
pub async fn unseen_msgs_count(&self) -> usize {
self.vault.unseen_msgs_count().await
}
async fn stabilize_pseudo_msg(&mut self) { async fn stabilize_pseudo_msg(&mut self) {
if let Some(id_rx) = &mut self.last_msg_sent { if let Some(id_rx) = &mut self.last_msg_sent {
match id_rx.try_recv() { match id_rx.try_recv() {
@ -169,6 +176,7 @@ impl EuphRoom {
} }
fn status_widget(&self, status: &Option<Option<Status>>) -> BoxedWidget { fn status_widget(&self, status: &Option<Option<Status>>) -> BoxedWidget {
// TODO Include unread message count
let room = self.chat.store().room(); let room = self.chat.store().room();
let room_style = ContentStyle::default().bold().blue(); let room_style = ContentStyle::default().bold().blue();
let mut info = Styled::new(format!("&{room}"), room_style); let mut info = Styled::new(format!("&{room}"), room_style);

View file

@ -154,12 +154,44 @@ impl Rooms {
result.join(" ") result.join(" ")
} }
fn format_status(status: &Option<Status>) -> String { async fn format_status(room: &EuphRoom) -> Option<String> {
match status { match room.status().await {
None => " (connecting)".to_string(), None => None,
Some(Status::Joining(j)) if j.bounce.is_some() => " (auth required)".to_string(), Some(None) => Some("connecting".to_string()),
Some(Status::Joining(_)) => " (joining)".to_string(), Some(Some(Status::Joining(j))) if j.bounce.is_some() => {
Some(Status::Joined(j)) => format!(" ({})", Self::format_pbln(j)), Some("auth required".to_string())
}
Some(Some(Status::Joining(_))) => Some("joining".to_string()),
Some(Some(Status::Joined(joined))) => Some(Self::format_pbln(&joined)),
}
}
async fn format_unseen_msgs(room: &EuphRoom) -> Option<String> {
let unseen = room.unseen_msgs_count().await;
if unseen == 0 {
None
} else {
Some(format!("{unseen}"))
}
}
async fn format_room_info(room: &EuphRoom) -> Styled {
let unseen_style = ContentStyle::default().bold().green();
let status = Self::format_status(room).await;
let unseen = Self::format_unseen_msgs(room).await;
match (status, unseen) {
(None, None) => Styled::default(),
(None, Some(u)) => Styled::new_plain(" (")
.then(&u, unseen_style)
.then_plain(")"),
(Some(s), None) => Styled::new_plain(" (").then_plain(&s).then_plain(")"),
(Some(s), Some(u)) => Styled::new_plain(" (")
.then_plain(&s)
.then_plain(", ")
.then(&u, unseen_style)
.then_plain(")"),
} }
} }
@ -176,26 +208,18 @@ impl Rooms {
} }
for room in rooms { for room in rooms {
let bg_style = ContentStyle::default();
let bg_sel_style = ContentStyle::default().black().on_white();
let room_style = ContentStyle::default().bold().blue(); let room_style = ContentStyle::default().bold().blue();
let room_sel_style = ContentStyle::default().bold().black().on_white(); let room_sel_style = ContentStyle::default().bold().black().on_white();
let mut normal = Styled::new(format!("&{room}"), room_style); let mut normal = Styled::new(format!("&{room}"), room_style);
let mut selected = Styled::new(format!("&{room}"), room_sel_style); let mut selected = Styled::new(format!("&{room}"), room_sel_style);
if let Some(room) = self.euph_rooms.get(&room) { if let Some(room) = self.euph_rooms.get(&room) {
if let Some(status) = room.status().await { let info = Self::format_room_info(room).await;
let status = Self::format_status(&status); normal = normal.and_then(info.clone());
normal = normal.then(status.clone(), bg_style); selected = selected.and_then(info);
selected = selected.then(status, bg_sel_style);
}
}; };
list.add_sel( list.add_sel(room, Text::new(normal), Text::new(selected));
room,
Text::new(normal),
Background::new(Text::new(selected)).style(bg_sel_style),
);
} }
} }

View file

@ -305,6 +305,17 @@ impl MsgStore<SmallMessage> for EuphVault {
rx.await.unwrap() rx.await.unwrap()
} }
async fn unseen_msgs_count(&self) -> usize {
// TODO vault::Error
let (tx, rx) = oneshot::channel();
let request = EuphRequest::GetUnseenMsgsCount {
room: self.room.clone(),
result: tx,
};
let _ = self.vault.tx.send(request.into());
rx.await.unwrap()
}
async fn set_seen(&self, id: &Snowflake, seen: bool) { async fn set_seen(&self, id: &Snowflake, seen: bool) {
let request = EuphRequest::SetSeen { let request = EuphRequest::SetSeen {
room: self.room.clone(), room: self.room.clone(),
@ -432,6 +443,10 @@ pub(super) enum EuphRequest {
id: Snowflake, id: Snowflake,
result: oneshot::Sender<Option<Snowflake>>, result: oneshot::Sender<Option<Snowflake>>,
}, },
GetUnseenMsgsCount {
room: String,
result: oneshot::Sender<usize>,
},
SetSeen { SetSeen {
room: String, room: String,
id: Snowflake, id: Snowflake,
@ -503,6 +518,9 @@ impl EuphRequest {
EuphRequest::GetNewerUnseenMsgId { room, id, result } => { EuphRequest::GetNewerUnseenMsgId { room, id, result } => {
Self::get_newer_unseen_msg_id(conn, room, id, result) Self::get_newer_unseen_msg_id(conn, room, id, result)
} }
EuphRequest::GetUnseenMsgsCount { room, result } => {
Self::get_unseen_msgs_count(conn, room, result)
}
EuphRequest::SetSeen { room, id, seen } => Self::set_seen(conn, room, id, seen), EuphRequest::SetSeen { room, id, seen } => Self::set_seen(conn, room, id, seen),
EuphRequest::SetOlderSeen { room, id, seen } => { EuphRequest::SetOlderSeen { room, id, seen } => {
Self::set_older_seen(conn, room, id, seen) Self::set_older_seen(conn, room, id, seen)
@ -1198,6 +1216,25 @@ impl EuphRequest {
Ok(()) Ok(())
} }
fn get_unseen_msgs_count(
conn: &Connection,
room: String,
result: oneshot::Sender<usize>,
) -> rusqlite::Result<()> {
let amount = conn
.prepare(
"
SELECT COUNT(*)
FROM euph_msgs
WHERE room = ?
AND NOT seen
",
)?
.query_row(params![room], |row| row.get(0))?;
let _ = result.send(amount);
Ok(())
}
fn set_seen( fn set_seen(
conn: &Connection, conn: &Connection,
room: String, room: String,