fractal/session/model/
session_settings.rs

1use std::collections::BTreeSet;
2
3use gtk::{glib, prelude::*, subclass::prelude::*};
4use serde::{Deserialize, Serialize};
5
6use super::SidebarSectionName;
7use crate::Application;
8
9#[derive(Debug, Clone, Serialize, Deserialize, glib::Boxed)]
10#[boxed_type(name = "StoredSessionSettings")]
11pub struct StoredSessionSettings {
12    /// Custom servers to explore.
13    #[serde(default, skip_serializing_if = "Vec::is_empty")]
14    explore_custom_servers: Vec<String>,
15
16    /// Whether notifications are enabled for this session.
17    #[serde(
18        default = "ruma::serde::default_true",
19        skip_serializing_if = "ruma::serde::is_true"
20    )]
21    notifications_enabled: bool,
22
23    /// Whether public read receipts are enabled for this session.
24    #[serde(
25        default = "ruma::serde::default_true",
26        skip_serializing_if = "ruma::serde::is_true"
27    )]
28    public_read_receipts_enabled: bool,
29
30    /// Whether typing notifications are enabled for this session.
31    #[serde(
32        default = "ruma::serde::default_true",
33        skip_serializing_if = "ruma::serde::is_true"
34    )]
35    typing_enabled: bool,
36
37    /// The sections that are expanded.
38    #[serde(default)]
39    sections_expanded: SectionsExpanded,
40}
41
42impl Default for StoredSessionSettings {
43    fn default() -> Self {
44        Self {
45            explore_custom_servers: Default::default(),
46            notifications_enabled: true,
47            public_read_receipts_enabled: true,
48            typing_enabled: true,
49            sections_expanded: Default::default(),
50        }
51    }
52}
53
54mod imp {
55    use std::{
56        cell::{OnceCell, RefCell},
57        marker::PhantomData,
58    };
59
60    use super::*;
61
62    #[derive(Debug, Default, glib::Properties)]
63    #[properties(wrapper_type = super::SessionSettings)]
64    pub struct SessionSettings {
65        /// The ID of the session these settings are for.
66        #[property(get, construct_only)]
67        pub session_id: OnceCell<String>,
68        /// The stored settings.
69        #[property(get, construct_only)]
70        pub stored_settings: RefCell<StoredSessionSettings>,
71        /// Whether notifications are enabled for this session.
72        #[property(get = Self::notifications_enabled, set = Self::set_notifications_enabled, explicit_notify, default = true)]
73        pub notifications_enabled: PhantomData<bool>,
74        /// Whether public read receipts are enabled for this session.
75        #[property(get = Self::public_read_receipts_enabled, set = Self::set_public_read_receipts_enabled, explicit_notify, default = true)]
76        pub public_read_receipts_enabled: PhantomData<bool>,
77        /// Whether typing notifications are enabled for this session.
78        #[property(get = Self::typing_enabled, set = Self::set_typing_enabled, explicit_notify, default = true)]
79        pub typing_enabled: PhantomData<bool>,
80    }
81
82    #[glib::object_subclass]
83    impl ObjectSubclass for SessionSettings {
84        const NAME: &'static str = "SessionSettings";
85        type Type = super::SessionSettings;
86    }
87
88    #[glib::derived_properties]
89    impl ObjectImpl for SessionSettings {}
90
91    impl SessionSettings {
92        /// Whether notifications are enabled for this session.
93        fn notifications_enabled(&self) -> bool {
94            self.stored_settings.borrow().notifications_enabled
95        }
96
97        /// Set whether notifications are enabled for this session.
98        fn set_notifications_enabled(&self, enabled: bool) {
99            if self.notifications_enabled() == enabled {
100                return;
101            }
102
103            self.stored_settings.borrow_mut().notifications_enabled = enabled;
104            super::SessionSettings::save();
105            self.obj().notify_notifications_enabled();
106        }
107
108        /// Whether public read receipts are enabled for this session.
109        fn public_read_receipts_enabled(&self) -> bool {
110            self.stored_settings.borrow().public_read_receipts_enabled
111        }
112
113        /// Set whether public read receipts are enabled for this session.
114        fn set_public_read_receipts_enabled(&self, enabled: bool) {
115            if self.public_read_receipts_enabled() == enabled {
116                return;
117            }
118
119            self.stored_settings
120                .borrow_mut()
121                .public_read_receipts_enabled = enabled;
122            super::SessionSettings::save();
123            self.obj().notify_public_read_receipts_enabled();
124        }
125
126        /// Whether typing notifications are enabled for this session.
127        fn typing_enabled(&self) -> bool {
128            self.stored_settings.borrow().typing_enabled
129        }
130
131        /// Set whether typing notifications are enabled for this session.
132        fn set_typing_enabled(&self, enabled: bool) {
133            if self.typing_enabled() == enabled {
134                return;
135            }
136
137            self.stored_settings.borrow_mut().typing_enabled = enabled;
138            super::SessionSettings::save();
139            self.obj().notify_typing_enabled();
140        }
141    }
142}
143
144glib::wrapper! {
145    /// The settings of a `Session`.
146    pub struct SessionSettings(ObjectSubclass<imp::SessionSettings>);
147}
148
149impl SessionSettings {
150    /// Create a new `SessionSettings` for the given session ID.
151    pub fn new(session_id: &str) -> Self {
152        glib::Object::builder()
153            .property("session-id", session_id)
154            .property("stored-settings", StoredSessionSettings::default())
155            .build()
156    }
157
158    /// Restore existing `SessionSettings` with the given session ID and stored
159    /// settings.
160    pub fn restore(session_id: &str, stored_settings: &StoredSessionSettings) -> Self {
161        glib::Object::builder()
162            .property("session-id", session_id)
163            .property("stored-settings", stored_settings)
164            .build()
165    }
166
167    /// Save these settings in the application settings.
168    fn save() {
169        Application::default().session_list().settings().save();
170    }
171
172    /// Delete the settings from the application settings.
173    pub fn delete(&self) {
174        Application::default()
175            .session_list()
176            .settings()
177            .remove(&self.session_id());
178    }
179
180    /// Custom servers to explore.
181    pub fn explore_custom_servers(&self) -> Vec<String> {
182        self.imp()
183            .stored_settings
184            .borrow()
185            .explore_custom_servers
186            .clone()
187    }
188
189    /// Set the custom servers to explore.
190    pub fn set_explore_custom_servers(&self, servers: Vec<String>) {
191        if self.explore_custom_servers() == servers {
192            return;
193        }
194
195        self.imp()
196            .stored_settings
197            .borrow_mut()
198            .explore_custom_servers = servers;
199        Self::save();
200    }
201
202    /// Whether the section with the given name is expanded.
203    pub fn is_section_expanded(&self, section_name: SidebarSectionName) -> bool {
204        self.imp()
205            .stored_settings
206            .borrow()
207            .sections_expanded
208            .is_section_expanded(section_name)
209    }
210
211    /// Set whether the section with the given name is expanded.
212    pub fn set_section_expanded(&self, section_name: SidebarSectionName, expanded: bool) {
213        self.imp()
214            .stored_settings
215            .borrow_mut()
216            .sections_expanded
217            .set_section_expanded(section_name, expanded);
218        Self::save();
219    }
220}
221
222/// The sections that are expanded.
223#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
224pub struct SectionsExpanded(BTreeSet<SidebarSectionName>);
225
226impl SectionsExpanded {
227    /// Whether the section with the given name is expanded.
228    pub fn is_section_expanded(&self, section_name: SidebarSectionName) -> bool {
229        self.0.contains(&section_name)
230    }
231
232    /// Set whether the section with the given name is expanded.
233    pub fn set_section_expanded(&mut self, section_name: SidebarSectionName, expanded: bool) {
234        if expanded {
235            self.0.insert(section_name);
236        } else {
237            self.0.remove(&section_name);
238        }
239    }
240}
241
242impl Default for SectionsExpanded {
243    fn default() -> Self {
244        Self(BTreeSet::from([
245            SidebarSectionName::VerificationRequest,
246            SidebarSectionName::Invited,
247            SidebarSectionName::Favorite,
248            SidebarSectionName::Normal,
249            SidebarSectionName::LowPriority,
250        ]))
251    }
252}