1pub 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
34pub 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}