1use iced::{
24 Alignment::{self, Center},
25 Element,
26 widget::{center, column, container, row, rule, svg::Handle, text},
27};
28
29use crate::{
30 Message,
31 ferrix::Ferrix,
32 fl,
33 icons::ERROR_ICON,
34 widgets::{header_text, link_button},
35};
36
37mod battery;
38mod cpu;
39mod cpu_freq;
40mod dashboard;
41mod distro;
42mod dmi;
43mod drm;
44mod env;
45mod export;
46mod groups;
47mod kernel;
48mod net;
49mod ram;
50mod settings;
51mod soft;
52mod storage;
53mod sysmon;
54mod system;
55mod systemd;
56mod users;
57mod vulnerabilities;
58
59pub use sysmon::*;
60
61#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
62pub enum Page {
63 #[default]
67 Dashboard,
68 Processors,
69 CPUFrequency,
70 CPUVulnerabilities,
71 SystemMonitor,
72 Memory,
73 FileSystems,
74 Network,
75 DMI,
76 Battery,
77 Screen,
78
79 Distro,
83 SystemMisc,
84 Users,
85 Groups,
86 SystemManager,
87 Software,
88 Environment,
89 Sensors,
90
91 Kernel,
95 KModules,
96 Development,
97
98 Settings,
102 About,
103 Export,
104 Todo,
105}
106
107impl From<&str> for Page {
108 fn from(value: &str) -> Self {
109 match value {
110 "dash" | "dashboard" => Self::Dashboard,
111 "sysmon" | "monitor" | "system" | "system-monitor" => Self::SystemMonitor,
112 "proc" | "cpu" | "processors" => Self::Processors,
113 "cpu-frequency" | "cpufreq" => Self::CPUFrequency,
114 "cpu-vuln" | "vulnerabilities" => Self::CPUVulnerabilities,
115 "memory" | "mem" | "ram" => Self::Memory,
116 "fs" | "storage" => Self::FileSystems,
117 "net" => Self::Network,
118 "dmi" => Self::DMI,
119 "battery" | "bat" => Self::Battery,
120 "edid" | "screen" => Self::Screen,
121 "distro" => Self::Distro,
122 "users" => Self::Users,
123 "groups" => Self::Groups,
124 "misc" => Self::SystemMisc,
125 "init" | "sysd" | "systemd" => Self::SystemManager,
126 "software" | "soft" | "pkg" | "pkgs" => Self::Software,
127 "env" => Self::Environment,
128 "sensors" => Self::Sensors,
129 "kernel" | "linux" => Self::Kernel,
130 "kmods" | "mod" | "modules" => Self::KModules,
131 "dev" => Self::Development,
132 "settings" => Self::Settings,
133 "about" | "version" | "--version" | "-V" | "-v" => {
134 println!("FSM (Ferrix System Monitor) v{}", env!("CARGO_PKG_VERSION"));
135
136 eprintln!(" *** If you are from Russia, you can send me a donation:");
137 eprintln!(" 2202 2062 5233 5406\n Thank you!");
138
139 Self::About
140 }
141 "export" => Self::Export,
142 _ => {
143 eprintln!("ERROR: Unknown page name: \"{value}\"!\n");
144 eprintln!(" *** If you are from Russia, you can send me a donation:");
145 eprintln!(" 2202 2062 5233 5406\n Thank you!");
146
147 Self::default()
148 }
149 }
150 }
151}
152
153impl From<usize> for Page {
154 fn from(value: usize) -> Self {
155 match value {
156 0 => Self::Dashboard,
157 1 => Self::SystemMonitor,
158 2 => Self::Processors,
159 3 => Self::CPUFrequency,
160 4 => Self::CPUVulnerabilities,
161 5 => Self::Memory,
162 6 => Self::FileSystems,
163 7 => Self::Network,
164 8 => Self::DMI,
165 9 => Self::Battery,
166 10 => Self::Screen,
167 11 => Self::Sensors,
168 12 => Self::Distro,
169 13 => Self::Users,
170 14 => Self::Groups,
171 15 => Self::Environment,
172 16 => Self::SystemManager,
173 17 => Self::Software,
174 18 => Self::Kernel,
175 19 => Self::KModules,
176 20 => Self::SystemMisc,
177 21 => Self::Settings,
178 22 => Self::About,
179 _ => Page::Dashboard,
180 }
181 }
182}
183
184impl<'a> Page {
185 pub fn title(&'a self) -> iced::widget::Column<'a, Message> {
186 header_text(self.title_str())
187 }
188
189 pub fn page_num(&self) -> usize {
190 match self {
191 Self::Dashboard => 0,
192 Self::SystemMonitor => 1,
193 Self::Processors => 2,
194 Self::CPUFrequency => 3,
195 Self::CPUVulnerabilities => 4,
196 Self::Memory => 5,
197 Self::FileSystems => 6,
198 Self::Network => 7,
199 Self::DMI => 8,
200 Self::Battery => 9,
201 Self::Screen => 10,
202 Self::Sensors => 11,
203 Self::Distro => 12,
204 Self::Users => 13,
205 Self::Groups => 14,
206 Self::Environment => 15,
207 Self::SystemManager => 16,
208 Self::Software => 17,
209 Self::Kernel => 18,
210 Self::KModules => 19,
211 Self::SystemMisc => 20,
212 Self::Settings => 21,
213 Self::About => 22,
214 _ => 0,
215 }
216 }
217
218 pub fn next_page(&self) -> Self {
219 let mut id = self.page_num() + 1;
220 if id > Self::About.page_num() {
221 id = 0;
222 }
223 Self::from(id)
224 }
225
226 pub fn prev_page(&self) -> Self {
227 let cur_id = self.page_num();
228 let next_id = if cur_id == 0 {
229 Self::About.page_num()
230 } else {
231 cur_id - 1
232 };
233 Self::from(next_id)
234 }
235
236 pub fn scrolled_list_id(&self) -> Option<&'static str> {
237 match self {
238 Self::Processors => Some("proc-list"),
239 _ => None,
240 }
241 }
242
243 pub fn page_id(&self) -> &'static str {
244 match self {
245 Self::Dashboard => "dash",
246 Self::Processors => "proc",
247 Self::CPUFrequency => "cpufreq",
248 Self::CPUVulnerabilities => "cpuvuln",
249 Self::SystemMonitor => "sysmon",
250 Self::Memory => "mem",
251 Self::FileSystems => "fs",
252 Self::Network => "net",
253 Self::DMI => "dmi",
254 Self::Battery => "bat",
255 Self::Screen => "drm",
256 Self::Distro => "distro",
257 Self::SystemMisc => "sys",
258 Self::Users => "usr",
259 Self::Groups => "grp",
260 Self::SystemManager => "sysd",
261 Self::Software => "pkg",
262 Self::Environment => "env",
263 Self::Sensors => "hwmon",
264 Self::Kernel => "krn",
265 Self::KModules => "kmds",
266 Self::Development => "dev",
267 Self::Settings => "set",
268 Self::About => "about",
269 Self::Export => "export",
270 Self::Todo => "todo",
271 }
272 }
273
274 pub fn title_str(&self) -> String {
275 match self {
276 Self::Dashboard => fl!("page-dashboard"),
277 Self::Processors => fl!("page-procs"),
278 Self::CPUFrequency => fl!("page-cpufreq"),
279 Self::CPUVulnerabilities => fl!("page-vuln"),
280 Self::SystemMonitor => fl!("page-sysmon"),
281 Self::Memory => fl!("page-memory"),
282 Self::FileSystems => fl!("page-fsystems"),
283 Self::Network => fl!("page-net"),
284 Self::DMI => fl!("page-dmi"),
285 Self::Battery => fl!("page-battery"),
286 Self::Screen => fl!("page-screen"),
287 Self::Distro => fl!("page-distro"),
288 Self::Users => fl!("page-users"),
289 Self::Groups => fl!("page-groups"),
290 Self::SystemManager => fl!("page-sysmgr"),
291 Self::Software => fl!("page-software"),
292 Self::Environment => fl!("page-env"),
293 Self::Sensors => fl!("page-sensors"),
294 Self::Kernel => fl!("page-kernel"),
295 Self::KModules => fl!("page-kmods"),
296 Self::Development => fl!("page-dev"),
297 Self::SystemMisc => fl!("page-sysmisc"),
298 Self::Settings => fl!("page-settings"),
299 Self::About => fl!("page-about"),
300 Self::Export => fl!("page-export"),
301 Self::Todo => fl!("page-todo"),
302 }
303 }
304
305 pub fn page(&'a self, state: &'a Ferrix) -> Element<'a, Message> {
306 let page = match self {
307 Self::Dashboard => dashboard::dashboard(&state.data).into(),
308 Self::SystemMonitor => sysmon::usage_charts_page(
309 &state.data,
310 &state.data.curr_proc_stat,
311 &state.data.prev_proc_stat,
312 )
313 .into(), Self::Processors => {
315 cpu::proc_page(&state.data.proc_data, state.data.selected_proc).into()
316 }
317 Self::CPUFrequency => cpu_freq::cpu_freq_page(&state.data.cpu_freq).into(),
318 Self::CPUVulnerabilities => {
319 vulnerabilities::vulnerabilities_page(&state.data.cpu_vulnerabilities).into()
320 }
321 Self::Memory => ram::ram_page(&state.data.ram_data, &state.data.swap_data).into(),
322 Self::FileSystems => storage::storage_page(&state.data.storages).into(),
323 Self::Network => net::net_page(&state.data.networks).into(),
324 Self::DMI => dmi::dmi_page(&state.data.dmi_data).into(),
325 Self::Battery => battery::bat_page(&state.data.bat_data).into(),
326 Self::Screen => drm::drm_page(&state.data.drm_data).into(),
327 Self::Distro => distro::distro_page(&state.data.osrel_data).into(),
328 Self::Kernel => kernel::kernel_page(&state.data.kernel_data).into(),
329 Self::KModules => kernel::kmods_page(&state.data.kmods_data).into(),
330 Self::SystemMisc => system::system_page(&state.data.system).into(),
331 Self::Users => users::users_page(&state.data.users_list).into(),
332 Self::Groups => groups::groups_page(&state.data.groups_list).into(),
333 Self::SystemManager => systemd::services_page(
334 &state.data.boot_time,
335 &state.data.sysd_services_list,
336 )
337 .into(),
338 Self::Software => soft::soft_page(&state.data.installed_pkgs_list).into(),
339 Self::Environment => env::env_page(&state.data.system).into(),
340 Self::Settings => settings::settings_page(&state).into(),
341 Self::Export => export::export_page().into(),
342 Self::About => self.about_page().into(),
343 _ => self.todo_page(),
344 };
345
346 column![self.title(), page,].spacing(5).into()
347 }
348
349 fn todo_page(&self) -> Element<'a, Message> {
350 container(center(
351 text(fl!("page-todo-msg")).size(16).style(text::secondary),
352 ))
353 .into()
354 }
355
356 fn about_page(&'a self) -> container::Container<'a, Message> {
357 let img = iced::widget::svg("/usr/share/Ferrix/com.mskrasnov.Ferrix.svg")
358 .width(128)
359 .height(128);
360 let header = row![
361 img,
362 column![
363 text(fl!("about-hdr")).size(24),
364 text(format!(
365 "{}: {}, {}: {}",
366 fl!("about-ferrix"),
367 env!("CARGO_PKG_VERSION"),
368 fl!("about-flib"),
369 ferrix_lib::FX_LIB_VERSION,
370 ))
371 .size(14),
372 ]
373 .spacing(5),
374 ]
375 .align_y(Center)
376 .spacing(5);
377
378 let about_info = row![
379 column![
380 text(fl!("about-author-hdr")).style(text::secondary),
381 text(fl!("about-feedback-hdr")).style(text::secondary),
382 text(fl!("about-source-hdr")).style(text::secondary),
383 text("crates.io:").style(text::secondary),
384 text(fl!("about-blog")).style(text::secondary),
385 ]
386 .align_x(Alignment::End)
387 .spacing(3),
388 column![
389 row![
390 text(fl!("about-author")),
391 link_button("(GitHub)", "https://github.com/mskrasnov"),
392 ]
393 .spacing(5),
394 link_button("mskrasnov07 at ya dot ru", "mailto:mskrasnov07@ya.ru"),
395 link_button("GitHub", "https://github.com/mskrasnov/Ferrix"),
396 row![
397 link_button("ferrix-app", "https://crates.io/crates/ferrix-app"),
398 text(", "),
399 link_button("ferrix-lib", "https://crates.io/crates/ferrix-lib"),
400 ],
401 link_button("mskrasnov", "https://boosty.to/mskrasnov"),
402 ]
403 .spacing(3),
404 ]
405 .spacing(5);
406
407 let donate = column![
408 text(fl!("about-donate")),
409 link_button(fl!("about-donate-lbl"), "https://boosty.to/mskrasnov"),
410 ]
411 .spacing(5);
412
413 let contents = column![
414 column![header, rule::horizontal(1)].spacing(2),
415 about_info,
416 row![
417 text(fl!("about-support")).style(text::warning).size(16),
418 rule::horizontal(1)
419 ]
420 .align_y(Center)
421 .spacing(5),
422 donate,
423 ]
424 .spacing(5);
425
426 container(contents)
427 }
428}
429
430fn loading_page<'a>() -> container::Container<'a, Message> {
431 container(center(
432 text(fl!("ldr-page-tooltip"))
433 .style(text::secondary)
434 .size(14),
435 ))
436}
437
438fn error_page<'a>(etext: &'a str) -> container::Container<'a, Message> {
439 container(center(
440 column![
441 row![
442 iced::widget::svg(Handle::from_memory(ERROR_ICON))
443 .width(20)
444 .height(20),
445 text(fl!("err-page-tooltip")).size(20),
446 ]
447 .align_y(Center)
448 .spacing(5),
449 text(etext).style(text::secondary).size(14),
450 ]
451 .align_x(Center)
452 .spacing(5),
453 ))
454}