matrix_sdk_base/response_processors/account_data/
room.rs

1// Copyright 2025 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 ruma::{
16    events::{marked_unread::MarkedUnreadEventContent, AnyRoomAccountDataEvent},
17    serde::Raw,
18    RoomId,
19};
20use tracing::{instrument, warn};
21
22use super::super::{Context, RoomInfoNotableUpdates};
23use crate::{store::BaseStateStore, RoomInfo, RoomInfoNotableUpdateReasons, StateChanges};
24
25#[instrument(skip_all, fields(?room_id))]
26pub async fn for_room(
27    context: &mut Context,
28    room_id: &RoomId,
29    events: &[Raw<AnyRoomAccountDataEvent>],
30    state_store: &BaseStateStore,
31) {
32    // Handle new events.
33    for raw_event in events {
34        match raw_event.deserialize() {
35            Ok(event) => {
36                context.state_changes.add_room_account_data(
37                    room_id,
38                    event.clone(),
39                    raw_event.clone(),
40                );
41
42                match event {
43                    AnyRoomAccountDataEvent::MarkedUnread(event) => {
44                        on_room_info(
45                            room_id,
46                            &mut context.state_changes,
47                            state_store,
48                            |room_info| {
49                                on_unread_marker(
50                                    room_id,
51                                    &event.content,
52                                    room_info,
53                                    &mut context.room_info_notable_updates,
54                                );
55                            },
56                        );
57                    }
58                    AnyRoomAccountDataEvent::UnstableMarkedUnread(event) => {
59                        on_room_info(
60                            room_id,
61                            &mut context.state_changes,
62                            state_store,
63                            |room_info| {
64                                on_unread_marker(
65                                    room_id,
66                                    &event.content.0,
67                                    room_info,
68                                    &mut context.room_info_notable_updates,
69                                );
70                            },
71                        );
72                    }
73                    AnyRoomAccountDataEvent::Tag(event) => {
74                        on_room_info(
75                            room_id,
76                            &mut context.state_changes,
77                            state_store,
78                            |room_info| {
79                                room_info.base_info.handle_notable_tags(&event.content.tags);
80                            },
81                        );
82                    }
83
84                    // Nothing.
85                    _ => {}
86                }
87            }
88
89            Err(err) => {
90                warn!("unable to deserialize account data event: {err}");
91            }
92        }
93    }
94}
95
96// Small helper to make the code easier to read.
97//
98// It finds the appropriate `RoomInfo`, allowing the caller to modify it, and
99// save it in the correct place.
100fn on_room_info<F>(
101    room_id: &RoomId,
102    state_changes: &mut StateChanges,
103    state_store: &BaseStateStore,
104    mut on_room_info: F,
105) where
106    F: FnMut(&mut RoomInfo),
107{
108    // `StateChanges` has the `RoomInfo`.
109    if let Some(room_info) = state_changes.room_infos.get_mut(room_id) {
110        // Show time.
111        on_room_info(room_info);
112    }
113    // The `BaseStateStore` has the `Room`, which has the `RoomInfo`.
114    else if let Some(room) = state_store.room(room_id) {
115        // Clone the `RoomInfo`.
116        let mut room_info = room.clone_info();
117
118        // Show time.
119        on_room_info(&mut room_info);
120
121        // Update the `RoomInfo` via `StateChanges`.
122        state_changes.add_room(room_info);
123    }
124}
125
126// Helper to update the unread marker for stable and unstable prefixes.
127fn on_unread_marker(
128    room_id: &RoomId,
129    content: &MarkedUnreadEventContent,
130    room_info: &mut RoomInfo,
131    room_info_notable_updates: &mut RoomInfoNotableUpdates,
132) {
133    if room_info.base_info.is_marked_unread != content.unread {
134        // Notify the room list about a manual read marker change if the
135        // value's changed.
136        room_info_notable_updates
137            .entry(room_id.to_owned())
138            .or_default()
139            .insert(RoomInfoNotableUpdateReasons::UNREAD_MARKER);
140    }
141
142    room_info.base_info.is_marked_unread = content.unread;
143}