Update toss and remove more async
This commit is contained in:
parent
a638caadcb
commit
ade7be594e
16 changed files with 109 additions and 116 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1313,7 +1313,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toss"
|
name = "toss"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/Garmelon/toss.git?rev=57788a9dd9688bdf3e59bf7366ba6276fc660715#57788a9dd9688bdf3e59bf7366ba6276fc660715"
|
source = "git+https://github.com/Garmelon/toss.git?rev=f414db40d526295c74cbcae6c3d194088da8f1d9#f414db40d526295c74cbcae6c3d194088da8f1d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ features = ["bot"]
|
||||||
|
|
||||||
[dependencies.toss]
|
[dependencies.toss]
|
||||||
git = "https://github.com/Garmelon/toss.git"
|
git = "https://github.com/Garmelon/toss.git"
|
||||||
rev = "57788a9dd9688bdf3e59bf7366ba6276fc660715"
|
rev = "f414db40d526295c74cbcae6c3d194088da8f1d9"
|
||||||
|
|
||||||
# [patch."https://github.com/Garmelon/toss.git"]
|
# [patch."https://github.com/Garmelon/toss.git"]
|
||||||
# toss = { path = "../toss/" }
|
# toss = { path = "../toss/" }
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,7 @@ impl Ui {
|
||||||
|
|
||||||
key_bindings_list
|
key_bindings_list
|
||||||
.widget(list_state)
|
.widget(list_state)
|
||||||
|
.desync()
|
||||||
.above(widget)
|
.above(widget)
|
||||||
.boxed_async()
|
.boxed_async()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use std::sync::Arc;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use parking_lot::FairMutex;
|
use parking_lot::FairMutex;
|
||||||
use toss::widgets::EditorState;
|
use toss::widgets::EditorState;
|
||||||
use toss::{AsyncWidget, Frame, Pos, Size, Terminal, WidthDb};
|
use toss::{AsyncWidget, Frame, Pos, Size, Terminal, WidgetExt, WidthDb};
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore};
|
use crate::store::{Msg, MsgStore};
|
||||||
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
||||||
|
|
@ -488,7 +488,7 @@ where
|
||||||
for (range, block) in renderer.into_visible_blocks() {
|
for (range, block) in renderer.into_visible_blocks() {
|
||||||
let widget = block.into_widget();
|
let widget = block.into_widget();
|
||||||
frame.push(Pos::new(0, range.top), widget.size());
|
frame.push(Pos::new(0, range.top), widget.size());
|
||||||
widget.draw(frame).await.infallible();
|
widget.desync().draw(frame).await.infallible();
|
||||||
frame.pop();
|
frame.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crossterm::style::Stylize;
|
use crossterm::style::Stylize;
|
||||||
use euphoxide::api::PersonalAccountView;
|
use euphoxide::api::PersonalAccountView;
|
||||||
use euphoxide::conn;
|
use euphoxide::conn;
|
||||||
use toss::widgets::{BoxedAsync, EditorState, Empty, Join3, Join4, Text};
|
use toss::widgets::{EditorState, Empty, Join3, Join4, Text};
|
||||||
use toss::{Style, Terminal, WidgetExt};
|
use toss::{Style, Terminal, Widget, WidgetExt};
|
||||||
|
|
||||||
use crate::euph::{self, Room};
|
use crate::euph::{self, Room};
|
||||||
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
||||||
|
|
@ -30,7 +30,7 @@ impl LoggedOut {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn widget(&mut self) -> BoxedAsync<'_, UiError> {
|
fn widget(&mut self) -> impl Widget<UiError> + '_ {
|
||||||
let bold = Style::new().bold();
|
let bold = Style::new().bold();
|
||||||
Join4::vertical(
|
Join4::vertical(
|
||||||
Text::new(("Not logged in", bold.yellow())).segment(),
|
Text::new(("Not logged in", bold.yellow())).segment(),
|
||||||
|
|
@ -57,14 +57,13 @@ impl LoggedOut {
|
||||||
)
|
)
|
||||||
.segment(),
|
.segment(),
|
||||||
)
|
)
|
||||||
.boxed_async()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LoggedIn(PersonalAccountView);
|
pub struct LoggedIn(PersonalAccountView);
|
||||||
|
|
||||||
impl LoggedIn {
|
impl LoggedIn {
|
||||||
fn widget(&self) -> BoxedAsync<'_, UiError> {
|
fn widget(&self) -> impl Widget<UiError> {
|
||||||
let bold = Style::new().bold();
|
let bold = Style::new().bold();
|
||||||
Join3::vertical(
|
Join3::vertical(
|
||||||
Text::new(("Logged in", bold.green())).segment(),
|
Text::new(("Logged in", bold.green())).segment(),
|
||||||
|
|
@ -78,7 +77,6 @@ impl LoggedIn {
|
||||||
)
|
)
|
||||||
.segment(),
|
.segment(),
|
||||||
)
|
)
|
||||||
.boxed_async()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,15 +110,15 @@ impl AccountUiState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn widget(&mut self) -> BoxedAsync<'_, UiError> {
|
pub fn widget(&mut self) -> impl Widget<UiError> + '_ {
|
||||||
let inner = match self {
|
let inner = match self {
|
||||||
Self::LoggedOut(logged_out) => logged_out.widget(),
|
Self::LoggedOut(logged_out) => logged_out.widget().first2(),
|
||||||
Self::LoggedIn(logged_in) => logged_in.widget(),
|
Self::LoggedIn(logged_in) => logged_in.widget().second2(),
|
||||||
}
|
}
|
||||||
.resize()
|
.resize()
|
||||||
.with_min_width(40);
|
.with_min_width(40);
|
||||||
|
|
||||||
Popup::new(inner, "Account").boxed_async()
|
Popup::new(inner, "Account")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
pub fn list_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use toss::widgets::{BoxedAsync, EditorState};
|
use toss::widgets::EditorState;
|
||||||
use toss::{Terminal, WidgetExt};
|
use toss::{Terminal, Widget};
|
||||||
|
|
||||||
use crate::euph::Room;
|
use crate::euph::Room;
|
||||||
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
||||||
|
|
@ -10,12 +10,11 @@ pub fn new() -> EditorState {
|
||||||
EditorState::new()
|
EditorState::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn widget(editor: &mut EditorState) -> BoxedAsync<'_, UiError> {
|
pub fn widget(editor: &mut EditorState) -> impl Widget<UiError> + '_ {
|
||||||
Popup::new(
|
Popup::new(
|
||||||
editor.widget().with_hidden_default_placeholder(),
|
editor.widget().with_hidden_default_placeholder(),
|
||||||
"Enter password",
|
"Enter password",
|
||||||
)
|
)
|
||||||
.boxed_async()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_key_bindings(bindings: &mut KeyBindingsList) {
|
pub fn list_key_bindings(bindings: &mut KeyBindingsList) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crossterm::style::Stylize;
|
use crossterm::style::Stylize;
|
||||||
use euphoxide::api::{Message, NickEvent, SessionView};
|
use euphoxide::api::{Message, NickEvent, SessionView};
|
||||||
use euphoxide::conn::SessionInfo;
|
use euphoxide::conn::SessionInfo;
|
||||||
use toss::widgets::{BoxedAsync, Text};
|
use toss::widgets::Text;
|
||||||
use toss::{Style, Styled, WidgetExt};
|
use toss::{Style, Styled, Widget};
|
||||||
|
|
||||||
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
||||||
use crate::ui::widgets::Popup;
|
use crate::ui::widgets::Popup;
|
||||||
|
|
@ -88,7 +88,7 @@ fn message_lines(mut text: Styled, msg: &Message) -> Styled {
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn session_widget(session: &SessionInfo) -> BoxedAsync<'static, UiError> {
|
pub fn session_widget(session: &SessionInfo) -> impl Widget<UiError> {
|
||||||
let heading_style = Style::new().bold();
|
let heading_style = Style::new().bold();
|
||||||
|
|
||||||
let text = match session {
|
let text = match session {
|
||||||
|
|
@ -102,10 +102,10 @@ pub fn session_widget(session: &SessionInfo) -> BoxedAsync<'static, UiError> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Popup::new(Text::new(text), "Inspect session").boxed_async()
|
Popup::new(Text::new(text), "Inspect session")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message_widget(msg: &Message) -> BoxedAsync<'static, UiError> {
|
pub fn message_widget(msg: &Message) -> impl Widget<UiError> {
|
||||||
let heading_style = Style::new().bold();
|
let heading_style = Style::new().bold();
|
||||||
|
|
||||||
let mut text = Styled::new("Message", heading_style).then_plain("\n");
|
let mut text = Styled::new("Message", heading_style).then_plain("\n");
|
||||||
|
|
@ -119,7 +119,7 @@ pub fn message_widget(msg: &Message) -> BoxedAsync<'static, UiError> {
|
||||||
|
|
||||||
text = session_view_lines(text, &msg.sender);
|
text = session_view_lines(text, &msg.sender);
|
||||||
|
|
||||||
Popup::new(Text::new(text), "Inspect message").boxed_async()
|
Popup::new(Text::new(text), "Inspect message")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_key_bindings(bindings: &mut KeyBindingsList) {
|
pub fn list_key_bindings(bindings: &mut KeyBindingsList) {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use std::io;
|
||||||
|
|
||||||
use crossterm::style::Stylize;
|
use crossterm::style::Stylize;
|
||||||
use linkify::{LinkFinder, LinkKind};
|
use linkify::{LinkFinder, LinkKind};
|
||||||
use toss::widgets::{BoxedAsync, Text};
|
use toss::widgets::Text;
|
||||||
use toss::{Style, Styled, WidgetExt};
|
use toss::{Style, Styled, Widget};
|
||||||
|
|
||||||
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
||||||
use crate::ui::widgets::{ListBuilder, ListState, Popup};
|
use crate::ui::widgets::{ListBuilder, ListState, Popup};
|
||||||
|
|
@ -38,7 +38,7 @@ impl LinksState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn widget(&mut self) -> BoxedAsync<'_, UiError> {
|
pub fn widget(&mut self) -> impl Widget<UiError> + '_ {
|
||||||
let style_selected = Style::new().black().on_white();
|
let style_selected = Style::new().black().on_white();
|
||||||
|
|
||||||
let mut list_builder = ListBuilder::new();
|
let mut list_builder = ListBuilder::new();
|
||||||
|
|
@ -74,7 +74,7 @@ impl LinksState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Popup::new(list_builder.build(&mut self.list), "Links").boxed_async()
|
Popup::new(list_builder.build(&mut self.list), "Links")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_link_by_id(&self, id: usize) -> EventResult {
|
fn open_link_by_id(&self, id: usize) -> EventResult {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use euphoxide::conn::Joined;
|
use euphoxide::conn::Joined;
|
||||||
use toss::widgets::{BoxedAsync, EditorState};
|
use toss::widgets::EditorState;
|
||||||
use toss::{Style, Terminal, WidgetExt};
|
use toss::{Style, Terminal, Widget};
|
||||||
|
|
||||||
use crate::euph::{self, Room};
|
use crate::euph::{self, Room};
|
||||||
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
use crate::ui::input::{key, InputEvent, KeyBindingsList};
|
||||||
|
|
@ -11,12 +11,12 @@ pub fn new(joined: Joined) -> EditorState {
|
||||||
EditorState::with_initial_text(joined.session.name)
|
EditorState::with_initial_text(joined.session.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn widget(editor: &mut EditorState) -> BoxedAsync<'_, UiError> {
|
pub fn widget(editor: &mut EditorState) -> impl Widget<UiError> + '_ {
|
||||||
let inner = editor
|
let inner = editor
|
||||||
.widget()
|
.widget()
|
||||||
.with_highlight(|s| euph::style_nick_exact(s, Style::new()));
|
.with_highlight(|s| euph::style_nick_exact(s, Style::new()));
|
||||||
|
|
||||||
Popup::new(inner, "Choose nick").boxed_async()
|
Popup::new(inner, "Choose nick")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nick_char(c: char) -> bool {
|
fn nick_char(c: char) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ use std::iter;
|
||||||
use crossterm::style::{Color, Stylize};
|
use crossterm::style::{Color, Stylize};
|
||||||
use euphoxide::api::{NickEvent, SessionId, SessionType, SessionView, UserId};
|
use euphoxide::api::{NickEvent, SessionId, SessionType, SessionView, UserId};
|
||||||
use euphoxide::conn::{Joined, SessionInfo};
|
use euphoxide::conn::{Joined, SessionInfo};
|
||||||
use toss::widgets::{BoxedAsync, Empty, Text};
|
use toss::widgets::{Background, Text};
|
||||||
use toss::{Style, Styled, WidgetExt};
|
use toss::{Style, Styled, Widget, WidgetExt};
|
||||||
|
|
||||||
use crate::euph;
|
use crate::euph;
|
||||||
use crate::ui::widgets::{ListBuilder, ListState};
|
use crate::ui::widgets::{ListBuilder, ListState};
|
||||||
|
|
@ -14,10 +14,10 @@ pub fn widget<'a>(
|
||||||
list: &'a mut ListState<SessionId>,
|
list: &'a mut ListState<SessionId>,
|
||||||
joined: &Joined,
|
joined: &Joined,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
) -> BoxedAsync<'a, UiError> {
|
) -> impl Widget<UiError> + 'a {
|
||||||
let mut list_builder = ListBuilder::new();
|
let mut list_builder = ListBuilder::new();
|
||||||
render_rows(&mut list_builder, joined, focused);
|
render_rows(&mut list_builder, joined, focused);
|
||||||
list_builder.build(list).boxed_async()
|
list_builder.build(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
|
@ -59,7 +59,7 @@ impl HalfSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_rows(
|
fn render_rows(
|
||||||
list_builder: &mut ListBuilder<'_, SessionId, BoxedAsync<'static, UiError>>,
|
list_builder: &mut ListBuilder<'_, SessionId, Background<Text>>,
|
||||||
joined: &Joined,
|
joined: &Joined,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
) {
|
) {
|
||||||
|
|
@ -94,7 +94,7 @@ fn render_rows(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_section(
|
fn render_section(
|
||||||
list_builder: &mut ListBuilder<'_, SessionId, BoxedAsync<'static, UiError>>,
|
list_builder: &mut ListBuilder<'_, SessionId, Background<Text>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
sessions: &[HalfSession],
|
sessions: &[HalfSession],
|
||||||
own_session: &SessionView,
|
own_session: &SessionView,
|
||||||
|
|
@ -107,13 +107,13 @@ fn render_section(
|
||||||
let heading_style = Style::new().bold();
|
let heading_style = Style::new().bold();
|
||||||
|
|
||||||
if !list_builder.is_empty() {
|
if !list_builder.is_empty() {
|
||||||
list_builder.add_unsel(Empty::new().boxed_async());
|
list_builder.add_unsel(Text::new("").background());
|
||||||
}
|
}
|
||||||
|
|
||||||
let row = Styled::new_plain(" ")
|
let row = Styled::new_plain(" ")
|
||||||
.then(name, heading_style)
|
.then(name, heading_style)
|
||||||
.then_plain(format!(" ({})", sessions.len()));
|
.then_plain(format!(" ({})", sessions.len()));
|
||||||
list_builder.add_unsel(Text::new(row).boxed_async());
|
list_builder.add_unsel(Text::new(row).background());
|
||||||
|
|
||||||
for session in sessions {
|
for session in sessions {
|
||||||
render_row(list_builder, session, own_session, focused);
|
render_row(list_builder, session, own_session, focused);
|
||||||
|
|
@ -121,7 +121,7 @@ fn render_section(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_row(
|
fn render_row(
|
||||||
list_builder: &mut ListBuilder<'_, SessionId, BoxedAsync<'static, UiError>>,
|
list_builder: &mut ListBuilder<'_, SessionId, Background<Text>>,
|
||||||
session: &HalfSession,
|
session: &HalfSession,
|
||||||
own_session: &SessionView,
|
own_session: &SessionView,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
|
|
@ -163,15 +163,12 @@ fn render_row(
|
||||||
let text = Styled::new_plain(owner)
|
let text = Styled::new_plain(owner)
|
||||||
.then(name, style_inv)
|
.then(name, style_inv)
|
||||||
.then(perms, perms_style_inv);
|
.then(perms, perms_style_inv);
|
||||||
Text::new(text)
|
Text::new(text).background().with_style(style_inv)
|
||||||
.background()
|
|
||||||
.with_style(style_inv)
|
|
||||||
.boxed_async()
|
|
||||||
} else {
|
} else {
|
||||||
let text = Styled::new_plain(owner)
|
let text = Styled::new_plain(owner)
|
||||||
.then(&name, style)
|
.then(&name, style)
|
||||||
.then_plain(perms);
|
.then_plain(perms);
|
||||||
Text::new(text).boxed_async()
|
Text::new(text).background()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crossterm::style::Stylize;
|
use crossterm::style::Stylize;
|
||||||
use toss::widgets::{BoxedAsync, Text};
|
use toss::widgets::Text;
|
||||||
use toss::{Style, Styled, WidgetExt};
|
use toss::{Style, Styled, Widget};
|
||||||
|
|
||||||
use crate::ui::widgets::Popup;
|
use crate::ui::widgets::Popup;
|
||||||
use crate::ui::UiError;
|
use crate::ui::UiError;
|
||||||
|
|
@ -10,19 +10,18 @@ pub enum RoomPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomPopup {
|
impl RoomPopup {
|
||||||
fn server_error_widget(description: &str, reason: &str) -> BoxedAsync<'static, UiError> {
|
fn server_error_widget(description: &str, reason: &str) -> impl Widget<UiError> {
|
||||||
let border_style = Style::new().red().bold();
|
let border_style = Style::new().red().bold();
|
||||||
let text = Styled::new_plain(description)
|
let text = Styled::new_plain(description)
|
||||||
.then_plain("\n\n")
|
.then_plain("\n\n")
|
||||||
.then("Reason:", Style::new().bold())
|
.then("Reason:", Style::new().bold())
|
||||||
.then_plain(" ")
|
.then_plain(" ")
|
||||||
.then_plain(reason);
|
.then_plain(reason);
|
||||||
Popup::new(Text::new(text), ("Error", border_style))
|
|
||||||
.with_border_style(border_style)
|
Popup::new(Text::new(text), ("Error", border_style)).with_border_style(border_style)
|
||||||
.boxed_async()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn widget(&self) -> BoxedAsync<'static, UiError> {
|
pub fn widget(&self) -> impl Widget<UiError> {
|
||||||
match self {
|
match self {
|
||||||
Self::Error {
|
Self::Error {
|
||||||
description,
|
description,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ 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::widgets::{BoxedAsync, EditorState, Join2, Layer, Text};
|
use toss::widgets::{BoxedAsync, EditorState, Join2, Layer, Text};
|
||||||
use toss::{AsyncWidget, Style, Styled, Terminal, WidgetExt};
|
use toss::{Style, Styled, Terminal, Widget, WidgetExt};
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::euph;
|
use crate::euph;
|
||||||
|
|
@ -223,16 +223,20 @@ impl EuphRoom {
|
||||||
|
|
||||||
match &mut self.state {
|
match &mut self.state {
|
||||||
State::Normal => {}
|
State::Normal => {}
|
||||||
State::Auth(editor) => layers.push(auth::widget(editor)),
|
State::Auth(editor) => layers.push(auth::widget(editor).desync().boxed_async()),
|
||||||
State::Nick(editor) => layers.push(nick::widget(editor)),
|
State::Nick(editor) => layers.push(nick::widget(editor).desync().boxed_async()),
|
||||||
State::Account(account) => layers.push(account.widget()),
|
State::Account(account) => layers.push(account.widget().desync().boxed_async()),
|
||||||
State::Links(links) => layers.push(links.widget()),
|
State::Links(links) => layers.push(links.widget().desync().boxed_async()),
|
||||||
State::InspectMessage(message) => layers.push(inspect::message_widget(message)),
|
State::InspectMessage(message) => {
|
||||||
State::InspectSession(session) => layers.push(inspect::session_widget(session)),
|
layers.push(inspect::message_widget(message).desync().boxed_async())
|
||||||
|
}
|
||||||
|
State::InspectSession(session) => {
|
||||||
|
layers.push(inspect::session_widget(session).desync().boxed_async())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for popup in &self.popups {
|
for popup in &self.popups {
|
||||||
layers.push(popup.widget());
|
layers.push(popup.widget().desync().boxed_async());
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer::new(layers).boxed_async()
|
Layer::new(layers).boxed_async()
|
||||||
|
|
@ -240,12 +244,12 @@ impl EuphRoom {
|
||||||
|
|
||||||
fn widget_without_nick_list(
|
fn widget_without_nick_list(
|
||||||
chat: &mut EuphChatState,
|
chat: &mut EuphChatState,
|
||||||
status_widget: impl AsyncWidget<UiError> + Send + Sync + 'static,
|
status_widget: impl Widget<UiError> + Send + Sync + 'static,
|
||||||
) -> BoxedAsync<'_, UiError> {
|
) -> BoxedAsync<'_, UiError> {
|
||||||
let chat_widget = chat.widget(String::new(), true);
|
let chat_widget = chat.widget(String::new(), true);
|
||||||
|
|
||||||
Join2::vertical(
|
Join2::vertical(
|
||||||
status_widget.segment().with_fixed(true),
|
status_widget.desync().segment().with_fixed(true),
|
||||||
chat_widget.segment(),
|
chat_widget.segment(),
|
||||||
)
|
)
|
||||||
.boxed_async()
|
.boxed_async()
|
||||||
|
|
@ -253,7 +257,7 @@ impl EuphRoom {
|
||||||
|
|
||||||
fn widget_with_nick_list<'a>(
|
fn widget_with_nick_list<'a>(
|
||||||
chat: &'a mut EuphChatState,
|
chat: &'a mut EuphChatState,
|
||||||
status_widget: impl AsyncWidget<UiError> + Send + Sync + 'static,
|
status_widget: impl Widget<UiError> + Send + Sync + 'static,
|
||||||
nick_list: &'a mut ListState<SessionId>,
|
nick_list: &'a mut ListState<SessionId>,
|
||||||
joined: &Joined,
|
joined: &Joined,
|
||||||
focus: Focus,
|
focus: Focus,
|
||||||
|
|
@ -261,13 +265,14 @@ impl EuphRoom {
|
||||||
let nick_list_widget = nick_list::widget(nick_list, joined, focus == Focus::NickList)
|
let nick_list_widget = nick_list::widget(nick_list, joined, focus == Focus::NickList)
|
||||||
.padding()
|
.padding()
|
||||||
.with_right(1)
|
.with_right(1)
|
||||||
.border();
|
.border()
|
||||||
|
.desync();
|
||||||
|
|
||||||
let chat_widget = chat.widget(joined.session.name.clone(), focus == Focus::Chat);
|
let chat_widget = chat.widget(joined.session.name.clone(), focus == Focus::Chat);
|
||||||
|
|
||||||
Join2::horizontal(
|
Join2::horizontal(
|
||||||
Join2::vertical(
|
Join2::vertical(
|
||||||
status_widget.segment().with_fixed(true),
|
status_widget.desync().segment().with_fixed(true),
|
||||||
chat_widget.segment(),
|
chat_widget.segment(),
|
||||||
)
|
)
|
||||||
.segment(),
|
.segment(),
|
||||||
|
|
@ -276,7 +281,7 @@ impl EuphRoom {
|
||||||
.boxed_async()
|
.boxed_async()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn status_widget(&self, state: Option<&euph::State>) -> BoxedAsync<'static, UiError> {
|
async fn status_widget(&self, state: Option<&euph::State>) -> impl Widget<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);
|
||||||
|
|
||||||
|
|
@ -309,11 +314,7 @@ impl EuphRoom {
|
||||||
.then_plain(")");
|
.then_plain(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
Text::new(info)
|
Text::new(info).padding().with_horizontal(1).border()
|
||||||
.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) {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use std::convert::Infallible;
|
||||||
|
|
||||||
use crossterm::event::{Event, KeyCode, KeyModifiers};
|
use crossterm::event::{Event, KeyCode, KeyModifiers};
|
||||||
use crossterm::style::Stylize;
|
use crossterm::style::Stylize;
|
||||||
use toss::widgets::{BoxedAsync, Empty, Join2, Text};
|
use toss::widgets::{Empty, Join2, Text};
|
||||||
use toss::{Style, Styled, WidgetExt};
|
use toss::{Style, Styled, Widget, WidgetExt};
|
||||||
|
|
||||||
use super::widgets::{ListBuilder, ListState};
|
use super::widgets::{ListBuilder, ListState};
|
||||||
use super::UiError;
|
use super::UiError;
|
||||||
|
|
@ -96,11 +96,11 @@ impl KeyBindingsList {
|
||||||
Style::new().cyan()
|
Style::new().cyan()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row_widget(row: Row) -> BoxedAsync<'static, UiError> {
|
fn row_widget(row: Row) -> impl Widget<UiError> {
|
||||||
match row {
|
match row {
|
||||||
Row::Empty => Empty::new().boxed_async(),
|
Row::Empty => Text::new("").first3(),
|
||||||
|
|
||||||
Row::Heading(name) => Text::new((name, Style::new().bold())).boxed_async(),
|
Row::Heading(name) => Text::new((name, Style::new().bold())).first3(),
|
||||||
|
|
||||||
Row::Binding(binding, description) => Join2::horizontal(
|
Row::Binding(binding, description) => Join2::horizontal(
|
||||||
Text::new((binding, Self::binding_style()))
|
Text::new((binding, Self::binding_style()))
|
||||||
|
|
@ -111,17 +111,17 @@ impl KeyBindingsList {
|
||||||
.segment(),
|
.segment(),
|
||||||
Text::new(description).segment(),
|
Text::new(description).segment(),
|
||||||
)
|
)
|
||||||
.boxed_async(),
|
.second3(),
|
||||||
|
|
||||||
Row::BindingContd(description) => Join2::horizontal(
|
Row::BindingContd(description) => Join2::horizontal(
|
||||||
Empty::new().with_width(Self::BINDING_WIDTH).segment(),
|
Empty::new().with_width(Self::BINDING_WIDTH).segment(),
|
||||||
Text::new(description).segment(),
|
Text::new(description).segment(),
|
||||||
)
|
)
|
||||||
.boxed_async(),
|
.third3(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn widget(self, list_state: &mut ListState<Infallible>) -> BoxedAsync<'_, UiError> {
|
pub fn widget(self, list_state: &mut ListState<Infallible>) -> impl Widget<UiError> + '_ {
|
||||||
let binding_style = Self::binding_style();
|
let binding_style = Self::binding_style();
|
||||||
|
|
||||||
let hint_text = Styled::new("jk/↓↑", binding_style)
|
let hint_text = Styled::new("jk/↓↑", binding_style)
|
||||||
|
|
@ -150,7 +150,6 @@ impl KeyBindingsList {
|
||||||
.background()
|
.background()
|
||||||
.float()
|
.float()
|
||||||
.with_center()
|
.with_center()
|
||||||
.boxed_async()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty(&mut self) {
|
pub fn empty(&mut self) {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use euphoxide::conn::{self, Joined};
|
||||||
use parking_lot::FairMutex;
|
use parking_lot::FairMutex;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use toss::widgets::{BoxedAsync, EditorState, Empty, Join2, Text};
|
use toss::widgets::{BoxedAsync, EditorState, Empty, Join2, Text};
|
||||||
use toss::{Style, Styled, Terminal, WidgetExt};
|
use toss::{Style, Styled, Terminal, Widget, WidgetExt};
|
||||||
|
|
||||||
use crate::config::{Config, RoomsSortOrder};
|
use crate::config::{Config, RoomsSortOrder};
|
||||||
use crate::euph;
|
use crate::euph;
|
||||||
|
|
@ -171,9 +171,10 @@ impl Rooms {
|
||||||
}
|
}
|
||||||
|
|
||||||
match &mut self.state {
|
match &mut self.state {
|
||||||
State::ShowList => {
|
State::ShowList => Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order)
|
||||||
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order).await
|
.await
|
||||||
}
|
.desync()
|
||||||
|
.boxed_async(),
|
||||||
|
|
||||||
State::ShowRoom(name) => {
|
State::ShowRoom(name) => {
|
||||||
self.euph_rooms
|
self.euph_rooms
|
||||||
|
|
@ -187,6 +188,7 @@ impl Rooms {
|
||||||
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order)
|
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order)
|
||||||
.await
|
.await
|
||||||
.below(Self::new_room_widget(editor))
|
.below(Self::new_room_widget(editor))
|
||||||
|
.desync()
|
||||||
.boxed_async()
|
.boxed_async()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,12 +196,13 @@ impl Rooms {
|
||||||
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order)
|
Self::rooms_widget(&mut self.list, &self.euph_rooms, self.order)
|
||||||
.await
|
.await
|
||||||
.below(Self::delete_room_widget(name, editor))
|
.below(Self::delete_room_widget(name, editor))
|
||||||
|
.desync()
|
||||||
.boxed_async()
|
.boxed_async()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_room_widget(editor: &mut EditorState) -> BoxedAsync<'_, UiError> {
|
fn new_room_widget(editor: &mut EditorState) -> impl Widget<UiError> + '_ {
|
||||||
let room_style = Style::new().bold().blue();
|
let room_style = Style::new().bold().blue();
|
||||||
|
|
||||||
let inner = Join2::horizontal(
|
let inner = Join2::horizontal(
|
||||||
|
|
@ -210,10 +213,13 @@ impl Rooms {
|
||||||
.segment(),
|
.segment(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Popup::new(inner, "Connect to").boxed_async()
|
Popup::new(inner, "Connect to")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_room_widget<'a>(name: &str, editor: &'a mut EditorState) -> BoxedAsync<'a, UiError> {
|
fn delete_room_widget<'a>(
|
||||||
|
name: &str,
|
||||||
|
editor: &'a mut EditorState,
|
||||||
|
) -> impl Widget<UiError> + 'a {
|
||||||
let warn_style = Style::new().bold().red();
|
let warn_style = Style::new().bold().red();
|
||||||
let room_style = Style::new().bold().blue();
|
let room_style = Style::new().bold().blue();
|
||||||
let text = Styled::new_plain("Are you sure you want to delete ")
|
let text = Styled::new_plain("Are you sure you want to delete ")
|
||||||
|
|
@ -249,9 +255,7 @@ impl Rooms {
|
||||||
.segment(),
|
.segment(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Popup::new(inner, "Delete room")
|
Popup::new(inner, "Delete room").with_border_style(warn_style)
|
||||||
.with_border_style(warn_style)
|
|
||||||
.boxed_async()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_pbln(joined: &Joined) -> String {
|
fn format_pbln(joined: &Joined) -> String {
|
||||||
|
|
@ -387,7 +391,7 @@ impl Rooms {
|
||||||
list: &'a mut ListState<String>,
|
list: &'a mut ListState<String>,
|
||||||
euph_rooms: &HashMap<String, EuphRoom>,
|
euph_rooms: &HashMap<String, EuphRoom>,
|
||||||
order: Order,
|
order: Order,
|
||||||
) -> BoxedAsync<'a, UiError> {
|
) -> impl Widget<UiError> + 'a {
|
||||||
let heading_style = Style::new().bold();
|
let heading_style = Style::new().bold();
|
||||||
let heading_text =
|
let heading_text =
|
||||||
Styled::new("Rooms", heading_style).then_plain(format!(" ({})", euph_rooms.len()));
|
Styled::new("Rooms", heading_style).then_plain(format!(" ({})", euph_rooms.len()));
|
||||||
|
|
@ -399,7 +403,6 @@ impl Rooms {
|
||||||
Text::new(heading_text).segment().with_fixed(true),
|
Text::new(heading_text).segment().with_fixed(true),
|
||||||
list_builder.build(list).segment(),
|
list_builder.build(list).segment(),
|
||||||
)
|
)
|
||||||
.boxed_async()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn room_char(c: char) -> bool {
|
fn room_char(c: char) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use toss::{Frame, Pos, Size, Widget, WidthDb};
|
||||||
use toss::{AsyncWidget, Frame, Pos, Size, WidthDb};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Cursor<Id> {
|
struct Cursor<Id> {
|
||||||
|
|
@ -298,13 +297,12 @@ pub struct List<'a, Id, W> {
|
||||||
rows: Vec<W>,
|
rows: Vec<W>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl<Id, E, W> Widget<E> for List<'_, Id, W>
|
||||||
impl<Id, E, W> AsyncWidget<E> for List<'_, Id, W>
|
|
||||||
where
|
where
|
||||||
Id: Clone + Eq + Send + Sync,
|
Id: Clone + Eq,
|
||||||
W: AsyncWidget<E> + Send + Sync,
|
W: Widget<E>,
|
||||||
{
|
{
|
||||||
async fn size(
|
fn size(
|
||||||
&self,
|
&self,
|
||||||
widthdb: &mut WidthDb,
|
widthdb: &mut WidthDb,
|
||||||
max_width: Option<u16>,
|
max_width: Option<u16>,
|
||||||
|
|
@ -312,14 +310,14 @@ where
|
||||||
) -> Result<Size, E> {
|
) -> Result<Size, E> {
|
||||||
let mut width = 0;
|
let mut width = 0;
|
||||||
for row in &self.rows {
|
for row in &self.rows {
|
||||||
let size = row.size(widthdb, max_width, Some(1)).await?;
|
let size = row.size(widthdb, max_width, Some(1))?;
|
||||||
width = width.max(size.width);
|
width = width.max(size.width);
|
||||||
}
|
}
|
||||||
let height = self.rows.len().try_into().unwrap_or(u16::MAX);
|
let height = self.rows.len().try_into().unwrap_or(u16::MAX);
|
||||||
Ok(Size::new(width, height))
|
Ok(Size::new(width, height))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn draw(self, frame: &mut Frame) -> Result<(), E> {
|
fn draw(self, frame: &mut Frame) -> Result<(), E> {
|
||||||
let size = frame.size();
|
let size = frame.size();
|
||||||
|
|
||||||
self.state.last_height = size.height;
|
self.state.last_height = size.height;
|
||||||
|
|
@ -332,7 +330,7 @@ where
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
frame.push(Pos::new(0, y as i32), Size::new(size.width, 1));
|
frame.push(Pos::new(0, y as i32), Size::new(size.width, 1));
|
||||||
row.draw(frame).await?;
|
row.draw(frame)?;
|
||||||
frame.pop();
|
frame.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
use async_trait::async_trait;
|
use toss::widgets::{Background, Border, Desync, Float, Layer2, Padding, Text};
|
||||||
use toss::widgets::{Background, Border, Float, Layer2, Padding, Text};
|
use toss::{Frame, Size, Style, Styled, Widget, WidgetExt, WidthDb};
|
||||||
use toss::{AsyncWidget, Frame, Size, Style, Styled, WidgetExt, WidthDb};
|
|
||||||
|
|
||||||
type Body<I> = Background<Border<Padding<I>>>;
|
type Body<I> = Background<Border<Padding<I>>>;
|
||||||
type Title = Float<Padding<Background<Padding<Text>>>>;
|
type Title = Float<Padding<Background<Padding<Text>>>>;
|
||||||
|
|
||||||
pub struct Popup<I>(Float<Layer2<Body<I>, Title>>);
|
pub struct Popup<I>(Float<Layer2<Body<I>, Desync<Title>>>);
|
||||||
|
|
||||||
impl<I> Popup<I> {
|
impl<I> Popup<I> {
|
||||||
pub fn new<S: Into<Styled>>(inner: I, title: S) -> Self {
|
pub fn new<S: Into<Styled>>(inner: I, title: S) -> Self {
|
||||||
|
|
@ -19,7 +18,8 @@ impl<I> Popup<I> {
|
||||||
.with_horizontal(2)
|
.with_horizontal(2)
|
||||||
.float()
|
.float()
|
||||||
.with_top()
|
.with_top()
|
||||||
.with_left();
|
.with_left()
|
||||||
|
.desync();
|
||||||
|
|
||||||
let body = inner.padding().with_horizontal(1).border().background();
|
let body = inner.padding().with_horizontal(1).border().background();
|
||||||
|
|
||||||
|
|
@ -33,22 +33,20 @@ impl<I> Popup<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl<E, I> Widget<E> for Popup<I>
|
||||||
impl<E, I> AsyncWidget<E> for Popup<I>
|
|
||||||
where
|
where
|
||||||
E: Send,
|
I: Widget<E>,
|
||||||
I: AsyncWidget<E> + Send + Sync,
|
|
||||||
{
|
{
|
||||||
async fn size(
|
fn size(
|
||||||
&self,
|
&self,
|
||||||
widthdb: &mut WidthDb,
|
widthdb: &mut WidthDb,
|
||||||
max_width: Option<u16>,
|
max_width: Option<u16>,
|
||||||
max_height: Option<u16>,
|
max_height: Option<u16>,
|
||||||
) -> Result<Size, E> {
|
) -> Result<Size, E> {
|
||||||
self.0.size(widthdb, max_width, max_height).await
|
self.0.size(widthdb, max_width, max_height)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn draw(self, frame: &mut Frame) -> Result<(), E> {
|
fn draw(self, frame: &mut Frame) -> Result<(), E> {
|
||||||
self.0.draw(frame).await
|
self.0.draw(frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue