Migrate nick list to AsyncWidget

This commit is contained in:
Joscha 2023-04-13 01:33:08 +02:00
parent d8d3e64776
commit c7cbd9856b
2 changed files with 62 additions and 49 deletions

View file

@ -4,19 +4,21 @@ 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::{Style, Styled}; use toss::widgets::{BoxedAsync, Empty, Text};
use toss::{Style, Styled, WidgetExt};
use crate::euph; use crate::euph;
use crate::ui::widgets::background::Background; use crate::ui::widgets2::{List, ListState};
use crate::ui::widgets::empty::Empty; use crate::ui::UiError;
use crate::ui::widgets::list::{List, ListState};
use crate::ui::widgets::text::Text;
use crate::ui::widgets::BoxedWidget;
pub fn widget(state: &ListState<SessionId>, joined: &Joined, focused: bool) -> BoxedWidget { pub fn widget<'a>(
let mut list = state.widget().focus(focused); list: &'a mut ListState<SessionId>,
render_rows(&mut list, joined); joined: &Joined,
list.into() focused: bool,
) -> BoxedAsync<'a, UiError> {
let mut list = list.widget();
render_rows(&mut list, joined, focused);
list.boxed_async()
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
@ -57,7 +59,11 @@ impl HalfSession {
} }
} }
fn render_rows(list: &mut List<SessionId>, joined: &Joined) { fn render_rows(
list: &mut List<'_, SessionId, BoxedAsync<'static, UiError>>,
joined: &Joined,
focused: bool,
) {
let mut people = vec![]; let mut people = vec![];
let mut bots = vec![]; let mut bots = vec![];
let mut lurkers = vec![]; let mut lurkers = vec![];
@ -82,17 +88,18 @@ fn render_rows(list: &mut List<SessionId>, joined: &Joined) {
lurkers.sort_unstable(); lurkers.sort_unstable();
nurkers.sort_unstable(); nurkers.sort_unstable();
render_section(list, "People", &people, &joined.session); render_section(list, "People", &people, &joined.session, focused);
render_section(list, "Bots", &bots, &joined.session); render_section(list, "Bots", &bots, &joined.session, focused);
render_section(list, "Lurkers", &lurkers, &joined.session); render_section(list, "Lurkers", &lurkers, &joined.session, focused);
render_section(list, "Nurkers", &nurkers, &joined.session); render_section(list, "Nurkers", &nurkers, &joined.session, focused);
} }
fn render_section( fn render_section(
list: &mut List<SessionId>, list: &mut List<'_, SessionId, BoxedAsync<'static, UiError>>,
name: &str, name: &str,
sessions: &[HalfSession], sessions: &[HalfSession],
own_session: &SessionView, own_session: &SessionView,
focused: bool,
) { ) {
if sessions.is_empty() { if sessions.is_empty() {
return; return;
@ -101,20 +108,25 @@ fn render_section(
let heading_style = Style::new().bold(); let heading_style = Style::new().bold();
if !list.is_empty() { if !list.is_empty() {
list.add_unsel(Empty::new()); list.add_unsel(Empty::new().boxed_async());
} }
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.add_unsel(Text::new(row)); list.add_unsel(Text::new(row).boxed_async());
for session in sessions { for session in sessions {
render_row(list, session, own_session); render_row(list, session, own_session, focused);
} }
} }
fn render_row(list: &mut List<SessionId>, session: &HalfSession, own_session: &SessionView) { fn render_row(
list: &mut List<'_, SessionId, BoxedAsync<'static, UiError>>,
session: &HalfSession,
own_session: &SessionView,
focused: bool,
) {
let (name, style, style_inv, perms_style_inv) = if session.name.is_empty() { let (name, style, style_inv, perms_style_inv) = if session.name.is_empty() {
let name = "lurk"; let name = "lurk";
let style = Style::new().grey(); let style = Style::new().grey();
@ -146,15 +158,20 @@ fn render_row(list: &mut List<SessionId>, session: &HalfSession, own_session: &S
" " " "
}; };
let normal = Styled::new_plain(owner) let widget = if focused && list.state().selected() == Some(&session.session_id) {
.then(&name, style) let text = Styled::new_plain(owner)
.then_plain(perms);
let selected = Styled::new_plain(owner)
.then(name, style_inv) .then(name, style_inv)
.then(perms, perms_style_inv); .then(perms, perms_style_inv);
list.add_sel( Text::new(text)
session.session_id.clone(), .background()
Text::new(normal), .with_style(style_inv)
Background::new(Text::new(selected)).style(style_inv), .boxed_async()
); } else {
let text = Styled::new_plain(owner)
.then(&name, style)
.then_plain(perms);
Text::new(text).boxed_async()
};
list.add_sel(session.session_id.clone(), widget);
} }

View file

@ -17,9 +17,9 @@ 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::editor::EditorState as OldEditorState; use crate::ui::widgets::editor::EditorState as OldEditorState;
use crate::ui::widgets::list::ListState as OldListState;
use crate::ui::widgets::WidgetWrapper; use crate::ui::widgets::WidgetWrapper;
use crate::ui::{util, UiError, UiEvent}; use crate::ui::widgets2::ListState;
use crate::ui::{util2, UiError, UiEvent};
use crate::vault::EuphRoomVault; use crate::vault::EuphRoomVault;
use super::account::{self, AccountUiState}; use super::account::{self, AccountUiState};
@ -60,7 +60,7 @@ pub struct EuphRoom {
chat: EuphChatState, chat: EuphChatState,
last_msg_sent: Option<oneshot::Receiver<MessageId>>, last_msg_sent: Option<oneshot::Receiver<MessageId>>,
nick_list: OldListState<SessionId>, nick_list: ListState<SessionId>,
} }
impl EuphRoom { impl EuphRoom {
@ -80,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: OldListState::new(), nick_list: ListState::new(),
} }
} }
@ -266,15 +266,11 @@ 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 AsyncWidget<UiError> + Send + Sync + 'static,
nick_list: &mut OldListState<SessionId>, nick_list: &'a mut ListState<SessionId>,
joined: &Joined, joined: &Joined,
focus: Focus, focus: Focus,
) -> BoxedAsync<'a, UiError> { ) -> BoxedAsync<'a, UiError> {
let nick_list_widget = WidgetWrapper::new(nick_list::widget( let nick_list_widget = nick_list::widget(nick_list, joined, focus == Focus::NickList)
nick_list,
joined,
focus == Focus::NickList,
))
.padding() .padding()
.with_right(1) .with_right(1)
.border(); .border();
@ -512,24 +508,24 @@ impl EuphRoom {
} }
fn list_nick_list_focus_key_bindings(&self, bindings: &mut KeyBindingsList) { fn list_nick_list_focus_key_bindings(&self, bindings: &mut KeyBindingsList) {
util::list_list_key_bindings(bindings); util2::list_list_key_bindings(bindings);
bindings.binding("i", "inspect session"); bindings.binding("i", "inspect session");
} }
fn handle_nick_list_focus_input_event(&mut self, event: &InputEvent) -> bool { fn handle_nick_list_focus_input_event(&mut self, event: &InputEvent) -> bool {
if util::handle_list_input_event(&mut self.nick_list, event) { if util2::handle_list_input_event(&mut self.nick_list, event) {
return true; return true;
} }
if let key!('i') = event { if let key!('i') = event {
if let Some(euph::State::Connected(_, conn::State::Joined(joined))) = self.room_state() if let Some(euph::State::Connected(_, conn::State::Joined(joined))) = self.room_state()
{ {
if let Some(id) = self.nick_list.cursor() { if let Some(id) = self.nick_list.selected() {
if id == joined.session.session_id { if *id == joined.session.session_id {
self.state = self.state =
State::InspectSession(SessionInfo::Full(joined.session.clone())); State::InspectSession(SessionInfo::Full(joined.session.clone()));
} else if let Some(session) = joined.listing.get(&id) { } else if let Some(session) = joined.listing.get(id) {
self.state = State::InspectSession(session.clone()); self.state = State::InspectSession(session.clone());
} }
} }