use std::fmt::{Display, Write}; use chrono::{DateTime, Utc}; use jid::JID; use rusqlite::{ ToSql, types::{FromSql, ToSqlOutput, Value}, }; use uuid::Uuid; #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "reactive_stores", derive(reactive_stores::Store))] pub struct Message { pub id: Uuid, // does not contain full user information // bare jid (for now) pub from: JID, pub delivery: Option, pub timestamp: DateTime, // TODO: originally_from // TODO: message edits // TODO: message timestamp pub body: Body, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum Delivery { Sending, Written, Sent, Delivered, Read, Failed, Queued, } impl Display for Delivery { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Delivery::Sending => f.write_str("sending"), Delivery::Written => f.write_str("written"), Delivery::Sent => f.write_str("sent"), Delivery::Delivered => f.write_str("delivered"), Delivery::Read => f.write_str("read"), Delivery::Failed => f.write_str("failed"), Delivery::Queued => f.write_str("queued"), } } } impl ToSql for Delivery { fn to_sql(&self) -> rusqlite::Result> { Ok(match self { Delivery::Sending => ToSqlOutput::Owned(Value::Text("sending".to_string())), Delivery::Written => ToSqlOutput::Owned(Value::Text("written".to_string())), Delivery::Sent => ToSqlOutput::Owned(Value::Text("sent".to_string())), Delivery::Delivered => ToSqlOutput::Owned(Value::Text("delivered".to_string())), Delivery::Read => ToSqlOutput::Owned(Value::Text("read".to_string())), Delivery::Failed => ToSqlOutput::Owned(Value::Text("failed".to_string())), Delivery::Queued => ToSqlOutput::Owned(Value::Text("queued".to_string())), }) } } impl FromSql for Delivery { fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult { Ok(match value.as_str()? { "sending" => Self::Sending, "written" => Self::Written, "sent" => Self::Sent, "delivered" => Self::Delivered, "read" => Self::Read, "failed" => Self::Failed, "queued" => Self::Queued, // TODO: don't have these lol value => panic!("unexpected subscription `{value}`"), }) } } // TODO: user migrations // pub enum Migrated { // Jabber(User), // Outside, // } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Body { // TODO: rich text, other contents, threads pub body: String, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "reactive_stores", derive(reactive_stores::Store))] pub struct Chat { pub correspondent: JID, pub have_chatted: bool, // pub unread_messages: i32, // pub latest_message: Message, // when a new message is received, the chat should be updated, and the new message should be delivered too. // message history is not stored in chat, retreived separately. // pub message_history: Vec, } pub enum ChatUpdate {} impl Chat { pub fn new(correspondent: JID, have_chatted: bool) -> Self { Self { correspondent, have_chatted, } } pub fn correspondent(&self) -> &JID { &self.correspondent } } // TODO: group chats // pub enum Chat { // Direct(DirectChat), // Channel(Channel), // } // pub struct Channel {}