Support choosing domain in room connection popup
This commit is contained in:
parent
f4967731a1
commit
970bc07ed9
3 changed files with 142 additions and 38 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod connect;
|
||||||
|
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
@ -17,6 +19,8 @@ use crate::euph;
|
||||||
use crate::macros::logging_unwrap;
|
use crate::macros::logging_unwrap;
|
||||||
use crate::vault::{EuphVault, RoomIdentifier, Vault};
|
use crate::vault::{EuphVault, RoomIdentifier, Vault};
|
||||||
|
|
||||||
|
use self::connect::{ConnectResult, ConnectState};
|
||||||
|
|
||||||
use super::euph::room::EuphRoom;
|
use super::euph::room::EuphRoom;
|
||||||
use super::widgets::{ListBuilder, ListState, Popup};
|
use super::widgets::{ListBuilder, ListState, Popup};
|
||||||
use super::{key_bindings, util, UiError, UiEvent};
|
use super::{key_bindings, util, UiError, UiEvent};
|
||||||
|
|
@ -24,7 +28,7 @@ use super::{key_bindings, util, UiError, UiEvent};
|
||||||
enum State {
|
enum State {
|
||||||
ShowList,
|
ShowList,
|
||||||
ShowRoom(RoomIdentifier),
|
ShowRoom(RoomIdentifier),
|
||||||
Connect(EditorState),
|
Connect(ConnectState),
|
||||||
Delete(RoomIdentifier, EditorState),
|
Delete(RoomIdentifier, EditorState),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,10 +246,10 @@ impl Rooms {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
State::Connect(editor) => {
|
State::Connect(connect) => {
|
||||||
Self::rooms_widget(self.config, &mut self.list, self.order, &self.euph_rooms)
|
Self::rooms_widget(self.config, &mut self.list, self.order, &self.euph_rooms)
|
||||||
.await
|
.await
|
||||||
.below(Self::new_room_widget(editor))
|
.below(connect.widget())
|
||||||
.desync()
|
.desync()
|
||||||
.boxed_async()
|
.boxed_async()
|
||||||
}
|
}
|
||||||
|
|
@ -261,20 +265,6 @@ impl Rooms {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_room_widget(editor: &mut EditorState) -> impl Widget<UiError> + '_ {
|
|
||||||
let room_style = Style::new().bold().blue();
|
|
||||||
|
|
||||||
let inner = Join2::horizontal(
|
|
||||||
Text::new(("&", room_style)).segment().with_fixed(true),
|
|
||||||
editor
|
|
||||||
.widget()
|
|
||||||
.with_highlight(|s| Styled::new(s, room_style))
|
|
||||||
.segment(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Popup::new(inner, "Connect to")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_room_widget<'a>(
|
fn delete_room_widget<'a>(
|
||||||
id: &RoomIdentifier,
|
id: &RoomIdentifier,
|
||||||
editor: &'a mut EditorState,
|
editor: &'a mut EditorState,
|
||||||
|
|
@ -472,10 +462,6 @@ impl Rooms {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn room_char(c: char) -> bool {
|
|
||||||
c.is_ascii_alphanumeric() || c == '_'
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_showlist_input_event(
|
async fn handle_showlist_input_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
event: &mut InputEvent<'_>,
|
event: &mut InputEvent<'_>,
|
||||||
|
|
@ -534,7 +520,7 @@ impl Rooms {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if event.matches(&keys.rooms.action.new) {
|
if event.matches(&keys.rooms.action.new) {
|
||||||
self.state = State::Connect(EditorState::new());
|
self.state = State::Connect(ConnectState::new());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if event.matches(&keys.rooms.action.delete) {
|
if event.matches(&keys.rooms.action.delete) {
|
||||||
|
|
@ -574,28 +560,21 @@ impl Rooms {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::Connect(editor) => {
|
State::Connect(connect) => match connect.handle_input_event(event, keys) {
|
||||||
if event.matches(&keys.general.abort) {
|
ConnectResult::Close => {
|
||||||
self.state = State::ShowList;
|
self.state = State::ShowList;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if event.matches(&keys.general.confirm) {
|
ConnectResult::Connect(room) => {
|
||||||
let name = editor.text().to_string();
|
self.connect_to_room(room.clone()).await;
|
||||||
if !name.is_empty() {
|
self.state = State::ShowRoom(room);
|
||||||
let room = RoomIdentifier {
|
|
||||||
// TODO Remove hardcoded domain
|
|
||||||
domain: "euphoria.leet.nu".to_string(),
|
|
||||||
name,
|
|
||||||
};
|
|
||||||
self.connect_to_room(room.clone()).await;
|
|
||||||
self.state = State::ShowRoom(room);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if util::handle_editor_input_event(editor, event, keys, Self::room_char) {
|
ConnectResult::Handled => {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
ConnectResult::Unhandled => {}
|
||||||
|
},
|
||||||
State::Delete(id, editor) => {
|
State::Delete(id, editor) => {
|
||||||
if event.matches(&keys.general.abort) {
|
if event.matches(&keys.general.abort) {
|
||||||
self.state = State::ShowList;
|
self.state = State::ShowList;
|
||||||
|
|
@ -607,7 +586,7 @@ impl Rooms {
|
||||||
self.state = State::ShowList;
|
self.state = State::ShowList;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if util::handle_editor_input_event(editor, event, keys, Self::room_char) {
|
if util::handle_editor_input_event(editor, event, keys, util::is_room_char) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
120
cove/src/ui/rooms/connect.rs
Normal file
120
cove/src/ui/rooms/connect.rs
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
use cove_config::Keys;
|
||||||
|
use cove_input::InputEvent;
|
||||||
|
use crossterm::style::Stylize;
|
||||||
|
use toss::widgets::{EditorState, Empty, Join2, Join3, Text};
|
||||||
|
use toss::{Style, Styled, Widget, WidgetExt};
|
||||||
|
|
||||||
|
use crate::ui::widgets::Popup;
|
||||||
|
use crate::ui::{util, UiError};
|
||||||
|
use crate::vault::RoomIdentifier;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum Focus {
|
||||||
|
Name,
|
||||||
|
Domain,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Focus {
|
||||||
|
fn advance(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Name => Self::Domain,
|
||||||
|
Self::Domain => Self::Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConnectState {
|
||||||
|
focus: Focus,
|
||||||
|
name: EditorState,
|
||||||
|
domain: EditorState,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ConnectResult {
|
||||||
|
Close,
|
||||||
|
Connect(RoomIdentifier),
|
||||||
|
Handled,
|
||||||
|
Unhandled,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
focus: Focus::Name,
|
||||||
|
name: EditorState::new(),
|
||||||
|
domain: EditorState::with_initial_text("euphoria.leet.nu".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_input_event(&mut self, event: &mut InputEvent<'_>, keys: &Keys) -> ConnectResult {
|
||||||
|
if event.matches(&keys.general.abort) {
|
||||||
|
return ConnectResult::Close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.matches(&keys.general.focus) {
|
||||||
|
self.focus = self.focus.advance();
|
||||||
|
return ConnectResult::Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.matches(&keys.general.confirm) {
|
||||||
|
let id = RoomIdentifier {
|
||||||
|
domain: self.domain.text().to_string(),
|
||||||
|
name: self.name.text().to_string(),
|
||||||
|
};
|
||||||
|
if !id.domain.is_empty() && !id.name.is_empty() {
|
||||||
|
return ConnectResult::Connect(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let handled = match self.focus {
|
||||||
|
Focus::Name => {
|
||||||
|
util::handle_editor_input_event(&mut self.name, event, keys, util::is_room_char)
|
||||||
|
}
|
||||||
|
Focus::Domain => {
|
||||||
|
util::handle_editor_input_event(&mut self.domain, event, keys, util::is_room_char)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if handled {
|
||||||
|
return ConnectResult::Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectResult::Unhandled
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn widget(&mut self) -> impl Widget<UiError> + '_ {
|
||||||
|
let room_style = Style::new().bold().blue();
|
||||||
|
let domain_style = Style::new().grey();
|
||||||
|
|
||||||
|
let name = Join2::horizontal(
|
||||||
|
Text::new(Styled::new_plain("Room: ").then("&", room_style))
|
||||||
|
.with_wrap(false)
|
||||||
|
.segment()
|
||||||
|
.with_fixed(true),
|
||||||
|
self.name
|
||||||
|
.widget()
|
||||||
|
.with_highlight(|s| Styled::new(s, room_style))
|
||||||
|
.with_focus(self.focus == Focus::Name)
|
||||||
|
.segment(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let domain = Join3::horizontal(
|
||||||
|
Text::new("Domain:")
|
||||||
|
.with_wrap(false)
|
||||||
|
.segment()
|
||||||
|
.with_fixed(true),
|
||||||
|
Empty::new().with_width(1).segment().with_fixed(true),
|
||||||
|
self.domain
|
||||||
|
.widget()
|
||||||
|
.with_highlight(|s| Styled::new(s, domain_style))
|
||||||
|
.with_focus(self.focus == Focus::Domain)
|
||||||
|
.segment(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let inner = Join2::vertical(
|
||||||
|
name.segment().with_fixed(true),
|
||||||
|
domain.segment().with_fixed(true),
|
||||||
|
);
|
||||||
|
|
||||||
|
Popup::new(inner, "Connect to")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,11 @@ use toss::widgets::EditorState;
|
||||||
|
|
||||||
use super::widgets::ListState;
|
use super::widgets::ListState;
|
||||||
|
|
||||||
|
/// Test if a character is allowed to be typed in a room name.
|
||||||
|
pub fn is_room_char(c: char) -> bool {
|
||||||
|
c.is_ascii_alphanumeric() || c == '_'
|
||||||
|
}
|
||||||
|
|
||||||
//////////
|
//////////
|
||||||
// List //
|
// List //
|
||||||
//////////
|
//////////
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue