mirror of
https://github.com/chatmail/core.git
synced 2026-05-05 06:16:30 +03:00
Introduce summary module
summary::Summary replaces Lot in the Rust API for methods returning chatlist summaries. Lot is a legacy type for C API compatibility, so Summary can be converted into Lot.
This commit is contained in:
@@ -2404,13 +2404,13 @@ pub unsafe extern "C" fn dc_chatlist_get_summary(
|
|||||||
let ctx = &*ffi_list.context;
|
let ctx = &*ffi_list.context;
|
||||||
|
|
||||||
block_on(async move {
|
block_on(async move {
|
||||||
let lot = ffi_list
|
let summary = ffi_list
|
||||||
.list
|
.list
|
||||||
.get_summary(ctx, index as usize, maybe_chat)
|
.get_summary(ctx, index as usize, maybe_chat)
|
||||||
.await
|
.await
|
||||||
.log_err(ctx, "get_summary failed")
|
.log_err(ctx, "get_summary failed")
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
Box::into_raw(Box::new(lot))
|
Box::into_raw(Box::new(summary.into()))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2430,13 +2430,15 @@ pub unsafe extern "C" fn dc_chatlist_get_summary2(
|
|||||||
} else {
|
} else {
|
||||||
Some(MsgId::new(msg_id))
|
Some(MsgId::new(msg_id))
|
||||||
};
|
};
|
||||||
block_on(async move {
|
let summary = block_on(Chatlist::get_summary2(
|
||||||
let lot = Chatlist::get_summary2(ctx, ChatId::new(chat_id), msg_id, None)
|
ctx,
|
||||||
.await
|
ChatId::new(chat_id),
|
||||||
|
msg_id,
|
||||||
|
None,
|
||||||
|
))
|
||||||
.log_err(ctx, "get_summary2 failed")
|
.log_err(ctx, "get_summary2 failed")
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
Box::into_raw(Box::new(lot))
|
Box::into_raw(Box::new(summary.into()))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -2978,10 +2980,10 @@ pub unsafe extern "C" fn dc_msg_get_summary(
|
|||||||
let ffi_msg = &mut *msg;
|
let ffi_msg = &mut *msg;
|
||||||
let ctx = &*ffi_msg.context;
|
let ctx = &*ffi_msg.context;
|
||||||
|
|
||||||
block_on(async move {
|
let summary = block_on(async move { ffi_msg.message.get_summary(ctx, maybe_chat).await })
|
||||||
let lot = ffi_msg.message.get_summary(ctx, maybe_chat).await;
|
.log_err(ctx, "dc_msg_get_summary failed")
|
||||||
Box::into_raw(Box::new(lot))
|
.unwrap_or_default();
|
||||||
})
|
Box::into_raw(Box::new(summary.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use deltachat::dc_tools::*;
|
|||||||
use deltachat::imex::*;
|
use deltachat::imex::*;
|
||||||
use deltachat::location;
|
use deltachat::location;
|
||||||
use deltachat::log::LogExt;
|
use deltachat::log::LogExt;
|
||||||
use deltachat::lot::LotState;
|
|
||||||
use deltachat::message::{self, Message, MessageState, MsgId};
|
use deltachat::message::{self, Message, MessageState, MsgId};
|
||||||
use deltachat::peerstate::*;
|
use deltachat::peerstate::*;
|
||||||
use deltachat::qr::*;
|
use deltachat::qr::*;
|
||||||
@@ -569,26 +568,25 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
""
|
""
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let lot = chatlist.get_summary(&context, i, Some(&chat)).await?;
|
let summary = chatlist.get_summary(&context, i, Some(&chat)).await?;
|
||||||
let statestr = if chat.visibility == ChatVisibility::Archived {
|
let statestr = if chat.visibility == ChatVisibility::Archived {
|
||||||
" [Archived]"
|
" [Archived]"
|
||||||
} else {
|
} else {
|
||||||
match lot.get_state() {
|
match summary.state {
|
||||||
LotState::MsgOutPending => " o",
|
MessageState::OutPending => " o",
|
||||||
LotState::MsgOutDelivered => " √",
|
MessageState::OutDelivered => " √",
|
||||||
LotState::MsgOutMdnRcvd => " √√",
|
MessageState::OutMdnRcvd => " √√",
|
||||||
LotState::MsgOutFailed => " !!",
|
MessageState::OutFailed => " !!",
|
||||||
_ => "",
|
_ => "",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let timestr = dc_timestamp_to_str(lot.get_timestamp());
|
let timestr = dc_timestamp_to_str(summary.timestamp);
|
||||||
let text1 = lot.get_text1();
|
|
||||||
let text2 = lot.get_text2();
|
|
||||||
println!(
|
println!(
|
||||||
"{}{}{}{} [{}]{}",
|
"{}{}{} [{}]{}",
|
||||||
text1.unwrap_or(""),
|
summary
|
||||||
if text1.is_some() { ": " } else { "" },
|
.prefix
|
||||||
text2.unwrap_or(""),
|
.map_or_else(String::new, |prefix| format!("{}: ", prefix)),
|
||||||
|
summary.text,
|
||||||
statestr,
|
statestr,
|
||||||
×tr,
|
×tr,
|
||||||
if chat.is_sending_locations() {
|
if chat.is_sending_locations() {
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ use crate::constants::{
|
|||||||
use crate::contact::Contact;
|
use crate::contact::Contact;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::ephemeral::delete_expired_messages;
|
use crate::ephemeral::delete_expired_messages;
|
||||||
use crate::lot::Lot;
|
|
||||||
use crate::message::{Message, MessageState, MsgId};
|
use crate::message::{Message, MessageState, MsgId};
|
||||||
use crate::stock_str;
|
use crate::stock_str;
|
||||||
|
use crate::summary::Summary;
|
||||||
|
|
||||||
/// An object representing a single chatlist in memory.
|
/// An object representing a single chatlist in memory.
|
||||||
///
|
///
|
||||||
@@ -288,26 +288,13 @@ impl Chatlist {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a summary for a chatlist index.
|
/// Returns a summary for a given chatlist index.
|
||||||
///
|
|
||||||
/// The summary is returned by a dc_lot_t object with the following fields:
|
|
||||||
///
|
|
||||||
/// - dc_lot_t::text1: contains the username or the strings "Me", "Draft" and so on.
|
|
||||||
/// The string may be colored by having a look at text1_meaning.
|
|
||||||
/// If there is no such name or it should not be displayed, the element is NULL.
|
|
||||||
/// - dc_lot_t::text1_meaning: one of DC_TEXT1_USERNAME, DC_TEXT1_SELF or DC_TEXT1_DRAFT.
|
|
||||||
/// Typically used to show dc_lot_t::text1 with different colors. 0 if not applicable.
|
|
||||||
/// - dc_lot_t::text2: contains an excerpt of the message text or strings as
|
|
||||||
/// "No messages". May be NULL of there is no such text (eg. for the archive link)
|
|
||||||
/// - dc_lot_t::timestamp: the timestamp of the message. 0 if not applicable.
|
|
||||||
/// - dc_lot_t::state: The state of the message as one of the DC_STATE_* constants (see #dc_msg_get_state()).
|
|
||||||
// 0 if not applicable.
|
|
||||||
pub async fn get_summary(
|
pub async fn get_summary(
|
||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
index: usize,
|
index: usize,
|
||||||
chat: Option<&Chat>,
|
chat: Option<&Chat>,
|
||||||
) -> Result<Lot> {
|
) -> Result<Summary> {
|
||||||
// The summary is created by the chat, not by the last message.
|
// The summary is created by the chat, not by the last message.
|
||||||
// This is because we may want to display drafts here or stuff as
|
// This is because we may want to display drafts here or stuff as
|
||||||
// "is typing".
|
// "is typing".
|
||||||
@@ -320,14 +307,13 @@ impl Chatlist {
|
|||||||
Chatlist::get_summary2(context, *chat_id, *lastmsg_id, chat).await
|
Chatlist::get_summary2(context, *chat_id, *lastmsg_id, chat).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a summary for a given chatlist item.
|
||||||
pub async fn get_summary2(
|
pub async fn get_summary2(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
lastmsg_id: Option<MsgId>,
|
lastmsg_id: Option<MsgId>,
|
||||||
chat: Option<&Chat>,
|
chat: Option<&Chat>,
|
||||||
) -> Result<Lot> {
|
) -> Result<Summary> {
|
||||||
let mut ret = Lot::new();
|
|
||||||
|
|
||||||
let chat_loaded: Chat;
|
let chat_loaded: Chat;
|
||||||
let chat = if let Some(chat) = chat {
|
let chat = if let Some(chat) = chat {
|
||||||
chat
|
chat
|
||||||
@@ -344,9 +330,8 @@ impl Chatlist {
|
|||||||
} else {
|
} else {
|
||||||
match chat.typ {
|
match chat.typ {
|
||||||
Chattype::Group | Chattype::Mailinglist => {
|
Chattype::Group | Chattype::Mailinglist => {
|
||||||
let lastcontact =
|
let lastcontact = Contact::load_from_db(context, lastmsg.from_id).await?;
|
||||||
Contact::load_from_db(context, lastmsg.from_id).await.ok();
|
(Some(lastmsg), Some(lastcontact))
|
||||||
(Some(lastmsg), lastcontact)
|
|
||||||
}
|
}
|
||||||
Chattype::Single | Chattype::Undefined => (Some(lastmsg), None),
|
Chattype::Single | Chattype::Undefined => (Some(lastmsg), None),
|
||||||
}
|
}
|
||||||
@@ -356,17 +341,15 @@ impl Chatlist {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if chat.id.is_archived_link() {
|
if chat.id.is_archived_link() {
|
||||||
ret.text2 = None;
|
Ok(Default::default())
|
||||||
} else if let Some(mut lastmsg) =
|
} else if let Some(lastmsg) = lastmsg.filter(|msg| msg.from_id != DC_CONTACT_ID_UNDEFINED) {
|
||||||
lastmsg.filter(|msg| msg.from_id != DC_CONTACT_ID_UNDEFINED)
|
Ok(Summary::new(context, &lastmsg, chat, lastcontact.as_ref()).await)
|
||||||
{
|
|
||||||
ret.fill(&mut lastmsg, chat, lastcontact.as_ref(), context)
|
|
||||||
.await;
|
|
||||||
} else {
|
} else {
|
||||||
ret.text2 = Some(stock_str::no_messages(context).await);
|
Ok(Summary {
|
||||||
|
text: stock_str::no_messages(context).await,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ret)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_index_for_id(&self, id: ChatId) -> Option<usize> {
|
pub fn get_index_for_id(&self, id: ChatId) -> Option<usize> {
|
||||||
@@ -637,6 +620,6 @@ mod tests {
|
|||||||
|
|
||||||
let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap();
|
let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap();
|
||||||
let summary = chats.get_summary(&t, 0, None).await.unwrap();
|
let summary = chats.get_summary(&t, 0, None).await.unwrap();
|
||||||
assert_eq!(summary.get_text2().unwrap(), "foo: bar test"); // the linebreak should be removed from summary
|
assert_eq!(summary.text, "foo: bar test"); // the linebreak should be removed from summary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ mod dehtml;
|
|||||||
mod color;
|
mod color;
|
||||||
pub mod html;
|
pub mod html;
|
||||||
pub mod plaintext;
|
pub mod plaintext;
|
||||||
|
pub mod summary;
|
||||||
|
|
||||||
pub mod dc_receive_imf;
|
pub mod dc_receive_imf;
|
||||||
pub mod dc_tools;
|
pub mod dc_tools;
|
||||||
|
|||||||
39
src/lot.rs
39
src/lot.rs
@@ -3,6 +3,8 @@
|
|||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
|
|
||||||
use crate::key::Fingerprint;
|
use crate::key::Fingerprint;
|
||||||
|
use crate::message::MessageState;
|
||||||
|
use crate::summary::{Summary, SummaryPrefix};
|
||||||
|
|
||||||
/// An object containing a set of values.
|
/// An object containing a set of values.
|
||||||
/// The meaning of the values is defined by the function returning the object.
|
/// The meaning of the values is defined by the function returning the object.
|
||||||
@@ -139,3 +141,40 @@ impl Default for LotState {
|
|||||||
LotState::Undefined
|
LotState::Undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<MessageState> for LotState {
|
||||||
|
fn from(s: MessageState) -> Self {
|
||||||
|
use MessageState::*;
|
||||||
|
match s {
|
||||||
|
Undefined => LotState::Undefined,
|
||||||
|
InFresh => LotState::MsgInFresh,
|
||||||
|
InNoticed => LotState::MsgInNoticed,
|
||||||
|
InSeen => LotState::MsgInSeen,
|
||||||
|
OutPreparing => LotState::MsgOutPreparing,
|
||||||
|
OutDraft => LotState::MsgOutDraft,
|
||||||
|
OutPending => LotState::MsgOutPending,
|
||||||
|
OutFailed => LotState::MsgOutFailed,
|
||||||
|
OutDelivered => LotState::MsgOutDelivered,
|
||||||
|
OutMdnRcvd => LotState::MsgOutMdnRcvd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Summary> for Lot {
|
||||||
|
fn from(summary: Summary) -> Self {
|
||||||
|
let (text1, text1_meaning) = match summary.prefix {
|
||||||
|
None => (None, Meaning::None),
|
||||||
|
Some(SummaryPrefix::Draft(text)) => (Some(text), Meaning::Text1Draft),
|
||||||
|
Some(SummaryPrefix::Username(username)) => (Some(username), Meaning::Text1Username),
|
||||||
|
Some(SummaryPrefix::Me(text)) => (Some(text), Meaning::Text1Self),
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
text1_meaning,
|
||||||
|
text1,
|
||||||
|
text2: Some(summary.text),
|
||||||
|
timestamp: summary.timestamp,
|
||||||
|
state: summary.state.into(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
382
src/message.rs
382
src/message.rs
@@ -6,7 +6,6 @@ use std::convert::TryInto;
|
|||||||
use anyhow::{ensure, format_err, Context as _, Result};
|
use anyhow::{ensure, format_err, Context as _, Result};
|
||||||
use async_std::path::{Path, PathBuf};
|
use async_std::path::{Path, PathBuf};
|
||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
use itertools::Itertools;
|
|
||||||
use rusqlite::types::ValueRef;
|
use rusqlite::types::ValueRef;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -26,15 +25,11 @@ use crate::ephemeral::Timer as EphemeralTimer;
|
|||||||
use crate::events::EventType;
|
use crate::events::EventType;
|
||||||
use crate::job::{self, Action};
|
use crate::job::{self, Action};
|
||||||
use crate::log::LogExt;
|
use crate::log::LogExt;
|
||||||
use crate::lot::{Lot, LotState, Meaning};
|
|
||||||
use crate::mimeparser::{parse_message_id, FailureReport, SystemMessage};
|
use crate::mimeparser::{parse_message_id, FailureReport, SystemMessage};
|
||||||
use crate::param::{Param, Params};
|
use crate::param::{Param, Params};
|
||||||
use crate::pgp::split_armored_data;
|
use crate::pgp::split_armored_data;
|
||||||
use crate::stock_str;
|
use crate::stock_str;
|
||||||
|
use crate::summary::{get_summarytext_by_raw, Summary};
|
||||||
// In practice, the user additionally cuts the string themselves
|
|
||||||
// pixel-accurate.
|
|
||||||
const SUMMARY_CHARACTERS: usize = 160;
|
|
||||||
|
|
||||||
/// Message ID, including reserved IDs.
|
/// Message ID, including reserved IDs.
|
||||||
///
|
///
|
||||||
@@ -592,23 +587,21 @@ impl Message {
|
|||||||
self.ephemeral_timestamp
|
self.ephemeral_timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_summary(&mut self, context: &Context, chat: Option<&Chat>) -> Lot {
|
/// Returns message summary for display in the search results.
|
||||||
let mut ret = Lot::new();
|
pub async fn get_summary(&mut self, context: &Context, chat: Option<&Chat>) -> Result<Summary> {
|
||||||
|
|
||||||
let chat_loaded: Chat;
|
let chat_loaded: Chat;
|
||||||
let chat = if let Some(chat) = chat {
|
let chat = if let Some(chat) = chat {
|
||||||
chat
|
chat
|
||||||
} else if let Ok(chat) = Chat::load_from_db(context, self.chat_id).await {
|
} else {
|
||||||
|
let chat = Chat::load_from_db(context, self.chat_id).await?;
|
||||||
chat_loaded = chat;
|
chat_loaded = chat;
|
||||||
&chat_loaded
|
&chat_loaded
|
||||||
} else {
|
|
||||||
return ret;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let contact = if self.from_id != DC_CONTACT_ID_SELF {
|
let contact = if self.from_id != DC_CONTACT_ID_SELF {
|
||||||
match chat.typ {
|
match chat.typ {
|
||||||
Chattype::Group | Chattype::Mailinglist => {
|
Chattype::Group | Chattype::Mailinglist => {
|
||||||
Contact::get_by_id(context, self.from_id).await.ok()
|
Some(Contact::get_by_id(context, self.from_id).await?)
|
||||||
}
|
}
|
||||||
Chattype::Single | Chattype::Undefined => None,
|
Chattype::Single | Chattype::Undefined => None,
|
||||||
}
|
}
|
||||||
@@ -616,9 +609,7 @@ impl Message {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
ret.fill(self, chat, contact.as_ref(), context).await;
|
Ok(Summary::new(context, self, chat, contact.as_ref()).await)
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_summarytext(&self, context: &Context, approx_characters: usize) -> String {
|
pub async fn get_summarytext(&self, context: &Context, approx_characters: usize) -> String {
|
||||||
@@ -1029,24 +1020,6 @@ impl std::fmt::Display for MessageState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MessageState> for LotState {
|
|
||||||
fn from(s: MessageState) -> Self {
|
|
||||||
use MessageState::*;
|
|
||||||
match s {
|
|
||||||
Undefined => LotState::Undefined,
|
|
||||||
InFresh => LotState::MsgInFresh,
|
|
||||||
InNoticed => LotState::MsgInNoticed,
|
|
||||||
InSeen => LotState::MsgInSeen,
|
|
||||||
OutPreparing => LotState::MsgOutPreparing,
|
|
||||||
OutDraft => LotState::MsgOutDraft,
|
|
||||||
OutPending => LotState::MsgOutPending,
|
|
||||||
OutFailed => LotState::MsgOutFailed,
|
|
||||||
OutDelivered => LotState::MsgOutDelivered,
|
|
||||||
OutMdnRcvd => LotState::MsgOutMdnRcvd,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MessageState {
|
impl MessageState {
|
||||||
pub fn can_fail(self) -> bool {
|
pub fn can_fail(self) -> bool {
|
||||||
use MessageState::*;
|
use MessageState::*;
|
||||||
@@ -1064,68 +1037,6 @@ impl MessageState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lot {
|
|
||||||
/* library-internal */
|
|
||||||
/* in practice, the user additionally cuts the string himself pixel-accurate */
|
|
||||||
pub async fn fill(
|
|
||||||
&mut self,
|
|
||||||
msg: &mut Message,
|
|
||||||
chat: &Chat,
|
|
||||||
contact: Option<&Contact>,
|
|
||||||
context: &Context,
|
|
||||||
) {
|
|
||||||
if msg.state == MessageState::OutDraft {
|
|
||||||
self.text1 = Some(stock_str::draft(context).await);
|
|
||||||
self.text1_meaning = Meaning::Text1Draft;
|
|
||||||
} else if msg.from_id == DC_CONTACT_ID_SELF {
|
|
||||||
if msg.is_info() || chat.is_self_talk() {
|
|
||||||
self.text1 = None;
|
|
||||||
self.text1_meaning = Meaning::None;
|
|
||||||
} else {
|
|
||||||
self.text1 = Some(stock_str::self_msg(context).await);
|
|
||||||
self.text1_meaning = Meaning::Text1Self;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match chat.typ {
|
|
||||||
Chattype::Group | Chattype::Mailinglist => {
|
|
||||||
if msg.is_info() || contact.is_none() {
|
|
||||||
self.text1 = None;
|
|
||||||
self.text1_meaning = Meaning::None;
|
|
||||||
} else {
|
|
||||||
self.text1 = msg
|
|
||||||
.get_override_sender_name()
|
|
||||||
.or_else(|| contact.map(|contact| msg.get_sender_name(contact)));
|
|
||||||
self.text1_meaning = Meaning::Text1Username;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Chattype::Single | Chattype::Undefined => {
|
|
||||||
self.text1 = None;
|
|
||||||
self.text1_meaning = Meaning::None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut text2 = get_summarytext_by_raw(
|
|
||||||
msg.viewtype,
|
|
||||||
msg.text.as_ref(),
|
|
||||||
msg.is_forwarded(),
|
|
||||||
&msg.param,
|
|
||||||
SUMMARY_CHARACTERS,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if text2.is_empty() && msg.quoted_text().is_some() {
|
|
||||||
text2 = stock_str::reply_noun(context).await
|
|
||||||
}
|
|
||||||
|
|
||||||
self.text2 = Some(text2);
|
|
||||||
|
|
||||||
self.timestamp = msg.get_timestamp();
|
|
||||||
self.state = msg.state.into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result<String> {
|
pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result<String> {
|
||||||
let msg = Message::load_from_db(context, msg_id).await?;
|
let msg = Message::load_from_db(context, msg_id).await?;
|
||||||
let rawtxt: Option<String> = context
|
let rawtxt: Option<String> = context
|
||||||
@@ -1491,88 +1402,6 @@ pub async fn update_msg_state(context: &Context, msg_id: MsgId, state: MessageSt
|
|||||||
.is_ok()
|
.is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a summary text.
|
|
||||||
pub async fn get_summarytext_by_raw(
|
|
||||||
viewtype: Viewtype,
|
|
||||||
text: Option<impl AsRef<str>>,
|
|
||||||
was_forwarded: bool,
|
|
||||||
param: &Params,
|
|
||||||
approx_characters: usize,
|
|
||||||
context: &Context,
|
|
||||||
) -> String {
|
|
||||||
let mut append_text = true;
|
|
||||||
let prefix = match viewtype {
|
|
||||||
Viewtype::Image => stock_str::image(context).await,
|
|
||||||
Viewtype::Gif => stock_str::gif(context).await,
|
|
||||||
Viewtype::Sticker => stock_str::sticker(context).await,
|
|
||||||
Viewtype::Video => stock_str::video(context).await,
|
|
||||||
Viewtype::Voice => stock_str::voice_message(context).await,
|
|
||||||
Viewtype::Audio | Viewtype::File => {
|
|
||||||
if param.get_cmd() == SystemMessage::AutocryptSetupMessage {
|
|
||||||
append_text = false;
|
|
||||||
stock_str::ac_setup_msg_subject(context).await
|
|
||||||
} else {
|
|
||||||
let file_name: String = param
|
|
||||||
.get_path(Param::File, context)
|
|
||||||
.unwrap_or(None)
|
|
||||||
.and_then(|path| {
|
|
||||||
path.file_name()
|
|
||||||
.map(|fname| fname.to_string_lossy().into_owned())
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| String::from("ErrFileName"));
|
|
||||||
let label = if viewtype == Viewtype::Audio {
|
|
||||||
stock_str::audio(context).await
|
|
||||||
} else {
|
|
||||||
stock_str::file(context).await
|
|
||||||
};
|
|
||||||
format!("{} – {}", label, file_name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Viewtype::VideochatInvitation => {
|
|
||||||
append_text = false;
|
|
||||||
stock_str::videochat_invitation(context).await
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if param.get_cmd() != SystemMessage::LocationOnly {
|
|
||||||
"".to_string()
|
|
||||||
} else {
|
|
||||||
append_text = false;
|
|
||||||
stock_str::location(context).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if !append_text {
|
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
let summary_content = if let Some(text) = text {
|
|
||||||
if text.as_ref().is_empty() {
|
|
||||||
prefix
|
|
||||||
} else if prefix.is_empty() {
|
|
||||||
dc_truncate(text.as_ref(), approx_characters).to_string()
|
|
||||||
} else {
|
|
||||||
let tmp = format!("{} – {}", prefix, text.as_ref());
|
|
||||||
dc_truncate(&tmp, approx_characters).to_string()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
prefix
|
|
||||||
};
|
|
||||||
|
|
||||||
let summary = if was_forwarded {
|
|
||||||
let tmp = format!(
|
|
||||||
"{}: {}",
|
|
||||||
stock_str::forwarded(context).await,
|
|
||||||
summary_content
|
|
||||||
);
|
|
||||||
dc_truncate(&tmp, approx_characters).to_string()
|
|
||||||
} else {
|
|
||||||
summary_content
|
|
||||||
};
|
|
||||||
|
|
||||||
summary.split_whitespace().join(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// as we do not cut inside words, this results in about 32-42 characters.
|
// as we do not cut inside words, this results in about 32-42 characters.
|
||||||
// Do not use too long subjects - we add a tag after the subject which gets truncated by the clients otherwise.
|
// Do not use too long subjects - we add a tag after the subject which gets truncated by the clients otherwise.
|
||||||
// It should also be very clear, the subject is _not_ the whole message.
|
// It should also be very clear, the subject is _not_ the whole message.
|
||||||
@@ -2239,203 +2068,6 @@ mod tests {
|
|||||||
assert!(chat::prepare_msg(ctx, chat.id, &mut msg).await.is_err());
|
assert!(chat::prepare_msg(ctx, chat.id, &mut msg).await.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
|
||||||
async fn test_get_summarytext_by_raw() {
|
|
||||||
let d = test::TestContext::new().await;
|
|
||||||
let ctx = &d.ctx;
|
|
||||||
|
|
||||||
let some_text = Some(" bla \t\n\tbla\n\t".to_string());
|
|
||||||
let empty_text = Some("".to_string());
|
|
||||||
let no_text: Option<String> = None;
|
|
||||||
|
|
||||||
let mut some_file = Params::new();
|
|
||||||
some_file.set(Param::File, "foo.bar");
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Text,
|
|
||||||
some_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&Params::new(),
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"bla bla" // for simple text, the type is not added to the summary
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Image,
|
|
||||||
no_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Image" // file names are not added for images
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Video,
|
|
||||||
no_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Video" // file names are not added for videos
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(Viewtype::Gif, no_text.as_ref(), false, &some_file, 50, ctx,)
|
|
||||||
.await,
|
|
||||||
"GIF" // file names are not added for GIFs
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Sticker,
|
|
||||||
no_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx,
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Sticker" // file names are not added for stickers
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Voice,
|
|
||||||
empty_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx,
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Voice message" // file names are not added for voice messages, empty text is skipped
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Voice,
|
|
||||||
no_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Voice message" // file names are not added for voice messages
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Voice,
|
|
||||||
some_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Voice message \u{2013} bla bla" // `\u{2013}` explicitly checks for "EN DASH"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Audio,
|
|
||||||
no_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Audio \u{2013} foo.bar" // file name is added for audio
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Audio,
|
|
||||||
empty_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx,
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Audio \u{2013} foo.bar" // file name is added for audio, empty text is not added
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Audio,
|
|
||||||
some_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Audio \u{2013} foo.bar \u{2013} bla bla" // file name and text added for audio
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::File,
|
|
||||||
some_text.as_ref(),
|
|
||||||
false,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"File \u{2013} foo.bar \u{2013} bla bla" // file name is added for files
|
|
||||||
);
|
|
||||||
|
|
||||||
// Forwarded
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::Text,
|
|
||||||
some_text.as_ref(),
|
|
||||||
true,
|
|
||||||
&Params::new(),
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Forwarded: bla bla" // for simple text, the type is not added to the summary
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(
|
|
||||||
Viewtype::File,
|
|
||||||
some_text.as_ref(),
|
|
||||||
true,
|
|
||||||
&some_file,
|
|
||||||
50,
|
|
||||||
ctx
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
"Forwarded: File \u{2013} foo.bar \u{2013} bla bla"
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut asm_file = Params::new();
|
|
||||||
asm_file.set(Param::File, "foo.bar");
|
|
||||||
asm_file.set_cmd(SystemMessage::AutocryptSetupMessage);
|
|
||||||
assert_eq!(
|
|
||||||
get_summarytext_by_raw(Viewtype::File, no_text.as_ref(), false, &asm_file, 50, ctx)
|
|
||||||
.await,
|
|
||||||
"Autocrypt Setup Message" // file name is not added for autocrypt setup messages
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_parse_webrtc_instance() {
|
async fn test_parse_webrtc_instance() {
|
||||||
let (webrtc_type, url) = Message::parse_webrtc_instance("basicwebrtc:https://foo/bar");
|
let (webrtc_type, url) = Message::parse_webrtc_instance("basicwebrtc:https://foo/bar");
|
||||||
|
|||||||
394
src/summary.rs
Normal file
394
src/summary.rs
Normal file
@@ -0,0 +1,394 @@
|
|||||||
|
//! # Message summary for chatlist.
|
||||||
|
|
||||||
|
use crate::chat::Chat;
|
||||||
|
use crate::constants::{Chattype, Viewtype, DC_CONTACT_ID_SELF};
|
||||||
|
use crate::contact::Contact;
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::dc_tools::dc_truncate;
|
||||||
|
use crate::message::{Message, MessageState};
|
||||||
|
use crate::mimeparser::SystemMessage;
|
||||||
|
use crate::param::{Param, Params};
|
||||||
|
use crate::stock_str;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
// In practice, the user additionally cuts the string themselves
|
||||||
|
// pixel-accurate.
|
||||||
|
const SUMMARY_CHARACTERS: usize = 160;
|
||||||
|
|
||||||
|
/// Prefix displayed before message and separated by ":" in the chatlist.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SummaryPrefix {
|
||||||
|
/// Username.
|
||||||
|
Username(String),
|
||||||
|
|
||||||
|
/// Stock string saying "Draft".
|
||||||
|
Draft(String),
|
||||||
|
|
||||||
|
/// Stock string saying "Me".
|
||||||
|
Me(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SummaryPrefix {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
SummaryPrefix::Username(username) => write!(f, "{}", username),
|
||||||
|
SummaryPrefix::Draft(text) => write!(f, "{}", text),
|
||||||
|
SummaryPrefix::Me(text) => write!(f, "{}", text),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Message summary.
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Summary {
|
||||||
|
/// Part displayed before ":", such as an username or a string "Draft".
|
||||||
|
pub prefix: Option<SummaryPrefix>,
|
||||||
|
|
||||||
|
/// Summary text, always present.
|
||||||
|
pub text: String,
|
||||||
|
|
||||||
|
/// Message timestamp.
|
||||||
|
pub timestamp: i64,
|
||||||
|
|
||||||
|
/// Message state.
|
||||||
|
pub state: MessageState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Summary {
|
||||||
|
pub async fn new(
|
||||||
|
context: &Context,
|
||||||
|
msg: &Message,
|
||||||
|
chat: &Chat,
|
||||||
|
contact: Option<&Contact>,
|
||||||
|
) -> Self {
|
||||||
|
let prefix = if msg.state == MessageState::OutDraft {
|
||||||
|
Some(SummaryPrefix::Draft(stock_str::draft(context).await))
|
||||||
|
} else if msg.from_id == DC_CONTACT_ID_SELF {
|
||||||
|
if msg.is_info() || chat.is_self_talk() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(SummaryPrefix::Me(stock_str::self_msg(context).await))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match chat.typ {
|
||||||
|
Chattype::Group | Chattype::Mailinglist => {
|
||||||
|
if msg.is_info() || contact.is_none() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
msg.get_override_sender_name()
|
||||||
|
.or_else(|| contact.map(|contact| msg.get_sender_name(contact)))
|
||||||
|
.map(SummaryPrefix::Username)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Chattype::Single | Chattype::Undefined => None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut text = get_summarytext_by_raw(
|
||||||
|
msg.viewtype,
|
||||||
|
msg.text.as_ref(),
|
||||||
|
msg.is_forwarded(),
|
||||||
|
&msg.param,
|
||||||
|
SUMMARY_CHARACTERS,
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if text.is_empty() && msg.quoted_text().is_some() {
|
||||||
|
text = stock_str::reply_noun(context).await
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
prefix,
|
||||||
|
text,
|
||||||
|
timestamp: msg.get_timestamp(),
|
||||||
|
state: msg.state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a summary text.
|
||||||
|
pub async fn get_summarytext_by_raw(
|
||||||
|
viewtype: Viewtype,
|
||||||
|
text: Option<impl AsRef<str>>,
|
||||||
|
was_forwarded: bool,
|
||||||
|
param: &Params,
|
||||||
|
approx_characters: usize,
|
||||||
|
context: &Context,
|
||||||
|
) -> String {
|
||||||
|
let mut append_text = true;
|
||||||
|
let prefix = match viewtype {
|
||||||
|
Viewtype::Image => stock_str::image(context).await,
|
||||||
|
Viewtype::Gif => stock_str::gif(context).await,
|
||||||
|
Viewtype::Sticker => stock_str::sticker(context).await,
|
||||||
|
Viewtype::Video => stock_str::video(context).await,
|
||||||
|
Viewtype::Voice => stock_str::voice_message(context).await,
|
||||||
|
Viewtype::Audio | Viewtype::File => {
|
||||||
|
if param.get_cmd() == SystemMessage::AutocryptSetupMessage {
|
||||||
|
append_text = false;
|
||||||
|
stock_str::ac_setup_msg_subject(context).await
|
||||||
|
} else {
|
||||||
|
let file_name: String = param
|
||||||
|
.get_path(Param::File, context)
|
||||||
|
.unwrap_or(None)
|
||||||
|
.and_then(|path| {
|
||||||
|
path.file_name()
|
||||||
|
.map(|fname| fname.to_string_lossy().into_owned())
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| String::from("ErrFileName"));
|
||||||
|
let label = if viewtype == Viewtype::Audio {
|
||||||
|
stock_str::audio(context).await
|
||||||
|
} else {
|
||||||
|
stock_str::file(context).await
|
||||||
|
};
|
||||||
|
format!("{} – {}", label, file_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Viewtype::VideochatInvitation => {
|
||||||
|
append_text = false;
|
||||||
|
stock_str::videochat_invitation(context).await
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if param.get_cmd() != SystemMessage::LocationOnly {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
append_text = false;
|
||||||
|
stock_str::location(context).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !append_text {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
let summary_content = if let Some(text) = text {
|
||||||
|
if text.as_ref().is_empty() {
|
||||||
|
prefix
|
||||||
|
} else if prefix.is_empty() {
|
||||||
|
dc_truncate(text.as_ref(), approx_characters).to_string()
|
||||||
|
} else {
|
||||||
|
let tmp = format!("{} – {}", prefix, text.as_ref());
|
||||||
|
dc_truncate(&tmp, approx_characters).to_string()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
prefix
|
||||||
|
};
|
||||||
|
|
||||||
|
let summary = if was_forwarded {
|
||||||
|
let tmp = format!(
|
||||||
|
"{}: {}",
|
||||||
|
stock_str::forwarded(context).await,
|
||||||
|
summary_content
|
||||||
|
);
|
||||||
|
dc_truncate(&tmp, approx_characters).to_string()
|
||||||
|
} else {
|
||||||
|
summary_content
|
||||||
|
};
|
||||||
|
|
||||||
|
summary.split_whitespace().join(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::test_utils as test;
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_get_summarytext_by_raw() {
|
||||||
|
let d = test::TestContext::new().await;
|
||||||
|
let ctx = &d.ctx;
|
||||||
|
|
||||||
|
let some_text = Some(" bla \t\n\tbla\n\t".to_string());
|
||||||
|
let empty_text = Some("".to_string());
|
||||||
|
let no_text: Option<String> = None;
|
||||||
|
|
||||||
|
let mut some_file = Params::new();
|
||||||
|
some_file.set(Param::File, "foo.bar");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Text,
|
||||||
|
some_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&Params::new(),
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"bla bla" // for simple text, the type is not added to the summary
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Image,
|
||||||
|
no_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Image" // file names are not added for images
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Video,
|
||||||
|
no_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Video" // file names are not added for videos
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(Viewtype::Gif, no_text.as_ref(), false, &some_file, 50, ctx,)
|
||||||
|
.await,
|
||||||
|
"GIF" // file names are not added for GIFs
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Sticker,
|
||||||
|
no_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Sticker" // file names are not added for stickers
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Voice,
|
||||||
|
empty_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Voice message" // file names are not added for voice messages, empty text is skipped
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Voice,
|
||||||
|
no_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Voice message" // file names are not added for voice messages
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Voice,
|
||||||
|
some_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Voice message \u{2013} bla bla" // `\u{2013}` explicitly checks for "EN DASH"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Audio,
|
||||||
|
no_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Audio \u{2013} foo.bar" // file name is added for audio
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Audio,
|
||||||
|
empty_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Audio \u{2013} foo.bar" // file name is added for audio, empty text is not added
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Audio,
|
||||||
|
some_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Audio \u{2013} foo.bar \u{2013} bla bla" // file name and text added for audio
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::File,
|
||||||
|
some_text.as_ref(),
|
||||||
|
false,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"File \u{2013} foo.bar \u{2013} bla bla" // file name is added for files
|
||||||
|
);
|
||||||
|
|
||||||
|
// Forwarded
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::Text,
|
||||||
|
some_text.as_ref(),
|
||||||
|
true,
|
||||||
|
&Params::new(),
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Forwarded: bla bla" // for simple text, the type is not added to the summary
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(
|
||||||
|
Viewtype::File,
|
||||||
|
some_text.as_ref(),
|
||||||
|
true,
|
||||||
|
&some_file,
|
||||||
|
50,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
"Forwarded: File \u{2013} foo.bar \u{2013} bla bla"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut asm_file = Params::new();
|
||||||
|
asm_file.set(Param::File, "foo.bar");
|
||||||
|
asm_file.set_cmd(SystemMessage::AutocryptSetupMessage);
|
||||||
|
assert_eq!(
|
||||||
|
get_summarytext_by_raw(Viewtype::File, no_text.as_ref(), false, &asm_file, 50, ctx)
|
||||||
|
.await,
|
||||||
|
"Autocrypt Setup Message" // file name is not added for autocrypt setup messages
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user