ferrix_app/
lib.rs

1/* lib.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
21pub mod export;
22pub mod i18n;
23pub mod icons;
24pub mod load_state;
25pub mod modals;
26pub mod pages;
27pub mod styles;
28pub mod utils;
29pub mod widgets;
30
31pub mod dmi;
32pub mod kernel;
33
34// REFACTORED MODULES
35pub mod messages;
36pub mod settings;
37pub mod subscription;
38use messages::*;
39
40pub use load_state::DataLoadingState;
41pub use pages::*;
42
43use dmi::DMIData;
44use serde::Serialize;
45use widgets::{icon_button, sidebar_button};
46
47use anyhow::Result;
48use ferrix_lib::{
49    battery::BatInfo,
50    cpu::{Processors, Stat},
51    cpu_freq::CpuFreq,
52    drm::Video,
53    init::SystemdServices,
54    parts::Mounts,
55    ram::{RAM, Swaps},
56    soft::InstalledPackages,
57    sys::{
58        Groups, KModules, Kernel, LoadAVG, OsRelease, Uptime, Users, get_current_desktop,
59        get_env_vars, get_hostname, get_lang,
60    },
61    vulnerabilities::Vulnerabilities,
62};
63use iced::{
64    Alignment::Center,
65    Element, Length, Padding, Task, Theme,
66    widget::{column, container, row, scrollable, text},
67};
68use std::{collections::HashSet, env::args};
69
70use crate::{settings::FXSettings, utils::get_home, widgets::line_charts::LineChart};
71
72const SETTINGS_PATH: &str = "./ferrix.conf";
73
74#[derive(Debug)]
75pub struct Ferrix {
76    pub current_page: Page,
77
78    pub proc_data: DataLoadingState<Processors>,
79    pub prev_proc_stat: DataLoadingState<Stat>,
80    pub curr_proc_stat: DataLoadingState<Stat>,
81    pub cpu_usage_chart: LineChart,
82    pub show_cpus_chart: HashSet<usize>,
83    pub show_chart_elements: usize,
84    pub cpu_freq: DataLoadingState<CpuFreq>,
85    pub cpu_vulnerabilities: DataLoadingState<Vulnerabilities>,
86
87    pub ram_data: DataLoadingState<RAM>,
88    pub swap_data: DataLoadingState<Swaps>,
89    pub show_mem_chart: HashSet<usize>,
90    pub show_ram_chart: bool,
91    pub ram_usage_chart: LineChart,
92
93    pub storages: DataLoadingState<Mounts>,
94    pub dmi_data: DataLoadingState<DMIData>,
95    pub bat_data: DataLoadingState<BatInfo>,
96    pub drm_data: DataLoadingState<Video>,
97    pub osrel_data: DataLoadingState<OsRelease>,
98
99    pub kernel_data: DataLoadingState<Kernel>,
100    pub kmods_data: DataLoadingState<KModules>,
101
102    pub users_list: DataLoadingState<Users>,
103    pub groups_list: DataLoadingState<Groups>,
104    pub sysd_services_list: DataLoadingState<SystemdServices>,
105    pub installed_pkgs_list: DataLoadingState<InstalledPackages>,
106    pub system: DataLoadingState<System>,
107
108    pub settings: FXSettings,
109    pub is_polkit: bool,
110    pub show_copy_toast: bool,
111}
112
113impl Default for Ferrix {
114    fn default() -> Self {
115        let a = args().nth(1);
116        let page = match &a {
117            Some(a) => Page::from(a as &str),
118            None => Page::default(),
119        };
120
121        Self {
122            current_page: page,
123
124            proc_data: DataLoadingState::Loading,
125            prev_proc_stat: DataLoadingState::Loading,
126            curr_proc_stat: DataLoadingState::Loading,
127            cpu_usage_chart: LineChart::new().legend(true).fill_alpha(0.25).animated(1.),
128            show_cpus_chart: HashSet::new(),
129            show_chart_elements: 45,
130            cpu_freq: DataLoadingState::Loading,
131            cpu_vulnerabilities: DataLoadingState::Loading,
132            ram_data: DataLoadingState::Loading,
133            swap_data: DataLoadingState::Loading,
134            ram_usage_chart: LineChart::new().legend(true).fill_alpha(0.25).animated(1.),
135            show_mem_chart: HashSet::new(),
136            show_ram_chart: true,
137            storages: DataLoadingState::Loading,
138            dmi_data: DataLoadingState::Loading,
139            bat_data: DataLoadingState::Loading,
140            drm_data: DataLoadingState::Loading,
141            osrel_data: DataLoadingState::Loading,
142            kernel_data: DataLoadingState::Loading,
143            kmods_data: DataLoadingState::Loading,
144            users_list: DataLoadingState::Loading,
145            groups_list: DataLoadingState::Loading,
146            sysd_services_list: DataLoadingState::Loading,
147            installed_pkgs_list: DataLoadingState::Loading,
148            system: DataLoadingState::Loading,
149            settings: FXSettings::read(get_home().join(".config").join(SETTINGS_PATH))
150                .unwrap_or_default(),
151            is_polkit: false,
152            show_copy_toast: false,
153        }
154    }
155}
156
157#[derive(Debug, Clone, Serialize)]
158pub struct System {
159    pub hostname: Option<String>,
160    pub loadavg: Option<LoadAVG>,
161    pub uptime: Option<Uptime>,
162    pub desktop: Option<String>,
163    pub language: Option<String>,
164    pub env_vars: Vec<(String, String)>,
165}
166
167impl System {
168    pub fn new() -> Result<Self> {
169        Ok(Self {
170            hostname: get_hostname(),
171            loadavg: Some(LoadAVG::new()?),
172            uptime: Some(Uptime::new()?),
173            desktop: get_current_desktop(),
174            language: get_lang(),
175            env_vars: get_env_vars(),
176        })
177    }
178}
179
180impl Ferrix {
181    pub fn theme(&self) -> Theme {
182        self.settings.style.to_theme()
183    }
184
185    pub fn title(&self) -> String {
186        format!("Ferrix System Monitor — {}", self.current_page.title_str())
187    }
188
189    pub fn update(&mut self, message: Message) -> Task<Message> {
190        message.update(self)
191    }
192
193    pub fn view<'a>(&'a self) -> Element<'a, Message> {
194        let win = row![sidebar(self.current_page), self.current_page.page(&self)]
195            .spacing(5)
196            .padding(5);
197
198        if self.show_copy_toast {
199            modals::toast(win, fl!("toast-copy")).into()
200        } else {
201            win.into()
202        }
203    }
204}
205
206fn sidebar<'a>(cur_page: Page) -> container::Container<'a, Message> {
207    let buttons_bar = row![
208        icon_button("export", fl!("sidebar-export")).on_press(Message::SelectPage(Page::Export)),
209        icon_button("settings", fl!("sidebar-settings"))
210            .on_press(Message::SelectPage(Page::Settings)),
211        icon_button("about", fl!("sidebar-about")).on_press(Message::SelectPage(Page::About)),
212    ]
213    .spacing(2)
214    .align_y(Center);
215
216    let pages_bar = column![
217        text(fl!("sidebar-basic")).style(text::secondary),
218        sidebar_button(Page::Dashboard, cur_page),
219        sidebar_button(Page::SystemMonitor, cur_page),
220        text(fl!("sidebar-hardware")).style(text::secondary),
221        sidebar_button(Page::Processors, cur_page),
222        sidebar_button(Page::CPUFrequency, cur_page),
223        sidebar_button(Page::CPUVulnerabilities, cur_page),
224        sidebar_button(Page::Memory, cur_page),
225        sidebar_button(Page::FileSystems, cur_page),
226        sidebar_button(Page::DMI, cur_page),
227        sidebar_button(Page::Battery, cur_page),
228        sidebar_button(Page::Screen, cur_page),
229        sidebar_button(Page::Sensors, cur_page),
230        text(fl!("sidebar-admin")).style(text::secondary),
231        sidebar_button(Page::Distro, cur_page),
232        sidebar_button(Page::Users, cur_page),
233        sidebar_button(Page::Groups, cur_page),
234        sidebar_button(Page::SystemManager, cur_page),
235        sidebar_button(Page::Software, cur_page),
236        sidebar_button(Page::Environment, cur_page),
237        text(fl!("sidebar-system")).style(text::secondary),
238        sidebar_button(Page::Kernel, cur_page),
239        sidebar_button(Page::KModules, cur_page),
240        sidebar_button(Page::Development, cur_page),
241        sidebar_button(Page::SystemMisc, cur_page),
242        text(fl!("sidebar-manage")).style(text::secondary),
243        sidebar_button(Page::Settings, cur_page),
244        sidebar_button(Page::About, cur_page),
245    ]
246    .padding(Padding::new(0.).right(5.))
247    .spacing(3);
248
249    container(column![buttons_bar, scrollable(pages_bar)].spacing(5))
250        .padding(5)
251        .style(container::bordered_box)
252        .height(Length::Fill)
253}