framework_tool_tui/tui/component/
title.rs1use ratatui::{
2 layout::{Constraint, Layout, Rect},
3 prelude::*,
4 widgets::{Block, BorderType, Borders, Paragraph},
5 Frame,
6};
7
8use crate::{
9 app::APP_TITLE,
10 framework::info::FrameworkInfo,
11 tui::{
12 component::Component,
13 theme::{Theme, ThemeVariant},
14 },
15};
16
17pub struct TitleComponent {
18 theme_name: String,
19 tick_interval_ms: u64,
20}
21
22impl TitleComponent {
23 pub fn new(theme: ThemeVariant) -> Self {
24 Self {
25 theme_name: theme.name().to_string(),
26 tick_interval_ms: 1000,
27 }
28 }
29
30 pub fn set_theme_name(&mut self, name: String) {
31 self.theme_name = name;
32 }
33
34 pub fn set_tick_interval(&mut self, interval_ms: u64) {
35 self.tick_interval_ms = interval_ms;
36 }
37}
38
39impl Component for TitleComponent {
40 fn render(&mut self, frame: &mut Frame, area: Rect, theme: &Theme, info: &FrameworkInfo) {
41 let block = Block::default()
42 .title(APP_TITLE)
43 .borders(Borders::ALL)
44 .border_style(Style::default().fg(theme.border))
45 .border_type(BorderType::Rounded);
46
47 let [smbios_version_area, charging_status_area, charge_percentage_area, max_charge_limit_area, fan_speed_area, theme_area, tick_interval_area] =
48 Layout::horizontal([
49 Constraint::Max(10),
50 Constraint::Max(15),
51 Constraint::Max(6),
52 Constraint::Max(13),
53 Constraint::Min(18),
54 Constraint::Max(30),
55 Constraint::Max(12),
56 ])
57 .spacing(1)
58 .areas(block.inner(area));
59
60 if let Some(smbios_version) = &info.smbios_version {
62 frame.render_widget(
63 Paragraph::new(format!("[ v{} ]", smbios_version))
64 .style(Style::default().fg(theme.informative_text)),
65 smbios_version_area,
66 );
67 }
68
69 let charge_percentage = info.charge_percentage;
70 let charge_style = match charge_percentage {
71 Some(charge_percentage) if charge_percentage < 15 => {
72 Style::default().fg(theme.indication_warning)
73 }
74 _ => Style::default().fg(theme.indication_ok),
75 };
76
77 frame.render_widget(
79 Paragraph::new(format!("[ {}", info.charging_status)).style(charge_style),
80 charging_status_area,
81 );
82
83 if let Some(charge_percentage) = info.charge_percentage {
85 frame.render_widget(
86 Paragraph::new(format!("{}% ]", charge_percentage)).style(charge_style),
87 charge_percentage_area,
88 );
89 }
90
91 if let Some(max_charge_limit) = info.max_charge_limit {
93 frame.render_widget(
94 Paragraph::new(format!("[ Max: {}% ]", max_charge_limit))
95 .style(Style::default().fg(theme.informative_text)),
96 max_charge_limit_area,
97 );
98 }
99
100 if let Some(fan_rpm) = &info.fan_rpm {
102 let text = fan_rpm
103 .iter()
104 .enumerate()
105 .map(|(n, rpm)| format!("FAN{}: {} RPM", n + 1, rpm))
106 .collect::<Vec<String>>()
107 .join(", ");
108
109 frame.render_widget(
110 Paragraph::new(format!("[ {} ]", text))
111 .style(Style::default().fg(theme.informative_text)),
112 fan_speed_area,
113 );
114 }
115
116 if !self.theme_name.is_empty() {
118 frame.render_widget(
119 Paragraph::new(format!("ćāb {} nāć", self.theme_name))
120 .style(Style::default().fg(theme.highlighted_text))
121 .alignment(Alignment::Right),
122 theme_area,
123 );
124 }
125
126 frame.render_widget(
128 Paragraph::new(format!("- {:4}ms +", self.tick_interval_ms))
129 .style(Style::default().fg(theme.highlighted_text))
130 .alignment(Alignment::Right),
131 tick_interval_area,
132 );
133
134 frame.render_widget(block, area);
135 }
136}