diff --git a/src/ui/euph.rs b/src/ui/euph.rs index 0c522c7..b6836f6 100644 --- a/src/ui/euph.rs +++ b/src/ui/euph.rs @@ -1,3 +1,4 @@ +mod nick; mod nick_list; mod popup; pub mod room; diff --git a/src/ui/euph/nick.rs b/src/ui/euph/nick.rs new file mode 100644 index 0000000..ca027f8 --- /dev/null +++ b/src/ui/euph/nick.rs @@ -0,0 +1,83 @@ +use std::sync::Arc; + +use crossterm::event::KeyCode; +use euphoxide::conn::{Joined, Status}; +use parking_lot::FairMutex; +use toss::styled::Styled; +use toss::terminal::Terminal; + +use crate::euph::{self, Room}; +use crate::ui::input::{key, InputEvent, KeyBindingsList, KeyEvent}; +use crate::ui::util; +use crate::ui::widgets::editor::EditorState; +use crate::ui::widgets::padding::Padding; +use crate::ui::widgets::popup::Popup; +use crate::ui::widgets::BoxedWidget; + +use super::room::RoomStatus; + +pub fn new(joined: Joined) -> EditorState { + EditorState::with_initial_text(joined.session.name) +} + +pub fn stable(status: &RoomStatus) -> bool { + matches!(status, RoomStatus::Connected(Status::Joined(_))) +} + +pub fn widget(editor: &EditorState) -> BoxedWidget { + let editor = editor + .widget() + .highlight(|s| Styled::new(s, euph::nick_style(s))); + Popup::new(Padding::new(editor).left(1)) + .title("Choose nick") + .inner_padding(false) + .build() +} + +fn nick_char(c: char) -> bool { + c != '\n' +} + +pub fn list_key_bindings(bindings: &mut KeyBindingsList) { + bindings.binding("esc", "abort"); + bindings.binding("enter", "set nick"); + util::list_editor_key_bindings(bindings, nick_char, false); +} + +pub enum EventResult { + NotHandled, + Handled, + ResetState, +} + +pub fn handle_input_event( + terminal: &mut Terminal, + crossterm_lock: &Arc>, + event: &InputEvent, + room: &Option, + editor: &EditorState, +) -> EventResult { + match event { + key!(Esc) => EventResult::ResetState, + key!(Enter) => { + if let Some(room) = &room { + let _ = room.nick(editor.text()); + } + EventResult::ResetState + } + _ => { + if util::handle_editor_input_event( + editor, + terminal, + crossterm_lock, + event, + nick_char, + false, + ) { + EventResult::Handled + } else { + EventResult::NotHandled + } + } + } +} diff --git a/src/ui/euph/room.rs b/src/ui/euph/room.rs index 88b2965..9ba2ff3 100644 --- a/src/ui/euph/room.rs +++ b/src/ui/euph/room.rs @@ -29,8 +29,8 @@ use crate::ui::widgets::BoxedWidget; use crate::ui::{util, UiEvent}; use crate::vault::EuphVault; -use super::nick_list; use super::popup::RoomPopup; +use super::{nick, nick_list}; enum State { Normal, @@ -166,9 +166,7 @@ impl EuphRoom { { self.state = State::Normal } - State::Nick(_) if !matches!(status, RoomStatus::Connected(Status::Joined(_))) => { - self.state = State::Normal - } + State::Nick(_) if !nick::stable(status) => self.state = State::Normal, _ => {} } } @@ -193,7 +191,7 @@ impl EuphRoom { match &self.state { State::Normal => {} State::Auth(_) => layers.push(Self::auth_widget()), - State::Nick(editor) => layers.push(Self::nick_widget(editor)), + State::Nick(editor) => layers.push(nick::widget(editor)), } for popup in &self.popups { @@ -216,16 +214,6 @@ impl EuphRoom { .build() } - fn nick_widget(editor: &EditorState) -> BoxedWidget { - let editor = editor - .widget() - .highlight(|s| Styled::new(s, euph::nick_style(s))); - Popup::new(Padding::new(editor).left(1)) - .title("Choose nick") - .inner_padding(false) - .build() - } - async fn widget_without_nick_list(&self, status: &RoomStatus) -> BoxedWidget { VJoin::new(vec![ Segment::new(Border::new( @@ -288,10 +276,6 @@ impl EuphRoom { Text::new(info).into() } - fn nick_char(c: char) -> bool { - c != '\n' - } - pub async fn list_key_bindings(&self, bindings: &mut KeyBindingsList) { bindings.heading("Room"); @@ -305,14 +289,14 @@ impl EuphRoom { bindings.binding("esc", "leave room"); let can_compose = if let Some(room) = &self.room { - match room.status().await { - Ok(Some(Status::Joining(Joining { + match room.status().await.ok().flatten() { + Some(Status::Joining(Joining { bounce: Some(_), .. - }))) => { + })) => { bindings.binding("a", "authenticate"); false } - Ok(Some(Status::Joined(_))) => { + Some(Status::Joined(_)) => { bindings.binding("n", "change nick"); true } @@ -328,13 +312,9 @@ impl EuphRoom { State::Auth(_) => { bindings.binding("esc", "abort"); bindings.binding("enter", "authenticate"); - util::list_editor_key_bindings(bindings, Self::nick_char, false); - } - State::Nick(_) => { - bindings.binding("esc", "abort"); - bindings.binding("enter", "set nick"); - util::list_editor_key_bindings(bindings, Self::nick_char, false); + util::list_editor_key_bindings(bindings, |_| true, false); } + State::Nick(_) => nick::list_key_bindings(bindings), } } @@ -376,18 +356,15 @@ impl EuphRoom { } } - match status { - Ok(Some(Status::Joining(Joining { + match status.ok().flatten() { + Some(Status::Joining(Joining { bounce: Some(_), .. - }))) if matches!(event, key!('a') | key!('A')) => { + })) if matches!(event, key!('a') | key!('A')) => { self.state = State::Auth(EditorState::new()); true } - Ok(Some(Status::Joined(joined))) - if matches!(event, key!('n') | key!('N')) => - { - let name = joined.session.name; - self.state = State::Nick(EditorState::with_initial_text(name)); + Some(Status::Joined(joined)) if matches!(event, key!('n') | key!('N')) => { + self.state = State::Nick(nick::new(joined)); true } _ => false, @@ -416,31 +393,21 @@ impl EuphRoom { terminal, crossterm_lock, event, - Self::nick_char, + |_| true, false, ), }, - State::Nick(ed) => match event { - key!(Esc) => { - self.state = State::Normal; - true - } - key!(Enter) => { - if let Some(room) = &self.room { - let _ = room.nick(ed.text()); + State::Nick(editor) => { + match nick::handle_input_event(terminal, crossterm_lock, event, &self.room, editor) + { + nick::EventResult::NotHandled => false, + nick::EventResult::Handled => true, + nick::EventResult::ResetState => { + self.state = State::Normal; + true } - self.state = State::Normal; - true } - _ => util::handle_editor_input_event( - ed, - terminal, - crossterm_lock, - event, - Self::nick_char, - false, - ), - }, + } } }