fractal/session/view/content/explore/
public_room.rs1use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*};
2use matrix_sdk::ruma::directory::PublicRoomsChunk;
3
4use crate::{
5 components::{AvatarData, AvatarImage, AvatarUriSource},
6 session::model::{Room, RoomList},
7};
8
9mod imp {
10 use std::cell::{Cell, OnceCell, RefCell};
11
12 use glib::signal::SignalHandlerId;
13
14 use super::*;
15
16 #[derive(Debug, Default, glib::Properties)]
17 #[properties(wrapper_type = super::PublicRoom)]
18 pub struct PublicRoom {
19 #[property(get, construct_only)]
21 pub room_list: OnceCell<RoomList>,
22 #[property(get, construct_only)]
24 pub server: OnceCell<String>,
25 pub matrix_public_room: OnceCell<PublicRoomsChunk>,
26 #[property(get)]
28 pub avatar_data: OnceCell<AvatarData>,
29 #[property(get)]
32 pub room: RefCell<Option<Room>>,
33 #[property(get)]
37 pub pending: Cell<bool>,
38 pub room_handler: RefCell<Option<SignalHandlerId>>,
39 }
40
41 #[glib::object_subclass]
42 impl ObjectSubclass for PublicRoom {
43 const NAME: &'static str = "PublicRoom";
44 type Type = super::PublicRoom;
45 }
46
47 #[glib::derived_properties]
48 impl ObjectImpl for PublicRoom {
49 fn constructed(&self) {
50 self.parent_constructed();
51 let obj = self.obj();
52
53 let avatar_data = if let Some(session) = obj.room_list().session() {
54 AvatarData::with_image(AvatarImage::new(
55 &session,
56 AvatarUriSource::Room,
57 None,
58 None,
59 ))
60 } else {
61 AvatarData::new()
62 };
63
64 self.avatar_data.set(avatar_data).unwrap();
65
66 obj.room_list().connect_pending_rooms_changed(clone!(
67 #[weak]
68 obj,
69 move |_| {
70 let Some(matrix_public_room) = obj.matrix_public_room() else {
71 return;
72 };
73
74 obj.set_pending(
75 obj.room_list()
76 .is_pending_room((*matrix_public_room.room_id).into()),
77 );
78 }
79 ));
80 }
81
82 fn dispose(&self) {
83 if let Some(handler_id) = self.room_handler.take() {
84 self.obj().room_list().disconnect(handler_id);
85 }
86 }
87 }
88}
89
90glib::wrapper! {
91 pub struct PublicRoom(ObjectSubclass<imp::PublicRoom>);
93}
94
95impl PublicRoom {
96 pub fn new(room_list: &RoomList, server: &str) -> Self {
97 glib::Object::builder()
98 .property("room-list", room_list)
99 .property("server", server)
100 .build()
101 }
102
103 fn set_room(&self, room: Room) {
105 self.imp().room.replace(Some(room));
106 self.notify_room();
107 }
108
109 fn set_pending(&self, pending: bool) {
111 if self.pending() == pending {
112 return;
113 }
114
115 self.imp().pending.set(pending);
116 self.notify_pending();
117 }
118
119 pub fn set_matrix_public_room(&self, room: PublicRoomsChunk) {
120 let imp = self.imp();
121
122 if let Some(display_name) = room.name.clone() {
123 self.avatar_data().set_display_name(display_name);
124 }
125 self.avatar_data()
126 .image()
127 .unwrap()
128 .set_uri_and_info(room.avatar_url.clone(), None);
129
130 if let Some(room) = self.room_list().get(&room.room_id) {
131 self.set_room(room);
132 } else {
133 let room_id = room.room_id.clone();
134 let handler_id = self.room_list().connect_items_changed(clone!(
135 #[weak(rename_to = obj)]
136 self,
137 move |room_list, _, _, _| {
138 if let Some(room) = room_list.get(&room_id) {
139 if let Some(handler_id) = obj.imp().room_handler.take() {
140 obj.set_room(room);
141 room_list.disconnect(handler_id);
142 }
143 }
144 }
145 ));
146
147 imp.room_handler.replace(Some(handler_id));
148 }
149
150 self.set_pending(self.room_list().is_pending_room((*room.room_id).into()));
151
152 imp.matrix_public_room.set(room).unwrap();
153 }
154
155 pub fn matrix_public_room(&self) -> Option<&PublicRoomsChunk> {
156 self.imp().matrix_public_room.get()
157 }
158
159 pub fn display_name(&self) -> String {
163 let Some(matrix_public_room) = self.matrix_public_room() else {
164 return String::new();
165 };
166
167 matrix_public_room
168 .name
169 .as_deref()
170 .or(matrix_public_room
171 .canonical_alias
172 .as_ref()
173 .map(|a| a.as_str()))
174 .unwrap_or_else(|| matrix_public_room.room_id.as_str())
175 .to_owned()
176 }
177}