diff --git a/src/todolist.rs b/src/todolist.rs index 514855b..c6cf12d 100644 --- a/src/todolist.rs +++ b/src/todolist.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; use serde_json::from_reader; use std::fs::File; +use std::fmt; use std::io::BufReader; pub struct TodoList { @@ -25,6 +26,12 @@ impl Todo { } } +impl fmt::Display for Todo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[{}] {}", if self.done { 'x' } else { ' ' }, self.text) + } +} + fn read_todos(path: &str) -> Option> { File::open(path) .ok() @@ -41,13 +48,6 @@ impl TodoList { } } - pub fn printable_todos(&self) -> Vec { - self.todos - .iter() - .map(|todo| format!("[{}] {}", if todo.done { 'x' } else { ' ' }, todo.text)) - .collect() - } - pub fn selection_down(&mut self) { self.selected = (self.selected + 1).min(self.todos.len().saturating_sub(1)); } @@ -97,4 +97,8 @@ impl TodoList { pub fn current_pop(&mut self) { self.todos[self.selected].text.pop(); } + + pub fn printable(&self) -> Vec { + self.todos.iter().map(Todo::to_string).collect() + } } diff --git a/src/tracc.rs b/src/tracc.rs index 40e4434..b423170 100644 --- a/src/tracc.rs +++ b/src/tracc.rs @@ -1,9 +1,10 @@ use super::todolist::TodoList; use std::default::Default; -use std::io::{self,Write}; +use std::io::{self, Write}; use termion::event::Key; use termion::input::TermRead; use tui::backend::TermionBackend; +use tui::layout::*; use tui::style::{Color, Style}; use tui::widgets::*; @@ -19,6 +20,7 @@ pub struct Tracc { todos: TodoList, terminal: Terminal, input_mode: Mode, + top_panel_selected: bool, } impl Tracc { @@ -27,13 +29,14 @@ impl Tracc { todos: TodoList::open_or_create(JSON_PATH), terminal, input_mode: Mode::Normal, + top_panel_selected: true, } } pub fn run(&mut self) -> Result<(), io::Error> { let mut inputs = io::stdin().keys(); loop { - refresh(&mut self.terminal, &self.todos)?; + refresh(&mut self.terminal, &self.todos, self.top_panel_selected)?; // I need to find a better way to handle inputs. This is awful. let input = inputs.next().unwrap()?; match self.input_mode { @@ -58,6 +61,7 @@ impl Tracc { self.todos.insert(self.todos.register.clone().unwrap()); } } + Key::Char('\t') => self.top_panel_selected = !self.top_panel_selected, _ => (), }, Mode::Insert => match input { @@ -86,17 +90,52 @@ impl Tracc { } } -fn refresh(terminal: &mut Terminal, todos: &TodoList) -> Result<(), io::Error> { - terminal.draw(|mut frame| { - let size = frame.size(); - let block = Block::default().title(" t r a c c ").borders(Borders::ALL); +fn refresh(terminal: &mut Terminal, todos: &TodoList, top_selected: bool) -> Result<(), io::Error> { + fn selectable_list<'a, C: AsRef>( + title: &'a str, + content: &'a [C], + selected: Option, + ) -> SelectableList<'a> { SelectableList::default() - .block(block) - .items(&todos.printable_todos()) - .select(Some(todos.selected)) + .block( + Block::default() + .title(title) + .borders(Borders::TOP | Borders::RIGHT | Borders::LEFT), + ) + .items(content) + .select(selected.into()) .highlight_style(Style::default().fg(Color::LightGreen)) .highlight_symbol(">") - .render(&mut frame, size); + } + + terminal.draw(|mut frame| { + let size = frame.size(); + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Percentage(42), + Constraint::Percentage(42), + Constraint::Percentage(16), + ] + .as_ref(), + ) + .split(size); + selectable_list( + " t r a c c ", + &todos.printable(), + Some(todos.selected).filter(|_| top_selected), + ) + .render(&mut frame, chunks[0]); + selectable_list( + " 🕑 ", + &["[08:23] start", "[09:35] end"], + Some(0).filter(|_| !top_selected), + ) + .render(&mut frame, chunks[1]); + Paragraph::new([Text::raw("Sum for today: 1:12")].iter()) + .block(Block::default().borders(Borders::ALL)) + .render(&mut frame, chunks[2]); })?; Ok(()) }