matrix_sdk_ui/spaces/
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 that specific language governing permissions and
13// limitations under the License.
14
15use matrix_sdk::{Room, RoomHero, RoomState};
16use ruma::{
17    OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedServerName,
18    events::room::{guest_access::GuestAccess, history_visibility::HistoryVisibility},
19    room::{JoinRuleSummary, RoomSummary, RoomType},
20};
21
22/// Structure representing a room in a space and aggregated information
23/// relevant to the UI layer.
24#[derive(Debug, Clone, PartialEq)]
25pub struct SpaceRoom {
26    /// The ID of the room.
27    pub room_id: OwnedRoomId,
28    /// The canonical alias of the room, if any.
29    pub canonical_alias: Option<OwnedRoomAliasId>,
30    /// The name of the room, if any.
31    pub name: Option<String>,
32    /// Calculated display name based on the room's name, aliases, and members.
33    pub display_name: String,
34    /// The topic of the room, if any.
35    pub topic: Option<String>,
36    /// The URL for the room's avatar, if one is set.
37    pub avatar_url: Option<OwnedMxcUri>,
38    /// The type of room from `m.room.create`, if any.
39    pub room_type: Option<RoomType>,
40    /// The number of members joined to the room.
41    pub num_joined_members: u64,
42    /// The join rule of the room.
43    pub join_rule: Option<JoinRuleSummary>,
44    /// Whether the room may be viewed by users without joining.
45    pub world_readable: Option<bool>,
46    /// Whether guest users may join the room and participate in it.
47    pub guest_can_join: bool,
48
49    /// Whether this room is a direct room.
50    ///
51    /// Only set if the room is known to the client otherwise we
52    /// assume DMs shouldn't be exposed publicly in spaces.
53    pub is_direct: Option<bool>,
54    /// The number of children room this has, if a space.
55    pub children_count: u64,
56    /// Whether this room is joined, left etc.
57    pub state: Option<RoomState>,
58    /// A list of room members considered to be heroes.
59    pub heroes: Option<Vec<RoomHero>>,
60    /// The via parameters of the room.
61    pub via: Vec<OwnedServerName>,
62}
63
64impl SpaceRoom {
65    /// Build a `SpaceRoom` from a `RoomSummary` received from the /hierarchy
66    /// endpoint.
67    pub(crate) fn new_from_summary(
68        summary: &RoomSummary,
69        known_room: Option<Room>,
70        children_count: u64,
71        via: Vec<OwnedServerName>,
72    ) -> Self {
73        let display_name = matrix_sdk_base::Room::compute_display_name_with_fields(
74            summary.name.clone(),
75            summary.canonical_alias.as_deref(),
76            known_room.as_ref().map(|r| r.heroes().to_vec()).unwrap_or_default(),
77            summary.num_joined_members.into(),
78        )
79        .to_string();
80
81        Self {
82            room_id: summary.room_id.clone(),
83            canonical_alias: summary.canonical_alias.clone(),
84            name: summary.name.clone(),
85            display_name,
86            topic: summary.topic.clone(),
87            avatar_url: summary.avatar_url.clone(),
88            room_type: summary.room_type.clone(),
89            num_joined_members: summary.num_joined_members.into(),
90            join_rule: Some(summary.join_rule.clone()),
91            world_readable: Some(summary.world_readable),
92            guest_can_join: summary.guest_can_join,
93            is_direct: known_room.as_ref().map(|r| r.direct_targets_length() != 0),
94            children_count,
95            state: known_room.as_ref().map(|r| r.state()),
96            heroes: known_room.map(|r| r.heroes()),
97            via,
98        }
99    }
100
101    /// Build a `SpaceRoom` from a room already known to this client.
102    pub(crate) fn new_from_known(known_room: &Room, children_count: u64) -> Self {
103        let room_info = known_room.clone_info();
104
105        let name = room_info.name().map(ToOwned::to_owned);
106        let display_name = matrix_sdk_base::Room::compute_display_name_with_fields(
107            name.clone(),
108            room_info.canonical_alias(),
109            room_info.heroes().to_vec(),
110            known_room.joined_members_count(),
111        )
112        .to_string();
113
114        Self {
115            room_id: room_info.room_id().to_owned(),
116            canonical_alias: room_info.canonical_alias().map(ToOwned::to_owned),
117            name,
118            display_name,
119            topic: room_info.topic().map(ToOwned::to_owned),
120            avatar_url: room_info.avatar_url().map(ToOwned::to_owned),
121            room_type: room_info.room_type().cloned(),
122            num_joined_members: known_room.joined_members_count(),
123            join_rule: room_info.join_rule().cloned().map(Into::into),
124            world_readable: room_info
125                .history_visibility()
126                .map(|vis| *vis == HistoryVisibility::WorldReadable),
127            guest_can_join: known_room.guest_access() == GuestAccess::CanJoin,
128            is_direct: Some(known_room.direct_targets_length() != 0),
129            children_count,
130            state: Some(known_room.state()),
131            heroes: Some(room_info.heroes().to_vec()),
132            via: vec![],
133        }
134    }
135}