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