2025-05-26 16:52:38 -07:00
|
|
|
|
use kordophone::model::message::AttachmentMetadata;
|
2025-06-06 16:39:31 -07:00
|
|
|
|
use pretty::RcDoc;
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
use std::fmt::Display;
|
|
|
|
|
|
use time::OffsetDateTime;
|
2025-01-08 13:32:55 -08:00
|
|
|
|
|
|
|
|
|
|
pub struct PrintableConversation {
|
|
|
|
|
|
pub guid: String,
|
|
|
|
|
|
pub date: OffsetDateTime,
|
|
|
|
|
|
pub unread_count: i32,
|
|
|
|
|
|
pub last_message_preview: Option<String>,
|
|
|
|
|
|
pub participants: Vec<String>,
|
|
|
|
|
|
pub display_name: Option<String>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<kordophone::model::Conversation> for PrintableConversation {
|
|
|
|
|
|
fn from(value: kordophone::model::Conversation) -> Self {
|
|
|
|
|
|
Self {
|
2025-06-06 16:39:31 -07:00
|
|
|
|
guid: value.guid,
|
2025-01-08 13:32:55 -08:00
|
|
|
|
date: value.date,
|
|
|
|
|
|
unread_count: value.unread_count,
|
|
|
|
|
|
last_message_preview: value.last_message_preview,
|
|
|
|
|
|
participants: value.participant_display_names,
|
|
|
|
|
|
display_name: value.display_name,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<kordophone_db::models::Conversation> for PrintableConversation {
|
|
|
|
|
|
fn from(value: kordophone_db::models::Conversation) -> Self {
|
|
|
|
|
|
Self {
|
|
|
|
|
|
guid: value.guid,
|
|
|
|
|
|
date: OffsetDateTime::from_unix_timestamp(value.date.and_utc().timestamp()).unwrap(),
|
|
|
|
|
|
unread_count: value.unread_count.into(),
|
|
|
|
|
|
last_message_preview: value.last_message_preview,
|
2025-06-06 16:39:31 -07:00
|
|
|
|
participants: value
|
|
|
|
|
|
.participants
|
|
|
|
|
|
.into_iter()
|
|
|
|
|
|
.map(|p| p.display_name())
|
|
|
|
|
|
.collect(),
|
2025-01-08 13:32:55 -08:00
|
|
|
|
display_name: value.display_name,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-11-10 19:40:39 -08:00
|
|
|
|
|
2025-07-31 19:19:29 -07:00
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
|
impl From<dbus::arg::PropMap> for PrintableConversation {
|
|
|
|
|
|
fn from(value: dbus::arg::PropMap) -> Self {
|
2025-04-27 18:07:58 -07:00
|
|
|
|
Self {
|
|
|
|
|
|
guid: value.get("guid").unwrap().as_str().unwrap().to_string(),
|
2025-06-06 16:39:31 -07:00
|
|
|
|
date: OffsetDateTime::from_unix_timestamp(value.get("date").unwrap().as_i64().unwrap())
|
|
|
|
|
|
.unwrap(),
|
|
|
|
|
|
unread_count: value
|
|
|
|
|
|
.get("unread_count")
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.as_i64()
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.try_into()
|
|
|
|
|
|
.unwrap(),
|
|
|
|
|
|
last_message_preview: value
|
|
|
|
|
|
.get("last_message_preview")
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.as_str()
|
|
|
|
|
|
.map(|s| s.to_string()),
|
|
|
|
|
|
participants: value
|
|
|
|
|
|
.get("participants")
|
2025-04-27 18:07:58 -07:00
|
|
|
|
.unwrap()
|
|
|
|
|
|
.0
|
|
|
|
|
|
.as_iter()
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.map(|s| s.as_str().unwrap().to_string())
|
|
|
|
|
|
.collect(),
|
2025-06-06 16:39:31 -07:00
|
|
|
|
display_name: value
|
|
|
|
|
|
.get("display_name")
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.as_str()
|
|
|
|
|
|
.map(|s| s.to_string()),
|
2025-04-27 18:07:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-20 19:43:21 -08:00
|
|
|
|
pub struct PrintableMessage {
|
|
|
|
|
|
pub guid: String,
|
|
|
|
|
|
pub date: OffsetDateTime,
|
|
|
|
|
|
pub sender: String,
|
|
|
|
|
|
pub text: String,
|
2025-05-26 16:52:38 -07:00
|
|
|
|
pub file_transfer_guids: Vec<String>,
|
|
|
|
|
|
pub attachment_metadata: Option<HashMap<String, AttachmentMetadata>>,
|
2025-01-20 19:43:21 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<kordophone::model::Message> for PrintableMessage {
|
|
|
|
|
|
fn from(value: kordophone::model::Message) -> Self {
|
|
|
|
|
|
Self {
|
|
|
|
|
|
guid: value.guid,
|
|
|
|
|
|
date: value.date,
|
|
|
|
|
|
sender: value.sender.unwrap_or("<me>".to_string()),
|
|
|
|
|
|
text: value.text,
|
2025-05-26 16:52:38 -07:00
|
|
|
|
file_transfer_guids: value.file_transfer_guids,
|
|
|
|
|
|
attachment_metadata: value.attachment_metadata,
|
2025-01-20 19:43:21 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-20 22:23:18 -08:00
|
|
|
|
impl From<kordophone_db::models::Message> for PrintableMessage {
|
|
|
|
|
|
fn from(value: kordophone_db::models::Message) -> Self {
|
|
|
|
|
|
Self {
|
|
|
|
|
|
guid: value.id,
|
|
|
|
|
|
date: OffsetDateTime::from_unix_timestamp(value.date.and_utc().timestamp()).unwrap(),
|
|
|
|
|
|
sender: value.sender.display_name(),
|
|
|
|
|
|
text: value.text,
|
2025-05-26 16:52:38 -07:00
|
|
|
|
file_transfer_guids: value.file_transfer_guids,
|
|
|
|
|
|
attachment_metadata: value.attachment_metadata,
|
2025-01-20 22:23:18 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-31 19:19:29 -07:00
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
|
impl From<dbus::arg::PropMap> for PrintableMessage {
|
|
|
|
|
|
fn from(value: dbus::arg::PropMap) -> Self {
|
2025-05-26 16:52:38 -07:00
|
|
|
|
// Parse file transfer GUIDs from JSON if present
|
2025-06-06 16:39:31 -07:00
|
|
|
|
let file_transfer_guids = value
|
|
|
|
|
|
.get("file_transfer_guids")
|
2025-05-26 16:52:38 -07:00
|
|
|
|
.and_then(|v| v.as_str())
|
|
|
|
|
|
.and_then(|json_str| serde_json::from_str(json_str).ok())
|
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
|
|
// Parse attachment metadata from JSON if present
|
2025-06-06 16:39:31 -07:00
|
|
|
|
let attachment_metadata = value
|
|
|
|
|
|
.get("attachment_metadata")
|
2025-05-26 16:52:38 -07:00
|
|
|
|
.and_then(|v| v.as_str())
|
|
|
|
|
|
.and_then(|json_str| serde_json::from_str(json_str).ok());
|
|
|
|
|
|
|
2025-04-28 16:00:04 -07:00
|
|
|
|
Self {
|
|
|
|
|
|
guid: value.get("id").unwrap().as_str().unwrap().to_string(),
|
2025-06-06 16:39:31 -07:00
|
|
|
|
date: OffsetDateTime::from_unix_timestamp(value.get("date").unwrap().as_i64().unwrap())
|
|
|
|
|
|
.unwrap(),
|
2025-04-28 16:00:04 -07:00
|
|
|
|
sender: value.get("sender").unwrap().as_str().unwrap().to_string(),
|
|
|
|
|
|
text: value.get("text").unwrap().as_str().unwrap().to_string(),
|
2025-05-26 16:52:38 -07:00
|
|
|
|
file_transfer_guids,
|
|
|
|
|
|
attachment_metadata,
|
2025-04-28 16:00:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-10 19:40:39 -08:00
|
|
|
|
pub struct ConversationPrinter<'a> {
|
2025-06-06 16:39:31 -07:00
|
|
|
|
doc: RcDoc<'a, PrintableConversation>,
|
2024-11-10 19:40:39 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> ConversationPrinter<'a> {
|
2025-01-08 13:32:55 -08:00
|
|
|
|
pub fn new(conversation: &'a PrintableConversation) -> Self {
|
2025-06-06 16:39:31 -07:00
|
|
|
|
let preview = conversation
|
|
|
|
|
|
.last_message_preview
|
2024-11-10 19:40:39 -08:00
|
|
|
|
.as_deref()
|
|
|
|
|
|
.unwrap_or("<null>")
|
|
|
|
|
|
.replace('\n', " ");
|
|
|
|
|
|
|
|
|
|
|
|
let doc = RcDoc::text(format!("<Conversation: \"{}\"", &conversation.guid))
|
|
|
|
|
|
.append(
|
|
|
|
|
|
RcDoc::line()
|
|
|
|
|
|
.append("Display Name: ")
|
|
|
|
|
|
.append(conversation.display_name.as_deref().unwrap_or("<null>"))
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.append(RcDoc::line())
|
2024-11-10 19:40:39 -08:00
|
|
|
|
.append("Date: ")
|
|
|
|
|
|
.append(conversation.date.to_string())
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.append(RcDoc::line())
|
2025-01-20 19:43:21 -08:00
|
|
|
|
.append("Unread Count: ")
|
|
|
|
|
|
.append(conversation.unread_count.to_string())
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.append(RcDoc::line())
|
2024-11-10 19:40:39 -08:00
|
|
|
|
.append("Participants: ")
|
|
|
|
|
|
.append("[")
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.append(
|
|
|
|
|
|
RcDoc::line()
|
|
|
|
|
|
.append(
|
|
|
|
|
|
conversation
|
|
|
|
|
|
.participants
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.map(|name| RcDoc::text(name).append(",").append(RcDoc::line()))
|
|
|
|
|
|
.fold(RcDoc::nil(), |acc, x| acc.append(x)),
|
|
|
|
|
|
)
|
|
|
|
|
|
.nest(4),
|
2024-11-10 19:40:39 -08:00
|
|
|
|
)
|
|
|
|
|
|
.append("]")
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.append(RcDoc::line())
|
2024-11-10 19:40:39 -08:00
|
|
|
|
.append("Last Message Preview: ")
|
|
|
|
|
|
.append(preview)
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.nest(4),
|
2024-11-10 19:40:39 -08:00
|
|
|
|
)
|
|
|
|
|
|
.append(RcDoc::line())
|
|
|
|
|
|
.append(">");
|
|
|
|
|
|
|
|
|
|
|
|
ConversationPrinter { doc }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-28 16:06:51 -07:00
|
|
|
|
impl Display for ConversationPrinter<'_> {
|
2024-11-10 19:40:39 -08:00
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
|
self.doc.render_fmt(180, f)
|
|
|
|
|
|
}
|
2025-01-20 19:43:21 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub struct MessagePrinter<'a> {
|
2025-06-06 16:39:31 -07:00
|
|
|
|
doc: RcDoc<'a, PrintableMessage>,
|
2025-01-20 19:43:21 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-28 16:06:51 -07:00
|
|
|
|
impl Display for MessagePrinter<'_> {
|
2025-01-20 19:43:21 -08:00
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
|
self.doc.render_fmt(180, f)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> MessagePrinter<'a> {
|
|
|
|
|
|
pub fn new(message: &'a PrintableMessage) -> Self {
|
2025-06-06 16:39:31 -07:00
|
|
|
|
let mut doc = RcDoc::text(format!("<Message: \"{}\"", &message.guid)).append(
|
|
|
|
|
|
RcDoc::line()
|
|
|
|
|
|
.append("Date: ")
|
|
|
|
|
|
.append(message.date.to_string())
|
2025-05-26 16:52:38 -07:00
|
|
|
|
.append(RcDoc::line())
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.append("Sender: ")
|
|
|
|
|
|
.append(&message.sender)
|
2025-05-26 16:52:38 -07:00
|
|
|
|
.append(RcDoc::line())
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.append("Body: ")
|
|
|
|
|
|
.append(&message.text)
|
|
|
|
|
|
.nest(4),
|
|
|
|
|
|
);
|
2025-05-26 16:52:38 -07:00
|
|
|
|
|
|
|
|
|
|
// Add file transfer GUIDs and attachment metadata if present
|
|
|
|
|
|
if !message.file_transfer_guids.is_empty() {
|
2025-06-06 16:39:31 -07:00
|
|
|
|
doc = doc.append(RcDoc::line()).append(
|
|
|
|
|
|
RcDoc::line()
|
|
|
|
|
|
.append("Attachments:")
|
|
|
|
|
|
.append(
|
|
|
|
|
|
message
|
|
|
|
|
|
.file_transfer_guids
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.map(|guid| {
|
|
|
|
|
|
let mut attachment_doc = RcDoc::line().append("- ").append(guid);
|
2025-05-26 16:52:38 -07:00
|
|
|
|
|
|
|
|
|
|
// Add metadata if available for this GUID
|
|
|
|
|
|
if let Some(ref metadata) = message.attachment_metadata {
|
|
|
|
|
|
if let Some(attachment_meta) = metadata.get(guid) {
|
2025-06-06 16:39:31 -07:00
|
|
|
|
if let Some(ref attribution) =
|
|
|
|
|
|
attachment_meta.attribution_info
|
|
|
|
|
|
{
|
|
|
|
|
|
if let (Some(width), Some(height)) =
|
|
|
|
|
|
(attribution.width, attribution.height)
|
|
|
|
|
|
{
|
2025-05-26 16:52:38 -07:00
|
|
|
|
attachment_doc = attachment_doc
|
|
|
|
|
|
.append(RcDoc::line())
|
|
|
|
|
|
.append(" Dimensions: ")
|
|
|
|
|
|
.append(width.to_string())
|
|
|
|
|
|
.append(" × ")
|
|
|
|
|
|
.append(height.to_string());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
attachment_doc
|
|
|
|
|
|
})
|
2025-06-06 16:39:31 -07:00
|
|
|
|
.fold(RcDoc::nil(), |acc, x| acc.append(x)),
|
|
|
|
|
|
)
|
|
|
|
|
|
.nest(4),
|
|
|
|
|
|
);
|
2025-05-26 16:52:38 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
doc = doc.append(RcDoc::line()).append(">");
|
2025-01-20 19:43:21 -08:00
|
|
|
|
|
|
|
|
|
|
MessagePrinter { doc }
|
|
|
|
|
|
}
|
2025-06-06 16:39:31 -07:00
|
|
|
|
}
|