folder_view.rs (5287B)
1 use gtk::{prelude::*, Align}; 2 use relm4::{factory::FactoryVecDeque, prelude::*}; 3 4 pub struct MailboxesView { 5 mailboxes: FactoryVecDeque<Mailbox>, 6 } 7 8 pub struct MailboxesInit { 9 pub mailboxes: Vec<MailboxInit>, 10 } 11 12 #[derive(Debug)] 13 pub enum MailboxesMsg { 14 AddMailbox(MailboxInit), 15 // TODO: Is this the correct type? 16 RemoveMailbox(MailboxInit), 17 } 18 19 #[relm4::component(pub)] 20 impl SimpleComponent for MailboxesView { 21 type Init = MailboxesInit; 22 type Input = MailboxesMsg; 23 type Output = (); 24 25 view! { 26 gtk::ScrolledWindow { 27 set_propagate_natural_width: true, 28 set_hscrollbar_policy: gtk::PolicyType::Never, 29 30 #[local_ref] 31 mailbox_list_box -> gtk::Box {} 32 } 33 } 34 35 fn init( 36 init: Self::Init, 37 root: &Self::Root, 38 sender: ComponentSender<Self>, 39 ) -> ComponentParts<Self> { 40 let mut model = MailboxesView { 41 mailboxes: FactoryVecDeque::new(gtk::Box::default(), sender.input_sender()), 42 }; 43 44 for mailbox in init.mailboxes { 45 model.mailboxes.guard().push_back(mailbox); 46 } 47 let mailbox_list_box = model.mailboxes.widget(); 48 let widgets = view_output!(); 49 50 ComponentParts { model, widgets } 51 } 52 53 fn update(&mut self, msg: MailboxesMsg, _sender: ComponentSender<Self>) { 54 match msg { 55 MailboxesMsg::AddMailbox(mailbox) => self.mailboxes.guard().push_back(mailbox), 56 MailboxesMsg::RemoveMailbox(mailbox) => todo!(), 57 }; 58 } 59 } 60 61 struct Mailbox { 62 icon_name: String, 63 mailbox_name: String, 64 folders: FactoryVecDeque<Folder>, 65 } 66 67 #[derive(Debug)] 68 enum MailboxInput { 69 SetIconName(String), 70 SetName(String), 71 } 72 73 #[derive(Debug)] 74 pub struct MailboxInit { 75 pub icon_name: String, 76 pub mailbox_name: String, 77 pub folders: Vec<FolderInit>, 78 } 79 80 #[relm4::factory] 81 impl FactoryComponent for Mailbox { 82 type Init = MailboxInit; 83 type Input = MailboxInput; 84 type Output = (); 85 type CommandOutput = (); 86 type ParentInput = MailboxesMsg; 87 type ParentWidget = gtk::Box; 88 89 view! { 90 root = gtk::Expander { 91 set_expanded: true, 92 set_halign: Align::Fill, 93 set_hexpand: true, 94 #[wrap(Some)] 95 set_label_widget = >k::Box { 96 gtk::Image { 97 set_margin_end: 8, 98 #[watch] 99 set_from_icon_name: Some(&self.icon_name) 100 }, 101 gtk::Label { 102 #[watch] 103 set_label: &self.mailbox_name, 104 } 105 }, 106 107 #[wrap(Some)] 108 set_child = self.folders.widget(), 109 } 110 } 111 112 fn init_model(value: Self::Init, _index: &DynamicIndex, sender: FactorySender<Self>) -> Self { 113 let box_parent = gtk::ListBox::default(); 114 box_parent.set_halign(Align::Fill); 115 let mut model = Self { 116 icon_name: value.icon_name, 117 mailbox_name: value.mailbox_name, 118 folders: FactoryVecDeque::new(box_parent, sender.input_sender()), 119 }; 120 121 for folder in value.folders { 122 model.folders.guard().push_back(folder); 123 } 124 125 model 126 } 127 128 fn update(&mut self, msg: Self::Input, _sender: FactorySender<Self>) { 129 match msg { 130 MailboxInput::SetIconName(icon_name) => { 131 self.icon_name = icon_name; 132 } 133 MailboxInput::SetName(mailbox_name) => { 134 self.mailbox_name = mailbox_name; 135 } // TODO: Add and Remove Folders 136 } 137 } 138 } 139 140 struct Folder { 141 icon_name: String, 142 folder_name: String, 143 pub depth: i32, 144 } 145 146 #[derive(Debug)] 147 enum FolderInput { 148 SetIconName(String), 149 SetName(String), 150 } 151 152 #[derive(Debug)] 153 pub struct FolderInit { 154 pub icon_name: String, 155 pub folder_name: String, 156 pub depth: i32, 157 } 158 159 #[relm4::factory] 160 impl FactoryComponent for Folder { 161 type Init = FolderInit; 162 type Input = FolderInput; 163 type Output = (); 164 type CommandOutput = (); 165 type ParentInput = MailboxInput; 166 type ParentWidget = gtk::ListBox; 167 168 view! { 169 root = gtk::ListBoxRow { 170 set_halign: Align::Fill, 171 172 gtk::Box { 173 set_margin_start: 40_i32*self.depth, 174 set_halign: Align::Fill, 175 gtk::Image { 176 set_margin_end: 8, 177 #[watch] 178 set_from_icon_name: Some(&self.icon_name) 179 }, 180 gtk::Label { 181 #[watch] 182 set_label: &self.folder_name, 183 } 184 } 185 } 186 } 187 188 fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self { 189 Self { 190 depth: value.depth, 191 icon_name: value.icon_name, 192 folder_name: value.folder_name, 193 } 194 } 195 196 fn update(&mut self, msg: Self::Input, _sender: FactorySender<Self>) { 197 match msg { 198 FolderInput::SetIconName(icon_name) => { 199 self.icon_name = icon_name; 200 } 201 FolderInput::SetName(folder_name) => { 202 self.folder_name = folder_name; 203 } 204 } 205 } 206 }