Migrate room to AsyncWidget
This commit is contained in:
parent
ead4fa7c8a
commit
d8d3e64776
2 changed files with 90 additions and 70 deletions
|
|
@ -8,22 +8,18 @@ use euphoxide::conn::{self, Joined, Joining, SessionInfo};
|
||||||
use parking_lot::FairMutex;
|
use parking_lot::FairMutex;
|
||||||
use tokio::sync::oneshot::error::TryRecvError;
|
use tokio::sync::oneshot::error::TryRecvError;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
use toss::{Style, Styled, Terminal};
|
use toss::widgets::{BoxedAsync, Join2, Layer, Text};
|
||||||
|
use toss::{AsyncWidget, Style, Styled, Terminal, WidgetExt};
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::euph;
|
use crate::euph;
|
||||||
use crate::macros::logging_unwrap;
|
use crate::macros::logging_unwrap;
|
||||||
use crate::ui::chat::{ChatState, Reaction};
|
use crate::ui::chat::{ChatState, Reaction};
|
||||||
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
||||||
use crate::ui::widgets::border::Border;
|
use crate::ui::widgets::editor::EditorState as OldEditorState;
|
||||||
use crate::ui::widgets::editor::EditorState;
|
use crate::ui::widgets::list::ListState as OldListState;
|
||||||
use crate::ui::widgets::join::{HJoin, Segment, VJoin};
|
use crate::ui::widgets::WidgetWrapper;
|
||||||
use crate::ui::widgets::layer::Layer;
|
use crate::ui::{util, UiError, UiEvent};
|
||||||
use crate::ui::widgets::list::ListState;
|
|
||||||
use crate::ui::widgets::padding::Padding;
|
|
||||||
use crate::ui::widgets::text::Text;
|
|
||||||
use crate::ui::widgets::BoxedWidget;
|
|
||||||
use crate::ui::{util, UiEvent};
|
|
||||||
use crate::vault::EuphRoomVault;
|
use crate::vault::EuphRoomVault;
|
||||||
|
|
||||||
use super::account::{self, AccountUiState};
|
use super::account::{self, AccountUiState};
|
||||||
|
|
@ -31,7 +27,7 @@ use super::links::{self, LinksState};
|
||||||
use super::popup::RoomPopup;
|
use super::popup::RoomPopup;
|
||||||
use super::{auth, inspect, nick, nick_list};
|
use super::{auth, inspect, nick, nick_list};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum Focus {
|
enum Focus {
|
||||||
Chat,
|
Chat,
|
||||||
NickList,
|
NickList,
|
||||||
|
|
@ -40,14 +36,16 @@ enum Focus {
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
enum State {
|
enum State {
|
||||||
Normal,
|
Normal,
|
||||||
Auth(EditorState),
|
Auth(OldEditorState),
|
||||||
Nick(EditorState),
|
Nick(OldEditorState),
|
||||||
Account(AccountUiState),
|
Account(AccountUiState),
|
||||||
Links(LinksState),
|
Links(LinksState),
|
||||||
InspectMessage(Message),
|
InspectMessage(Message),
|
||||||
InspectSession(SessionInfo),
|
InspectSession(SessionInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EuphChatState = ChatState<euph::SmallMessage, EuphRoomVault>;
|
||||||
|
|
||||||
pub struct EuphRoom {
|
pub struct EuphRoom {
|
||||||
server_config: ServerConfig,
|
server_config: ServerConfig,
|
||||||
config: config::EuphRoom,
|
config: config::EuphRoom,
|
||||||
|
|
@ -59,10 +57,10 @@ pub struct EuphRoom {
|
||||||
state: State,
|
state: State,
|
||||||
popups: VecDeque<RoomPopup>,
|
popups: VecDeque<RoomPopup>,
|
||||||
|
|
||||||
chat: ChatState<euph::SmallMessage, EuphRoomVault>,
|
chat: EuphChatState,
|
||||||
last_msg_sent: Option<oneshot::Receiver<MessageId>>,
|
last_msg_sent: Option<oneshot::Receiver<MessageId>>,
|
||||||
|
|
||||||
nick_list: ListState<SessionId>,
|
nick_list: OldListState<SessionId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EuphRoom {
|
impl EuphRoom {
|
||||||
|
|
@ -82,7 +80,7 @@ impl EuphRoom {
|
||||||
popups: VecDeque::new(),
|
popups: VecDeque::new(),
|
||||||
chat: ChatState::new(vault),
|
chat: ChatState::new(vault),
|
||||||
last_msg_sent: None,
|
last_msg_sent: None,
|
||||||
nick_list: ListState::new(),
|
nick_list: OldListState::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,77 +203,97 @@ impl EuphRoom {
|
||||||
self.stabilize_state();
|
self.stabilize_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn widget(&mut self) -> BoxedWidget {
|
pub async fn widget(&mut self) -> BoxedAsync<'_, UiError> {
|
||||||
self.stabilize().await;
|
self.stabilize().await;
|
||||||
|
|
||||||
let room_state = self.room_state();
|
let room_state = self.room.as_ref().map(|room| room.state());
|
||||||
|
let status_widget = self.status_widget(room_state).await;
|
||||||
let chat = if let Some(euph::State::Connected(_, conn::State::Joined(joined))) = room_state
|
let chat = if let Some(euph::State::Connected(_, conn::State::Joined(joined))) = room_state
|
||||||
{
|
{
|
||||||
self.widget_with_nick_list(room_state, joined).await
|
Self::widget_with_nick_list(
|
||||||
|
&mut self.chat,
|
||||||
|
status_widget,
|
||||||
|
&mut self.nick_list,
|
||||||
|
joined,
|
||||||
|
self.focus,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
self.widget_without_nick_list(room_state).await
|
Self::widget_without_nick_list(&mut self.chat, status_widget)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut layers = vec![chat];
|
let mut layers = vec![chat];
|
||||||
|
|
||||||
match &self.state {
|
match &self.state {
|
||||||
State::Normal => {}
|
State::Normal => {}
|
||||||
State::Auth(editor) => layers.push(auth::widget(editor)),
|
State::Auth(editor) => {
|
||||||
State::Nick(editor) => layers.push(nick::widget(editor)),
|
layers.push(WidgetWrapper::new(auth::widget(editor)).boxed_async())
|
||||||
State::Account(account) => layers.push(account.widget()),
|
}
|
||||||
State::Links(links) => layers.push(links.widget()),
|
State::Nick(editor) => {
|
||||||
State::InspectMessage(message) => layers.push(inspect::message_widget(message)),
|
layers.push(WidgetWrapper::new(nick::widget(editor)).boxed_async())
|
||||||
State::InspectSession(session) => layers.push(inspect::session_widget(session)),
|
}
|
||||||
|
State::Account(account) => {
|
||||||
|
layers.push(WidgetWrapper::new(account.widget()).boxed_async())
|
||||||
|
}
|
||||||
|
State::Links(links) => layers.push(WidgetWrapper::new(links.widget()).boxed_async()),
|
||||||
|
State::InspectMessage(message) => {
|
||||||
|
layers.push(WidgetWrapper::new(inspect::message_widget(message)).boxed_async())
|
||||||
|
}
|
||||||
|
State::InspectSession(session) => {
|
||||||
|
layers.push(WidgetWrapper::new(inspect::session_widget(session)).boxed_async())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for popup in &self.popups {
|
for popup in &self.popups {
|
||||||
layers.push(popup.widget());
|
layers.push(WidgetWrapper::new(popup.widget()).boxed_async());
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer::new(layers).into()
|
Layer::new(layers).boxed_async()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn widget_without_nick_list(&self, state: Option<&euph::State>) -> BoxedWidget {
|
fn widget_without_nick_list(
|
||||||
VJoin::new(vec![
|
chat: &mut EuphChatState,
|
||||||
Segment::new(Border::new(
|
status_widget: impl AsyncWidget<UiError> + Send + Sync + 'static,
|
||||||
Padding::new(self.status_widget(state).await).horizontal(1),
|
) -> BoxedAsync<'_, UiError> {
|
||||||
)),
|
let chat_widget = WidgetWrapper::new(chat.widget(String::new(), true));
|
||||||
// TODO Use last known nick?
|
|
||||||
Segment::new(self.chat.widget(String::new(), true)).expanding(true),
|
Join2::vertical(
|
||||||
])
|
status_widget.segment().with_fixed(true),
|
||||||
.into()
|
chat_widget.segment(),
|
||||||
|
)
|
||||||
|
.boxed_async()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn widget_with_nick_list(
|
fn widget_with_nick_list<'a>(
|
||||||
&self,
|
chat: &'a mut EuphChatState,
|
||||||
state: Option<&euph::State>,
|
status_widget: impl AsyncWidget<UiError> + Send + Sync + 'static,
|
||||||
|
nick_list: &mut OldListState<SessionId>,
|
||||||
joined: &Joined,
|
joined: &Joined,
|
||||||
) -> BoxedWidget {
|
focus: Focus,
|
||||||
HJoin::new(vec![
|
) -> BoxedAsync<'a, UiError> {
|
||||||
Segment::new(VJoin::new(vec![
|
let nick_list_widget = WidgetWrapper::new(nick_list::widget(
|
||||||
Segment::new(Border::new(
|
nick_list,
|
||||||
Padding::new(self.status_widget(state).await).horizontal(1),
|
joined,
|
||||||
)),
|
focus == Focus::NickList,
|
||||||
Segment::new(
|
))
|
||||||
self.chat
|
.padding()
|
||||||
.widget(joined.session.name.clone(), self.focus == Focus::Chat),
|
.with_right(1)
|
||||||
)
|
.border();
|
||||||
.expanding(true),
|
|
||||||
]))
|
let chat_widget =
|
||||||
.expanding(true),
|
WidgetWrapper::new(chat.widget(joined.session.name.clone(), focus == Focus::Chat));
|
||||||
Segment::new(Border::new(
|
|
||||||
Padding::new(nick_list::widget(
|
Join2::horizontal(
|
||||||
&self.nick_list,
|
Join2::vertical(
|
||||||
joined,
|
status_widget.segment().with_fixed(true),
|
||||||
self.focus == Focus::NickList,
|
chat_widget.segment(),
|
||||||
))
|
)
|
||||||
.right(1),
|
.segment(),
|
||||||
)),
|
nick_list_widget.segment().with_fixed(true),
|
||||||
])
|
)
|
||||||
.into()
|
.boxed_async()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn status_widget(&self, state: Option<&euph::State>) -> BoxedWidget {
|
async fn status_widget(&self, state: Option<&euph::State>) -> BoxedAsync<'static, UiError> {
|
||||||
let room_style = Style::new().bold().blue();
|
let room_style = Style::new().bold().blue();
|
||||||
let mut info = Styled::new(format!("&{}", self.name()), room_style);
|
let mut info = Styled::new(format!("&{}", self.name()), room_style);
|
||||||
|
|
||||||
|
|
@ -308,7 +326,11 @@ impl EuphRoom {
|
||||||
.then_plain(")");
|
.then_plain(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(info).into()
|
Text::new(info)
|
||||||
|
.padding()
|
||||||
|
.with_horizontal(1)
|
||||||
|
.border()
|
||||||
|
.boxed_async()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_chat_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
async fn list_chat_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ use crate::vault::Vault;
|
||||||
|
|
||||||
use super::euph::room::EuphRoom;
|
use super::euph::room::EuphRoom;
|
||||||
use super::input::{key, InputEvent, KeyBindingsList};
|
use super::input::{key, InputEvent, KeyBindingsList};
|
||||||
use super::widgets::WidgetWrapper;
|
|
||||||
use super::widgets2::{List, ListState, Popup};
|
use super::widgets2::{List, ListState, Popup};
|
||||||
use super::{util2, UiError, UiEvent};
|
use super::{util2, UiError, UiEvent};
|
||||||
|
|
||||||
|
|
@ -176,14 +175,13 @@ impl Rooms {
|
||||||
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order).await
|
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order).await
|
||||||
}
|
}
|
||||||
|
|
||||||
State::ShowRoom(name) => WidgetWrapper::new(
|
State::ShowRoom(name) => {
|
||||||
self.euph_rooms
|
self.euph_rooms
|
||||||
.get_mut(name)
|
.get_mut(name)
|
||||||
.expect("room exists after stabilization")
|
.expect("room exists after stabilization")
|
||||||
.widget()
|
.widget()
|
||||||
.await,
|
.await
|
||||||
)
|
}
|
||||||
.boxed_async(),
|
|
||||||
|
|
||||||
State::Connect(editor) => {
|
State::Connect(editor) => {
|
||||||
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order)
|
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue