Implement account login and logout
This commit is contained in:
parent
84930c8c34
commit
8128342099
8 changed files with 299 additions and 29 deletions
204
src/ui/euph/account.rs
Normal file
204
src/ui/euph/account.rs
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crossterm::event::KeyCode;
|
||||
use euphoxide::api::PersonalAccountView;
|
||||
use euphoxide::conn::Status;
|
||||
use parking_lot::FairMutex;
|
||||
use toss::styled::Styled;
|
||||
use toss::terminal::Terminal;
|
||||
|
||||
use crate::euph::Room;
|
||||
use crate::ui::input::{key, InputEvent, KeyBindingsList, KeyEvent};
|
||||
use crate::ui::util;
|
||||
use crate::ui::widgets::editor::EditorState;
|
||||
use crate::ui::widgets::empty::Empty;
|
||||
use crate::ui::widgets::join::{Segment, VJoin};
|
||||
use crate::ui::widgets::popup::Popup;
|
||||
use crate::ui::widgets::text::Text;
|
||||
use crate::ui::widgets::BoxedWidget;
|
||||
|
||||
use super::room::RoomStatus;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum Focus {
|
||||
Email,
|
||||
Password,
|
||||
}
|
||||
|
||||
pub struct LoggedOut {
|
||||
focus: Focus,
|
||||
email: EditorState,
|
||||
password: EditorState,
|
||||
}
|
||||
|
||||
impl LoggedOut {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
focus: Focus::Email,
|
||||
email: EditorState::new(),
|
||||
password: EditorState::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn widget(&self) -> BoxedWidget {
|
||||
VJoin::new(vec![
|
||||
Segment::new(Text::new("Email address")),
|
||||
Segment::new(self.email.widget().focus(self.focus == Focus::Email)),
|
||||
Segment::new(Empty::new().height(1)),
|
||||
Segment::new(Text::new("Password")),
|
||||
Segment::new(
|
||||
self.password
|
||||
.widget()
|
||||
.focus(self.focus == Focus::Password)
|
||||
.hidden(),
|
||||
),
|
||||
])
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoggedIn(PersonalAccountView);
|
||||
|
||||
impl LoggedIn {
|
||||
fn widget(&self) -> BoxedWidget {
|
||||
let text = Styled::new_plain("Name: ")
|
||||
.then_plain(&self.0.name)
|
||||
.then_plain("\n")
|
||||
.then_plain("Email: ")
|
||||
.then_plain(&self.0.email);
|
||||
Text::new(text).into()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum AccountUiState {
|
||||
LoggedOut(LoggedOut),
|
||||
LoggedIn(LoggedIn),
|
||||
}
|
||||
|
||||
pub enum EventResult {
|
||||
NotHandled,
|
||||
Handled,
|
||||
ResetState,
|
||||
}
|
||||
|
||||
impl AccountUiState {
|
||||
pub fn new() -> Self {
|
||||
Self::LoggedOut(LoggedOut::new())
|
||||
}
|
||||
|
||||
/// Returns `false` if the account UI should not be displayed any longer.
|
||||
pub fn stabilize(&mut self, status: &RoomStatus) -> bool {
|
||||
if let RoomStatus::Connected(Status::Joined(status)) = status {
|
||||
match (&self, &status.account) {
|
||||
(Self::LoggedOut(_), Some(view)) => *self = Self::LoggedIn(LoggedIn(view.clone())),
|
||||
(Self::LoggedIn(_), None) => *self = Self::LoggedOut(LoggedOut::new()),
|
||||
_ => {}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn widget(&self) -> BoxedWidget {
|
||||
let inner = match self {
|
||||
Self::LoggedOut(logged_out) => logged_out.widget(),
|
||||
Self::LoggedIn(logged_in) => logged_in.widget(),
|
||||
};
|
||||
Popup::new(inner).title("Account").build()
|
||||
}
|
||||
|
||||
pub fn list_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||
bindings.binding("esc", "close account ui");
|
||||
|
||||
match self {
|
||||
Self::LoggedOut(logged_out) => {
|
||||
match logged_out.focus {
|
||||
Focus::Email => bindings.binding("enter", "focus on password"),
|
||||
Focus::Password => bindings.binding("enter", "log in"),
|
||||
}
|
||||
bindings.binding("tab", "switch focus");
|
||||
util::list_editor_key_bindings(bindings, |c| c != '\n', false);
|
||||
}
|
||||
Self::LoggedIn(_) => bindings.binding("L", "log out"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_input_event(
|
||||
&mut self,
|
||||
terminal: &mut Terminal,
|
||||
crossterm_lock: &Arc<FairMutex<()>>,
|
||||
event: &InputEvent,
|
||||
room: &Option<Room>,
|
||||
) -> EventResult {
|
||||
if let key!(Esc) = event {
|
||||
return EventResult::ResetState;
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::LoggedOut(logged_out) => {
|
||||
if let key!(Tab) = event {
|
||||
logged_out.focus = match logged_out.focus {
|
||||
Focus::Email => Focus::Password,
|
||||
Focus::Password => Focus::Email,
|
||||
};
|
||||
return EventResult::Handled;
|
||||
}
|
||||
|
||||
match logged_out.focus {
|
||||
Focus::Email => {
|
||||
if let key!(Enter) = event {
|
||||
logged_out.focus = Focus::Password;
|
||||
return EventResult::Handled;
|
||||
}
|
||||
|
||||
if util::handle_editor_input_event(
|
||||
&logged_out.email,
|
||||
terminal,
|
||||
crossterm_lock,
|
||||
event,
|
||||
|c| c != '\n',
|
||||
false,
|
||||
) {
|
||||
EventResult::Handled
|
||||
} else {
|
||||
EventResult::NotHandled
|
||||
}
|
||||
}
|
||||
Focus::Password => {
|
||||
if let key!(Enter) = event {
|
||||
if let Some(room) = room {
|
||||
let _ =
|
||||
room.login(logged_out.email.text(), logged_out.password.text());
|
||||
}
|
||||
return EventResult::Handled;
|
||||
}
|
||||
|
||||
if util::handle_editor_input_event(
|
||||
&logged_out.password,
|
||||
terminal,
|
||||
crossterm_lock,
|
||||
event,
|
||||
|c| c != '\n',
|
||||
false,
|
||||
) {
|
||||
EventResult::Handled
|
||||
} else {
|
||||
EventResult::NotHandled
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::LoggedIn(_) => {
|
||||
if let key!('L') = event {
|
||||
if let Some(room) = room {
|
||||
let _ = room.logout();
|
||||
}
|
||||
EventResult::Handled
|
||||
} else {
|
||||
EventResult::NotHandled
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue