1use std::io::{self, Stdout};
2use std::time::Duration;
3
4use crossterm::{
5 event::{self, Event, KeyCode},
6 execute,
7 terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
8};
9use ratatui::{prelude::*, widgets::*};
10
11struct State {
12 form: Form,
13 submissions: Option<Vec<String>>,
14 should_quit: bool,
15}
16
17use tui_form_widget::{Form, FormSelection};
18
19fn main() -> io::Result<()> {
20 let mut state = State {
21 form: Form::from(vec!["Account", "Username / Email", "Password"]),
22 should_quit: false,
23 submissions: None,
24 };
25 let mut terminal = setup_terminal()?;
26 run(&mut terminal, &mut state)?;
27 restore_terminal(&mut terminal)?;
28 Ok(())
29}
30
31fn setup_terminal() -> io::Result<Terminal<CrosstermBackend<Stdout>>> {
32 let mut stdout = io::stdout();
33 enable_raw_mode()?;
34 execute!(stdout, EnterAlternateScreen)?;
35 Terminal::new(CrosstermBackend::new(stdout))
36}
37
38fn restore_terminal(terminal: &mut Terminal<CrosstermBackend<Stdout>>) -> io::Result<()> {
39 disable_raw_mode()?;
40 execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
41 terminal.show_cursor()
42}
43
44fn run(terminal: &mut Terminal<CrosstermBackend<Stdout>>, state: &mut State) -> io::Result<()> {
45 loop {
46 terminal.draw(|f| render_app(f, state))?;
47 handle_input(state)?;
48 if state.should_quit {
49 break;
50 }
51 }
52 Ok(())
53}
54
55fn render_app(frame: &mut Frame<CrosstermBackend<Stdout>>, state: &State) {
56 match &state.submissions {
57 Some(fields) => frame.render_widget(Paragraph::new(fields.join("\n")), frame.size()),
58 None => frame.render_widget(state.form.widget(), frame.size()),
59 }
60}
61
62fn handle_input(state: &mut State) -> io::Result<()> {
63 if event::poll(Duration::from_millis(250))? {
64 if let Event::Key(key) = event::read()? {
65 match state.form.selected() {
66 FormSelection::NoSelection => match key.code {
67 KeyCode::Esc | KeyCode::Char('q') => state.should_quit = true,
68 KeyCode::Char('s') => {
69 let fields = state.form.submit();
70 if fields.iter().any(|f| !f.is_valid()) {
71 } else {
72 state.submissions = Some(fields.into_iter().map(Into::into).collect());
74
75 state.form.deselect();
76 }
77 }
78 _ => {}
79 },
80 _ => {}
81 }
82
83 state.form.input(key.code);
84 }
85 }
86
87 Ok(())
88}