fractal/session/sidebar_data/
item_list.rs1use std::cell::Cell;
2
3use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*};
4
5use super::{
6 SidebarIconItem, SidebarIconItemType, SidebarItem, SidebarSection, SidebarSectionName,
7};
8use crate::session::{RoomCategory, RoomList, VerificationList};
9
10const TOP_LEVEL_ITEMS_COUNT: usize = 9;
12
13mod imp {
14 use std::cell::OnceCell;
15
16 use super::*;
17
18 #[derive(Debug, Default, glib::Properties)]
19 #[properties(wrapper_type = super::SidebarItemList)]
20 pub struct SidebarItemList {
21 list: OnceCell<[SidebarItem; TOP_LEVEL_ITEMS_COUNT]>,
23 #[property(get, construct_only)]
25 room_list: OnceCell<RoomList>,
26 #[property(get, construct_only)]
28 verification_list: OnceCell<VerificationList>,
29 show_all_for_room_category: Cell<Option<RoomCategory>>,
35 }
36
37 #[glib::object_subclass]
38 impl ObjectSubclass for SidebarItemList {
39 const NAME: &'static str = "SidebarItemList";
40 type Type = super::SidebarItemList;
41 type Interfaces = (gio::ListModel,);
42 }
43
44 #[glib::derived_properties]
45 impl ObjectImpl for SidebarItemList {
46 fn constructed(&self) {
47 self.parent_constructed();
48 let obj = self.obj();
49
50 let room_list = obj.room_list();
51 let verification_list = obj.verification_list();
52
53 let list = self.list.get_or_init(|| {
54 [
55 SidebarItem::new(SidebarIconItem::new(SidebarIconItemType::Explore)),
56 SidebarItem::new(SidebarSection::new(
57 SidebarSectionName::VerificationRequest,
58 &verification_list,
59 )),
60 SidebarItem::new(SidebarSection::new(
61 SidebarSectionName::InviteRequest,
62 &room_list,
63 )),
64 SidebarItem::new(SidebarSection::new(SidebarSectionName::Invited, &room_list)),
65 SidebarItem::new(SidebarSection::new(
66 SidebarSectionName::Favorite,
67 &room_list,
68 )),
69 SidebarItem::new(SidebarSection::new(SidebarSectionName::Normal, &room_list)),
70 SidebarItem::new(SidebarSection::new(
71 SidebarSectionName::LowPriority,
72 &room_list,
73 )),
74 SidebarItem::new(SidebarSection::new(SidebarSectionName::Left, &room_list)),
75 SidebarItem::new(SidebarIconItem::new(SidebarIconItemType::Forget)),
76 ]
77 });
78
79 for item in list {
80 if let Some(section) = item.inner_item().downcast_ref::<SidebarSection>() {
81 section.connect_is_empty_notify(clone!(
82 #[weak(rename_to = imp)]
83 self,
84 #[weak]
85 item,
86 move |_| {
87 imp.update_item_visibility(&item);
88 }
89 ));
90 }
91 self.update_item_visibility(item);
92 }
93 }
94 }
95
96 impl ListModelImpl for SidebarItemList {
97 fn item_type(&self) -> glib::Type {
98 SidebarItem::static_type()
99 }
100
101 fn n_items(&self) -> u32 {
102 TOP_LEVEL_ITEMS_COUNT as u32
103 }
104
105 fn item(&self, position: u32) -> Option<glib::Object> {
106 self.list().get(position as usize).cloned().and_upcast()
107 }
108 }
109
110 impl SidebarItemList {
111 pub(super) fn list(&self) -> &[SidebarItem; TOP_LEVEL_ITEMS_COUNT] {
113 self.list.get().unwrap()
114 }
115
116 pub(super) fn set_show_all_for_room_category(&self, category: Option<RoomCategory>) {
119 if self.show_all_for_room_category.get() == category {
120 return;
121 }
122
123 self.show_all_for_room_category.set(category);
124 for item in self.list() {
125 self.update_item_visibility(item);
126 }
127 }
128
129 fn update_item_visibility(&self, item: &SidebarItem) {
131 item.update_visibility_for_room_category(self.show_all_for_room_category.get());
132 }
133
134 pub(super) fn inhibit_expanded(&self, inhibit: bool) {
139 for item in self.list() {
140 item.set_inhibit_expanded(inhibit);
141 }
142 }
143 }
144}
145
146glib::wrapper! {
147 pub struct SidebarItemList(ObjectSubclass<imp::SidebarItemList>)
152 @implements gio::ListModel;
153}
154
155impl SidebarItemList {
156 pub fn new(room_list: &RoomList, verification_list: &VerificationList) -> Self {
159 glib::Object::builder()
160 .property("room-list", room_list)
161 .property("verification-list", verification_list)
162 .build()
163 }
164
165 pub(crate) fn set_show_all_for_room_category(&self, category: Option<RoomCategory>) {
168 self.imp().set_show_all_for_room_category(category);
169 }
170
171 pub(crate) fn inhibit_expanded(&self, inhibit: bool) {
176 self.imp().inhibit_expanded(inhibit);
177 }
178
179 pub(crate) fn section_from_room_category(
181 &self,
182 category: RoomCategory,
183 ) -> Option<SidebarSection> {
184 const FIRST_ROOM_SECTION_INDEX: usize = 2;
185
186 let index = match category {
187 RoomCategory::Knocked => FIRST_ROOM_SECTION_INDEX,
188 RoomCategory::Invited => FIRST_ROOM_SECTION_INDEX + 1,
189 RoomCategory::Favorite => FIRST_ROOM_SECTION_INDEX + 2,
190 RoomCategory::Normal => FIRST_ROOM_SECTION_INDEX + 3,
191 RoomCategory::LowPriority => FIRST_ROOM_SECTION_INDEX + 4,
192 RoomCategory::Left => FIRST_ROOM_SECTION_INDEX + 5,
193 _ => return None,
194 };
195
196 self.imp()
197 .list()
198 .get(index)
199 .map(SidebarItem::inner_item)
200 .and_downcast()
201 }
202}