This commit is contained in:
146
src/tui/app.rs
Normal file
146
src/tui/app.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
use crate::tui::{render, TuiState};
|
||||
use crossterm::{
|
||||
event::{self, Event, KeyCode, KeyEventKind},
|
||||
terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType},
|
||||
ExecutableCommand,
|
||||
};
|
||||
use ratatui::{backend::CrosstermBackend, Terminal};
|
||||
use std::io::Stdout;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::models::TechDebtItem;
|
||||
|
||||
pub struct TuiApp {
|
||||
state: TuiState,
|
||||
terminal: Terminal<CrosstermBackend<Stdout>>,
|
||||
}
|
||||
|
||||
impl TuiApp {
|
||||
pub fn new(items: Vec<TechDebtItem>, path: PathBuf) -> Self {
|
||||
let state = TuiState::new(items, path);
|
||||
let terminal = Terminal::new(CrosstermBackend::new(std::io::stdout()))
|
||||
.expect("Failed to create terminal");
|
||||
|
||||
Self { state, terminal }
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> anyhow::Result<()> {
|
||||
enable_raw_mode()?;
|
||||
|
||||
std::io::stdout().execute(Clear(ClearType::All))?;
|
||||
|
||||
loop {
|
||||
self.terminal.draw(|f| render(f, &self.state))?;
|
||||
|
||||
if let Event::Key(key) = event::read()? {
|
||||
if key.kind == KeyEventKind::Press {
|
||||
match self.handle_input(key.code) {
|
||||
Ok(should_exit) => {
|
||||
if should_exit {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error handling input: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disable_raw_mode()?;
|
||||
std::io::stdout().execute(Clear(ClearType::All))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_input(&mut self, code: KeyCode) -> anyhow::Result<bool> {
|
||||
let mut should_exit = false;
|
||||
|
||||
match code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => {
|
||||
should_exit = true;
|
||||
}
|
||||
KeyCode::Tab => {
|
||||
self.state.current_view = match self.state.current_view {
|
||||
crate::tui::View::Dashboard => crate::tui::View::List,
|
||||
crate::tui::View::List => crate::tui::View::Dashboard,
|
||||
crate::tui::View::Detail => crate::tui::View::List,
|
||||
crate::tui::View::Export => crate::tui::View::Dashboard,
|
||||
};
|
||||
}
|
||||
KeyCode::Up => {
|
||||
if self.state.selected_index > 0 {
|
||||
self.state.selected_index -= 1;
|
||||
}
|
||||
}
|
||||
KeyCode::Down => {
|
||||
let filtered_len = self.state.filtered_items().len();
|
||||
if filtered_len > 0 && self.state.selected_index < filtered_len - 1 {
|
||||
self.state.selected_index += 1;
|
||||
}
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
if self.state.current_view == crate::tui::View::List {
|
||||
self.state.current_view = crate::tui::View::Detail;
|
||||
}
|
||||
}
|
||||
KeyCode::Char('/') => {
|
||||
self.enable_filter_mode()?;
|
||||
}
|
||||
KeyCode::Char('f') => {
|
||||
self.enable_filter_mode()?;
|
||||
}
|
||||
KeyCode::Char('s') => {
|
||||
self.state.sort_order = match self.state.sort_order {
|
||||
crate::tui::SortOrder::Priority => crate::tui::SortOrder::File,
|
||||
crate::tui::SortOrder::File => crate::tui::SortOrder::Line,
|
||||
crate::tui::SortOrder::Line => crate::tui::SortOrder::Keyword,
|
||||
crate::tui::SortOrder::Keyword => crate::tui::SortOrder::Priority,
|
||||
};
|
||||
}
|
||||
KeyCode::Char('c') => {
|
||||
self.state.filter_priority = None;
|
||||
self.state.filter_text.clear();
|
||||
}
|
||||
KeyCode::Char('1') => {
|
||||
self.state.filter_priority = Some(crate::models::Priority::Critical);
|
||||
}
|
||||
KeyCode::Char('2') => {
|
||||
self.state.filter_priority = Some(crate::models::Priority::High);
|
||||
}
|
||||
KeyCode::Char('3') => {
|
||||
self.state.filter_priority = Some(crate::models::Priority::Medium);
|
||||
}
|
||||
KeyCode::Char('4') => {
|
||||
self.state.filter_priority = Some(crate::models::Priority::Low);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(should_exit)
|
||||
}
|
||||
|
||||
fn enable_filter_mode(&mut self) -> anyhow::Result<()> {
|
||||
disable_raw_mode()?;
|
||||
|
||||
println!("Enter filter text (or press ESC to cancel): ");
|
||||
std::io::stdout().flush()?;
|
||||
|
||||
let mut input = String::new();
|
||||
std::io::stdin().read_line(&mut input)?;
|
||||
|
||||
input = input.trim_end().to_string();
|
||||
|
||||
if input.is_empty() || input.as_bytes().first() == Some(&0x1b) {
|
||||
self.state.filter_text.clear();
|
||||
} else {
|
||||
self.state.filter_text = input;
|
||||
}
|
||||
|
||||
enable_raw_mode()?;
|
||||
std::io::stdout().execute(Clear(ClearType::All))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user