cove/src/ui/chat/tree.rs

110 lines
2.8 KiB
Rust

// mod action;
mod blocks;
// mod cursor;
mod layout;
// mod render;
mod util;
use std::sync::Arc;
use async_trait::async_trait;
use tokio::sync::Mutex;
use toss::frame::{Frame, Size};
use crate::store::{Msg, MsgStore};
use crate::ui::widgets::Widget;
use self::blocks::Blocks;
///////////
// State //
///////////
/// Position of a cursor that is displayed as the last child of its parent
/// message, or last thread if it has no parent.
#[derive(Debug, Clone, Copy)]
struct LastChild<I> {
coming_from: Option<I>,
after: Option<I>,
}
#[derive(Debug, Clone, Copy)]
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.
Msg(I),
/// The cursor has turned into an editor because we're composing a new
/// message.
Compose(LastChild<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.
Placeholder(LastChild<I>),
}
struct InnerTreeViewState<M: Msg, S: MsgStore<M>> {
store: S,
last_blocks: Blocks<M::Id>,
last_cursor: Cursor<M::Id>,
cursor: Cursor<M::Id>,
/// Set to true if the chat should be scrolled such that the cursor is fully
/// visible (if possible). If set to false, then the cursor itself is moved
/// to a different message such that it remains visible.
make_cursor_visible: bool,
editor: (), // TODO
}
impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
fn new(store: S) -> Self {
Self {
store,
last_blocks: Blocks::new(),
last_cursor: Cursor::Bottom,
cursor: Cursor::Bottom,
make_cursor_visible: false,
editor: (),
}
}
}
pub struct TreeViewState<M: Msg, S: MsgStore<M>>(Arc<Mutex<InnerTreeViewState<M, S>>>);
impl<M: Msg, S: MsgStore<M>> TreeViewState<M, S> {
pub fn new(store: S) -> Self {
Self(Arc::new(Mutex::new(InnerTreeViewState::new(store))))
}
pub fn widget(&self) -> TreeView<M, S> {
TreeView(self.0.clone())
}
}
////////////
// Widget //
////////////
pub struct TreeView<M: Msg, S: MsgStore<M>>(Arc<Mutex<InnerTreeViewState<M, S>>>);
#[async_trait]
impl<M, S> Widget for TreeView<M, S>
where
M: Msg,
M::Id: Send + Sync,
S: MsgStore<M> + Send + Sync,
{
fn size(&self, _frame: &mut Frame, _max_width: Option<u16>, _max_height: Option<u16>) -> Size {
Size::ZERO
}
async fn render(self: Box<Self>, frame: &mut Frame) {
let mut guard = self.0.lock().await;
guard.relayout(frame).await;
// Draw layout to screen
todo!()
}
}