mod blocks; mod tree; use std::sync::Arc; use async_trait::async_trait; use parking_lot::FairMutex; use time::OffsetDateTime; use toss::frame::{Frame, Size}; use toss::styled::Styled; use toss::terminal::Terminal; use crate::store::{Msg, MsgStore}; use self::tree::{TreeView, TreeViewState}; use super::input::{InputEvent, KeyBindingsList}; use super::widgets::Widget; /////////// // Trait // /////////// pub trait ChatMsg { fn time(&self) -> OffsetDateTime; fn styled(&self) -> (Styled, Styled); fn edit(nick: &str, content: &str) -> (Styled, Styled); fn pseudo(nick: &str, content: &str) -> (Styled, Styled); } /////////// // State // /////////// pub enum Mode { Tree, // Thread, // Flat, } pub struct ChatState> { store: S, mode: Mode, tree: TreeViewState, // thread: ThreadView, // flat: FlatView, } impl + Clone> ChatState { pub fn new(store: S) -> Self { Self { mode: Mode::Tree, tree: TreeViewState::new(store.clone()), store, } } } impl> ChatState { pub fn store(&self) -> &S { &self.store } pub fn widget(&self, nick: String) -> Chat { match self.mode { Mode::Tree => Chat::Tree(self.tree.widget(nick)), } } } pub enum Reaction { NotHandled, Handled, Composed { parent: Option, content: String, }, } impl Reaction { pub fn handled(&self) -> bool { !matches!(self, Self::NotHandled) } } impl> ChatState { pub async fn list_key_bindings(&self, bindings: &mut KeyBindingsList, can_compose: bool) { match self.mode { Mode::Tree => self.tree.list_key_bindings(bindings, can_compose).await, } } pub async fn handle_input_event( &mut self, terminal: &mut Terminal, crossterm_lock: &Arc>, event: &InputEvent, can_compose: bool, ) -> Reaction { match self.mode { Mode::Tree => { self.tree .handle_input_event(terminal, crossterm_lock, event, can_compose) .await } } } /// A [`Reaction::Composed`] message was sent, either successfully or /// unsuccessfully. /// /// If successful, include the message's id as an argument. If unsuccessful, /// instead pass a `None`. pub async fn sent(&mut self, id: Option) { match self.mode { Mode::Tree => self.tree.sent(id).await, } } } //////////// // Widget // //////////// pub enum Chat> { Tree(TreeView), } #[async_trait] impl Widget for Chat where M: Msg + ChatMsg, M::Id: Send + Sync, S: MsgStore + Send + Sync, { fn size(&self, frame: &mut Frame, max_width: Option, max_height: Option) -> Size { match self { Self::Tree(tree) => tree.size(frame, max_width, max_height), } } async fn render(self: Box, frame: &mut Frame) { match *self { Self::Tree(tree) => Box::new(tree).render(frame).await, } } }