Skip to main content

ferrix_app/
pages.rs

1/* pages.rs
2 *
3 * Copyright 2025 Michail Krasnov <mskrasnov07@ya.ru>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21//! Pages with information about hardware and software
22
23use 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 ram;
49mod settings;
50mod soft;
51mod storage;
52mod sysmon;
53mod system;
54mod systemd;
55mod users;
56mod vulnerabilities;
57
58pub use sysmon::*;
59
60#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
61pub enum Page {
62    /************************************
63     *       Hardware & dashboard       *
64     ************************************/
65    #[default]
66    Dashboard,
67    Processors,
68    CPUFrequency,
69    CPUVulnerabilities,
70    SystemMonitor,
71    Memory,
72    FileSystems,
73    DMI,
74    Battery,
75    Screen,
76
77    /************************************
78     *          Administration          *
79     ************************************/
80    Distro,
81    SystemMisc,
82    Users,
83    Groups,
84    SystemManager,
85    Software,
86    Environment,
87    Sensors,
88
89    /************************************
90     *               Kernel             *
91     ************************************/
92    Kernel,
93    KModules,
94    Development,
95
96    /************************************
97     *              Service             *
98     ************************************/
99    Settings,
100    About,
101    Export,
102    Todo,
103}
104
105impl From<&str> for Page {
106    fn from(value: &str) -> Self {
107        match value {
108            "dash" | "dashboard" => Self::Dashboard,
109            "sysmon" | "monitor" | "system" | "system-monitor" => Self::SystemMonitor,
110            "proc" | "cpu" | "processors" => Self::Processors,
111            "cpu-frequency" | "cpufreq" => Self::CPUFrequency,
112            "cpu-vuln" | "vulnerabilities" => Self::CPUVulnerabilities,
113            "memory" | "mem" | "ram" => Self::Memory,
114            "storage" => Self::FileSystems,
115            "dmi" => Self::DMI,
116            "battery" | "bat" => Self::Battery,
117            "edid" | "screen" => Self::Screen,
118            "distro" => Self::Distro,
119            "users" => Self::Users,
120            "groups" => Self::Groups,
121            "misc" => Self::SystemMisc,
122            "systemd" => Self::SystemManager,
123            "software" | "soft" | "pkg" | "pkgs" => Self::Software,
124            "env" => Self::Environment,
125            "sensors" => Self::Sensors,
126            "kernel" | "linux" => Self::Kernel,
127            "kmods" | "mod" | "modules" => Self::KModules,
128            "dev" => Self::Development,
129            "settings" => Self::Settings,
130            "about" | "version" | "--version" | "-V" | "-v" => {
131                println!("FSM (Ferrix System Monitor) v{}", env!("CARGO_PKG_VERSION"));
132
133                eprintln!(" *** If you are from Russia, you can send me a donation:");
134                eprintln!("     2202 2062 5233 5406\n Thank you!");
135
136                Self::About
137            }
138            "export" => Self::Export,
139            _ => {
140                eprintln!("ERROR: Unknown page name: \"{value}\"!\n");
141                eprintln!(" *** If you are from Russia, you can send me a donation:");
142                eprintln!("     2202 2062 5233 5406\n Thank you!");
143
144                Self::default()
145            }
146        }
147    }
148}
149
150impl<'a> Page {
151    pub fn title(&'a self) -> iced::widget::Column<'a, Message> {
152        header_text(self.title_str())
153    }
154
155    pub fn title_str(&self) -> String {
156        match self {
157            Self::Dashboard => fl!("page-dashboard"),
158            Self::Processors => fl!("page-procs"),
159            Self::CPUFrequency => fl!("page-cpufreq"),
160            Self::CPUVulnerabilities => fl!("page-vuln"),
161            Self::SystemMonitor => fl!("page-sysmon"),
162            Self::Memory => fl!("page-memory"),
163            Self::FileSystems => fl!("page-fsystems"),
164            Self::DMI => fl!("page-dmi"),
165            Self::Battery => fl!("page-battery"),
166            Self::Screen => fl!("page-screen"),
167            Self::Distro => fl!("page-distro"),
168            Self::Users => fl!("page-users"),
169            Self::Groups => fl!("page-groups"),
170            Self::SystemManager => fl!("page-sysmgr"),
171            Self::Software => fl!("page-software"),
172            Self::Environment => fl!("page-env"),
173            Self::Sensors => fl!("page-sensors"),
174            Self::Kernel => fl!("page-kernel"),
175            Self::KModules => fl!("page-kmods"),
176            Self::Development => fl!("page-dev"),
177            Self::SystemMisc => fl!("page-sysmisc"),
178            Self::Settings => fl!("page-settings"),
179            Self::About => fl!("page-about"),
180            Self::Export => fl!("page-export"),
181            Self::Todo => fl!("page-todo"),
182        }
183    }
184
185    pub fn page(&'a self, state: &'a Ferrix) -> Element<'a, Message> {
186        let page = match self {
187            Self::Dashboard => dashboard::dashboard(&state.data).into(),
188            Self::SystemMonitor => sysmon::usage_charts_page(
189                &state.data,
190                &state.data.curr_proc_stat,
191                &state.data.prev_proc_stat,
192            )
193            .into(), // TODO: cur_stat and proc_stat - ???
194            // TODO: replace multiple arguments!
195            Self::Processors => cpu::proc_page(&state.data.proc_data).into(),
196            Self::CPUFrequency => cpu_freq::cpu_freq_page(&state.data.cpu_freq).into(),
197            Self::CPUVulnerabilities => {
198                vulnerabilities::vulnerabilities_page(&state.data.cpu_vulnerabilities).into()
199            }
200            Self::Memory => ram::ram_page(&state.data.ram_data, &state.data.swap_data).into(),
201            Self::FileSystems => storage::storage_page(&state.data.storages).into(),
202            Self::DMI => dmi::dmi_page(&state.data.dmi_data).into(),
203            Self::Battery => battery::bat_page(&state.data.bat_data).into(),
204            Self::Screen => drm::drm_page(&state.data.drm_data).into(),
205            Self::Distro => distro::distro_page(&state.data.osrel_data).into(),
206            Self::Kernel => kernel::kernel_page(&state.data.kernel_data).into(),
207            Self::KModules => kernel::kmods_page(&state.data.kmods_data).into(),
208            Self::SystemMisc => system::system_page(&state.data.system).into(),
209            Self::Users => users::users_page(&state.data.users_list).into(),
210            Self::Groups => groups::groups_page(&state.data.groups_list).into(),
211            Self::SystemManager => systemd::services_page(&state.data.sysd_services_list).into(),
212            Self::Software => soft::soft_page(&state.data.installed_pkgs_list).into(),
213            Self::Environment => env::env_page(&state.data.system).into(),
214            Self::Settings => settings::settings_page(&state).into(),
215            Self::Export => export::export_page().into(),
216            Self::About => self.about_page().into(),
217            _ => self.todo_page(),
218        };
219
220        column![self.title(), page,].spacing(5).into()
221    }
222
223    fn todo_page(&self) -> Element<'a, Message> {
224        container(center(
225            text(fl!("page-todo-msg")).size(16).style(text::secondary),
226        ))
227        .into()
228    }
229
230    fn about_page(&'a self) -> container::Container<'a, Message> {
231        let img = iced::widget::svg("/usr/share/Ferrix/com.mskrasnov.Ferrix.svg")
232            .width(128)
233            .height(128);
234        let header = row![
235            img,
236            column![
237                text(fl!("about-hdr")).size(24),
238                text(format!(
239                    "{}: {}, {}: {}",
240                    fl!("about-ferrix"),
241                    env!("CARGO_PKG_VERSION"),
242                    fl!("about-flib"),
243                    ferrix_lib::FX_LIB_VERSION,
244                ))
245                .size(14),
246            ]
247            .spacing(5),
248        ]
249        .align_y(Center)
250        .spacing(5);
251
252        let about_info = row![
253            column![
254                text(fl!("about-author-hdr")).style(text::secondary),
255                text(fl!("about-feedback-hdr")).style(text::secondary),
256                text(fl!("about-source-hdr")).style(text::secondary),
257                text("crates.io:").style(text::secondary),
258                text(fl!("about-blog")).style(text::secondary),
259            ]
260            .align_x(Alignment::End)
261            .spacing(3),
262            column![
263                row![
264                    text(fl!("about-author")),
265                    link_button("(GitHub)", "https://github.com/mskrasnov"),
266                ]
267                .spacing(5),
268                link_button("mskrasnov07 at ya dot ru", "mailto:mskrasnov07@ya.ru"),
269                link_button("GitHub", "https://github.com/mskrasnov/Ferrix"),
270                row![
271                    link_button("ferrix-app", "https://crates.io/crates/ferrix-app"),
272                    text(", "),
273                    link_button("ferrix-lib", "https://crates.io/crates/ferrix-lib"),
274                ],
275                link_button("mskrasnov", "https://boosty.to/mskrasnov"),
276            ]
277            .spacing(3),
278        ]
279        .spacing(5);
280
281        let donate = column![
282            text(fl!("about-donate")),
283            link_button(fl!("about-donate-lbl"), "https://boosty.to/mskrasnov"),
284        ]
285        .spacing(5);
286
287        let contents = column![
288            column![header, rule::horizontal(1)].spacing(2),
289            about_info,
290            row![
291                text(fl!("about-support")).style(text::warning).size(16),
292                rule::horizontal(1)
293            ]
294            .align_y(Center)
295            .spacing(5),
296            donate,
297        ]
298        .spacing(5);
299
300        container(contents)
301    }
302}
303
304fn loading_page<'a>() -> container::Container<'a, Message> {
305    container(center(
306        text(fl!("ldr-page-tooltip"))
307            .style(text::secondary)
308            .size(14),
309    ))
310}
311
312fn error_page<'a>(etext: &'a str) -> container::Container<'a, Message> {
313    container(center(
314        column![
315            row![
316                iced::widget::svg(Handle::from_memory(ERROR_ICON))
317                    .width(20)
318                    .height(20),
319                text(fl!("err-page-tooltip")).size(20),
320            ]
321            .align_y(Center)
322            .spacing(5),
323            text(etext).style(text::secondary).size(14),
324        ]
325        .align_x(Center)
326        .spacing(5),
327    ))
328}