azalea_shell/window/taskbar/widget/startmenu/
mod.rs

1use azalea_service::{LocalListenerHandle, StaticServiceManager};
2use gtk::prelude::*;
3use relm4::{
4    Component, ComponentController, ComponentParts, ComponentSender, SimpleComponent, component,
5};
6
7use crate::{
8    component::{image, login},
9    service,
10};
11
12crate::init! {
13    Model {
14        taskbar_image: relm4::Controller<image::Model>,
15        popup_image: relm4::Controller<image::Model>,
16        login_widget: relm4::Controller<login::Model>,
17        sysinfo: SystemInformation,
18        temperature: (f64, String),
19        _service_handle: LocalListenerHandle,
20    }
21
22    Config {
23    }
24}
25
26// TODO: Service that polls for updates
27struct SystemInformation {
28    os_name: String,
29    username: String,
30    hostname: String,
31    kernel: String,
32    cpu: String,
33    gpu: String,
34    memory: String,
35    compositor: String,
36}
37
38impl Default for SystemInformation {
39    fn default() -> Self {
40        Self {
41            os_name: ffetch::get_os_name().unwrap_or("unknown".to_string()),
42            kernel: ffetch::get_kernel_version().unwrap_or("unknown".to_string()),
43            username: ffetch::get_username(),
44            hostname: ffetch::get_hostname().unwrap_or("unknown".to_string()),
45            cpu: ffetch::get_cpu_name().unwrap_or("unknown".to_string()),
46            gpu: ffetch::get_gpu(),
47            memory: ffetch::get_memory().unwrap_or("unknown".to_string()),
48            compositor: ffetch::get_desktop_env(),
49        }
50    }
51}
52
53#[derive(Debug)]
54pub enum Input {
55    Weather(service::weather::Output),
56}
57
58#[derive(Debug)]
59pub enum CommandOutput {}
60
61#[component(pub)]
62impl SimpleComponent for Model {
63    type Init = Init;
64    type Input = Input;
65    type Output = ();
66
67    view! {
68        gtk::MenuButton {
69            #[wrap(Some)]
70            set_child= &gtk::Box {
71                set_spacing: 12,
72
73                #[local_ref]
74                taskbar_image_widget -> gtk::Widget {
75                    set_height_request: 30,
76                },
77
78                gtk::Label {
79                    set_label: "Azalea"
80                },
81            },
82
83            #[wrap(Some)]
84            set_popover = &gtk::Popover {
85                gtk::Box {
86                    gtk::Box {
87                        set_orientation: gtk::Orientation::Vertical,
88
89                        #[local_ref]
90                        popup_image_widget -> gtk::Widget {
91                        },
92
93                        gtk::Separator {},
94
95                        #[local_ref]
96                        login_widget -> gtk::Widget {},
97
98                        gtk::Separator {},
99
100                        gtk::Box {
101                            set_spacing: 8,
102                            set_halign: gtk::Align::Start,
103                            gtk::Label {
104                                set_css_classes: &[ "azalea-primary-fg", ],
105                                set_label: &format!("{}@{}", model.sysinfo.username, model.sysinfo.hostname),
106                            },
107                        },
108
109                        gtk::Box {
110                            set_spacing: 8,
111                            set_halign: gtk::Align::Start,
112                            gtk::Label {
113                                set_css_classes: &[ "azalea-secondary-fg", ],
114                                set_label: " OS:",
115                            },
116                            gtk::Label {
117                                set_label: &model.sysinfo.os_name,
118                            },
119                        },
120
121                        gtk::Box {
122                            set_spacing: 8,
123                            set_halign: gtk::Align::Start,
124                            gtk::Label {
125                                set_css_classes: &[ "azalea-tertiary-fg", ],
126                                set_label: " Kernel:",
127                            },
128                            gtk::Label {
129                                set_label: &model.sysinfo.kernel,
130                            },
131                        },
132
133                        gtk::Box {
134                            set_spacing: 8,
135                            set_halign: gtk::Align::Start,
136                            gtk::Label {
137                                set_css_classes: &[ "azalea-primary-fg", ],
138                                set_label: "󰻠 CPU:",
139                            },
140                            gtk::Label {
141                                set_label: &model.sysinfo.cpu,
142                            },
143                        },
144
145                        gtk::Box {
146                            set_spacing: 8,
147                            set_halign: gtk::Align::Start,
148                            gtk::Label {
149                                set_css_classes: &[ "azalea-secondary-fg", ],
150                                set_label: "󰍛 GPU:",
151                            },
152                            gtk::Label {
153                                set_label: &model.sysinfo.gpu,
154                            },
155                        },
156
157                        gtk::Box {
158                            set_spacing: 8,
159                            set_halign: gtk::Align::Start,
160                            gtk::Label {
161                                set_css_classes: &[ "azalea-tertiary-fg", ],
162                                set_label: "󰑭 Memory:",
163                            },
164                            gtk::Label {
165                                set_label: &model.sysinfo.memory,
166                            },
167                        },
168
169                        gtk::Box {
170                            set_spacing: 8,
171                            set_halign: gtk::Align::Start,
172                            gtk::Label {
173                                set_css_classes: &[ "azalea-secondary-fg", ],
174                                set_label: " Compositor:",
175                            },
176                            gtk::Label {
177                                set_label: &model.sysinfo.compositor,
178                            },
179                        },
180                    },
181                }
182            }
183        }
184    }
185
186    fn init(
187        _init: Self::Init,
188        _root: Self::Root,
189        sender: ComponentSender<Self>,
190    ) -> ComponentParts<Self> {
191        let model = Model {
192            temperature: Default::default(),
193            sysinfo: Default::default(),
194            taskbar_image: image::Model::builder()
195                .launch(image::Init {
196                    fallback: None,
197                    width: None,
198                    height: Some(30),
199                })
200                .detach(),
201            popup_image: image::Model::builder()
202                .launch(image::Init {
203                    fallback: None,
204                    width: None,
205                    height: Some(200),
206                })
207                .detach(),
208            login_widget: login::Model::builder().launch(()).detach(),
209            _service_handle: service::weather::Service::forward_local(
210                sender.input_sender().clone(),
211                Input::Weather,
212            ),
213        };
214
215        drop(model.taskbar_image.sender().send(image::Input::LoadBytes(
216            include_bytes!("../../../../../../assets/azalea-logo.png").to_vec(),
217        )));
218
219        drop(model.popup_image.sender().send(image::Input::LoadBytes(
220            include_bytes!("../../../../../../assets/azalea-logo.png").to_vec(),
221        )));
222
223        let taskbar_image_widget: &gtk::Widget = model.taskbar_image.widget().upcast_ref();
224        let popup_image_widget: &gtk::Widget = model.popup_image.widget().upcast_ref();
225        let login_widget: &gtk::Widget = model.login_widget.widget().upcast_ref();
226        let widgets = view_output!();
227
228        ComponentParts { model, widgets }
229    }
230
231    fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
232        match message {
233            Input::Weather(weather) => match weather {
234                service::weather::Output::Temperature(temperature) => {
235                    self.temperature = temperature;
236                }
237            },
238        }
239    }
240}