mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Add commands for viewing and clearing unreads (#332)
This commit is contained in:
parent
4fc05c7b40
commit
480888a1fc
5 changed files with 135 additions and 0 deletions
|
@ -61,6 +61,8 @@ Log out of
|
|||
View a list of joined rooms.
|
||||
.It Sy ":spaces"
|
||||
View a list of joined spaces.
|
||||
.It Sy ":unreads"
|
||||
View a list of unread rooms.
|
||||
.It Sy ":welcome"
|
||||
View the startup Welcome window.
|
||||
.El
|
||||
|
@ -95,6 +97,8 @@ React to the selected message with an Emoji.
|
|||
Redact the selected message.
|
||||
.It Sy ":reply"
|
||||
Reply to the selected message.
|
||||
.It Sy ":unreads clear"
|
||||
Mark all unread rooms as read.
|
||||
.It Sy ":unreact [shortcode]"
|
||||
Remove your reaction from the selected message.
|
||||
When no arguments are given, remove all of your reactions from the message.
|
||||
|
|
45
src/base.rs
45
src/base.rs
|
@ -510,6 +510,9 @@ pub enum IambAction {
|
|||
|
||||
/// Toggle the focus within the focused room.
|
||||
ToggleScrollbackFocus,
|
||||
|
||||
/// Clear all unread messages.
|
||||
ClearUnreads,
|
||||
}
|
||||
|
||||
impl IambAction {
|
||||
|
@ -546,6 +549,7 @@ impl From<SendAction> for IambAction {
|
|||
impl ApplicationAction for IambAction {
|
||||
fn is_edit_sequence(&self, _: &EditContext) -> SequenceStatus {
|
||||
match self {
|
||||
IambAction::ClearUnreads => SequenceStatus::Break,
|
||||
IambAction::Homeserver(..) => SequenceStatus::Break,
|
||||
IambAction::Keys(..) => SequenceStatus::Break,
|
||||
IambAction::Message(..) => SequenceStatus::Break,
|
||||
|
@ -560,6 +564,7 @@ impl ApplicationAction for IambAction {
|
|||
|
||||
fn is_last_action(&self, _: &EditContext) -> SequenceStatus {
|
||||
match self {
|
||||
IambAction::ClearUnreads => SequenceStatus::Atom,
|
||||
IambAction::Homeserver(..) => SequenceStatus::Atom,
|
||||
IambAction::Keys(..) => SequenceStatus::Atom,
|
||||
IambAction::Message(..) => SequenceStatus::Atom,
|
||||
|
@ -574,6 +579,7 @@ impl ApplicationAction for IambAction {
|
|||
|
||||
fn is_last_selection(&self, _: &EditContext) -> SequenceStatus {
|
||||
match self {
|
||||
IambAction::ClearUnreads => SequenceStatus::Ignore,
|
||||
IambAction::Homeserver(..) => SequenceStatus::Ignore,
|
||||
IambAction::Keys(..) => SequenceStatus::Ignore,
|
||||
IambAction::Message(..) => SequenceStatus::Ignore,
|
||||
|
@ -588,6 +594,7 @@ impl ApplicationAction for IambAction {
|
|||
|
||||
fn is_switchable(&self, _: &EditContext) -> bool {
|
||||
match self {
|
||||
IambAction::ClearUnreads => false,
|
||||
IambAction::Homeserver(..) => false,
|
||||
IambAction::Message(..) => false,
|
||||
IambAction::Room(..) => false,
|
||||
|
@ -1148,6 +1155,14 @@ impl RoomInfo {
|
|||
self.user_receipts.insert(user_id, event_id);
|
||||
}
|
||||
|
||||
pub fn fully_read(&mut self, user_id: OwnedUserId) {
|
||||
let Some(((_, event_id), _)) = self.messages.last_key_value() else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.set_receipt(user_id, event_id.clone());
|
||||
}
|
||||
|
||||
pub fn get_receipt(&self, user_id: &UserId) -> Option<&OwnedEventId> {
|
||||
self.user_receipts.get(user_id)
|
||||
}
|
||||
|
@ -1309,6 +1324,20 @@ pub struct SyncInfo {
|
|||
pub dms: Vec<Arc<(MatrixRoom, Option<Tags>)>>,
|
||||
}
|
||||
|
||||
impl SyncInfo {
|
||||
pub fn rooms(&self) -> impl Iterator<Item = &RoomId> {
|
||||
self.rooms.iter().map(|r| r.0.room_id())
|
||||
}
|
||||
|
||||
pub fn dms(&self) -> impl Iterator<Item = &RoomId> {
|
||||
self.dms.iter().map(|r| r.0.room_id())
|
||||
}
|
||||
|
||||
pub fn chats(&self) -> impl Iterator<Item = &RoomId> {
|
||||
self.rooms().chain(self.dms())
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// Load-needs
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
|
@ -1480,6 +1509,9 @@ pub enum IambId {
|
|||
|
||||
/// The `:chats` window.
|
||||
ChatList,
|
||||
|
||||
/// The `:unreads` window.
|
||||
UnreadList,
|
||||
}
|
||||
|
||||
impl Display for IambId {
|
||||
|
@ -1500,6 +1532,7 @@ impl Display for IambId {
|
|||
IambId::VerifyList => f.write_str("iamb://verify"),
|
||||
IambId::Welcome => f.write_str("iamb://welcome"),
|
||||
IambId::ChatList => f.write_str("iamb://chats"),
|
||||
IambId::UnreadList => f.write_str("iamb://unreads"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1631,6 +1664,13 @@ impl<'de> Visitor<'de> for IambIdVisitor {
|
|||
|
||||
Ok(IambId::ChatList)
|
||||
},
|
||||
Some("unreads") => {
|
||||
if url.path() != "" {
|
||||
return Err(E::custom("iamb://unreads takes no path"));
|
||||
}
|
||||
|
||||
Ok(IambId::UnreadList)
|
||||
},
|
||||
Some(s) => Err(E::custom(format!("{s:?} is not a valid window"))),
|
||||
None => Err(E::custom("Invalid iamb window URL")),
|
||||
}
|
||||
|
@ -1691,6 +1731,9 @@ pub enum IambBufferId {
|
|||
|
||||
/// The `:chats` window.
|
||||
ChatList,
|
||||
|
||||
/// The `:unreads` window.
|
||||
UnreadList,
|
||||
}
|
||||
|
||||
impl IambBufferId {
|
||||
|
@ -1706,6 +1749,7 @@ impl IambBufferId {
|
|||
IambBufferId::VerifyList => IambId::VerifyList,
|
||||
IambBufferId::Welcome => IambId::Welcome,
|
||||
IambBufferId::ChatList => IambId::ChatList,
|
||||
IambBufferId::UnreadList => IambId::UnreadList,
|
||||
};
|
||||
|
||||
Some(id)
|
||||
|
@ -1740,6 +1784,7 @@ impl ApplicationInfo for IambInfo {
|
|||
IambBufferId::VerifyList => vec![],
|
||||
IambBufferId::Welcome => vec![],
|
||||
IambBufferId::ChatList => vec![],
|
||||
IambBufferId::UnreadList => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -307,6 +307,30 @@ fn iamb_chats(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
|||
return Ok(step);
|
||||
}
|
||||
|
||||
fn iamb_unreads(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||
let mut args = desc.arg.strings()?;
|
||||
|
||||
if args.len() > 1 {
|
||||
return Result::Err(CommandError::InvalidArgument);
|
||||
}
|
||||
|
||||
match args.pop().as_deref() {
|
||||
Some("clear") => {
|
||||
let clear = IambAction::ClearUnreads;
|
||||
let step = CommandStep::Continue(clear.into(), ctx.context.clone());
|
||||
|
||||
return Ok(step);
|
||||
},
|
||||
Some(_) => return Result::Err(CommandError::InvalidArgument),
|
||||
None => {
|
||||
let open = ctx.switch(OpenTarget::Application(IambId::UnreadList));
|
||||
let step = CommandStep::Continue(open, ctx.context.clone());
|
||||
|
||||
return Ok(step);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn iamb_spaces(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||
if !desc.arg.text.is_empty() {
|
||||
return Result::Err(CommandError::InvalidArgument);
|
||||
|
@ -648,6 +672,11 @@ fn add_iamb_commands(cmds: &mut ProgramCommands) {
|
|||
aliases: vec![],
|
||||
f: iamb_spaces,
|
||||
});
|
||||
cmds.add_command(ProgramCommand {
|
||||
name: "unreads".into(),
|
||||
aliases: vec![],
|
||||
f: iamb_unreads,
|
||||
});
|
||||
cmds.add_command(ProgramCommand {
|
||||
name: "unreact".into(),
|
||||
aliases: vec![],
|
||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -529,6 +529,18 @@ impl Application {
|
|||
}
|
||||
|
||||
let info = match action {
|
||||
IambAction::ClearUnreads => {
|
||||
let user_id = &store.application.settings.profile.user_id;
|
||||
|
||||
for room_id in store.application.sync_info.chats() {
|
||||
if let Some(room) = store.application.rooms.get_mut(room_id) {
|
||||
room.fully_read(user_id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
},
|
||||
|
||||
IambAction::ToggleScrollbackFocus => {
|
||||
self.screen.current_window_mut()?.focus_toggle();
|
||||
|
||||
|
|
|
@ -315,6 +315,7 @@ macro_rules! delegate {
|
|||
IambWindow::VerifyList($id) => $e,
|
||||
IambWindow::Welcome($id) => $e,
|
||||
IambWindow::ChatList($id) => $e,
|
||||
IambWindow::UnreadList($id) => $e,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -328,6 +329,7 @@ pub enum IambWindow {
|
|||
SpaceList(SpaceListState),
|
||||
Welcome(WelcomeState),
|
||||
ChatList(ChatListState),
|
||||
UnreadList(UnreadListState),
|
||||
}
|
||||
|
||||
impl IambWindow {
|
||||
|
@ -383,6 +385,7 @@ pub type DirectListState = ListState<DirectItem, IambInfo>;
|
|||
pub type MemberListState = ListState<MemberItem, IambInfo>;
|
||||
pub type RoomListState = ListState<RoomItem, IambInfo>;
|
||||
pub type ChatListState = ListState<GenericChatItem, IambInfo>;
|
||||
pub type UnreadListState = ListState<GenericChatItem, IambInfo>;
|
||||
pub type SpaceListState = ListState<SpaceItem, IambInfo>;
|
||||
pub type VerifyListState = ListState<VerifyItem, IambInfo>;
|
||||
|
||||
|
@ -579,6 +582,39 @@ impl WindowOps<IambInfo> for IambWindow {
|
|||
.focus(focused)
|
||||
.render(area, buf, state);
|
||||
},
|
||||
IambWindow::UnreadList(state) => {
|
||||
let mut items = store
|
||||
.application
|
||||
.sync_info
|
||||
.rooms
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|room_info| GenericChatItem::new(room_info, store, false))
|
||||
.filter(RoomLikeItem::is_unread)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let dms = store
|
||||
.application
|
||||
.sync_info
|
||||
.dms
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|room_info| GenericChatItem::new(room_info, store, true))
|
||||
.filter(RoomLikeItem::is_unread);
|
||||
|
||||
items.extend(dms);
|
||||
|
||||
let fields = &store.application.settings.tunables.sort.chats;
|
||||
items.sort_by(|a, b| room_fields_cmp(a, b, fields));
|
||||
|
||||
state.set(items);
|
||||
|
||||
List::new(store)
|
||||
.empty_message("You do not have rooms or dms yet")
|
||||
.empty_alignment(Alignment::Center)
|
||||
.focus(focused)
|
||||
.render(area, buf, state);
|
||||
},
|
||||
IambWindow::SpaceList(state) => {
|
||||
let mut items = store
|
||||
.application
|
||||
|
@ -630,6 +666,7 @@ impl WindowOps<IambInfo> for IambWindow {
|
|||
IambWindow::VerifyList(w) => w.dup(store).into(),
|
||||
IambWindow::Welcome(w) => w.dup(store).into(),
|
||||
IambWindow::ChatList(w) => w.dup(store).into(),
|
||||
IambWindow::UnreadList(w) => w.dup(store).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,6 +707,7 @@ impl Window<IambInfo> for IambWindow {
|
|||
IambWindow::VerifyList(_) => IambId::VerifyList,
|
||||
IambWindow::Welcome(_) => IambId::Welcome,
|
||||
IambWindow::ChatList(_) => IambId::ChatList,
|
||||
IambWindow::UnreadList(_) => IambId::UnreadList,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -681,6 +719,7 @@ impl Window<IambInfo> for IambWindow {
|
|||
IambWindow::VerifyList(_) => bold_spans("Verifications"),
|
||||
IambWindow::Welcome(_) => bold_spans("Welcome to iamb"),
|
||||
IambWindow::ChatList(_) => bold_spans("DMs & Rooms"),
|
||||
IambWindow::UnreadList(_) => bold_spans("Unread Messages"),
|
||||
|
||||
IambWindow::Room(w) => {
|
||||
let title = store.application.get_room_title(w.id());
|
||||
|
@ -708,6 +747,7 @@ impl Window<IambInfo> for IambWindow {
|
|||
IambWindow::VerifyList(_) => bold_spans("Verifications"),
|
||||
IambWindow::Welcome(_) => bold_spans("Welcome to iamb"),
|
||||
IambWindow::ChatList(_) => bold_spans("DMs & Rooms"),
|
||||
IambWindow::UnreadList(_) => bold_spans("Unread Messages"),
|
||||
|
||||
IambWindow::Room(w) => w.get_title(store),
|
||||
IambWindow::MemberList(state, room_id, _) => {
|
||||
|
@ -769,6 +809,11 @@ impl Window<IambInfo> for IambWindow {
|
|||
|
||||
Ok(list.into())
|
||||
},
|
||||
IambId::UnreadList => {
|
||||
let list = UnreadListState::new(IambBufferId::UnreadList, vec![]);
|
||||
|
||||
Ok(IambWindow::UnreadList(list))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue