api: new dc_msg_get_summarytext_without_prefix()

This commit is contained in:
B. Petersen
2026-10-08 01:20:00 +02:00
parent 0bee156449
commit 3cc5b90235
4 changed files with 68 additions and 23 deletions
+8 -1
View File
@@ -4293,11 +4293,18 @@ dc_lot_t* dc_msg_get_summary (const dc_msg_t* msg, const dc_cha
* @memberof dc_msg_t
* @param msg The message object.
* @param approx_characters A rough length of the expected string.
* @param full_summary 1=return full summary with all details,
* 0=skip type and "forwarded" prefixes as they're rendered by the UI alerady,
* used for pinned messages that show e.g. an image and do not need the type in the summary therefore.
* @return A summary for the given messages.
* The returned string must be released using dc_str_unref().
* Returns an empty string on errors, never returns NULL.
*/
char* dc_msg_get_summarytext (const dc_msg_t* msg, int approx_characters);
char* dc_msg_get_summary_text (const dc_msg_t* msg, int approx_characters, int with_emoji);
// depreacted 2026-10-07, the old variant took a string length as second parameter, which is converted to true.
#define dc_msg_get_summarytext(a, b) dc_msg_get_summary_text((a), (b), true)
/**
+10 -11
View File
@@ -12,7 +12,6 @@
extern crate human_panic;
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fmt::Write;
use std::future::Future;
use std::mem::ManuallyDrop;
@@ -3474,24 +3473,24 @@ pub unsafe extern "C" fn dc_msg_get_summary(
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn dc_msg_get_summarytext(
pub unsafe extern "C" fn dc_msg_get_summary_text(
msg: *mut dc_msg_t,
approx_characters: libc::c_int,
full_summary: libc::c_int,
) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_summarytext()");
eprintln!("ignoring careless call to dc_msg_get_summary_text()");
return "".strdup();
}
let ffi_msg = unsafe { &mut *msg };
let summary = block_on(ffi_msg.message.get_summary(&ffi_msg.context, None))
.context("dc_msg_get_summarytext failed")
.log_err(&ffi_msg.context)
.unwrap_or_default();
match usize::try_from(approx_characters) {
Ok(chars) => summary.truncated_text(chars).strdup(),
Err(_) => summary.text.strdup(),
}
block_on(ffi_msg.message.get_summary_text_ext(
&ffi_msg.context,
approx_characters as usize,
full_summary != 0,
full_summary != 0,
))
.strdup()
}
#[unsafe(no_mangle)]
+1 -1
View File
@@ -188,7 +188,7 @@ class Message:
def get_summarytext(self, width: int) -> str:
"""Get a message summary as a single line of text. Typically used for notifications."""
return from_dc_charpointer(lib.dc_msg_get_summarytext(self._dc_msg, width))
return from_dc_charpointer(lib.dc_msg_get_summary_text(self._dc_msg, width, True))
@props.with_doc
def time_sent(self):
+49 -10
View File
@@ -138,19 +138,35 @@ impl Summary {
}
impl Message {
/// Returns a summary text.
/// Returns a summary text with emoji and "Forwarded:" prefixes.
/// This is the standard summary to be used in chatlists, notifications etc.
pub(crate) async fn get_summary_text(&self, context: &Context) -> String {
let summary = self.get_summary_text_without_prefix(context).await;
if self.is_forwarded() {
format!("{}: {}", stock_str::forwarded(context), summary)
} else {
summary
}
let approx_chars = 0;
let with_forwarded = true;
let with_emoji = true;
self.get_summary_text_ext(context, approx_chars, with_forwarded, with_emoji)
.await
}
/// Returns a summary text without "Forwarded:" prefix.
/// Returns a summary text with emoji prefixes but without "Forwarded:" prefix.
/// Used for shorter reaction summaries as "USER reactes 👋 to SUMMARY"
async fn get_summary_text_without_prefix(&self, context: &Context) -> String {
let approx_chars = 0;
let with_forwarded = false;
let with_emoji = true;
self.get_summary_text_ext(context, approx_chars, with_forwarded, with_emoji)
.await
}
/// Returns a summary text with optional "Forwarded:" and emoji prefixes.
/// If approx_chars is >0, the string is truncated at about that position.
pub async fn get_summary_text_ext(
&self,
context: &Context,
approx_chars: usize,
with_forwarded: bool,
with_emoji: bool,
) -> String {
let (emoji, type_name, type_file, append_text);
let viewtype = match self
.param
@@ -264,7 +280,11 @@ impl Message {
}
};
let text = self.text.clone();
let text = if approx_chars > 0 {
truncate(&self.text, approx_chars).to_string()
} else {
self.text.clone()
};
let summary = if let Some(type_file) = type_file {
if append_text && !text.is_empty() {
@@ -286,12 +306,19 @@ impl Message {
"".to_string()
};
let emoji = emoji.filter(|_| with_emoji);
let summary = if let Some(emoji) = emoji {
format!("{emoji} {summary}")
} else {
summary
};
let summary = if with_forwarded && self.is_forwarded() {
format!("{}: {}", stock_str::forwarded(context), summary)
} else {
summary
};
summary.split_whitespace().collect::<Vec<&str>>().join(" ")
}
}
@@ -336,6 +363,10 @@ mod tests {
msg.set_file_and_deduplicate(&d, &file, Some("foo.jpg"), None)
.unwrap();
assert_summary_texts(&msg, ctx, "📷 Image").await; // file names are not added for images
assert_eq!(
msg.get_summary_text_ext(ctx, 500, false, false).await,
"Image"
);
let file = write_file_to_blobdir(&d).await;
let mut msg = Message::new(Viewtype::Image);
@@ -343,6 +374,10 @@ mod tests {
msg.set_file_and_deduplicate(&d, &file, Some("foo.jpg"), None)
.unwrap();
assert_summary_texts(&msg, ctx, "📷 bla bla").await; // type is visible by emoji if text is set
assert_eq!(
msg.get_summary_text_ext(ctx, 500, false, false).await,
"bla bla"
);
let file = write_file_to_blobdir(&d).await;
let mut msg = Message::new(Viewtype::Video);
@@ -473,6 +508,10 @@ mod tests {
msg.get_summary_text_without_prefix(ctx).await,
"📎 foo.bar \u{2013} bla bla"
); // skipping prefix used for reactions summaries
assert_eq!(
msg.get_summary_text_ext(ctx, 500, false, false).await,
"foo.bar \u{2013} bla bla"
);
d.assert_warn("Not a valid DeltaChat vCard").await;
}
}