Move to prev/next unseen message
This commit is contained in:
parent
05ce069121
commit
bfc221106d
5 changed files with 225 additions and 0 deletions
|
|
@ -123,6 +123,22 @@ impl MsgStore<LogMsg> for Logger {
|
||||||
self.next_tree_id(id).await
|
self.next_tree_id(id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn oldest_unseen_msg_id(&self) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn newest_unseen_msg_id(&self) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn older_unseen_msg_id(&self, _id: &usize) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn newer_unseen_msg_id(&self, _id: &usize) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
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) {}
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,10 @@ pub trait MsgStore<M: Msg> {
|
||||||
async fn newest_msg_id(&self) -> Option<M::Id>;
|
async fn newest_msg_id(&self) -> Option<M::Id>;
|
||||||
async fn older_msg_id(&self, id: &M::Id) -> Option<M::Id>;
|
async fn older_msg_id(&self, id: &M::Id) -> Option<M::Id>;
|
||||||
async fn newer_msg_id(&self, id: &M::Id) -> Option<M::Id>;
|
async fn newer_msg_id(&self, id: &M::Id) -> Option<M::Id>;
|
||||||
|
async fn oldest_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 newer_unseen_msg_id(&self, id: &M::Id) -> Option<M::Id>;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
pub fn list_movement_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
pub fn list_movement_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||||
bindings.binding("j/k, ↓/↑", "move cursor up/down");
|
bindings.binding("j/k, ↓/↑", "move cursor up/down");
|
||||||
bindings.binding("h/l, ←/→", "move cursor chronologically");
|
bindings.binding("h/l, ←/→", "move cursor chronologically");
|
||||||
|
bindings.binding("H/L, ctrl+←/→", "move cursor to prev/next unseen message");
|
||||||
bindings.binding("g, home", "move cursor to top");
|
bindings.binding("g, home", "move cursor to top");
|
||||||
bindings.binding("G, end", "move cursor to bottom");
|
bindings.binding("G, end", "move cursor to bottom");
|
||||||
bindings.binding("ctrl+y/e", "scroll up/down a line");
|
bindings.binding("ctrl+y/e", "scroll up/down a line");
|
||||||
|
|
@ -80,6 +81,8 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
key!('j') | key!(Down) => self.move_cursor_down().await,
|
key!('j') | key!(Down) => self.move_cursor_down().await,
|
||||||
key!('h') | key!(Left) => self.move_cursor_older().await,
|
key!('h') | key!(Left) => self.move_cursor_older().await,
|
||||||
key!('l') | key!(Right) => self.move_cursor_newer().await,
|
key!('l') | key!(Right) => self.move_cursor_newer().await,
|
||||||
|
key!('H') | key!(Ctrl + Left) => self.move_cursor_older_unseen().await,
|
||||||
|
key!('L') | key!(Ctrl + Right) => self.move_cursor_newer_unseen().await,
|
||||||
key!('g') | key!(Home) => self.move_cursor_to_top().await,
|
key!('g') | key!(Home) => self.move_cursor_to_top().await,
|
||||||
key!('G') | key!(End) => self.move_cursor_to_bottom().await,
|
key!('G') | key!(End) => self.move_cursor_to_bottom().await,
|
||||||
key!(Ctrl + 'y') => self.scroll_up(1),
|
key!(Ctrl + 'y') => self.scroll_up(1),
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,40 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
self.correction = Some(Correction::MakeCursorVisible);
|
self.correction = Some(Correction::MakeCursorVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn move_cursor_older_unseen(&mut self) {
|
||||||
|
match &mut self.cursor {
|
||||||
|
Cursor::Msg(id) => {
|
||||||
|
if let Some(prev_id) = self.store.older_unseen_msg_id(id).await {
|
||||||
|
*id = prev_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Cursor::Bottom | Cursor::Pseudo { .. } => {
|
||||||
|
if let Some(id) = self.store.newest_unseen_msg_id().await {
|
||||||
|
self.cursor = Cursor::Msg(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.correction = Some(Correction::MakeCursorVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn move_cursor_newer_unseen(&mut self) {
|
||||||
|
match &mut self.cursor {
|
||||||
|
Cursor::Msg(id) => {
|
||||||
|
if let Some(prev_id) = self.store.newer_unseen_msg_id(id).await {
|
||||||
|
*id = prev_id;
|
||||||
|
} else {
|
||||||
|
self.cursor = Cursor::Bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Cursor::Pseudo { .. } => {
|
||||||
|
self.cursor = Cursor::Bottom;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.correction = Some(Correction::MakeCursorVisible);
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn move_cursor_to_top(&mut self) {
|
pub async fn move_cursor_to_top(&mut self) {
|
||||||
if let Some(first_tree_id) = self.store.first_tree_id().await {
|
if let Some(first_tree_id) = self.store.first_tree_id().await {
|
||||||
self.cursor = Cursor::Msg(first_tree_id);
|
self.cursor = Cursor::Msg(first_tree_id);
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,52 @@ impl MsgStore<SmallMessage> for EuphVault {
|
||||||
rx.await.unwrap()
|
rx.await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn oldest_unseen_msg_id(&self) -> Option<Snowflake> {
|
||||||
|
// TODO vault::Error
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let request = EuphRequest::GetOldestUnseenMsgId {
|
||||||
|
room: self.room.clone(),
|
||||||
|
result: tx,
|
||||||
|
};
|
||||||
|
let _ = self.vault.tx.send(request.into());
|
||||||
|
rx.await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn newest_unseen_msg_id(&self) -> Option<Snowflake> {
|
||||||
|
// TODO vault::Error
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let request = EuphRequest::GetNewestUnseenMsgId {
|
||||||
|
room: self.room.clone(),
|
||||||
|
result: tx,
|
||||||
|
};
|
||||||
|
let _ = self.vault.tx.send(request.into());
|
||||||
|
rx.await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn older_unseen_msg_id(&self, id: &Snowflake) -> Option<Snowflake> {
|
||||||
|
// TODO vault::Error
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let request = EuphRequest::GetOlderUnseenMsgId {
|
||||||
|
room: self.room.clone(),
|
||||||
|
id: *id,
|
||||||
|
result: tx,
|
||||||
|
};
|
||||||
|
let _ = self.vault.tx.send(request.into());
|
||||||
|
rx.await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn newer_unseen_msg_id(&self, id: &Snowflake) -> Option<Snowflake> {
|
||||||
|
// TODO vault::Error
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let request = EuphRequest::GetNewerUnseenMsgId {
|
||||||
|
room: self.room.clone(),
|
||||||
|
id: *id,
|
||||||
|
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(),
|
||||||
|
|
@ -368,6 +414,24 @@ pub(super) enum EuphRequest {
|
||||||
id: Snowflake,
|
id: Snowflake,
|
||||||
result: oneshot::Sender<Option<Snowflake>>,
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
},
|
},
|
||||||
|
GetOlderUnseenMsgId {
|
||||||
|
room: String,
|
||||||
|
id: Snowflake,
|
||||||
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
|
},
|
||||||
|
GetOldestUnseenMsgId {
|
||||||
|
room: String,
|
||||||
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
|
},
|
||||||
|
GetNewestUnseenMsgId {
|
||||||
|
room: String,
|
||||||
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
|
},
|
||||||
|
GetNewerUnseenMsgId {
|
||||||
|
room: String,
|
||||||
|
id: Snowflake,
|
||||||
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
|
},
|
||||||
SetSeen {
|
SetSeen {
|
||||||
room: String,
|
room: String,
|
||||||
id: Snowflake,
|
id: Snowflake,
|
||||||
|
|
@ -427,6 +491,18 @@ impl EuphRequest {
|
||||||
EuphRequest::GetNewerMsgId { room, id, result } => {
|
EuphRequest::GetNewerMsgId { room, id, result } => {
|
||||||
Self::get_newer_msg_id(conn, room, id, result)
|
Self::get_newer_msg_id(conn, room, id, result)
|
||||||
}
|
}
|
||||||
|
EuphRequest::GetOldestUnseenMsgId { room, result } => {
|
||||||
|
Self::get_oldest_unseen_msg_id(conn, room, result)
|
||||||
|
}
|
||||||
|
EuphRequest::GetNewestUnseenMsgId { room, result } => {
|
||||||
|
Self::get_newest_unseen_msg_id(conn, room, result)
|
||||||
|
}
|
||||||
|
EuphRequest::GetOlderUnseenMsgId { room, id, result } => {
|
||||||
|
Self::get_older_unseen_msg_id(conn, room, id, result)
|
||||||
|
}
|
||||||
|
EuphRequest::GetNewerUnseenMsgId { room, id, result } => {
|
||||||
|
Self::get_newer_unseen_msg_id(conn, room, id, 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)
|
||||||
|
|
@ -1030,6 +1106,98 @@ impl EuphRequest {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_oldest_unseen_msg_id(
|
||||||
|
conn: &Connection,
|
||||||
|
room: String,
|
||||||
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
|
) -> rusqlite::Result<()> {
|
||||||
|
let tree = conn
|
||||||
|
.prepare(
|
||||||
|
"
|
||||||
|
SELECT id
|
||||||
|
FROM euph_msgs
|
||||||
|
WHERE room = ?
|
||||||
|
AND NOT seen
|
||||||
|
ORDER BY id ASC
|
||||||
|
LIMIT 1
|
||||||
|
",
|
||||||
|
)?
|
||||||
|
.query_row([room], |row| row.get(0))
|
||||||
|
.optional()?;
|
||||||
|
let _ = result.send(tree);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_newest_unseen_msg_id(
|
||||||
|
conn: &Connection,
|
||||||
|
room: String,
|
||||||
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
|
) -> rusqlite::Result<()> {
|
||||||
|
let tree = conn
|
||||||
|
.prepare(
|
||||||
|
"
|
||||||
|
SELECT id
|
||||||
|
FROM euph_msgs
|
||||||
|
WHERE room = ?
|
||||||
|
AND NOT seen
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT 1
|
||||||
|
",
|
||||||
|
)?
|
||||||
|
.query_row([room], |row| row.get(0))
|
||||||
|
.optional()?;
|
||||||
|
let _ = result.send(tree);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_older_unseen_msg_id(
|
||||||
|
conn: &Connection,
|
||||||
|
room: String,
|
||||||
|
id: Snowflake,
|
||||||
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
|
) -> rusqlite::Result<()> {
|
||||||
|
let tree = conn
|
||||||
|
.prepare(
|
||||||
|
"
|
||||||
|
SELECT id
|
||||||
|
FROM euph_msgs
|
||||||
|
WHERE room = ?
|
||||||
|
AND NOT seen
|
||||||
|
AND id < ?
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT 1
|
||||||
|
",
|
||||||
|
)?
|
||||||
|
.query_row(params![room, id], |row| row.get(0))
|
||||||
|
.optional()?;
|
||||||
|
let _ = result.send(tree);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_newer_unseen_msg_id(
|
||||||
|
conn: &Connection,
|
||||||
|
room: String,
|
||||||
|
id: Snowflake,
|
||||||
|
result: oneshot::Sender<Option<Snowflake>>,
|
||||||
|
) -> rusqlite::Result<()> {
|
||||||
|
let tree = conn
|
||||||
|
.prepare(
|
||||||
|
"
|
||||||
|
SELECT id
|
||||||
|
FROM euph_msgs
|
||||||
|
WHERE room = ?
|
||||||
|
AND NOT seen
|
||||||
|
AND id > ?
|
||||||
|
ORDER BY id ASC
|
||||||
|
LIMIT 1
|
||||||
|
",
|
||||||
|
)?
|
||||||
|
.query_row(params![room, id], |row| row.get(0))
|
||||||
|
.optional()?;
|
||||||
|
let _ = result.send(tree);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn set_seen(
|
fn set_seen(
|
||||||
conn: &Connection,
|
conn: &Connection,
|
||||||
room: String,
|
room: String,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue