use ratatui::{
Frame,
crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers},
layout::Rect,
style::Style,
widgets::{Clear, List, ListState},
};
use serde_json::Value;
use crate::{DetailsScreen, PostEventAction};
pub struct LogScreen {
log: Vec<String>,
list_state: ListState,
area: Option<Rect>,
}
impl LogScreen {
pub fn new(log: Vec<String>) -> Self {
Self {
log,
list_state: ListState::default().with_selected(Some(0)),
area: None,
}
}
pub fn handle_event(&mut self, event: Event) -> Option<PostEventAction> {
match event {
Event::Key(KeyEvent {
code: KeyCode::Esc | KeyCode::Char('q'),
kind: KeyEventKind::Press,
..
}) => Some(PostEventAction::PopScreen),
Event::Key(KeyEvent {
code: KeyCode::Down | KeyCode::Char('j'),
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
}) => {
self.list_state.select_next();
None
}
Event::Key(KeyEvent {
code: KeyCode::Up | KeyCode::Char('k'),
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
}) => {
self.list_state.select_previous();
None
}
Event::Key(KeyEvent {
code: KeyCode::Home | KeyCode::Char('g'),
kind: KeyEventKind::Press,
..
}) => {
self.list_state.select_first();
None
}
Event::Key(KeyEvent {
code: KeyCode::End | KeyCode::Char('G'),
kind: KeyEventKind::Press,
..
}) => {
self.list_state.select_last();
None
}
Event::Key(
KeyEvent {
code: KeyCode::Char('f'),
modifiers: KeyModifiers::CONTROL,
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
}
| KeyEvent {
code: KeyCode::PageDown,
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
},
) => {
if let Some(area) = self.area
&& let Some(selected) = self.list_state.selected_mut() {
*selected = selected.saturating_add(area.height as usize);
}
None
}
Event::Key(KeyEvent {
code: KeyCode::Char('d'),
modifiers: KeyModifiers::CONTROL,
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
}) => {
if let Some(area) = self.area
&& let Some(selected) = self.list_state.selected_mut() {
*selected = selected.saturating_add(area.height as usize / 2);
}
None
}
Event::Key(
KeyEvent {
code: KeyCode::Char('b'),
modifiers: KeyModifiers::CONTROL,
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
}
| KeyEvent {
code: KeyCode::PageUp,
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
},
) => {
if let Some(area) = self.area
&& let Some(selected) = self.list_state.selected_mut() {
*selected = selected.saturating_sub(area.height as usize);
}
None
}
Event::Key(KeyEvent {
code: KeyCode::Char('u'),
modifiers: KeyModifiers::CONTROL,
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
}) => {
if let Some(area) = self.area
&& let Some(selected) = self.list_state.selected_mut() {
*selected = selected.saturating_sub(area.height as usize / 2);
}
None
}
Event::Key(KeyEvent {
code: KeyCode::Enter,
kind: KeyEventKind::Press,
..
}) => {
let selected_line = &self.log[self.list_state.selected().unwrap()];
let value = match serde_json::from_str(selected_line) {
Ok(value) => value,
Err(_) => Value::String(selected_line.clone()),
};
Some(PostEventAction::PushScreen(
DetailsScreen::new(value).into(),
))
}
_ => None,
}
}
pub fn render(&mut self, frame: &mut Frame) {
self.area = Some(frame.area());
let list = List::new(self.log.clone()).highlight_style(Style::default().reversed());
frame.render_widget(Clear, frame.area());
frame.render_stateful_widget(list, frame.area(), &mut self.list_state);
}
}