use rho_sdk::model::Message;
use serde::{Deserialize, Serialize};
use crate::presentation::NotificationCard;
const PREFIX: &str = "[rho boundary transcript v1]";
const FAMILY: &str = "[rho boundary transcript ";
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum DisplayRow {
#[serde(rename = "Message")]
Notification(Box<NotificationCard>),
Notice(String),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct DisplayTranscript(pub(crate) Vec<DisplayRow>);
impl DisplayTranscript {
pub(crate) fn display_message(&self) -> Message {
Message::System(format!(
"{PREFIX}\n{}",
serde_json::to_string(self).expect("display rows contain only serializable data")
))
}
pub(crate) fn from_display(text: &str) -> Option<Self> {
if !text.starts_with(FAMILY) {
return None;
}
Some(text.strip_prefix(PREFIX)
.and_then(|body| serde_json::from_str(body).ok())
.unwrap_or_else(|| Self(vec![DisplayRow::Notice(
"could not restore notification display: unsupported or malformed saved record; the original record remains in the session file".into(),
)])))
}
pub(crate) fn plain_text(&self) -> String {
self.0
.iter()
.map(|row| match row {
DisplayRow::Notification(card) => {
format!("{}\n{}\n{}", card.title, subtitle(card), card.plain_body())
}
DisplayRow::Notice(text) => text.clone(),
})
.collect::<Vec<_>>()
.join("\n\n")
}
}
impl DisplayRow {
pub(crate) fn card_text(&self) -> CardText<'_> {
match self {
Self::Notification(card) => {
let subtitle = subtitle(card);
CardText {
title: &card.title,
markdown: format!("{subtitle}\n{}", card.markdown_body()),
plain: format!("{subtitle}\n{}", card.plain_body()),
}
}
Self::Notice(text) => match text.split_once('\n') {
Some((title, rest)) => CardText {
title,
markdown: rest.to_owned(),
plain: rest.to_owned(),
},
None => CardText {
title: text,
markdown: String::new(),
plain: String::new(),
},
},
}
}
}
pub(crate) struct CardText<'a> {
pub(crate) title: &'a str,
pub(crate) markdown: String,
pub(crate) plain: String,
}
fn subtitle(card: &NotificationCard) -> String {
card.subtitle.clone().unwrap_or_else(|| {
let reference = card
.reference
.as_deref()
.map(|id| format!(" · {id}"))
.unwrap_or_default();
format!("{} → {}{reference}", card.sender, card.recipient)
})
}
#[cfg(test)]
#[path = "display_transcript_tests.rs"]
mod tests;