cove/src/ui/euph/account.rs

211 lines
6.6 KiB
Rust

use crossterm::style::{ContentStyle, Stylize};
use euphoxide::api::PersonalAccountView;
use euphoxide::conn::Status;
use toss::terminal::Terminal;
use crate::euph::Room;
use crate::ui::input::{key, InputEvent, KeyBindingsList};
use crate::ui::util;
use crate::ui::widgets::editor::EditorState;
use crate::ui::widgets::empty::Empty;
use crate::ui::widgets::join::{HJoin, Segment, VJoin};
use crate::ui::widgets::popup::Popup;
use crate::ui::widgets::resize::Resize;
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 {
let bold = ContentStyle::default().bold();
VJoin::new(vec![
Segment::new(Text::new(("Not logged in", bold.yellow()))),
Segment::new(Empty::new().height(1)),
Segment::new(HJoin::new(vec![
Segment::new(Text::new(("Email address:", bold))),
Segment::new(Empty::new().width(1)),
Segment::new(self.email.widget().focus(self.focus == Focus::Email)),
])),
Segment::new(HJoin::new(vec![
Segment::new(Text::new(("Password:", bold))),
Segment::new(Empty::new().width(5 + 1)),
Segment::new(
self.password
.widget()
.focus(self.focus == Focus::Password)
.hidden(),
),
])),
])
.into()
}
}
pub struct LoggedIn(PersonalAccountView);
impl LoggedIn {
fn widget(&self) -> BoxedWidget {
let bold = ContentStyle::default().bold();
VJoin::new(vec![
Segment::new(Text::new(("Logged in", bold.green()))),
Segment::new(Empty::new().height(1)),
Segment::new(HJoin::new(vec![
Segment::new(Text::new(("Email address:", bold))),
Segment::new(Empty::new().width(1)),
Segment::new(Text::new((&self.0.email,))),
])),
])
.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(Resize::new(inner).min_width(40))
.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');
}
Self::LoggedIn(_) => bindings.binding("L", "log out"),
}
}
pub fn handle_input_event(
&mut self,
terminal: &mut Terminal,
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,
event,
|c| c != '\n',
) {
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,
event,
|c| c != '\n',
) {
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
}
}
}
}
}