reel-moby/src/ui.rs

199 lines
7.3 KiB
Rust
Raw Normal View History

2021-08-23 14:06:00 +02:00
use std::sync::mpsc;
use std::{io, thread};
2021-08-25 12:23:15 +02:00
use termion::event::Key;
2021-08-23 14:06:00 +02:00
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use tui::backend::TermionBackend;
2021-08-25 12:23:15 +02:00
use tui::layout::{Constraint, Direction, Layout};
2021-08-23 14:06:00 +02:00
use tui::Terminal;
2021-08-25 12:23:15 +02:00
use crate::widget::repo_entry;
use crate::widget::service_switcher;
2021-08-25 12:23:15 +02:00
use crate::widget::tag_list;
2021-08-23 14:06:00 +02:00
pub struct Ui {
state: State,
repo: crate::widget::repo_entry::RepoEntry,
tags: crate::widget::tag_list::TagList,
services: crate::widget::service_switcher::ServiceSwitcher,
2021-08-23 14:06:00 +02:00
}
#[derive(PartialEq, Clone)]
pub enum State {
EditRepo,
SelectTag,
SelectService,
2021-08-23 14:06:00 +02:00
}
impl State {
fn next(&self) -> State {
match self {
State::EditRepo => State::SelectTag,
State::SelectTag => State::SelectService,
State::SelectService => State::EditRepo,
}
}
}
2021-08-23 14:06:00 +02:00
impl Ui {
2021-08-29 00:23:40 +02:00
pub fn run(repo_id: &str) {
2021-08-23 14:06:00 +02:00
let mut ui = Ui {
state: State::SelectService,
2021-08-29 00:23:40 +02:00
repo: repo_entry::RepoEntry::new(repo_id),
tags: tag_list::TagList::with_status("Select image or edit Repository"),
services: service_switcher::ServiceSwitcher::new(),
2021-08-23 14:06:00 +02:00
};
//setup tui
2021-08-25 12:23:15 +02:00
let stdout = io::stdout().into_raw_mode().unwrap();
2021-08-23 14:06:00 +02:00
let backend = TermionBackend::new(stdout);
2021-08-25 12:23:15 +02:00
let mut terminal = Terminal::new(backend).unwrap();
2021-08-23 14:06:00 +02:00
//setup input thread
let receiver = ui.spawn_stdin_channel();
//core interaction loop
'core: loop {
//draw
2021-08-25 12:23:15 +02:00
terminal
.draw(|rect| {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints(
[
Constraint::Min(3),
Constraint::Length(3),
Constraint::Max(7),
]
.as_ref(),
)
2021-08-25 12:23:15 +02:00
.split(rect.size());
2021-08-23 14:06:00 +02:00
let (list, state) = ui.services.render(&ui.state);
rect.render_stateful_widget(list, chunks[0], state);
rect.render_widget(ui.repo.render(&ui.state), chunks[1]);
2021-08-28 17:37:55 +02:00
let (list, state) = ui.tags.render(&ui.state);
rect.render_stateful_widget(list, chunks[2], state);
2021-08-25 12:23:15 +02:00
})
.unwrap();
2021-08-23 14:06:00 +02:00
//handle input
match receiver.try_recv() {
Ok(Key::Ctrl('q')) => break 'core, //quit program without saving
Ok(Key::Char('\t')) => ui.state = ui.state.next(),
2021-09-01 23:04:07 +02:00
Ok(Key::Ctrl('s')) => match ui.services.save() {
Err(e) => {
ui.show_info(&format!("{}", e));
continue;
}
2021-09-01 23:04:07 +02:00
Ok(_) => (),
},
Ok(Key::Char('\n')) => match ui.state {
State::EditRepo => {
2021-08-23 14:06:00 +02:00
ui.repo.confirm();
ui.tags = tag_list::TagList::with_repo(ui.repo.get());
2021-08-23 14:06:00 +02:00
}
State::SelectTag => {
2021-09-02 01:00:09 +02:00
let mut repo = ui.repo.get();
let tag = match ui.tags.get_selected() {
Err(e) => {
ui.show_info(&format!("{}", e));
continue;
}
Ok(tag) => tag,
};
repo.push_str(":");
repo.push_str(&tag);
ui.services.change_current_line(repo);
}
_ => (),
},
2021-08-28 17:37:55 +02:00
Ok(Key::Char(key)) => {
if ui.state == State::EditRepo {
ui.show_info("Editing Repository");
2021-08-23 14:06:00 +02:00
}
2021-08-28 17:37:55 +02:00
ui.repo.handle_input(&ui.state, Key::Char(key));
ui.tags.handle_input(&ui.state, Key::Char(key));
2021-08-23 14:06:00 +02:00
}
Ok(Key::Backspace) => {
2021-08-28 17:37:55 +02:00
if ui.state == State::EditRepo {
ui.show_info("Editing Repository");
2021-08-28 17:37:55 +02:00
}
ui.repo.handle_input(&ui.state, Key::Backspace);
ui.tags.handle_input(&ui.state, Key::Backspace);
2021-08-23 14:06:00 +02:00
}
Ok(Key::Up) => {
if ui.state == State::SelectService && ui.services.find_previous_match() {
match ui.services.extract_repo() {
Err(e) => ui.show_info(&format!("{}", e)),
Ok(s) => {
let repo = match crate::tags::Tags::check_repo(s) {
Err(e) => {
ui.show_info(&format!("{}", e));
continue;
}
Ok(s) => s,
};
ui.repo.set(repo);
ui.tags = tag_list::TagList::with_repo(ui.repo.get());
}
}
}
ui.tags.handle_input(&ui.state, Key::Up);
ui.repo.handle_input(&ui.state, Key::Up);
}
Ok(Key::Down) => match ui.state {
State::SelectService if ui.services.find_next_match() => {
match ui.services.extract_repo() {
Err(e) => ui.show_info(&format!("{}", e)),
Ok(s) => {
2021-09-02 01:00:09 +02:00
let repo = match crate::tags::Tags::check_repo(s) {
Err(e) => {
ui.show_info(&format!("{}", e));
continue;
}
2021-09-02 01:00:09 +02:00
Ok(s) => s,
};
ui.repo.set(repo);
ui.tags = tag_list::TagList::with_repo(ui.repo.get());
}
}
}
_ => {
ui.tags.handle_input(&ui.state, Key::Down);
ui.repo.handle_input(&ui.state, Key::Down);
}
},
2021-08-23 14:06:00 +02:00
Ok(key) => {
ui.repo.handle_input(&ui.state, Key::Down);
2021-08-28 17:37:55 +02:00
ui.tags.handle_input(&ui.state, key);
2021-08-23 14:06:00 +02:00
}
_ => (),
}
//sleep for 32ms (30 fps)
2021-08-25 10:34:42 +02:00
thread::sleep(std::time::Duration::from_millis(32));
2021-08-23 14:06:00 +02:00
}
2021-09-01 23:04:07 +02:00
terminal.clear().unwrap();
2021-08-23 14:06:00 +02:00
}
fn show_info(&mut self, error: &str) {
self.tags = tag_list::TagList::with_status(error);
}
2021-08-23 14:06:00 +02:00
pub fn spawn_stdin_channel(&self) -> mpsc::Receiver<termion::event::Key> {
let (tx, rx) = mpsc::channel::<termion::event::Key>();
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
}
}