fractal/session/view/content/room_history/
title.rs1use adw::{prelude::*, subclass::prelude::*};
2use gtk::{glib, glib::clone, CompositeTemplate};
3
4use crate::{prelude::*, session::model::Room, utils::BoundObjectWeakRef};
5
6mod imp {
7 use std::cell::RefCell;
8
9 use glib::subclass::InitializingObject;
10
11 use super::*;
12
13 #[derive(Debug, Default, CompositeTemplate, glib::Properties)]
14 #[template(resource = "/org/gnome/Fractal/ui/session/view/content/room_history/title.ui")]
15 #[properties(wrapper_type = super::RoomHistoryTitle)]
16 pub struct RoomHistoryTitle {
17 #[template_child]
18 button: TemplateChild<gtk::Button>,
19 #[template_child]
20 subtitle_label: TemplateChild<gtk::Label>,
21 #[property(get, set = Self::set_room, explicit_notify, nullable)]
23 room: BoundObjectWeakRef<Room>,
24 #[property(get)]
26 title: RefCell<String>,
27 #[property(get)]
29 subtitle: RefCell<Option<String>>,
30 }
31
32 #[glib::object_subclass]
33 impl ObjectSubclass for RoomHistoryTitle {
34 const NAME: &'static str = "RoomHistoryTitle";
35 type Type = super::RoomHistoryTitle;
36 type ParentType = adw::Bin;
37
38 fn class_init(klass: &mut Self::Class) {
39 Self::bind_template(klass);
40
41 klass.set_css_name("room-title");
42 }
43
44 fn instance_init(obj: &InitializingObject<Self>) {
45 obj.init_template();
46 }
47 }
48
49 #[glib::derived_properties]
50 impl ObjectImpl for RoomHistoryTitle {}
51
52 impl WidgetImpl for RoomHistoryTitle {}
53 impl BinImpl for RoomHistoryTitle {}
54
55 impl RoomHistoryTitle {
56 fn set_room(&self, room: Option<Room>) {
58 if self.room.obj() == room {
59 return;
60 }
61
62 self.room.disconnect_signals();
63
64 if let Some(room) = room {
65 let display_name_handler = room.connect_display_name_notify(clone!(
66 #[weak(rename_to = imp)]
67 self,
68 move |_| {
69 imp.update_title();
70 }
71 ));
72 let topic_handler = room.connect_topic_notify(clone!(
73 #[weak(rename_to = imp)]
74 self,
75 move |_| {
76 imp.update_subtitle();
77 }
78 ));
79
80 self.room
81 .set(&room, vec![display_name_handler, topic_handler]);
82 }
83
84 self.obj().notify_room();
85 self.update_title();
86 self.update_subtitle();
87 }
88
89 fn update_title(&self) {
91 let Some(room) = self.room.obj() else {
92 return;
93 };
94
95 let mut title = room.display_name().replace('\n', "");
97 title.truncate_end_whitespaces();
99
100 if *self.title.borrow() == title {
101 return;
102 }
103
104 self.title.replace(title);
105 self.obj().notify_title();
106 }
107
108 fn update_subtitle(&self) {
110 let Some(room) = self.room.obj() else {
111 return;
112 };
113
114 let subtitle = room
115 .topic()
116 .map(|s| {
117 let mut s = s.replace('\n', "");
119 s.truncate_end_whitespaces();
121 s
122 })
123 .filter(|s| !s.is_empty());
124
125 if *self.subtitle.borrow() == subtitle {
126 return;
127 }
128
129 let has_subtitle = subtitle.is_some();
130
131 self.subtitle.replace(subtitle);
132
133 let obj = self.obj();
134 obj.notify_subtitle();
135
136 let button_valign = if has_subtitle {
137 obj.add_css_class("with-subtitle");
138 gtk::Align::Fill
139 } else {
140 obj.remove_css_class("with-subtitle");
141 gtk::Align::Center
142 };
143
144 self.button.set_valign(button_valign);
145 self.subtitle_label.set_visible(has_subtitle);
146 }
147 }
148}
149
150glib::wrapper! {
151 pub struct RoomHistoryTitle(ObjectSubclass<imp::RoomHistoryTitle>)
153 @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
154}
155
156impl RoomHistoryTitle {
157 pub fn new() -> Self {
159 glib::Object::new()
160 }
161}
162
163impl Default for RoomHistoryTitle {
164 fn default() -> Self {
165 Self::new()
166 }
167}