matrix_sdk_ui/room_list_service/filters/
unread.rs

1// Copyright 2024 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use matrix_sdk_base::read_receipts::RoomReadReceipts;
16
17use super::{super::Room, Filter};
18
19type IsMarkedUnread = bool;
20
21struct UnreadRoomMatcher<F>
22where
23    F: Fn(&Room) -> (RoomReadReceipts, IsMarkedUnread),
24{
25    read_receipts_and_unread: F,
26}
27
28impl<F> UnreadRoomMatcher<F>
29where
30    F: Fn(&Room) -> (RoomReadReceipts, IsMarkedUnread),
31{
32    fn matches(&self, room: &Room) -> bool {
33        let (read_receipts, is_marked_unread) = (self.read_receipts_and_unread)(room);
34
35        read_receipts.num_notifications > 0 || is_marked_unread
36    }
37}
38
39/// Create a new filter that will filter out rooms that have no unread
40/// notifications (different from unread messages), or is not marked as unread.
41pub fn new_filter() -> impl Filter {
42    let matcher = UnreadRoomMatcher {
43        read_receipts_and_unread: move |room| (room.read_receipts(), room.is_marked_unread()),
44    };
45
46    move |room_list_entry| -> bool { matcher.matches(room_list_entry) }
47}
48
49#[cfg(test)]
50mod tests {
51    use std::ops::Not;
52
53    use matrix_sdk::test_utils::logged_in_client_with_server;
54    use matrix_sdk_base::read_receipts::RoomReadReceipts;
55    use matrix_sdk_test::async_test;
56    use ruma::room_id;
57
58    use super::{super::new_rooms, *};
59
60    #[async_test]
61    async fn test_has_unread_notifications() {
62        let (client, server) = logged_in_client_with_server().await;
63        let [room] = new_rooms([room_id!("!a:b.c")], &client, &server).await;
64
65        for is_marked_as_unread in [true, false] {
66            let matcher = UnreadRoomMatcher {
67                read_receipts_and_unread: |_| {
68                    let mut read_receipts = RoomReadReceipts::default();
69                    read_receipts.num_unread = 42;
70                    read_receipts.num_notifications = 42;
71
72                    (read_receipts, is_marked_as_unread)
73                },
74            };
75
76            assert!(matcher.matches(&room));
77        }
78    }
79
80    #[async_test]
81    async fn test_has_unread_messages_but_no_unread_notifications_and_is_not_marked_as_unread() {
82        let (client, server) = logged_in_client_with_server().await;
83        let [room] = new_rooms([room_id!("!a:b.c")], &client, &server).await;
84
85        let matcher = UnreadRoomMatcher {
86            read_receipts_and_unread: |_| {
87                let mut read_receipts = RoomReadReceipts::default();
88                read_receipts.num_unread = 42;
89                read_receipts.num_notifications = 0;
90
91                (read_receipts, false)
92            },
93        };
94
95        assert!(matcher.matches(&room).not());
96    }
97
98    #[async_test]
99    async fn test_has_unread_messages_but_no_unread_notifications_and_is_marked_as_unread() {
100        let (client, server) = logged_in_client_with_server().await;
101        let [room] = new_rooms([room_id!("!a:b.c")], &client, &server).await;
102
103        let matcher = UnreadRoomMatcher {
104            read_receipts_and_unread: |_| {
105                let mut read_receipts = RoomReadReceipts::default();
106                read_receipts.num_unread = 42;
107                read_receipts.num_notifications = 0;
108
109                (read_receipts, true)
110            },
111        };
112
113        assert!(matcher.matches(&room));
114    }
115
116    #[async_test]
117    async fn test_has_no_unread_notifications_and_is_not_marked_as_unread() {
118        let (client, server) = logged_in_client_with_server().await;
119        let [room] = new_rooms([room_id!("!a:b.c")], &client, &server).await;
120
121        let matcher = UnreadRoomMatcher {
122            read_receipts_and_unread: |_| (RoomReadReceipts::default(), false),
123        };
124
125        assert!(matcher.matches(&room).not());
126    }
127
128    #[async_test]
129    async fn test_has_no_unread_notifications_and_is_marked_as_unread() {
130        let (client, server) = logged_in_client_with_server().await;
131        let [room] = new_rooms([room_id!("!a:b.c")], &client, &server).await;
132
133        let matcher =
134            UnreadRoomMatcher { read_receipts_and_unread: |_| (RoomReadReceipts::default(), true) };
135
136        assert!(matcher.matches(&room));
137    }
138}