mirror of
https://github.com/chatmail/core.git
synced 2026-05-07 00:46:31 +03:00
handle parent for webxdc info-messages (#2984)
* set parent for webxdc info-messages * test parent() for info-messages * add dc_msg_get_parent() ffi
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
- added `DC_MSG_WEBXDC`, `dc_send_webxdc_status_update()`,
|
- added `DC_MSG_WEBXDC`, `dc_send_webxdc_status_update()`,
|
||||||
`dc_get_webxdc_status_updates()`, `dc_msg_get_webxdc_blob()`,
|
`dc_get_webxdc_status_updates()`, `dc_msg_get_webxdc_blob()`,
|
||||||
`dc_msg_get_webxdc_info()`, and `DC_EVENT_WEBXDC_STATUS_UPDATE` #2826
|
`dc_msg_get_webxdc_info()`, and `DC_EVENT_WEBXDC_STATUS_UPDATE` #2826
|
||||||
|
- added `dc_msg_get_parent()` #2984
|
||||||
|
|
||||||
- Add `dc_msg_force_plaintext()` API for bots #2847
|
- Add `dc_msg_force_plaintext()` API for bots #2847
|
||||||
|
|
||||||
|
|||||||
@@ -3965,8 +3965,11 @@ int dc_msg_is_forwarded (const dc_msg_t* msg);
|
|||||||
* These messages are typically shown in the center of the chat view,
|
* These messages are typically shown in the center of the chat view,
|
||||||
* dc_msg_get_text() returns a descriptive text about what is going on.
|
* dc_msg_get_text() returns a descriptive text about what is going on.
|
||||||
*
|
*
|
||||||
|
* For informational messages created by Webxdc apps,
|
||||||
|
* dc_msg_get_parent() usually returns the Webxdc instance;
|
||||||
|
* UIs can use that to scroll to the Webxdc app when the info is tapped.
|
||||||
|
*
|
||||||
* There is no need to perform any action when seeing such a message - this is already done by the core.
|
* There is no need to perform any action when seeing such a message - this is already done by the core.
|
||||||
* Typically, these messages are displayed in the center of the chat.
|
|
||||||
*
|
*
|
||||||
* @memberof dc_msg_t
|
* @memberof dc_msg_t
|
||||||
* @param msg The message object.
|
* @param msg The message object.
|
||||||
@@ -4367,6 +4370,23 @@ char* dc_msg_get_quoted_text (const dc_msg_t* msg);
|
|||||||
*/
|
*/
|
||||||
dc_msg_t* dc_msg_get_quoted_msg (const dc_msg_t* msg);
|
dc_msg_t* dc_msg_get_quoted_msg (const dc_msg_t* msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get parent message, if available.
|
||||||
|
*
|
||||||
|
* Used for Webxdc-info-messages
|
||||||
|
* to jump to the corresponding instance that created the info message.
|
||||||
|
*
|
||||||
|
* For quotes, please use the more specialized
|
||||||
|
* dc_msg_get_quoted_text() and dc_msg_get_quoted_msg().
|
||||||
|
*
|
||||||
|
* @memberof dc_msg_t
|
||||||
|
* @param msg The message object.
|
||||||
|
* @return The parent message or NULL.
|
||||||
|
* Must be freed using dc_msg_unref() after usage.
|
||||||
|
*/
|
||||||
|
dc_msg_t* dc_msg_get_parent (const dc_msg_t* msg);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force the message to be sent in plain text.
|
* Force the message to be sent in plain text.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3594,6 +3594,29 @@ pub unsafe extern "C" fn dc_msg_get_quoted_msg(msg: *const dc_msg_t) -> *mut dc_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_msg_get_parent(msg: *const dc_msg_t) -> *mut dc_msg_t {
|
||||||
|
if msg.is_null() {
|
||||||
|
eprintln!("ignoring careless call to dc_msg_get_parent()");
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
let ffi_msg: &MessageWrapper = &*msg;
|
||||||
|
let context = &*ffi_msg.context;
|
||||||
|
let res = block_on(async move {
|
||||||
|
ffi_msg
|
||||||
|
.message
|
||||||
|
.parent(context)
|
||||||
|
.await
|
||||||
|
.log_err(context, "failed to get parent message")
|
||||||
|
.unwrap_or(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Some(message) => Box::into_raw(Box::new(MessageWrapper { context, message })),
|
||||||
|
None => ptr::null_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn dc_msg_force_plaintext(msg: *mut dc_msg_t) {
|
pub unsafe extern "C" fn dc_msg_force_plaintext(msg: *mut dc_msg_t) {
|
||||||
if msg.is_null() {
|
if msg.is_null() {
|
||||||
|
|||||||
32
src/chat.rs
32
src/chat.rs
@@ -443,6 +443,7 @@ impl ChatId {
|
|||||||
&msg_text,
|
&msg_text,
|
||||||
cmd,
|
cmd,
|
||||||
dc_create_smeared_timestamp(context).await,
|
dc_create_smeared_timestamp(context).await,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
@@ -3391,6 +3392,7 @@ pub(crate) async fn add_info_msg_with_cmd(
|
|||||||
text: &str,
|
text: &str,
|
||||||
cmd: SystemMessage,
|
cmd: SystemMessage,
|
||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
|
parent: Option<&Message>,
|
||||||
) -> Result<MsgId> {
|
) -> Result<MsgId> {
|
||||||
let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device");
|
let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device");
|
||||||
let ephemeral_timer = chat_id.get_ephemeral_timer(context).await?;
|
let ephemeral_timer = chat_id.get_ephemeral_timer(context).await?;
|
||||||
@@ -3402,7 +3404,7 @@ pub(crate) async fn add_info_msg_with_cmd(
|
|||||||
|
|
||||||
let row_id =
|
let row_id =
|
||||||
context.sql.insert(
|
context.sql.insert(
|
||||||
"INSERT INTO msgs (chat_id,from_id,to_id,timestamp,type,state,txt,rfc724_mid,ephemeral_timer, param) VALUES (?,?,?, ?,?,?, ?,?,?, ?);",
|
"INSERT INTO msgs (chat_id,from_id,to_id,timestamp,type,state,txt,rfc724_mid,ephemeral_timer, param,mime_in_reply_to) VALUES (?,?,?, ?,?,?, ?,?,?, ?,?);",
|
||||||
paramsv![
|
paramsv![
|
||||||
chat_id,
|
chat_id,
|
||||||
DC_CONTACT_ID_INFO,
|
DC_CONTACT_ID_INFO,
|
||||||
@@ -3414,6 +3416,7 @@ pub(crate) async fn add_info_msg_with_cmd(
|
|||||||
rfc724_mid,
|
rfc724_mid,
|
||||||
ephemeral_timer,
|
ephemeral_timer,
|
||||||
param.to_string(),
|
param.to_string(),
|
||||||
|
parent.map(|msg|msg.rfc724_mid.clone()).unwrap_or_default()
|
||||||
]
|
]
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
@@ -3429,7 +3432,15 @@ pub(crate) async fn add_info_msg(
|
|||||||
text: &str,
|
text: &str,
|
||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
) -> Result<MsgId> {
|
) -> Result<MsgId> {
|
||||||
add_info_msg_with_cmd(context, chat_id, text, SystemMessage::Unknown, timestamp).await
|
add_info_msg_with_cmd(
|
||||||
|
context,
|
||||||
|
chat_id,
|
||||||
|
text,
|
||||||
|
SystemMessage::Unknown,
|
||||||
|
timestamp,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -4415,34 +4426,37 @@ mod tests {
|
|||||||
assert_eq!(msg.get_text().unwrap(), "foo info");
|
assert_eq!(msg.get_text().unwrap(), "foo info");
|
||||||
assert!(msg.is_info());
|
assert!(msg.is_info());
|
||||||
assert_eq!(msg.get_info_type(), SystemMessage::Unknown);
|
assert_eq!(msg.get_info_type(), SystemMessage::Unknown);
|
||||||
|
assert!(msg.parent(&t).await?.is_none());
|
||||||
|
assert!(msg.quoted_message(&t).await?.is_none());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_add_info_msg_with_cmd() {
|
async fn test_add_info_msg_with_cmd() -> Result<()> {
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new().await;
|
||||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo")
|
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let msg_id = add_info_msg_with_cmd(
|
let msg_id = add_info_msg_with_cmd(
|
||||||
&t,
|
&t,
|
||||||
chat_id,
|
chat_id,
|
||||||
"foo bar info",
|
"foo bar info",
|
||||||
SystemMessage::EphemeralTimerChanged,
|
SystemMessage::EphemeralTimerChanged,
|
||||||
10000,
|
10000,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let msg = Message::load_from_db(&t, msg_id).await.unwrap();
|
let msg = Message::load_from_db(&t, msg_id).await?;
|
||||||
assert_eq!(msg.get_chat_id(), chat_id);
|
assert_eq!(msg.get_chat_id(), chat_id);
|
||||||
assert_eq!(msg.get_viewtype(), Viewtype::Text);
|
assert_eq!(msg.get_viewtype(), Viewtype::Text);
|
||||||
assert_eq!(msg.get_text().unwrap(), "foo bar info");
|
assert_eq!(msg.get_text().unwrap(), "foo bar info");
|
||||||
assert!(msg.is_info());
|
assert!(msg.is_info());
|
||||||
assert_eq!(msg.get_info_type(), SystemMessage::EphemeralTimerChanged);
|
assert_eq!(msg.get_info_type(), SystemMessage::EphemeralTimerChanged);
|
||||||
|
assert!(msg.parent(&t).await?.is_none());
|
||||||
|
assert!(msg.quoted_message(&t).await?.is_none());
|
||||||
|
|
||||||
let msg2 = t.get_last_msg_in(chat_id).await;
|
let msg2 = t.get_last_msg_in(chat_id).await;
|
||||||
assert_eq!(msg.get_id(), msg2.get_id());
|
assert_eq!(msg.get_id(), msg2.get_id());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
|
|||||||
@@ -830,7 +830,7 @@ impl Message {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn parent(&self, context: &Context) -> Result<Option<Message>> {
|
pub async fn parent(&self, context: &Context) -> Result<Option<Message>> {
|
||||||
if let Some(in_reply_to) = &self.in_reply_to {
|
if let Some(in_reply_to) = &self.in_reply_to {
|
||||||
if let Some(msg_id) = rfc724_mid_exists(context, in_reply_to).await? {
|
if let Some(msg_id) = rfc724_mid_exists(context, in_reply_to).await? {
|
||||||
let msg = Message::load_from_db(context, msg_id).await?;
|
let msg = Message::load_from_db(context, msg_id).await?;
|
||||||
|
|||||||
@@ -156,7 +156,15 @@ impl Context {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref info) = status_update_item.info {
|
if let Some(ref info) = status_update_item.info {
|
||||||
chat::add_info_msg(self, instance.chat_id, info.as_str(), timestamp).await?;
|
chat::add_info_msg_with_cmd(
|
||||||
|
self,
|
||||||
|
instance.chat_id,
|
||||||
|
info.as_str(),
|
||||||
|
SystemMessage::Unknown,
|
||||||
|
timestamp,
|
||||||
|
Some(instance),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref summary) = status_update_item.summary {
|
if let Some(ref summary) = status_update_item.summary {
|
||||||
@@ -1283,6 +1291,11 @@ sth_for_the = "future""#
|
|||||||
info_msg.get_text(),
|
info_msg.get_text(),
|
||||||
Some("this appears in-chat".to_string())
|
Some("this appears in-chat".to_string())
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
info_msg.parent(&alice).await?.unwrap().id,
|
||||||
|
alice_instance.id
|
||||||
|
);
|
||||||
|
assert!(info_msg.quoted_message(&alice).await?.is_none());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
alice
|
alice
|
||||||
.get_webxdc_status_updates(alice_instance.id, None)
|
.get_webxdc_status_updates(alice_instance.id, None)
|
||||||
@@ -1302,6 +1315,8 @@ sth_for_the = "future""#
|
|||||||
info_msg.get_text(),
|
info_msg.get_text(),
|
||||||
Some("this appears in-chat".to_string())
|
Some("this appears in-chat".to_string())
|
||||||
);
|
);
|
||||||
|
assert_eq!(info_msg.parent(&bob).await?.unwrap().id, bob_instance.id);
|
||||||
|
assert!(info_msg.quoted_message(&bob).await?.is_none());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bob.get_webxdc_status_updates(bob_instance.id, None).await?,
|
bob.get_webxdc_status_updates(bob_instance.id, None).await?,
|
||||||
r#"[{"payload":"sth. else","info":"this appears in-chat"}]"#
|
r#"[{"payload":"sth. else","info":"this appears in-chat"}]"#
|
||||||
@@ -1320,6 +1335,11 @@ sth_for_the = "future""#
|
|||||||
info_msg.get_text(),
|
info_msg.get_text(),
|
||||||
Some("this appears in-chat".to_string())
|
Some("this appears in-chat".to_string())
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
info_msg.parent(&alice2).await?.unwrap().id,
|
||||||
|
alice2_instance.id
|
||||||
|
);
|
||||||
|
assert!(info_msg.quoted_message(&alice2).await?.is_none());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
alice2
|
alice2
|
||||||
.get_webxdc_status_updates(alice2_instance.id, None)
|
.get_webxdc_status_updates(alice2_instance.id, None)
|
||||||
|
|||||||
Reference in New Issue
Block a user