Switch focus using tab
Also refactored some key event handling code in the process.
This commit is contained in:
parent
8703a62887
commit
9c9d9a51bb
1 changed files with 173 additions and 95 deletions
|
|
@ -322,74 +322,20 @@ impl EuphRoom {
|
||||||
Text::new(info).into()
|
Text::new(info).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_inspect_initiating_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
async fn list_chat_key_bindings(&self, bindings: &mut KeyBindingsList, status: &RoomStatus) {
|
||||||
bindings.binding("i", "inspect message");
|
let can_compose = matches!(status, RoomStatus::Connected(Status::Joined(_)));
|
||||||
bindings.binding("I", "show message links");
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_inspect_initiating_input_event(&mut self, event: &InputEvent) -> bool {
|
|
||||||
match event {
|
|
||||||
key!('i') => {
|
|
||||||
if let Some(id) = self.chat.cursor().await {
|
|
||||||
if let Some(msg) = self.vault.full_msg(id).await {
|
|
||||||
self.state = State::InspectMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
key!('I') => {
|
|
||||||
if let Some(id) = self.chat.cursor().await {
|
|
||||||
if let Some(msg) = self.vault.msg(id).await {
|
|
||||||
self.state = State::Links(LinksState::new(&msg.content));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn list_normal_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
|
||||||
bindings.binding("esc", "leave room");
|
|
||||||
|
|
||||||
let can_compose = if let Some(room) = &self.room {
|
|
||||||
match room.status().await.ok().flatten() {
|
|
||||||
Some(Status::Joining(Joining {
|
|
||||||
bounce: Some(_), ..
|
|
||||||
})) => {
|
|
||||||
bindings.binding("a", "authenticate");
|
|
||||||
false
|
|
||||||
}
|
|
||||||
Some(Status::Joined(_)) => {
|
|
||||||
bindings.binding("n", "change nick");
|
|
||||||
bindings.binding("m", "download more messages");
|
|
||||||
bindings.binding("A", "show account ui");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
self.list_inspect_initiating_key_bindings(bindings);
|
|
||||||
|
|
||||||
bindings.empty();
|
|
||||||
self.chat.list_key_bindings(bindings, can_compose).await;
|
self.chat.list_key_bindings(bindings, can_compose).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_normal_input_event(
|
async fn handle_chat_input_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
terminal: &mut Terminal,
|
terminal: &mut Terminal,
|
||||||
crossterm_lock: &Arc<FairMutex<()>>,
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
event: &InputEvent,
|
event: &InputEvent,
|
||||||
|
status: &RoomStatus,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(room) = &self.room {
|
let can_compose = matches!(status, RoomStatus::Connected(Status::Joined(_)));
|
||||||
let status = room.status().await;
|
|
||||||
let can_compose = matches!(status, Ok(Some(Status::Joined(_))));
|
|
||||||
|
|
||||||
// We need to handle chat input first, otherwise the other
|
|
||||||
// key bindings will shadow characters in the editor.
|
|
||||||
match self
|
match self
|
||||||
.chat
|
.chat
|
||||||
.handle_input_event(terminal, crossterm_lock, event, can_compose)
|
.handle_input_event(terminal, crossterm_lock, event, can_compose)
|
||||||
|
|
@ -398,12 +344,14 @@ impl EuphRoom {
|
||||||
Reaction::NotHandled => {}
|
Reaction::NotHandled => {}
|
||||||
Reaction::Handled => return true,
|
Reaction::Handled => return true,
|
||||||
Reaction::Composed { parent, content } => {
|
Reaction::Composed { parent, content } => {
|
||||||
|
if let Some(room) = &self.room {
|
||||||
match room.send(parent, content) {
|
match room.send(parent, content) {
|
||||||
Ok(id_rx) => self.last_msg_sent = Some(id_rx),
|
Ok(id_rx) => self.last_msg_sent = Some(id_rx),
|
||||||
Err(_) => self.chat.sent(None).await,
|
Err(_) => self.chat.sent(None).await,
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Reaction::ComposeError(e) => {
|
Reaction::ComposeError(e) => {
|
||||||
self.popups.push_front(RoomPopup::Error {
|
self.popups.push_front(RoomPopup::Error {
|
||||||
description: "Failed to use external editor".to_string(),
|
description: "Failed to use external editor".to_string(),
|
||||||
|
|
@ -413,52 +361,182 @@ impl EuphRoom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.handle_inspect_initiating_input_event(event).await {
|
false
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match status.ok().flatten() {
|
fn list_room_key_bindings(&self, bindings: &mut KeyBindingsList, status: &RoomStatus) {
|
||||||
Some(Status::Joining(Joining {
|
match status {
|
||||||
|
// Authenticating
|
||||||
|
RoomStatus::Connected(Status::Joining(Joining {
|
||||||
bounce: Some(_), ..
|
bounce: Some(_), ..
|
||||||
})) if matches!(event, key!('a')) => {
|
})) => {
|
||||||
self.state = State::Auth(auth::new());
|
bindings.binding("a", "authenticate");
|
||||||
true
|
|
||||||
}
|
}
|
||||||
Some(Status::Joined(joined)) => match event {
|
|
||||||
|
// Connected
|
||||||
|
RoomStatus::Connected(Status::Joined(_)) => {
|
||||||
|
bindings.binding("n", "change nick");
|
||||||
|
bindings.binding("m", "download more messages");
|
||||||
|
bindings.binding("A", "show account ui");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspecting messages
|
||||||
|
bindings.binding("i", "inspect message");
|
||||||
|
bindings.binding("I", "show message links");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_room_input_event(&mut self, event: &InputEvent, status: &RoomStatus) -> bool {
|
||||||
|
match status {
|
||||||
|
// Authenticating
|
||||||
|
RoomStatus::Connected(Status::Joining(Joining {
|
||||||
|
bounce: Some(_), ..
|
||||||
|
})) => {
|
||||||
|
if let key!('a') = event {
|
||||||
|
self.state = State::Auth(auth::new());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Joined
|
||||||
|
RoomStatus::Connected(Status::Joined(joined)) => match event {
|
||||||
key!('n') | key!('N') => {
|
key!('n') | key!('N') => {
|
||||||
self.state = State::Nick(nick::new(joined));
|
self.state = State::Nick(nick::new(joined.clone()));
|
||||||
true
|
return true;
|
||||||
}
|
}
|
||||||
key!('m') => {
|
key!('m') => {
|
||||||
if let Some(room) = &self.room {
|
if let Some(room) = &self.room {
|
||||||
let _ = room.log();
|
let _ = room.log();
|
||||||
}
|
}
|
||||||
true
|
return true;
|
||||||
}
|
}
|
||||||
key!('A') => {
|
key!('A') => {
|
||||||
self.state = State::Account(AccountUiState::new());
|
self.state = State::Account(AccountUiState::new());
|
||||||
true
|
return true;
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => {}
|
||||||
},
|
},
|
||||||
_ => false,
|
|
||||||
|
// Otherwise
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
// Inspecting messages
|
||||||
|
match event {
|
||||||
|
key!('i') => {
|
||||||
|
if let Some(id) = self.chat.cursor().await {
|
||||||
|
if let Some(msg) = self.vault.full_msg(id).await {
|
||||||
|
self.state = State::InspectMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
key!('I') => {
|
||||||
|
if let Some(id) = self.chat.cursor().await {
|
||||||
|
if let Some(msg) = self.vault.msg(id).await {
|
||||||
|
self.state = State::Links(LinksState::new(&msg.content));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn list_chat_focus_key_bindings(
|
||||||
|
&self,
|
||||||
|
bindings: &mut KeyBindingsList,
|
||||||
|
status: &RoomStatus,
|
||||||
|
) {
|
||||||
|
self.list_room_key_bindings(bindings, status);
|
||||||
|
bindings.empty();
|
||||||
|
self.list_chat_key_bindings(bindings, status).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_chat_focus_input_event(
|
||||||
|
&mut self,
|
||||||
|
terminal: &mut Terminal,
|
||||||
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
|
event: &InputEvent,
|
||||||
|
status: &RoomStatus,
|
||||||
|
) -> bool {
|
||||||
|
// We need to handle chat input first, otherwise the other
|
||||||
|
// key bindings will shadow characters in the editor.
|
||||||
if self
|
if self
|
||||||
.chat
|
.handle_chat_input_event(terminal, crossterm_lock, event, status)
|
||||||
.handle_input_event(terminal, crossterm_lock, event, false)
|
|
||||||
.await
|
.await
|
||||||
.handled()
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.handle_inspect_initiating_input_event(event).await {
|
if self.handle_room_input_event(event, status).await {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_normal_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||||
|
// Handled in rooms list, not here
|
||||||
|
// TODO Move to rooms list?
|
||||||
|
bindings.binding("esc", "leave room");
|
||||||
|
|
||||||
|
let status = self.status().await;
|
||||||
|
|
||||||
|
match self.focus {
|
||||||
|
Focus::Chat => {
|
||||||
|
if let RoomStatus::Connected(Status::Joined(_)) = status {
|
||||||
|
bindings.binding("tab", "focus on nick list");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.list_chat_focus_key_bindings(bindings, &status).await;
|
||||||
|
}
|
||||||
|
Focus::NickList => {
|
||||||
|
bindings.binding("tab", "focus on chat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_normal_input_event(
|
||||||
|
&mut self,
|
||||||
|
terminal: &mut Terminal,
|
||||||
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
|
event: &InputEvent,
|
||||||
|
) -> bool {
|
||||||
|
let status = self.status().await;
|
||||||
|
|
||||||
|
match self.focus {
|
||||||
|
Focus::Chat => {
|
||||||
|
// Needs to be handled first or the tab key may be shadowed
|
||||||
|
// during editing.
|
||||||
|
if self
|
||||||
|
.handle_chat_focus_input_event(terminal, crossterm_lock, event, &status)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let RoomStatus::Connected(Status::Joined(_)) = status {
|
||||||
|
if let key!(Tab) = event {
|
||||||
|
self.focus = Focus::NickList;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Focus::NickList => {
|
||||||
|
if let key!(Tab) = event {
|
||||||
|
self.focus = Focus::Chat;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
pub async fn list_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue