Start restructuring chat as widget
This commit is contained in:
parent
2ee64c11be
commit
26e988114c
4 changed files with 231 additions and 149 deletions
18
src/ui.rs
18
src/ui.rs
|
|
@ -20,8 +20,9 @@ use toss::terminal::Terminal;
|
||||||
use crate::logger::{LogMsg, Logger};
|
use crate::logger::{LogMsg, Logger};
|
||||||
use crate::vault::Vault;
|
use crate::vault::Vault;
|
||||||
|
|
||||||
use self::chat::Chat;
|
use self::chat::{Chat, ChatState};
|
||||||
use self::rooms::Rooms;
|
use self::rooms::Rooms;
|
||||||
|
use self::widgets::Widget;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum UiEvent {
|
pub enum UiEvent {
|
||||||
|
|
@ -45,7 +46,7 @@ pub struct Ui {
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
|
|
||||||
rooms: Rooms,
|
rooms: Rooms,
|
||||||
log_chat: Chat<LogMsg, Logger>,
|
log_chat: ChatState<LogMsg, Logger>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ui {
|
impl Ui {
|
||||||
|
|
@ -80,7 +81,7 @@ impl Ui {
|
||||||
event_tx: event_tx.clone(),
|
event_tx: event_tx.clone(),
|
||||||
mode: Mode::Main,
|
mode: Mode::Main,
|
||||||
rooms: Rooms::new(vault, event_tx.clone()),
|
rooms: Rooms::new(vault, event_tx.clone()),
|
||||||
log_chat: Chat::new(logger),
|
log_chat: ChatState::new(logger),
|
||||||
};
|
};
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
e = ui.run_main(terminal, event_rx, crossterm_lock) => Ok(e),
|
e = ui.run_main(terminal, event_rx, crossterm_lock) => Ok(e),
|
||||||
|
|
@ -166,11 +167,7 @@ impl Ui {
|
||||||
async fn render(&mut self, frame: &mut Frame) -> anyhow::Result<()> {
|
async fn render(&mut self, frame: &mut Frame) -> anyhow::Result<()> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::Main => self.rooms.render(frame).await,
|
Mode::Main => self.rooms.render(frame).await,
|
||||||
Mode::Log => {
|
Mode::Log => Box::new(self.log_chat.widget()).render(frame).await,
|
||||||
self.log_chat
|
|
||||||
.render(frame, Pos::new(0, 0), frame.size())
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +199,10 @@ impl Ui {
|
||||||
.handle_key_event(terminal, size, crossterm_lock, event)
|
.handle_key_event(terminal, size, crossterm_lock, event)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
Mode::Log => self.log_chat.handle_navigation(terminal, size, event).await,
|
Mode::Log => {
|
||||||
|
// TODO Uncomment
|
||||||
|
// self.log_chat.handle_navigation(terminal, size, event).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventHandleResult::Continue
|
EventHandleResult::Continue
|
||||||
|
|
|
||||||
144
src/ui/chat.rs
144
src/ui/chat.rs
|
|
@ -1,15 +1,17 @@
|
||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use async_trait::async_trait;
|
||||||
|
use toss::frame::{Frame, Size};
|
||||||
use crossterm::event::KeyEvent;
|
|
||||||
use parking_lot::FairMutex;
|
|
||||||
use toss::frame::{Frame, Pos, Size};
|
|
||||||
use toss::terminal::Terminal;
|
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore};
|
use crate::store::{Msg, MsgStore};
|
||||||
|
|
||||||
use self::tree::TreeView;
|
use self::tree::{TreeView, TreeViewState};
|
||||||
|
|
||||||
|
use super::widgets::Widget;
|
||||||
|
|
||||||
|
///////////
|
||||||
|
// State //
|
||||||
|
///////////
|
||||||
|
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
Tree,
|
Tree,
|
||||||
|
|
@ -34,74 +36,108 @@ impl<I> Cursor<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Chat<M: Msg, S: MsgStore<M>> {
|
pub struct ChatState<M: Msg, S: MsgStore<M>> {
|
||||||
store: S,
|
store: S,
|
||||||
cursor: Option<Cursor<M::Id>>,
|
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
tree: TreeView<M>,
|
tree: TreeViewState<M, S>,
|
||||||
// thread: ThreadView,
|
// thread: ThreadView,
|
||||||
// flat: FlatView,
|
// flat: FlatView,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
|
impl<M: Msg, S: MsgStore<M> + Clone> ChatState<M, S> {
|
||||||
pub fn new(store: S) -> Self {
|
pub fn new(store: S) -> Self {
|
||||||
Self {
|
Self {
|
||||||
store,
|
|
||||||
cursor: None,
|
|
||||||
mode: Mode::Tree,
|
mode: Mode::Tree,
|
||||||
tree: TreeView::new(),
|
tree: TreeViewState::new(store.clone()),
|
||||||
|
store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: Msg, S: MsgStore<M>> ChatState<M, S> {
|
||||||
pub fn store(&self) -> &S {
|
pub fn store(&self) -> &S {
|
||||||
&self.store
|
&self.store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn widget(&self) -> Chat<M, S> {
|
||||||
|
match self.mode {
|
||||||
|
Mode::Tree => Chat::Tree(self.tree.widget()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
|
impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
|
||||||
pub async fn handle_navigation(
|
// pub async fn handle_navigation(
|
||||||
&mut self,
|
// &mut self,
|
||||||
terminal: &mut Terminal,
|
// terminal: &mut Terminal,
|
||||||
size: Size,
|
// size: Size,
|
||||||
event: KeyEvent,
|
// event: KeyEvent,
|
||||||
) {
|
// ) {
|
||||||
match self.mode {
|
// match self.mode {
|
||||||
Mode::Tree => {
|
// Mode::Tree => {
|
||||||
self.tree
|
// self.tree
|
||||||
.handle_navigation(&mut self.store, &mut self.cursor, terminal, size, event)
|
// .handle_navigation(&mut self.store, &mut self.cursor, terminal, size, event)
|
||||||
.await
|
// .await
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub async fn handle_messaging(
|
||||||
|
// &mut self,
|
||||||
|
// terminal: &mut Terminal,
|
||||||
|
// crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
|
// event: KeyEvent,
|
||||||
|
// ) -> Option<(Option<M::Id>, String)> {
|
||||||
|
// match self.mode {
|
||||||
|
// Mode::Tree => {
|
||||||
|
// self.tree
|
||||||
|
// .handle_messaging(
|
||||||
|
// &mut self.store,
|
||||||
|
// &mut self.cursor,
|
||||||
|
// terminal,
|
||||||
|
// crossterm_lock,
|
||||||
|
// event,
|
||||||
|
// )
|
||||||
|
// .await
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub async fn render(&mut self, frame: &mut Frame, pos: Pos, size: Size) {
|
||||||
|
// match self.mode {
|
||||||
|
// Mode::Tree => {
|
||||||
|
// self.tree
|
||||||
|
// .render(&mut self.store, &self.cursor, frame, pos, size)
|
||||||
|
// .await
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////
|
||||||
|
// Widget //
|
||||||
|
////////////
|
||||||
|
|
||||||
|
pub enum Chat<M: Msg, S: MsgStore<M>> {
|
||||||
|
Tree(TreeView<M, S>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<M, S> Widget for Chat<M, S>
|
||||||
|
where
|
||||||
|
M: Msg,
|
||||||
|
M::Id: Send,
|
||||||
|
S: MsgStore<M> + Send + Sync,
|
||||||
|
{
|
||||||
|
fn size(&self, frame: &mut Frame, max_width: Option<u16>, max_height: Option<u16>) -> Size {
|
||||||
|
match self {
|
||||||
|
Self::Tree(tree) => tree.size(frame, max_width, max_height),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_messaging(
|
async fn render(self: Box<Self>, frame: &mut Frame) {
|
||||||
&mut self,
|
match *self {
|
||||||
terminal: &mut Terminal,
|
Self::Tree(tree) => Box::new(tree).render(frame).await,
|
||||||
crossterm_lock: &Arc<FairMutex<()>>,
|
|
||||||
event: KeyEvent,
|
|
||||||
) -> Option<(Option<M::Id>, String)> {
|
|
||||||
match self.mode {
|
|
||||||
Mode::Tree => {
|
|
||||||
self.tree
|
|
||||||
.handle_messaging(
|
|
||||||
&mut self.store,
|
|
||||||
&mut self.cursor,
|
|
||||||
terminal,
|
|
||||||
crossterm_lock,
|
|
||||||
event,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn render(&mut self, frame: &mut Frame, pos: Pos, size: Size) {
|
|
||||||
match self.mode {
|
|
||||||
Mode::Tree => {
|
|
||||||
self.tree
|
|
||||||
.render(&mut self.store, &self.cursor, frame, pos, size)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,84 +1,126 @@
|
||||||
mod action;
|
// mod action;
|
||||||
mod blocks;
|
// mod blocks;
|
||||||
mod cursor;
|
// mod cursor;
|
||||||
mod layout;
|
// mod layout;
|
||||||
mod render;
|
// mod render;
|
||||||
mod util;
|
// mod util;
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use async_trait::async_trait;
|
||||||
use parking_lot::FairMutex;
|
use tokio::sync::Mutex;
|
||||||
use toss::frame::{Frame, Pos, Size};
|
use toss::frame::{Frame, Size};
|
||||||
use toss::terminal::Terminal;
|
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore};
|
use crate::store::{Msg, MsgStore};
|
||||||
|
use crate::ui::widgets::Widget;
|
||||||
|
|
||||||
use super::Cursor;
|
///////////
|
||||||
|
// State //
|
||||||
|
///////////
|
||||||
|
|
||||||
pub struct TreeView<M: Msg> {
|
/// The anchor specifies a specific line in a room's history.
|
||||||
// pub focus: Option<M::Id>,
|
enum Anchor<I> {
|
||||||
// pub folded: HashSet<M::Id>,
|
/// The bottom of the room's history stays fixed.
|
||||||
// pub minimized: HashSet<M::Id>,
|
Bottom,
|
||||||
phantom: PhantomData<M::Id>, // TODO Remove
|
/// The top of a message stays fixed.
|
||||||
|
Msg(I),
|
||||||
|
/// The line after a message's subtree stays fixed.
|
||||||
|
After(I),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Msg> TreeView<M> {
|
struct Compose<I> {
|
||||||
pub fn new() -> Self {
|
/// The message that the cursor was on when composing began, or `None` if it
|
||||||
|
/// was [`Cursor::Bottom`].
|
||||||
|
///
|
||||||
|
/// Used to jump back to the original position when composing is aborted
|
||||||
|
/// because the editor may be moved during composing.
|
||||||
|
coming_from: Option<I>,
|
||||||
|
/// The parent message of this reply, or `None` if it will be a new
|
||||||
|
/// top-level message.
|
||||||
|
parent: Option<I>,
|
||||||
|
// TODO Editor state
|
||||||
|
// TODO Whether currently editing or moving cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Placeholder<I> {
|
||||||
|
/// See [`Composing::coming_from`].
|
||||||
|
coming_from: Option<I>,
|
||||||
|
/// See [`Composing::parent`].
|
||||||
|
after: Option<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Cursor<I> {
|
||||||
|
/// No cursor visible because it is at the bottom of the chat history.
|
||||||
|
///
|
||||||
|
/// See also [`Anchor::Bottom`].
|
||||||
|
Bottom,
|
||||||
|
/// The cursor points to a message.
|
||||||
|
///
|
||||||
|
/// See also [`Anchor::Msg`].
|
||||||
|
Msg(I),
|
||||||
|
/// The cursor has turned into an editor because we're composing a new
|
||||||
|
/// message.
|
||||||
|
///
|
||||||
|
/// See also [`Anchor::After`].
|
||||||
|
Compose(Compose<I>),
|
||||||
|
/// A placeholder message is being displayed for a message that was just
|
||||||
|
/// sent by the user.
|
||||||
|
///
|
||||||
|
/// Will be replaced by a [`Cursor::Msg`] as soon as the server replies to
|
||||||
|
/// the send command with the sent message. Otherwise, it will
|
||||||
|
///
|
||||||
|
/// See also [`Anchor::After`].
|
||||||
|
Placeholder(Placeholder<I>),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InnerTreeViewState<M: Msg, S: MsgStore<M>> {
|
||||||
|
store: S,
|
||||||
|
anchor: Anchor<M::Id>,
|
||||||
|
anchor_line: i32,
|
||||||
|
cursor: Cursor<M::Id>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
|
fn new(store: S) -> Self {
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
store,
|
||||||
|
anchor: Anchor::Bottom,
|
||||||
|
anchor_line: 0,
|
||||||
|
cursor: Cursor::Bottom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub async fn handle_navigation<S: MsgStore<M>>(
|
|
||||||
&mut self,
|
pub struct TreeViewState<M: Msg, S: MsgStore<M>>(Arc<Mutex<InnerTreeViewState<M, S>>>);
|
||||||
s: &mut S,
|
|
||||||
c: &mut Option<Cursor<M::Id>>,
|
impl<M: Msg, S: MsgStore<M>> TreeViewState<M, S> {
|
||||||
t: &mut Terminal,
|
pub fn new(store: S) -> Self {
|
||||||
z: Size,
|
Self(Arc::new(Mutex::new(InnerTreeViewState::new(store))))
|
||||||
event: KeyEvent,
|
}
|
||||||
) {
|
|
||||||
match event.code {
|
pub fn widget(&self) -> TreeView<M, S> {
|
||||||
KeyCode::Char('k') => self.move_up(s, c, t.frame(), z).await,
|
TreeView(self.0.clone())
|
||||||
KeyCode::Char('j') => self.move_down(s, c, t.frame(), z).await,
|
}
|
||||||
KeyCode::Char('K') => self.move_up_sibling(s, c, t.frame(), z).await,
|
}
|
||||||
KeyCode::Char('J') => self.move_down_sibling(s, c, t.frame(), z).await,
|
|
||||||
KeyCode::Char('z') | KeyCode::Char('Z') => self.center_cursor(s, c, t.frame(), z).await,
|
////////////
|
||||||
KeyCode::Char('g') => self.move_to_first(s, c, t.frame(), z).await,
|
// Widget //
|
||||||
KeyCode::Char('G') => self.move_to_last(s, c, t.frame(), z).await,
|
////////////
|
||||||
KeyCode::Esc => *c = None, // TODO Make 'G' do the same thing?
|
|
||||||
_ => {}
|
pub struct TreeView<M: Msg, S: MsgStore<M>>(Arc<Mutex<InnerTreeViewState<M, S>>>);
|
||||||
}
|
|
||||||
}
|
#[async_trait]
|
||||||
|
impl<M, S> Widget for TreeView<M, S>
|
||||||
pub async fn handle_messaging<S: MsgStore<M>>(
|
where
|
||||||
&mut self,
|
M: Msg,
|
||||||
s: &mut S,
|
M::Id: Send,
|
||||||
c: &mut Option<Cursor<M::Id>>,
|
S: MsgStore<M> + Send + Sync,
|
||||||
t: &mut Terminal,
|
{
|
||||||
l: &Arc<FairMutex<()>>,
|
fn size(&self, _frame: &mut Frame, _max_width: Option<u16>, _max_height: Option<u16>) -> Size {
|
||||||
event: KeyEvent,
|
Size::ZERO
|
||||||
) -> Option<(Option<M::Id>, String)> {
|
}
|
||||||
match event.code {
|
|
||||||
KeyCode::Char('r') => Self::reply_normal(s, c, t, l).await,
|
async fn render(self: Box<Self>, frame: &mut Frame) {
|
||||||
KeyCode::Char('R') => Self::reply_alternate(s, c, t, l).await,
|
todo!()
|
||||||
KeyCode::Char('t') | KeyCode::Char('T') => Self::create_new_thread(t, l).await,
|
}
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn render<S: MsgStore<M>>(
|
|
||||||
&mut self,
|
|
||||||
store: &mut S,
|
|
||||||
cursor: &Option<Cursor<M::Id>>,
|
|
||||||
frame: &mut Frame,
|
|
||||||
pos: Pos,
|
|
||||||
size: Size,
|
|
||||||
) {
|
|
||||||
let blocks = self
|
|
||||||
.layout_blocks(store, cursor.as_ref(), frame, size)
|
|
||||||
.await;
|
|
||||||
Self::render_blocks(frame, pos, size, blocks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use crate::euph::api::{SessionType, SessionView};
|
||||||
use crate::euph::{self, Joined, Status};
|
use crate::euph::{self, Joined, Status};
|
||||||
use crate::vault::{EuphMsg, EuphVault};
|
use crate::vault::{EuphMsg, EuphVault};
|
||||||
|
|
||||||
use super::chat::Chat;
|
use super::chat::ChatState;
|
||||||
use super::widgets::background::Background;
|
use super::widgets::background::Background;
|
||||||
use super::widgets::empty::Empty;
|
use super::widgets::empty::Empty;
|
||||||
use super::widgets::list::{List, ListState};
|
use super::widgets::list::{List, ListState};
|
||||||
|
|
@ -24,7 +24,7 @@ use super::{util, UiEvent};
|
||||||
pub struct EuphRoom {
|
pub struct EuphRoom {
|
||||||
ui_event_tx: mpsc::UnboundedSender<UiEvent>,
|
ui_event_tx: mpsc::UnboundedSender<UiEvent>,
|
||||||
room: Option<euph::Room>,
|
room: Option<euph::Room>,
|
||||||
chat: Chat<EuphMsg, EuphVault>,
|
chat: ChatState<EuphMsg, EuphVault>,
|
||||||
|
|
||||||
nick_list_width: u16,
|
nick_list_width: u16,
|
||||||
nick_list: ListState<String>,
|
nick_list: ListState<String>,
|
||||||
|
|
@ -35,7 +35,7 @@ impl EuphRoom {
|
||||||
Self {
|
Self {
|
||||||
ui_event_tx,
|
ui_event_tx,
|
||||||
room: None,
|
room: None,
|
||||||
chat: Chat::new(vault),
|
chat: ChatState::new(vault),
|
||||||
nick_list_width: 24,
|
nick_list_width: 24,
|
||||||
nick_list: ListState::new(),
|
nick_list: ListState::new(),
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +100,9 @@ impl EuphRoom {
|
||||||
let chat_pos = Pos::new(0, hsplit + 1);
|
let chat_pos = Pos::new(0, hsplit + 1);
|
||||||
let chat_size = Size::new(size.width, size.height.saturating_sub(hsplit as u16 + 1));
|
let chat_size = Size::new(size.width, size.height.saturating_sub(hsplit as u16 + 1));
|
||||||
|
|
||||||
self.chat.render(frame, chat_pos, chat_size).await;
|
frame.push(chat_pos, chat_size);
|
||||||
|
Box::new(self.chat.widget()).render(frame).await;
|
||||||
|
frame.pop();
|
||||||
self.render_status(frame, status_pos, status);
|
self.render_status(frame, status_pos, status);
|
||||||
Self::render_hsplit(frame, hsplit);
|
Self::render_hsplit(frame, hsplit);
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +129,9 @@ impl EuphRoom {
|
||||||
let nick_list_pos = Pos::new(vsplit + 1, 0);
|
let nick_list_pos = Pos::new(vsplit + 1, 0);
|
||||||
let nick_list_size = Size::new(self.nick_list_width, size.height);
|
let nick_list_size = Size::new(self.nick_list_width, size.height);
|
||||||
|
|
||||||
self.chat.render(frame, chat_pos, chat_size).await;
|
frame.push(chat_pos, chat_size);
|
||||||
|
Box::new(self.chat.widget()).render(frame).await;
|
||||||
|
frame.pop();
|
||||||
self.render_status(frame, status_pos, status);
|
self.render_status(frame, status_pos, status);
|
||||||
self.render_nick_list(frame, nick_list_pos, nick_list_size, joined)
|
self.render_nick_list(frame, nick_list_pos, nick_list_size, joined)
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -297,9 +301,9 @@ impl EuphRoom {
|
||||||
let hsplit = 1_i32;
|
let hsplit = 1_i32;
|
||||||
let chat_size = Size::new(vsplit as u16, size.height.saturating_sub(hsplit as u16 + 1));
|
let chat_size = Size::new(vsplit as u16, size.height.saturating_sub(hsplit as u16 + 1));
|
||||||
|
|
||||||
self.chat
|
// self.chat
|
||||||
.handle_navigation(terminal, chat_size, event)
|
// .handle_navigation(terminal, chat_size, event)
|
||||||
.await;
|
// .await;
|
||||||
|
|
||||||
if let Some(room) = &self.room {
|
if let Some(room) = &self.room {
|
||||||
if let Ok(Some(Status::Joined(_))) = room.status().await {
|
if let Ok(Some(Status::Joined(_))) = room.status().await {
|
||||||
|
|
@ -309,13 +313,13 @@ impl EuphRoom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((parent, content)) = self
|
// if let Some((parent, content)) = self
|
||||||
.chat
|
// .chat
|
||||||
.handle_messaging(terminal, crossterm_lock, event)
|
// .handle_messaging(terminal, crossterm_lock, event)
|
||||||
.await
|
// .await
|
||||||
{
|
// {
|
||||||
let _ = room.send(parent, content);
|
// let _ = room.send(parent, content);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue