use std::any::Any; use anyhow::{Error, Result}; use cli_log::{error, info, warn}; use indexmap::IndexMap; use matrix_sdk::{ room::MessagesOptions, ruma::{ events::{room::message::RoomMessageEventContent, AnyTimelineEvent, StateEventType}, RoomId, TransactionId, }, Client, }; pub enum State { None, Main, Setup, } pub struct Room { matrix_room: matrix_sdk::room::Joined, name: String, encrypted: bool, timeline: Vec, timeline_end: Option, view_scroll: Option, } pub struct Status { state: State, account_name: String, account_user_id: String, client: Option, rooms: IndexMap, current_room_id: String, } impl Room { pub fn new(matrix_room: matrix_sdk::room::Joined) -> Self { Self { matrix_room, name: "".to_string(), encrypted: false, timeline: Vec::new(), timeline_end: None, view_scroll: None, } } pub async fn poll_old_timeline(&mut self) -> Result<()> { if let Some(AnyTimelineEvent::State(event)) = &self.timeline.get(0) { if event.event_type() == StateEventType::RoomCreate { return Ok(()); } } let mut messages_options = MessagesOptions::backward(); messages_options = match &self.timeline_end { Some(end) => messages_options.from(end.as_str()), None => messages_options, }; let events = self.matrix_room.messages(messages_options).await?; self.timeline_end = events.end; for event in events.chunk.iter() { self.timeline.insert( 0, match event.event.deserialize() { Ok(ev) => ev, Err(err) => { warn!("Failed to deserialize timeline event - {err}"); continue; } }, ); } Ok(()) } pub fn name(&self) -> &String { &self.name } pub async fn update_name(&mut self) -> Result<()> { self.name = self.matrix_room.display_name().await?.to_string(); Ok(()) } pub fn timeline_add(&mut self, event: AnyTimelineEvent) { self.timeline.push(event); } pub fn timeline(&self) -> &Vec { &self.timeline } pub async fn send(&mut self, message: String) -> Result<()> { let content = RoomMessageEventContent::text_plain(message); let id = TransactionId::new(); self.matrix_room.send(content, Some(&id)).await?; Ok(()) } pub fn view_scroll(&self) -> Option { self.view_scroll } pub fn set_view_scroll(&mut self, scroll: Option) { self.view_scroll = scroll; } pub fn encrypted(&self) -> bool { self.matrix_room.is_encrypted() } } impl Status { pub fn new(client: Option) -> Self { let mut rooms = IndexMap::new(); if let Some(c) = &client { for r in c.joined_rooms() { rooms.insert(r.room_id().to_string(), Room::new(r.clone())); } }; Self { state: State::None, account_name: "".to_string(), account_user_id: "".to_string(), client, rooms, current_room_id: "".to_string(), } } pub fn account_name(&self) -> &String { &self.account_name } pub fn set_account_name(&mut self, name: String) { self.account_name = name; } pub fn account_user_id(&self) -> &String { &self.account_user_id } pub fn set_account_user_id(&mut self, user_id: String) { self.account_user_id = user_id; } pub fn room(&self) -> Option<&Room> { self.rooms.get(self.current_room_id.as_str()) } pub fn room_mut(&mut self) -> Option<&mut Room> { self.rooms.get_mut(self.current_room_id.as_str()) } pub fn rooms(&self) -> &IndexMap { &self.rooms } pub fn rooms_mut(&mut self) -> &mut IndexMap { &mut self.rooms } pub fn set_room(&mut self, room_id: &RoomId) -> Result<()> { if self.rooms.contains_key(room_id.as_str()) { self.current_room_id = room_id.to_string(); Ok(()) } else { Err(Error::msg(format!( "failed to set room -> invalid room id {}", room_id.to_string() ))) } } pub fn set_room_by_index(&mut self, room_index: usize) -> Result<()> { if let Some((room_id, _)) = self.rooms.get_index(room_index) { self.current_room_id = room_id.clone(); Ok(()) } else { Err(Error::msg(format!( "failed to set room -> invalid room index {}", room_index ))) } } pub fn get_room(&self, room_id: &RoomId) -> Option<&Room> { self.rooms.get(room_id.as_str()) } pub fn get_room_mut(&mut self, room_id: &RoomId) -> Option<&mut Room> { self.rooms.get_mut(room_id.as_str()) } pub fn state(&self) -> &State { &self.state } pub fn set_state(&mut self, state: State) { self.state = state; } }