use crossterm::{ event::{self, Event, KeyCode}, execute, terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode}, }; use ratatui::{ Terminal, backend::CrosstermBackend, layout::{Constraint, Direction, Layout}, style::{Color, Style}, widgets::{Block, Borders, Paragraph}, }; use std::io; /// Runs the TUI and returns the entered username and password. /// This module owns all terminal state. pub fn run() -> io::Result<(String, String)> { enable_raw_mode()?; let mut stdout = io::stdout(); execute!(stdout, EnterAlternateScreen)?; let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; let mut username = String::new(); let mut password = String::new(); let mut focus = 0; loop { terminal.draw(|f| { let chunks = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Length(3), Constraint::Length(3)]) .split(f.area()); let user = Paragraph::new(username.as_str()) .block(Block::default().borders(Borders::ALL).title("User")) .style(if focus == 0 { Style::new().fg(Color::from_u32(0x00235759)) } else { Style::default() }); let pass = Paragraph::new(password.as_str()) .block(Block::default().borders(Borders::ALL).title("Password")) .style(if focus == 1 { Style::new().fg(Color::from_u32(0x00235759)) } else { Style::default() }); f.render_widget(user, chunks[0]); f.render_widget(pass, chunks[1]); })?; if let Event::Key(key) = event::read()? { match key.code { KeyCode::Esc => break, KeyCode::Tab => focus = (focus + 1) % 2, KeyCode::Enter => break, KeyCode::Backspace => { if focus == 0 { username.pop(); } else { password.pop(); } } KeyCode::Char(c) => { if focus == 0 { username.push(c); } else { password.push(c); } } _ => {} } } } disable_raw_mode()?; execute!(terminal.backend_mut(), LeaveAlternateScreen)?; Ok((username, password)) }