fractal/session/view/content/room_history/message_row/
message_state_stack.rs1use adw::subclass::prelude::*;
2use gtk::{glib, glib::clone, prelude::*, CompositeTemplate};
3
4use crate::session::model::MessageState;
5
6const SENT_VISIBLE_SECONDS: u32 = 3;
9
10mod imp {
11 use std::cell::Cell;
12
13 use glib::subclass::InitializingObject;
14
15 use super::*;
16
17 #[derive(Debug, Default, CompositeTemplate, glib::Properties)]
18 #[template(
19 resource = "/org/gnome/Fractal/ui/session/view/content/room_history/message_row/message_state_stack.ui"
20 )]
21 #[properties(wrapper_type = super::MessageStateStack)]
22 pub struct MessageStateStack {
23 #[property(get, set = Self::set_state, explicit_notify, builder(MessageState::default()))]
25 state: Cell<MessageState>,
26 #[template_child]
27 stack: TemplateChild<gtk::Stack>,
28 }
29
30 #[glib::object_subclass]
31 impl ObjectSubclass for MessageStateStack {
32 const NAME: &'static str = "MessageStateStack";
33 type Type = super::MessageStateStack;
34 type ParentType = adw::Bin;
35
36 fn class_init(klass: &mut Self::Class) {
37 Self::bind_template(klass);
38 }
39
40 fn instance_init(obj: &InitializingObject<Self>) {
41 obj.init_template();
42 }
43 }
44
45 #[glib::derived_properties]
46 impl ObjectImpl for MessageStateStack {}
47
48 impl WidgetImpl for MessageStateStack {}
49 impl BinImpl for MessageStateStack {}
50
51 impl MessageStateStack {
52 fn set_state(&self, state: MessageState) {
54 let prev_state = self.state.get();
55
56 if prev_state == state {
57 return;
58 }
59
60 let stack = &self.stack;
61
62 let name = match state {
63 MessageState::None => {
64 if matches!(
65 prev_state,
66 MessageState::Sending
67 | MessageState::RecoverableError
68 | MessageState::PermanentError
69 ) {
70 glib::timeout_add_seconds_local_once(
72 SENT_VISIBLE_SECONDS,
73 clone!(
74 #[weak]
75 stack,
76 move || {
77 stack.set_visible_child_name("none");
78 }
79 ),
80 );
81
82 "sent"
83 } else {
84 "none"
85 }
86 }
87 MessageState::Sending => "sending",
88 MessageState::RecoverableError => "warning",
89 MessageState::PermanentError => "error",
90 MessageState::Edited => {
91 if matches!(
92 prev_state,
93 MessageState::Sending
94 | MessageState::RecoverableError
95 | MessageState::PermanentError
96 ) {
97 glib::timeout_add_seconds_local_once(
99 SENT_VISIBLE_SECONDS,
100 clone!(
101 #[weak]
102 stack,
103 move || {
104 stack.set_visible_child_name("edited");
105 }
106 ),
107 );
108
109 "sent"
110 } else {
111 "edited"
112 }
113 }
114 };
115 stack.set_visible_child_name(name);
116
117 self.state.set(state);
118 self.obj().notify_state();
119 }
120 }
121}
122
123glib::wrapper! {
124 pub struct MessageStateStack(ObjectSubclass<imp::MessageStateStack>)
126 @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
127}
128
129impl MessageStateStack {
130 pub fn new() -> Self {
132 glib::Object::new()
133 }
134}