use crate::systemfacts::{
os::OsInfo,
hardware::{CPUInfo, DiskInfo, NetworkInterface, MemoryInfo, GPUInfo},
capabilities::SystemCapabilities,
};
use crate::mui::widgets::{progress_bar};
pub struct SystemSection;
impl SystemSection {
pub fn render(os_info: &OsInfo) -> Vec<String> {
let mut lines = Vec::new();
lines.push(format!("Hostname: {}", os_info.hostname));
lines.push(format!("OS: {} ({})", os_info.distribution.name, os_info.distribution.version));
lines.push(format!("Kernel: {}", os_info.kernel_version));
lines.push(format!("Timezone: {}", os_info.timezone));
let uptime_secs = os_info.uptime.as_secs();
let days = uptime_secs / 86400;
let hours = (uptime_secs % 86400) / 3600;
let minutes = (uptime_secs % 3600) / 60;
lines.push(format!("Uptime: {}d {}h {}m", days, hours, minutes));
lines
}
}
pub struct ResourcesSection;
impl ResourcesSection {
pub fn render(cpu: &CPUInfo, memory: &MemoryInfo, gpus: &[GPUInfo]) -> Vec<String> {
let mut lines = Vec::new();
lines.push("CPU:".to_string());
let width = 30;
let bar = progress_bar(cpu.usage, width);
lines.push(format!("[{}]", bar));
lines.push(format!("Usage: {:.0}% Cores: {}", cpu.usage, cpu.logical_cores));
lines.push("".to_string());
lines.push("Memory:".to_string());
let mem_used = memory.used_kib as f64;
let mem_total = memory.total_kib as f64;
let mem_usage_pct = if mem_total > 0.0 { (mem_used / mem_total) * 100.0 } else { 0.0 };
let mem_bar = progress_bar(mem_usage_pct as f32, width);
lines.push(format!("[{}]", mem_bar));
let used_gb = mem_used / (1024.0 * 1024.0);
let total_gb = mem_total / (1024.0 * 1024.0);
lines.push(format!("Usage: {:.0}% {:.1}GB / {:.1}GB", mem_usage_pct, used_gb, total_gb));
if !gpus.is_empty() {
lines.push("".to_string());
lines.push("GPU:".to_string());
for gpu in gpus {
lines.push(format!("- {}", gpu.name));
}
}
lines
}
}
pub struct StorageSection;
impl StorageSection {
pub fn render(disks: &[DiskInfo]) -> Vec<String> {
let mut lines = Vec::new();
if disks.is_empty() {
lines.push("No disks found".to_string());
return lines;
}
for disk in disks {
let total = disk.total_space as f64;
let used = (disk.total_space.saturating_sub(disk.available_space)) as f64;
let usage_pct = if total > 0.0 { (used / total) * 100.0 } else { 0.0 };
lines.push(format!("{} ({}):", disk.name, disk.mount_point));
let width = 20;
let bar = progress_bar(usage_pct as f32, width);
lines.push(format!("[{}]", bar));
let used_gb = used / 1_073_741_824.0;
let total_gb = total / 1_073_741_824.0;
lines.push(format!("{:.0}% {:.1}GB / {:.1}GB", usage_pct, used_gb, total_gb));
lines.push("".to_string());
}
if let Some(last) = lines.last() {
if last.is_empty() {
lines.pop();
}
}
lines
}
}
pub struct NetworkSection;
impl NetworkSection {
pub fn render(interfaces: &[NetworkInterface]) -> Vec<String> {
let mut lines = Vec::new();
for iface in interfaces {
if iface.name == "lo" { continue; }
let ips = if iface.ip_addresses.is_empty() {
"No IP".to_string()
} else {
iface.ip_addresses.join(", ")
};
lines.push(format!("{}: {}", iface.name, ips));
}
lines
}
}
pub struct CapabilitiesSection;
impl CapabilitiesSection {
pub fn render(caps: &SystemCapabilities) -> Vec<String> {
let mut lines = Vec::new();
fn bool_str(b: bool) -> &'static str {
if b { "[Yes]" } else { "[No] " }
}
lines.push(format!("{} Virtualization", bool_str(caps.virtualization)));
lines.push(format!("{} KVM Support", bool_str(caps.kvm_support)));
lines.push(format!("{} Docker", bool_str(caps.docker_support)));
lines.push(format!("{} Systemd", bool_str(caps.systemd_support)));
lines.push(format!("CGroup Version: v{}", caps.cgroup_version));
lines
}
}