Skip to main content

nm_wifi/ui/
header_footer.rs

1use ratatui::{
2    Frame,
3    layout::{Alignment, Constraint, Direction, Layout, Rect},
4    style::{Modifier, Style},
5    text::{Line, Span},
6    widgets::{Block, Borders, Paragraph},
7};
8
9use crate::{
10    app_state::{App, AppState},
11    theme::CatppuccinColors,
12};
13
14pub fn keybindings_hint(state: &AppState) -> &'static str {
15    match state {
16        AppState::NetworkList => {
17            "↑↓/jk Move  Enter Connect  d Disconnect  r Rescan  i Info  h Help  q Quit"
18        }
19        AppState::Help => "h/q/Esc Back",
20        AppState::NetworkDetails => "q/i/Esc Back",
21        AppState::PasswordInput => "Enter Connect  Tab Show/Hide  Esc Cancel",
22        AppState::Connecting | AppState::Disconnecting => "Esc Quit",
23        AppState::Scanning => "Scanning  Esc Quit",
24        AppState::ConnectionResult => "Enter Return  q/Esc Quit",
25    }
26}
27
28pub fn render_header(f: &mut Frame, app: &App, area: Rect) {
29    let header_chunks = Layout::default()
30        .direction(Direction::Horizontal)
31        .constraints([
32            Constraint::Length(30),
33            Constraint::Min(0),
34            Constraint::Length(25),
35        ])
36        .split(area);
37
38    let title = Paragraph::new(Line::from(vec![
39        Span::styled(
40            "nm-wifi",
41            Style::default()
42                .fg(CatppuccinColors::MAUVE)
43                .add_modifier(Modifier::BOLD),
44        ),
45        Span::styled(
46            concat!(" v", env!("CARGO_PKG_VERSION")),
47            Style::default().fg(CatppuccinColors::SUBTEXT1),
48        ),
49    ]))
50    .block(Block::default().borders(Borders::ALL))
51    .style(Style::default().bg(CatppuccinColors::BASE));
52
53    let scan_info = if let Some(scan_time) = app.last_scan_time {
54        let elapsed = scan_time.elapsed().as_secs();
55        format!(
56            "Networks: {} | Last scan: {}s ago",
57            app.network_count, elapsed
58        )
59    } else {
60        format!("Networks: {}", app.network_count)
61    };
62
63    let info = Paragraph::new(scan_info)
64        .block(Block::default().borders(Borders::ALL))
65        .style(
66            Style::default()
67                .fg(CatppuccinColors::TEXT)
68                .bg(CatppuccinColors::BASE),
69        )
70        .alignment(Alignment::Center);
71
72    let adapter_text = app.adapter_name.as_deref().unwrap_or("WiFi Adapter");
73    let adapter = Paragraph::new(adapter_text)
74        .block(Block::default().borders(Borders::ALL))
75        .style(
76            Style::default()
77                .fg(CatppuccinColors::BLUE)
78                .bg(CatppuccinColors::BASE),
79        )
80        .alignment(Alignment::Center);
81
82    f.render_widget(title, header_chunks[0]);
83    f.render_widget(info, header_chunks[1]);
84    f.render_widget(adapter, header_chunks[2]);
85}
86
87pub fn render_status_bar(f: &mut Frame, app: &App, area: Rect) {
88    let status_chunks = Layout::default()
89        .direction(Direction::Horizontal)
90        .constraints([Constraint::Min(0), Constraint::Length(40)])
91        .split(area);
92
93    let status = Paragraph::new(app.status_message.as_str())
94        .block(Block::default().borders(Borders::ALL))
95        .style(
96            Style::default()
97                .fg(CatppuccinColors::SUBTEXT1)
98                .bg(CatppuccinColors::BASE),
99        )
100        .alignment(Alignment::Left);
101
102    let hints = Paragraph::new(keybindings_hint(&app.state))
103        .block(Block::default().borders(Borders::ALL))
104        .style(
105            Style::default()
106                .fg(CatppuccinColors::OVERLAY1)
107                .bg(CatppuccinColors::BASE),
108        )
109        .alignment(Alignment::Center);
110
111    f.render_widget(status, status_chunks[0]);
112    f.render_widget(hints, status_chunks[1]);
113}