use aranet_types::Status;
use ratatui::style::{Color, Modifier, Style};
use ratatui::widgets::BorderType;
use crate::tui::app::ConnectionStatus;
#[derive(Debug, Clone, Copy)]
pub struct AppTheme {
pub primary: Color,
pub success: Color,
pub warning: Color,
pub caution: Color,
pub danger: Color,
pub info: Color,
pub sensor_temperature: Color,
pub sensor_humidity: Color,
pub sensor_pressure: Color,
pub sensor_radiation: Color,
pub series_co2: Color,
pub series_radon: Color,
pub series_radiation: Color,
pub trend_rising: Color,
pub trend_falling: Color,
pub trend_stable: Color,
pub signal_excellent: Color,
pub signal_good: Color,
pub signal_fair: Color,
pub signal_weak: Color,
pub signal_offline: Color,
pub text_primary: Color,
pub text_secondary: Color,
pub text_muted: Color,
pub border_active: Color,
pub border_inactive: Color,
pub bg_selected: Color,
pub bg_header: Color,
}
impl Default for AppTheme {
fn default() -> Self {
Self::dark()
}
}
impl AppTheme {
#[must_use]
pub const fn dark() -> Self {
Self {
primary: Color::Rgb(34, 211, 238),
success: Color::Rgb(74, 222, 128), warning: Color::Rgb(251, 191, 36), caution: Color::Rgb(251, 146, 60), danger: Color::Rgb(248, 113, 113), info: Color::Rgb(96, 165, 250),
sensor_temperature: Color::Rgb(251, 191, 36), sensor_humidity: Color::Rgb(96, 165, 250), sensor_pressure: Color::Rgb(248, 250, 252), sensor_radiation: Color::Rgb(217, 70, 239), series_co2: Color::Rgb(74, 222, 128), series_radon: Color::Rgb(34, 211, 238), series_radiation: Color::Rgb(217, 70, 239),
trend_rising: Color::Rgb(248, 113, 113), trend_falling: Color::Rgb(74, 222, 128), trend_stable: Color::Rgb(100, 116, 139), signal_excellent: Color::Rgb(74, 222, 128), signal_good: Color::Rgb(74, 222, 128), signal_fair: Color::Rgb(251, 191, 36), signal_weak: Color::Rgb(248, 113, 113), signal_offline: Color::Rgb(100, 116, 139),
text_primary: Color::Rgb(248, 250, 252), text_secondary: Color::Rgb(148, 163, 184), text_muted: Color::Rgb(100, 116, 139),
border_active: Color::Rgb(34, 211, 238), border_inactive: Color::Rgb(71, 85, 105),
bg_selected: Color::Rgb(51, 65, 85), bg_header: Color::Rgb(30, 41, 59), }
}
#[must_use]
pub const fn light() -> Self {
Self {
primary: Color::Rgb(6, 182, 212),
success: Color::Rgb(22, 163, 74), warning: Color::Rgb(217, 119, 6), caution: Color::Rgb(234, 88, 12), danger: Color::Rgb(220, 38, 38), info: Color::Rgb(37, 99, 235),
sensor_temperature: Color::Rgb(217, 119, 6), sensor_humidity: Color::Rgb(37, 99, 235), sensor_pressure: Color::Rgb(15, 23, 42), sensor_radiation: Color::Rgb(147, 51, 234), series_co2: Color::Rgb(22, 163, 74), series_radon: Color::Rgb(8, 145, 178), series_radiation: Color::Rgb(147, 51, 234),
trend_rising: Color::Rgb(220, 38, 38), trend_falling: Color::Rgb(22, 163, 74), trend_stable: Color::Rgb(148, 163, 184), signal_excellent: Color::Rgb(22, 163, 74), signal_good: Color::Rgb(22, 163, 74), signal_fair: Color::Rgb(217, 119, 6), signal_weak: Color::Rgb(220, 38, 38), signal_offline: Color::Rgb(148, 163, 184),
text_primary: Color::Rgb(15, 23, 42), text_secondary: Color::Rgb(71, 85, 105), text_muted: Color::Rgb(148, 163, 184),
border_active: Color::Rgb(6, 182, 212), border_inactive: Color::Rgb(203, 213, 225),
bg_selected: Color::Rgb(226, 232, 240), bg_header: Color::Rgb(241, 245, 249), }
}
#[inline]
#[must_use]
pub fn border_active_style(&self) -> Style {
Style::default().fg(self.border_active)
}
#[inline]
#[must_use]
pub fn border_inactive_style(&self) -> Style {
Style::default().fg(self.border_inactive)
}
#[inline]
#[must_use]
pub fn selected_style(&self) -> Style {
Style::default()
.bg(self.bg_selected)
.fg(self.text_primary)
.add_modifier(Modifier::BOLD)
}
#[inline]
#[must_use]
pub fn title_style(&self) -> Style {
Style::default()
.fg(self.primary)
.add_modifier(Modifier::BOLD)
}
#[inline]
#[must_use]
pub fn header_style(&self) -> Style {
Style::default().bg(self.bg_header)
}
#[must_use]
pub fn co2_level_color(&self, ppm: u16) -> Color {
match ppm {
0..=800 => self.success,
801..=1000 => self.warning,
1001..=1500 => self.caution,
_ => self.danger,
}
}
#[must_use]
pub fn radon_level_color(&self, bq_m3: u32) -> Color {
match bq_m3 {
0..=100 => self.success,
101..=150 => self.warning,
151..=300 => self.caution,
_ => self.danger,
}
}
#[must_use]
pub fn battery_level_color(&self, percent: u8) -> Color {
match percent {
0..=20 => self.danger,
21..=50 => self.warning,
_ => self.success,
}
}
#[must_use]
pub fn sensor_status_color(&self, status: &Status) -> Color {
match status {
Status::Green => self.success,
Status::Yellow => self.warning,
Status::Red => self.danger,
Status::Error => self.signal_offline,
_ => self.signal_offline,
}
}
#[must_use]
pub fn connection_color(&self, status: &ConnectionStatus) -> Color {
match status {
ConnectionStatus::Disconnected => self.signal_offline,
ConnectionStatus::Connecting => self.warning,
ConnectionStatus::Connected => self.success,
ConnectionStatus::Error(_) => self.danger,
}
}
#[must_use]
pub fn signal_strength_display(&self, rssi: i16) -> (&'static str, Color) {
if rssi >= -50 {
("▂▄▆█", self.signal_excellent)
} else if rssi >= -60 {
("▂▄▆░", self.signal_good)
} else if rssi >= -70 {
("▂▄░░", self.signal_fair)
} else if rssi >= -80 {
("▂░░░", self.signal_weak)
} else {
("░░░░", self.signal_offline)
}
}
#[must_use]
pub fn trend_color(&self, diff: i32, threshold: i32) -> Color {
if diff > threshold {
self.trend_rising
} else if diff < -threshold {
self.trend_falling
} else {
self.trend_stable
}
}
}
pub const BORDER_TYPE: BorderType = BorderType::Rounded;