Support an "invite" field in the room sorting settings (#395)

Co-authored-by: Felix Van der Jeugt <felix.vanderjeugt@posteo.net>
This commit is contained in:
Felix Van der Jeugt 2025-05-15 04:39:22 +02:00 committed by GitHub
parent 1dcd658928
commit 7dd09e32a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 109 additions and 1 deletions

View file

@ -334,6 +334,26 @@ window.
Defaults to Defaults to
.Sy ["power",\ "id"] . .Sy ["power",\ "id"] .
.El .El
The available values are:
.Bl -tag -width Ds
.It Sy favorite
Put favorite rooms before other rooms.
.It Sy lowpriority
Put lowpriority rooms after other rooms.
.It Sy name
Sort rooms by alphabetically ascending room name.
.It Sy alias
Sort rooms by alphabetically ascending canonical room alias.
.It Sy id
Sort rooms by alphabetically ascending Matrix room identifier.
.It Sy unread
Put unread rooms before other rooms.
.It Sy recent
Sort rooms by most recent message timestamp.
.It Sy invite
Put invites before other rooms.
.El
.El .El
.Ss Example 1: Group room members by their server first .Ss Example 1: Group room members by their server first

View file

@ -243,6 +243,9 @@ pub enum SortFieldRoom {
/// Sort rooms by the timestamps of their most recent messages. /// Sort rooms by the timestamps of their most recent messages.
Recent, Recent,
/// Sort rooms by whether they are invites.
Invite,
} }
/// Fields that users can be sorted by. /// Fields that users can be sorted by.
@ -307,6 +310,7 @@ impl<'de> Visitor<'de> for SortRoomVisitor {
"name" => SortFieldRoom::Name, "name" => SortFieldRoom::Name,
"alias" => SortFieldRoom::Alias, "alias" => SortFieldRoom::Alias,
"id" => SortFieldRoom::RoomId, "id" => SortFieldRoom::RoomId,
"invite" => SortFieldRoom::Invite,
_ => { _ => {
let msg = format!("Unknown sort field: {value:?}"); let msg = format!("Unknown sort field: {value:?}");
return Err(E::custom(msg)); return Err(E::custom(msg));

View file

@ -45,8 +45,9 @@ const DEFAULT_MEMBERS_SORT: [SortColumn<SortFieldUser>; 2] = [
SortColumn(SortFieldUser::UserId, SortOrder::Ascending), SortColumn(SortFieldUser::UserId, SortOrder::Ascending),
]; ];
const DEFAULT_ROOM_SORT: [SortColumn<SortFieldRoom>; 4] = [ const DEFAULT_ROOM_SORT: [SortColumn<SortFieldRoom>; 5] = [
SortColumn(SortFieldRoom::Favorite, SortOrder::Ascending), SortColumn(SortFieldRoom::Favorite, SortOrder::Ascending),
SortColumn(SortFieldRoom::Invite, SortOrder::Ascending),
SortColumn(SortFieldRoom::LowPriority, SortOrder::Ascending), SortColumn(SortFieldRoom::LowPriority, SortOrder::Ascending),
SortColumn(SortFieldRoom::Unread, SortOrder::Ascending), SortColumn(SortFieldRoom::Unread, SortOrder::Ascending),
SortColumn(SortFieldRoom::Name, SortOrder::Ascending), SortColumn(SortFieldRoom::Name, SortOrder::Ascending),

View file

@ -23,6 +23,7 @@ use matrix_sdk::{
RoomAliasId, RoomAliasId,
RoomId, RoomId,
}, },
RoomState as MatrixRoomState,
}; };
use ratatui::{ use ratatui::{
@ -195,6 +196,10 @@ fn room_cmp<T: RoomLikeItem>(a: &T, b: &T, field: &SortFieldRoom) -> Ordering {
// sort larger timestamps towards the top. // sort larger timestamps towards the top.
some_cmp(a.recent_ts(), b.recent_ts(), |a, b| b.cmp(a)) some_cmp(a.recent_ts(), b.recent_ts(), |a, b| b.cmp(a))
}, },
SortFieldRoom::Invite => {
// sort invites before other rooms.
b.is_invite().cmp(&a.is_invite())
},
} }
} }
@ -273,6 +278,7 @@ trait RoomLikeItem {
fn recent_ts(&self) -> Option<&MessageTimeStamp>; fn recent_ts(&self) -> Option<&MessageTimeStamp>;
fn alias(&self) -> Option<&RoomAliasId>; fn alias(&self) -> Option<&RoomAliasId>;
fn name(&self) -> &str; fn name(&self) -> &str;
fn is_invite(&self) -> bool;
} }
#[inline] #[inline]
@ -914,6 +920,10 @@ impl RoomLikeItem for GenericChatItem {
fn is_unread(&self) -> bool { fn is_unread(&self) -> bool {
self.unread.is_unread() self.unread.is_unread()
} }
fn is_invite(&self) -> bool {
self.room().state() == MatrixRoomState::Invited
}
} }
impl Display for GenericChatItem { impl Display for GenericChatItem {
@ -1024,6 +1034,10 @@ impl RoomLikeItem for RoomItem {
fn is_unread(&self) -> bool { fn is_unread(&self) -> bool {
self.unread.is_unread() self.unread.is_unread()
} }
fn is_invite(&self) -> bool {
self.room().state() == MatrixRoomState::Invited
}
} }
impl Display for RoomItem { impl Display for RoomItem {
@ -1124,6 +1138,10 @@ impl RoomLikeItem for DirectItem {
fn is_unread(&self) -> bool { fn is_unread(&self) -> bool {
self.unread.is_unread() self.unread.is_unread()
} }
fn is_invite(&self) -> bool {
self.room().state() == MatrixRoomState::Invited
}
} }
impl Display for DirectItem { impl Display for DirectItem {
@ -1223,6 +1241,10 @@ impl RoomLikeItem for SpaceItem {
// XXX: this needs to check whether the space contains rooms with unread messages // XXX: this needs to check whether the space contains rooms with unread messages
false false
} }
fn is_invite(&self) -> bool {
self.room().state() == MatrixRoomState::Invited
}
} }
impl Display for SpaceItem { impl Display for SpaceItem {
@ -1556,6 +1578,7 @@ mod tests {
alias: Option<OwnedRoomAliasId>, alias: Option<OwnedRoomAliasId>,
name: &'static str, name: &'static str,
unread: UnreadInfo, unread: UnreadInfo,
invite: bool,
} }
impl RoomLikeItem for &TestRoomItem { impl RoomLikeItem for &TestRoomItem {
@ -1582,6 +1605,10 @@ mod tests {
fn is_unread(&self) -> bool { fn is_unread(&self) -> bool {
self.unread.is_unread() self.unread.is_unread()
} }
fn is_invite(&self) -> bool {
self.invite
}
} }
#[test] #[test]
@ -1594,6 +1621,7 @@ mod tests {
alias: Some(room_alias_id!("#room1:example.com").to_owned()), alias: Some(room_alias_id!("#room1:example.com").to_owned()),
name: "Z", name: "Z",
unread: UnreadInfo::default(), unread: UnreadInfo::default(),
invite: false,
}; };
let room2 = TestRoomItem { let room2 = TestRoomItem {
@ -1602,6 +1630,7 @@ mod tests {
alias: Some(room_alias_id!("#a:example.com").to_owned()), alias: Some(room_alias_id!("#a:example.com").to_owned()),
name: "Unnamed Room", name: "Unnamed Room",
unread: UnreadInfo::default(), unread: UnreadInfo::default(),
invite: false,
}; };
let room3 = TestRoomItem { let room3 = TestRoomItem {
@ -1610,6 +1639,7 @@ mod tests {
alias: None, alias: None,
name: "Cool Room", name: "Cool Room",
unread: UnreadInfo::default(), unread: UnreadInfo::default(),
invite: false,
}; };
// Sort by Name ascending. // Sort by Name ascending.
@ -1655,6 +1685,7 @@ mod tests {
alias: None, alias: None,
name: "Room 1", name: "Room 1",
unread: UnreadInfo { unread: false, latest: None }, unread: UnreadInfo { unread: false, latest: None },
invite: false,
}; };
let room2 = TestRoomItem { let room2 = TestRoomItem {
@ -1666,6 +1697,7 @@ mod tests {
unread: false, unread: false,
latest: Some(MessageTimeStamp::OriginServer(40u32.into())), latest: Some(MessageTimeStamp::OriginServer(40u32.into())),
}, },
invite: false,
}; };
let room3 = TestRoomItem { let room3 = TestRoomItem {
@ -1677,6 +1709,7 @@ mod tests {
unread: false, unread: false,
latest: Some(MessageTimeStamp::OriginServer(20u32.into())), latest: Some(MessageTimeStamp::OriginServer(20u32.into())),
}, },
invite: false,
}; };
// Sort by Recent ascending. // Sort by Recent ascending.
@ -1691,4 +1724,54 @@ mod tests {
rooms.sort_by(|a, b| room_fields_cmp(a, b, fields)); rooms.sort_by(|a, b| room_fields_cmp(a, b, fields));
assert_eq!(rooms, vec![&room1, &room3, &room2]); assert_eq!(rooms, vec![&room1, &room3, &room2]);
} }
#[test]
fn test_sort_room_invites() {
let server = server_name!("example.com");
let room1 = TestRoomItem {
room_id: RoomId::new(server).to_owned(),
tags: vec![],
alias: None,
name: "Old room 1",
unread: UnreadInfo::default(),
invite: false,
};
let room2 = TestRoomItem {
room_id: RoomId::new(server).to_owned(),
tags: vec![],
alias: None,
name: "Old room 2",
unread: UnreadInfo::default(),
invite: false,
};
let room3 = TestRoomItem {
room_id: RoomId::new(server).to_owned(),
tags: vec![],
alias: None,
name: "New Fancy Room",
unread: UnreadInfo::default(),
invite: true,
};
// Sort invites first
let mut rooms = vec![&room1, &room2, &room3];
let fields = &[
SortColumn(SortFieldRoom::Invite, SortOrder::Ascending),
SortColumn(SortFieldRoom::Name, SortOrder::Ascending),
];
rooms.sort_by(|a, b| room_fields_cmp(a, b, fields));
assert_eq!(rooms, vec![&room3, &room1, &room2]);
// Sort invites after
let mut rooms = vec![&room1, &room2, &room3];
let fields = &[
SortColumn(SortFieldRoom::Invite, SortOrder::Descending),
SortColumn(SortFieldRoom::Name, SortOrder::Ascending),
];
rooms.sort_by(|a, b| room_fields_cmp(a, b, fields));
assert_eq!(rooms, vec![&room1, &room2, &room3]);
}
} }