Skip to content

Commit

Permalink
Add commands for viewing and clearing unreads (#332)
Browse files Browse the repository at this point in the history
  • Loading branch information
ulyssa authored Aug 21, 2024
1 parent 4fc05c7 commit 480888a
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/iamb.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
45 changes: 45 additions & 0 deletions src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,9 @@ pub enum IambAction {

/// Toggle the focus within the focused room.
ToggleScrollbackFocus,

/// Clear all unread messages.
ClearUnreads,
}

impl IambAction {
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -1480,6 +1509,9 @@ pub enum IambId {

/// The `:chats` window.
ChatList,

/// The `:unreads` window.
UnreadList,
}

impl Display for IambId {
Expand All @@ -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"),
}
}
}
Expand Down Expand Up @@ -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")),
}
Expand Down Expand Up @@ -1691,6 +1731,9 @@ pub enum IambBufferId {

/// The `:chats` window.
ChatList,

/// The `:unreads` window.
UnreadList,
}

impl IambBufferId {
Expand All @@ -1706,6 +1749,7 @@ impl IambBufferId {
IambBufferId::VerifyList => IambId::VerifyList,
IambBufferId::Welcome => IambId::Welcome,
IambBufferId::ChatList => IambId::ChatList,
IambBufferId::UnreadList => IambId::UnreadList,
};

Some(id)
Expand Down Expand Up @@ -1740,6 +1784,7 @@ impl ApplicationInfo for IambInfo {
IambBufferId::VerifyList => vec![],
IambBufferId::Welcome => vec![],
IambBufferId::ChatList => vec![],
IambBufferId::UnreadList => vec![],
}
}

Expand Down
29 changes: 29 additions & 0 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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![],
Expand Down
12 changes: 12 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
45 changes: 45 additions & 0 deletions src/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ macro_rules! delegate {
IambWindow::VerifyList($id) => $e,
IambWindow::Welcome($id) => $e,
IambWindow::ChatList($id) => $e,
IambWindow::UnreadList($id) => $e,
}
};
}
Expand All @@ -328,6 +329,7 @@ pub enum IambWindow {
SpaceList(SpaceListState),
Welcome(WelcomeState),
ChatList(ChatListState),
UnreadList(UnreadListState),
}

impl IambWindow {
Expand Down Expand Up @@ -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>;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(),
}
}

Expand Down Expand Up @@ -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,
}
}

Expand All @@ -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());
Expand Down Expand Up @@ -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, _) => {
Expand Down Expand Up @@ -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))
},
}
}

Expand Down

0 comments on commit 480888a

Please sign in to comment.