Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update.href api #6248

Merged
merged 4 commits into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions deltachat-ffi/deltachat.h
Original file line number Diff line number Diff line change
Expand Up @@ -4518,6 +4518,24 @@ int dc_msg_get_info_type (const dc_msg_t* msg);
#define DC_INFO_INVALID_UNENCRYPTED_MAIL 13
#define DC_INFO_WEBXDC_INFO_MESSAGE 32


/**
* Get link attached to an webxdc info message.
* The info message needs to be of type DC_INFO_WEBXDC_INFO_MESSAGE.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this will not work for notifications using update.notify setting a summary but no info message 🤔 when showing such a notification (which potentially will have info-message sometimes) I guess we will add an "open" to the notification to jump to the app, for notifications with info-messages it would work for not for summary, it is a limitation but probably not a big deal for the first iterations and could be improved at a later point I guess

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, that is not possible currently. but that is no conceptual flaw, we could probably easily add the hash to the event as well, if we consider that an important usecase as well (or just to make documentation easier :)

however, i suggest to do that after this PR and after all UI have adapted to href approach - that way we can see if things work out as we exepect. if so, adpating UI for event-href is easy :)

*
* Typically, this is used to set `document.location.href` in JS land.
*
* Webxdc apps can define the link by setting `update.href` when sending and update,
* see dc_send_webxdc_status_update().
*
* @memberof dc_msg_t
* @param msg The info message object.
* Not: the webxdc instance.
* @return The link to be set to `document.location.href` in JS land.
* Returns NULL if there is no link attached to the info message and on errors.
*/
char* dc_msg_get_webxdc_href (const dc_msg_t* msg);

/**
* Check if a message is still in creation. A message is in creation between
* the calls to dc_prepare_msg() and dc_send_msg().
Expand Down
11 changes: 11 additions & 0 deletions deltachat-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3687,6 +3687,17 @@ pub unsafe extern "C" fn dc_msg_get_info_type(msg: *mut dc_msg_t) -> libc::c_int
ffi_msg.message.get_info_type() as libc::c_int
}

#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_webxdc_href(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_webxdc_href()");
return "".strdup();
}

let ffi_msg = &*msg;
ffi_msg.message.get_webxdc_href().strdup()
}

#[no_mangle]
pub unsafe extern "C" fn dc_msg_is_increation(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
Expand Down
1 change: 1 addition & 0 deletions src/debug_logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub async fn debug_logging_loop(context: &Context, events: Receiver<DebugEventLo
"time": time,
}),
info: None,
href: None,
summary: None,
document: None,
uid: None,
Expand Down
83 changes: 72 additions & 11 deletions src/webxdc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ pub struct StatusUpdateItem {
#[serde(skip_serializing_if = "Option::is_none")]
pub info: Option<String>,

/// Optional link the info message will point to.
/// Used to set `window.location.href` in JS land.
#[serde(skip_serializing_if = "Option::is_none")]
pub href: Option<String>,

/// The new name of the editing document.
/// This is not needed if the webxdc doesn't edit documents.
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -353,19 +358,22 @@ impl Context {

if can_info_msg {
if let Some(ref info) = status_update_item.info {
if let Some(info_msg_id) = self
let info_msg_id = self
.get_overwritable_info_msg_id(&instance, from_id)
.await?
{
chat::update_msg_text_and_timestamp(
self,
instance.chat_id,
info_msg_id,
info.as_str(),
timestamp,
)
.await?;
notify_msg_id = info_msg_id;

if info_msg_id.is_some() && status_update_item.href.is_none() {
if let Some(info_msg_id) = info_msg_id {
chat::update_msg_text_and_timestamp(
self,
instance.chat_id,
info_msg_id,
info.as_str(),
timestamp,
)
.await?;
notify_msg_id = info_msg_id;
}
} else {
notify_msg_id = chat::add_info_msg_with_cmd(
self,
Expand All @@ -380,6 +388,12 @@ impl Context {
.await?;
}
notify_text = info.to_string();

if let Some(href) = status_update_item.href {
let mut notify_msg = Message::load_from_db(self, notify_msg_id).await?;
notify_msg.param.set(Param::Arg, href);
notify_msg.update_param(self).await?;
}
}
}

Expand Down Expand Up @@ -944,6 +958,15 @@ impl Message {
let hash = Sha256::digest(data.as_bytes());
Ok(format!("{:x}", hash))
}

/// Get link attached to an info message.
///
/// The info message needs to be of type SystemMessage::WebxdcInfoMessage.
/// Typically, this is used to start the corresponding webxdc app
/// with `window.location.href` set in JS land.
pub fn get_webxdc_href(&self) -> Option<String> {
self.param.get(Param::Arg).map(|href| href.to_string())
}
}

#[cfg(test)]
Expand Down Expand Up @@ -1457,6 +1480,7 @@ mod tests {
StatusUpdateItem {
payload: json!({"foo": "bar"}),
info: None,
href: None,
document: None,
summary: None,
uid: Some("iecie2Ze".to_string()),
Expand All @@ -1482,6 +1506,7 @@ mod tests {
StatusUpdateItem {
payload: json!({"nothing": "this should be ignored"}),
info: None,
href: None,
document: None,
summary: None,
uid: Some("iecie2Ze".to_string()),
Expand Down Expand Up @@ -1516,6 +1541,7 @@ mod tests {
StatusUpdateItem {
payload: json!({"foo2": "bar2"}),
info: None,
href: None,
document: None,
summary: None,
uid: None,
Expand All @@ -1536,6 +1562,7 @@ mod tests {
StatusUpdateItem {
payload: Value::Bool(true),
info: None,
href: None,
document: None,
summary: None,
uid: None,
Expand Down Expand Up @@ -3069,4 +3096,38 @@ sth_for_the = "future""#

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_href() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = tcm.alice().await;
let bob = tcm.bob().await;

let grp_id = alice
.create_group_with_members(ProtectionStatus::Unprotected, "grp", &[&bob])
.await;
let instance = send_webxdc_instance(&alice, grp_id).await?;
let sent1 = alice.pop_sent_msg().await;

alice
.send_webxdc_status_update(
instance.id,
r##"{"payload": "my deeplink data", "info": "my move!", "href": "#foobar"}"##,
"d",
)
.await?;
alice.flush_status_updates().await?;
let sent2 = alice.pop_sent_msg().await;
let info_msg = alice.get_last_msg().await;
assert!(info_msg.is_info());
assert_eq!(info_msg.get_webxdc_href(), Some("#foobar".to_string()));

bob.recv_msg(&sent1).await;
bob.recv_msg_trash(&sent2).await;
let info_msg = bob.get_last_msg().await;
assert!(info_msg.is_info());
assert_eq!(info_msg.get_webxdc_href(), Some("#foobar".to_string()));

Ok(())
}
}
1 change: 1 addition & 0 deletions src/webxdc/maps_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ pub(crate) async fn intercept_get_updates(
item: StatusUpdateItem {
payload: serde_json::to_value(location_item)?,
info: None,
href: None,
document: None,
summary: None,
uid: None,
Expand Down
Loading