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}