use crossterm::event::
{
KeyCode,
KeyEvent,
};
use zeroize::Zeroizing;
use super::
{
input::InputBuffer,
login,
state::App,
};
#[derive(Clone, Copy, PartialEq)] pub enum Kind
{
Passwd,
Delete,
}
pub enum Request {
Passwd(String, String), Delete(String), }
pub struct Account {
pub kind: Kind,
pub fields: Vec<InputBuffer>,
pub focus: usize,
pub busy: bool, pub armed: bool, pub error: Option<String>, new: Zeroizing<String>, request: bool, }
impl Kind
{
pub fn labels(&self) -> &'static [&'static str]
{
match self
{
Kind::Passwd => &[ "Current password", "New password", "Confirm new password" ],
Kind::Delete => &[ "Current password" ],
}
}
pub fn title(&self) -> &'static str
{
match self
{
Kind::Passwd => " Change password ",
Kind::Delete => " Delete account ",
}
}
}
impl Account
{
pub fn new(kind: Kind) -> Self
{
Self
{
kind,
fields: kind.labels().iter().map(|_| InputBuffer::new()).collect(),
focus: 0,
busy: false,
armed: false,
error: None,
new: Zeroizing::default(),
request: false,
}
}
pub fn take_request(&mut self) -> Option<Request>
{
if !self.request { return None; }
self.request = false;
Some(match self.kind
{
Kind::Passwd => Request::Passwd(self.fields[0].text(), self.new.to_string()),
Kind::Delete => Request::Delete(self.fields[0].text()),
})
}
pub fn new_password(&self) -> &str { &self.new }
pub fn rejected(&mut self, error: String)
{
*self = Self::new(self.kind);
self.error = Some(error);
}
fn submit(&mut self)
{
if let Some(empty) = self.fields.iter().position(InputBuffer::is_empty)
{
self.focus = empty;
self.error = Some(format!("Enter the {}.", self.kind.labels()[empty].to_lowercase()));
return;
}
match self.kind
{
Kind::Passwd =>
{
let new = Zeroizing::new(self.fields[1].text());
if *new != self.fields[2].text()
{
self.fields[2].clear();
self.focus = 2;
self.error = Some(String::from("Passwords do not match."));
return;
}
self.new = new;
},
Kind::Delete => if !self.armed
{
self.armed = true;
self.error = None;
return;
},
}
self.error = None;
self.busy = true;
self.request = true;
}
}
pub fn handle_key(app: &mut App, key: KeyEvent)
{
let Some(form) = app.account.as_mut() else { return };
if form.busy { return; }
let last = form.fields.len() - 1;
match key.code
{
KeyCode::Esc => app.account = None,
KeyCode::Up | KeyCode::BackTab => form.focus = form.focus.saturating_sub(1),
KeyCode::Down | KeyCode::Tab => form.focus = (form.focus + 1).min(last),
KeyCode::Enter => match form.focus == last
{
true => form.submit(),
false => form.focus += 1,
},
_ => if login::edit(&mut form.fields[form.focus], key) { form.armed = false; },
}
}
pub fn insert_str(app: &mut App, text: &str) {
if let Some(form) = app.account.as_mut() && !form.busy
{
form.fields[form.focus].insert_str(&text.replace(['\r', '\n'], ""));
form.armed = false;
}
}