135 lines
4.4 KiB
Rust
135 lines
4.4 KiB
Rust
// This file is part of Deja-Vu.
|
|
//
|
|
// Deja-Vu is free software: you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Deja-Vu is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Deja-Vu. If not, see <https://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
use color_eyre::Result;
|
|
use core::{action::Action, components::Component, config::Config, state::Mode, tui::Event};
|
|
use crossterm::event::KeyCode;
|
|
use ratatui::{
|
|
prelude::*,
|
|
widgets::{Block, Borders, Clear, Paragraph},
|
|
};
|
|
use tokio::sync::mpsc::UnboundedSender;
|
|
use tui_input::{Input, InputRequest};
|
|
|
|
#[derive(Default)]
|
|
pub struct InputUsername {
|
|
command_tx: Option<UnboundedSender<Action>>,
|
|
config: Config,
|
|
input: Input,
|
|
mode: Mode,
|
|
}
|
|
|
|
impl InputUsername {
|
|
#[must_use]
|
|
pub fn new() -> Self {
|
|
Self {
|
|
input: Input::new(String::from("")),
|
|
..Default::default()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Component for InputUsername {
|
|
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
|
|
self.command_tx = Some(tx);
|
|
Ok(())
|
|
}
|
|
|
|
fn register_config_handler(&mut self, config: Config) -> Result<()> {
|
|
self.config = config;
|
|
Ok(())
|
|
}
|
|
|
|
fn handle_events(&mut self, event: Option<Event>) -> Result<Option<Action>> {
|
|
if self.mode != Mode::SetUserName {
|
|
return Ok(None);
|
|
}
|
|
let action = match event {
|
|
Some(Event::Key(key_event)) => match key_event.code {
|
|
KeyCode::Backspace => {
|
|
self.input.handle(InputRequest::DeletePrevChar);
|
|
None
|
|
}
|
|
KeyCode::Char(c) => {
|
|
let ok_chars: Vec<char> = vec![' ', '-', '_'];
|
|
if c.is_ascii_alphanumeric() || ok_chars.contains(&c) {
|
|
self.input.handle(InputRequest::InsertChar(c));
|
|
}
|
|
None
|
|
}
|
|
KeyCode::Enter => {
|
|
let username = self.input.value();
|
|
Some(Action::SetUserName(String::from(username)))
|
|
}
|
|
KeyCode::Esc => Some(Action::SetMode(Mode::Home)),
|
|
_ => None,
|
|
},
|
|
Some(Event::Mouse(_)) => None,
|
|
_ => None,
|
|
};
|
|
Ok(action)
|
|
}
|
|
|
|
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
|
match action {
|
|
Action::SetMode(mode) => self.mode = mode.clone(),
|
|
_ => {}
|
|
}
|
|
Ok(None)
|
|
}
|
|
|
|
fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> {
|
|
if self.mode != Mode::SetUserName {
|
|
// Bail early
|
|
return Ok(());
|
|
}
|
|
|
|
// Set areas
|
|
let [_, center_area, _] = Layout::horizontal([
|
|
Constraint::Length(1),
|
|
Constraint::Min(1),
|
|
Constraint::Length(1),
|
|
])
|
|
.areas(area);
|
|
let [_, input_area, _] = Layout::vertical([
|
|
Constraint::Length(1),
|
|
Constraint::Length(3),
|
|
Constraint::Length(1),
|
|
])
|
|
.areas(center_area);
|
|
|
|
frame.render_widget(Clear, area);
|
|
let outer_block = Block::bordered().cyan().bold();
|
|
frame.render_widget(outer_block, area);
|
|
|
|
// Input Box
|
|
let width = input_area.width.max(3) - 3; // keep 2 for borders and 1 for cursor
|
|
let scroll = self.input.visual_scroll(width as usize);
|
|
let input = Paragraph::new(self.input.value())
|
|
.scroll((0, scroll as u16))
|
|
.white()
|
|
.block(Block::new().borders(Borders::ALL).title("Enter Username"));
|
|
frame.render_widget(input, input_area);
|
|
|
|
// Ratatui hides the cursor unless it's explicitly set. Position the cursor past the
|
|
// end of the input text and one line down from the border to the input line
|
|
let x = self.input.visual_cursor().max(scroll) - scroll + 1;
|
|
frame.set_cursor_position((input_area.x + x as u16, input_area.y + 1));
|
|
|
|
// Done
|
|
Ok(())
|
|
}
|
|
}
|