kimun_notes/components/settings/
display_section.rs1use ratatui::Frame;
2use ratatui::layout::Rect;
3use ratatui::style::Style;
4use ratatui::widgets::{Block, Borders, List, ListItem, ListState};
5
6use crate::components::Component;
7use crate::components::event_state::EventState;
8use crate::components::events::{AppTx, InputEvent};
9use crate::settings::themes::Theme;
10
11pub struct DisplaySection {
12 pub use_nerd_fonts: bool,
13 list_state: ListState,
14}
15
16impl DisplaySection {
17 pub fn new(use_nerd_fonts: bool) -> Self {
18 let mut list_state = ListState::default();
19 list_state.select(Some(0));
20 Self {
21 use_nerd_fonts,
22 list_state,
23 }
24 }
25}
26
27impl Component for DisplaySection {
28 fn handle_input(&mut self, event: &InputEvent, _tx: &AppTx) -> EventState {
29 let InputEvent::Key(key) = event else {
30 return EventState::NotConsumed;
31 };
32 match key.code {
33 ratatui::crossterm::event::KeyCode::Enter
34 | ratatui::crossterm::event::KeyCode::Char(' ') => {
35 self.use_nerd_fonts = !self.use_nerd_fonts;
36 EventState::Consumed
37 }
38 _ => EventState::NotConsumed,
39 }
40 }
41
42 fn render(&mut self, f: &mut Frame, rect: Rect, theme: &Theme, focused: bool) {
43 let border_style = theme.border_style(focused);
44 let block = Block::default()
45 .title("Display")
46 .borders(Borders::ALL)
47 .border_style(border_style)
48 .style(theme.base_style());
49
50 let check = if self.use_nerd_fonts { "[x]" } else { "[ ]" };
51 let items = vec![
52 ListItem::new(format!(" Use Nerd Fonts {}", check))
53 .style(Style::default().fg(theme.fg.to_ratatui())),
54 ];
55
56 let list = List::new(items)
57 .block(block)
58 .style(theme.base_style())
59 .highlight_style(
60 Style::default()
61 .fg(theme.fg_selected.to_ratatui())
62 .bg(theme.bg_selected.to_ratatui()),
63 );
64 f.render_stateful_widget(list, rect, &mut self.list_state);
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::components::events::InputEvent;
72 use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
73
74 fn key(code: KeyCode) -> InputEvent {
75 InputEvent::Key(KeyEvent {
76 code,
77 modifiers: KeyModifiers::NONE,
78 kind: KeyEventKind::Press,
79 state: KeyEventState::NONE,
80 })
81 }
82
83 #[test]
84 fn enter_toggles_nerd_fonts() {
85 let (tx, _rx) = tokio::sync::mpsc::unbounded_channel();
86 let mut section = DisplaySection::new(true);
87 section.handle_input(&key(KeyCode::Enter), &tx);
88 assert!(!section.use_nerd_fonts);
89 section.handle_input(&key(KeyCode::Enter), &tx);
90 assert!(section.use_nerd_fonts);
91 }
92
93 #[test]
94 fn space_toggles_nerd_fonts() {
95 let (tx, _rx) = tokio::sync::mpsc::unbounded_channel();
96 let mut section = DisplaySection::new(false);
97 section.handle_input(&key(KeyCode::Char(' ')), &tx);
98 assert!(section.use_nerd_fonts);
99 }
100
101 #[test]
102 fn renders_checked_when_enabled() {
103 use ratatui::Terminal;
104 use ratatui::backend::TestBackend;
105 let backend = TestBackend::new(40, 10);
106 let mut terminal = Terminal::new(backend).unwrap();
107 let mut section = DisplaySection::new(true);
108 let theme = Theme::gruvbox_dark();
109 terminal
110 .draw(|f| section.render(f, f.area(), &theme, false))
111 .unwrap();
112 let buf = terminal.backend().buffer().clone();
113 let flat: String = buf.content.iter().map(|c| c.symbol()).collect();
114 assert!(flat.contains("[x]"), "expected [x] when nerd fonts enabled");
115 }
116
117 #[test]
118 fn renders_unchecked_when_disabled() {
119 use ratatui::Terminal;
120 use ratatui::backend::TestBackend;
121 let backend = TestBackend::new(40, 10);
122 let mut terminal = Terminal::new(backend).unwrap();
123 let mut section = DisplaySection::new(false);
124 let theme = Theme::gruvbox_dark();
125 terminal
126 .draw(|f| section.render(f, f.area(), &theme, false))
127 .unwrap();
128 let buf = terminal.backend().buffer().clone();
129 let flat: String = buf.content.iter().map(|c| c.symbol()).collect();
130 assert!(
131 flat.contains("[ ]"),
132 "expected [ ] when nerd fonts disabled"
133 );
134 }
135}