Private
Public Access
1
0
Files
Kordophone/core/kpcli/src/printers.rs
2025-09-06 19:33:33 -07:00

274 lines
9.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use kordophone::model::message::AttachmentMetadata;
use pretty::RcDoc;
use std::collections::HashMap;
use std::fmt::Display;
use time::OffsetDateTime;
#[cfg(target_os = "linux")]
use dbus::arg::{self, RefArg};
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 {
guid: value.guid,
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,
participants: value
.participants
.into_iter()
.map(|p| p.display_name())
.collect(),
display_name: value.display_name,
}
}
}
#[cfg(target_os = "linux")]
impl From<dbus::arg::PropMap> for PrintableConversation {
fn from(value: dbus::arg::PropMap) -> Self {
Self {
guid: value.get("guid").unwrap().as_str().unwrap().to_string(),
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")
.unwrap()
.0
.as_iter()
.unwrap()
.map(|s| s.as_str().unwrap().to_string())
.collect(),
display_name: value
.get("display_name")
.unwrap()
.as_str()
.map(|s| s.to_string()),
}
}
}
pub struct PrintableMessage {
pub guid: String,
pub date: OffsetDateTime,
pub sender: String,
pub text: String,
pub file_transfer_guids: Vec<String>,
pub attachment_metadata: Option<HashMap<String, AttachmentMetadata>>,
}
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,
file_transfer_guids: value.file_transfer_guids,
attachment_metadata: value.attachment_metadata,
}
}
}
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,
file_transfer_guids: value.file_transfer_guids,
attachment_metadata: value.attachment_metadata,
}
}
}
#[cfg(target_os = "linux")]
impl From<dbus::arg::PropMap> for PrintableMessage {
fn from(value: dbus::arg::PropMap) -> Self {
// Parse file transfer GUIDs from JSON if present
let file_transfer_guids = value
.get("file_transfer_guids")
.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
let attachment_metadata = value
.get("attachment_metadata")
.and_then(|v| v.as_str())
.and_then(|json_str| serde_json::from_str(json_str).ok());
Self {
guid: value.get("id").unwrap().as_str().unwrap().to_string(),
date: OffsetDateTime::from_unix_timestamp(value.get("date").unwrap().as_i64().unwrap())
.unwrap(),
sender: value.get("sender").unwrap().as_str().unwrap().to_string(),
text: value.get("text").unwrap().as_str().unwrap().to_string(),
file_transfer_guids,
attachment_metadata,
}
}
}
pub struct ConversationPrinter<'a> {
doc: RcDoc<'a, PrintableConversation>,
}
impl<'a> ConversationPrinter<'a> {
pub fn new(conversation: &'a PrintableConversation) -> Self {
let preview = conversation
.last_message_preview
.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>"))
.append(RcDoc::line())
.append("Date: ")
.append(conversation.date.to_string())
.append(RcDoc::line())
.append("Unread Count: ")
.append(conversation.unread_count.to_string())
.append(RcDoc::line())
.append("Participants: ")
.append("[")
.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),
)
.append("]")
.append(RcDoc::line())
.append("Last Message Preview: ")
.append(preview)
.nest(4),
)
.append(RcDoc::line())
.append(">");
ConversationPrinter { doc }
}
}
impl Display for ConversationPrinter<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.doc.render_fmt(180, f)
}
}
pub struct MessagePrinter<'a> {
doc: RcDoc<'a, PrintableMessage>,
}
impl Display for MessagePrinter<'_> {
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 {
let mut doc = RcDoc::text(format!("<Message: \"{}\"", &message.guid)).append(
RcDoc::line()
.append("Date: ")
.append(message.date.to_string())
.append(RcDoc::line())
.append("Sender: ")
.append(&message.sender)
.append(RcDoc::line())
.append("Body: ")
.append(&message.text)
.nest(4),
);
// Add file transfer GUIDs and attachment metadata if present
if !message.file_transfer_guids.is_empty() {
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);
// Add metadata if available for this GUID
if let Some(ref metadata) = message.attachment_metadata {
if let Some(attachment_meta) = metadata.get(guid) {
if let Some(ref attribution) =
attachment_meta.attribution_info
{
if let (Some(width), Some(height)) =
(attribution.width, attribution.height)
{
attachment_doc = attachment_doc
.append(RcDoc::line())
.append(" Dimensions: ")
.append(width.to_string())
.append(" × ")
.append(height.to_string());
}
}
}
}
attachment_doc
})
.fold(RcDoc::nil(), |acc, x| acc.append(x)),
)
.nest(4),
);
}
doc = doc.append(RcDoc::line()).append(">");
MessagePrinter { doc }
}
}