use std::sync::mpsc; use std::{io, thread}; use termion::event::Key; use termion::input::TermRead; use termion::raw::IntoRawMode; use tui::backend::TermionBackend; use tui::layout::{Constraint, Direction, Layout}; use tui::Terminal; use crate::tags; use crate::widget::repo_entry; use crate::widget::tag_list; use crate::widget::Widget; pub struct Ui { state: State, repo: crate::widget::repo_entry::RepoEntry, tags: crate::widget::tag_list::TagList, } #[derive(PartialEq, Clone)] pub enum State { EditRepo, SelectTag, } impl Ui { pub fn run() { let mut ui = Ui { state: State::EditRepo, repo: repo_entry::RepoEntry::new("This is a text"), tags: tag_list::TagList::new(vec![String::from("editing Repository")]), }; //setup tui let stdout = io::stdout().into_raw_mode().unwrap(); let backend = TermionBackend::new(stdout); let mut terminal = Terminal::new(backend).unwrap(); //setup input thread let receiver = ui.spawn_stdin_channel(); //core interaction loop 'core: loop { //draw terminal .draw(|rect| { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Length(3), Constraint::Min(1)].as_ref()) .split(rect.size()); rect.render_widget(ui.repo.render(), chunks[0]); let (list, state) = ui.tags.render(); rect.render_stateful_widget(list, chunks[1], state); }) .unwrap(); //handle input match receiver.try_recv() { Ok(Key::Ctrl('q')) => break 'core, //quit program without saving Ok(Key::Ctrl('s')) => { if ui.state == State::SelectTag { //TODO save currently selected tag } } Ok(Key::Char('\n')) => { if ui.state == State::EditRepo { ui.state = State::SelectTag; ui.repo.confirm(); //TODO query tags and show them switch match tags::Tags::get_tags(ui.repo.get()) { Ok(lines) => ui.tags = tag_list::TagList::new(lines), Err(_) => (), } } } Ok(Key::Down) => { if ui.state == State::SelectTag { ui.tags.next(); } } Ok(Key::Up) => { if ui.state == State::SelectTag { ui.tags.previous(); } } Ok(Key::Backspace) => { ui.state = State::EditRepo; ui.repo.input(Key::Backspace); ui.tags = tag_list::TagList::new(vec![String::from("editing Repository")]); } Ok(key) => { ui.state = State::EditRepo; ui.repo.input(key); ui.tags = tag_list::TagList::new(vec![String::from("editing Repository")]); } _ => (), } //sleep for 64ms (15 fps) thread::sleep(std::time::Duration::from_millis(32)); } } pub fn spawn_stdin_channel(&self) -> mpsc::Receiver { let (tx, rx) = mpsc::channel::(); thread::spawn(move || loop { let stdin = io::stdin(); for c in stdin.keys() { tx.send(c.unwrap()).unwrap(); } }); thread::sleep(std::time::Duration::from_millis(64)); rx } }