use matrix_sdk::room::Room as MatrixRoom; use matrix_sdk::ruma::RoomId; use matrix_sdk::DisplayName; use modalkit::tui::{buffer::Buffer, layout::Rect, widgets::StatefulWidget}; use modalkit::{ editing::action::{ Action, EditInfo, EditResult, Editable, EditorAction, Jumpable, PromptAction, Promptable, Scrollable, }, editing::base::{ Axis, CloseFlags, Count, MoveDir1D, OpenTarget, PositionList, ScrollStyle, WordStyle, }, input::InputContext, widgets::{TermOffset, TerminalCursor, WindowOps}, }; use crate::base::{ IambId, IambInfo, IambResult, ProgramAction, ProgramContext, ProgramStore, RoomAction, }; use self::chat::ChatState; use self::space::{Space, SpaceState}; mod chat; mod scrollback; mod space; macro_rules! delegate { ($s: expr, $id: ident => $e: expr) => { match $s { RoomState::Chat($id) => $e, RoomState::Space($id) => $e, } }; } pub enum RoomState { Chat(ChatState), Space(SpaceState), } impl From for RoomState { fn from(chat: ChatState) -> Self { RoomState::Chat(chat) } } impl From for RoomState { fn from(space: SpaceState) -> Self { RoomState::Space(space) } } impl RoomState { pub fn new(room: MatrixRoom, name: DisplayName, store: &mut ProgramStore) -> Self { let room_id = room.room_id().to_owned(); let info = store.application.get_room_info(room_id); info.name = name.to_string().into(); if room.is_space() { SpaceState::new(room).into() } else { ChatState::new(room, store).into() } } pub fn room_command( &mut self, act: RoomAction, _: ProgramContext, _: &mut ProgramStore, ) -> IambResult, ProgramContext)>> { match act { RoomAction::Members(mut cmd) => { let width = Count::Exact(30); let act = cmd.default_axis(Axis::Vertical).default_relation(MoveDir1D::Next).window( OpenTarget::Application(IambId::MemberList(self.id().to_owned())), width.into(), ); Ok(vec![(act, cmd.context.take())]) }, } } pub fn get_title(&self, store: &mut ProgramStore) -> String { store.application.get_room_title(self.id()) } pub fn focus_toggle(&mut self) { match self { RoomState::Chat(chat) => chat.focus_toggle(), RoomState::Space(_) => return, } } pub fn id(&self) -> &RoomId { match self { RoomState::Chat(chat) => chat.id(), RoomState::Space(space) => space.id(), } } } impl Editable for RoomState { fn editor_command( &mut self, act: &EditorAction, ctx: &ProgramContext, store: &mut ProgramStore, ) -> EditResult { delegate!(self, w => w.editor_command(act, ctx, store)) } } impl Jumpable for RoomState { fn jump( &mut self, list: PositionList, dir: MoveDir1D, count: usize, ctx: &ProgramContext, ) -> IambResult { delegate!(self, w => w.jump(list, dir, count, ctx)) } } impl Scrollable for RoomState { fn scroll( &mut self, style: &ScrollStyle, ctx: &ProgramContext, store: &mut ProgramStore, ) -> EditResult { delegate!(self, w => w.scroll(style, ctx, store)) } } impl Promptable for RoomState { fn prompt( &mut self, act: &PromptAction, ctx: &ProgramContext, store: &mut ProgramStore, ) -> EditResult, IambInfo> { delegate!(self, w => w.prompt(act, ctx, store)) } } impl TerminalCursor for RoomState { fn get_term_cursor(&self) -> Option { delegate!(self, w => w.get_term_cursor()) } } impl WindowOps for RoomState { fn draw(&mut self, area: Rect, buf: &mut Buffer, focused: bool, store: &mut ProgramStore) { match self { RoomState::Chat(chat) => chat.draw(area, buf, focused, store), RoomState::Space(space) => { Space::new(store).focus(focused).render(area, buf, space); }, } } fn dup(&self, store: &mut ProgramStore) -> Self { match self { RoomState::Chat(chat) => RoomState::Chat(chat.dup(store)), RoomState::Space(space) => RoomState::Space(space.dup(store)), } } fn close(&mut self, _: CloseFlags, _: &mut ProgramStore) -> bool { // XXX: what's the right closing behaviour for a room? // Should write send a message? true } fn get_cursor_word(&self, style: &WordStyle) -> Option { match self { RoomState::Chat(chat) => chat.get_cursor_word(style), RoomState::Space(space) => space.get_cursor_word(style), } } fn get_selected_word(&self) -> Option { match self { RoomState::Chat(chat) => chat.get_selected_word(), RoomState::Space(space) => space.get_selected_word(), } } }