allow webxdc document names (#3317)

* allow webxdc document names

* test document webxdc property

* update CHANGELOG
This commit is contained in:
bjoern
2022-05-15 12:10:09 +02:00
committed by GitHub
parent 715664273b
commit 2fc0a0964b
5 changed files with 83 additions and 4 deletions

View File

@@ -6,6 +6,7 @@
- send normal messages with higher priority than MDNs #3243 - send normal messages with higher priority than MDNs #3243
- make Scheduler stateless #3302 - make Scheduler stateless #3302
- support `source_code_url` from Webxdc manifests #3314 - support `source_code_url` from Webxdc manifests #3314
- support Webxdc document names and add `document` to `dc_msg_get_webxdc_info()` #3317
- improve chat encryption info, make it easier to find contacts without keys #3318 - improve chat encryption info, make it easier to find contacts without keys #3318
### API-Changes ### API-Changes

View File

@@ -3728,6 +3728,8 @@ char* dc_msg_get_webxdc_blob (const dc_msg_t* msg, const char*
* To get the file, use dc_msg_get_webxdc_blob(). * To get the file, use dc_msg_get_webxdc_blob().
* App icons should should be square, * App icons should should be square,
* the implementations will add round corners etc. as needed. * the implementations will add round corners etc. as needed.
* - document: if the Webxdc represents a document, this is the name of the document,
* otherwise, this is an empty string.
* - summary: short string describing the state of the app, * - summary: short string describing the state of the app,
* sth. as "2 votes", "Highscore: 123", * sth. as "2 votes", "Highscore: 123",
* can be changed by the apps and defaults to an empty string. * can be changed by the apps and defaults to an empty string.

View File

@@ -37,6 +37,8 @@ To get a shared state, the peers use `sendUpdate()` to send updates to each othe
eg. "Alice voted" or "Bob scored 123 in MyGame"; eg. "Alice voted" or "Bob scored 123 in MyGame";
usually only one line of text is shown, usually only one line of text is shown,
use this option sparingly to not spam the chat. use this option sparingly to not spam the chat.
- `update.document`: optional, name of the document in edit,
must not be used eg. in games where the Webxdc does not create documents
- `update.summary`: optional, short text, shown beside app icon; - `update.summary`: optional, short text, shown beside app icon;
it is recommended to use some aggregated value, eg. "8 votes", "Highscore: 123" it is recommended to use some aggregated value, eg. "8 votes", "Highscore: 123"

View File

@@ -169,6 +169,12 @@ pub enum Param {
/// For Chats: timestamp of protection settings update. /// For Chats: timestamp of protection settings update.
ProtectionSettingsTimestamp = b'L', ProtectionSettingsTimestamp = b'L',
/// For Webxdc Message Instances: Current document name
WebxdcDocument = b'R',
/// For Webxdc Message Instances: timestamp of document name update.
WebxdcDocumentTimestamp = b'W',
/// For Webxdc Message Instances: Current summary /// For Webxdc Message Instances: Current summary
WebxdcSummary = b'N', WebxdcSummary = b'N',

View File

@@ -59,6 +59,7 @@ struct WebxdcManifest {
pub struct WebxdcInfo { pub struct WebxdcInfo {
pub name: String, pub name: String,
pub icon: String, pub icon: String,
pub document: String,
pub summary: String, pub summary: String,
pub source_code_url: String, pub source_code_url: String,
} }
@@ -116,6 +117,9 @@ pub(crate) struct StatusUpdateItem {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
info: Option<String>, info: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
document: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
summary: Option<String>, summary: Option<String>,
} }
@@ -191,8 +195,8 @@ impl Context {
Ok(()) Ok(())
} }
/// Takes an update-json as `{payload: PAYLOAD}` (or legacy `PAYLOAD`) /// Takes an update-json as `{payload: PAYLOAD}`
/// writes it to the database and handles events, info-messages and summary. /// writes it to the database and handles events, info-messages, document name and summary.
async fn create_status_update_record( async fn create_status_update_record(
&self, &self,
instance: &mut Message, instance: &mut Message,
@@ -212,6 +216,7 @@ impl Context {
| MessageState::OutDraft => StatusUpdateItem { | MessageState::OutDraft => StatusUpdateItem {
payload: item.payload, payload: item.payload,
info: None, // no info-messages in draft mode info: None, // no info-messages in draft mode
document: item.document,
summary: item.summary, summary: item.summary,
}, },
_ => item, _ => item,
@@ -234,17 +239,33 @@ impl Context {
.await?; .await?;
} }
let mut param_changed = false;
if let Some(ref document) = status_update_item.document {
if instance
.param
.update_timestamp(Param::WebxdcDocumentTimestamp, timestamp)?
{
instance.param.set(Param::WebxdcDocument, document);
param_changed = true;
}
}
if let Some(ref summary) = status_update_item.summary { if let Some(ref summary) = status_update_item.summary {
if instance if instance
.param .param
.update_timestamp(Param::WebxdcSummaryTimestamp, timestamp)? .update_timestamp(Param::WebxdcSummaryTimestamp, timestamp)?
{ {
instance.param.set(Param::WebxdcSummary, summary); instance.param.set(Param::WebxdcSummary, summary);
instance.update_param(self).await; param_changed = true;
self.emit_msgs_changed(instance.chat_id, instance.id);
} }
} }
if param_changed {
instance.update_param(self).await;
self.emit_msgs_changed(instance.chat_id, instance.id);
}
let rowid = self let rowid = self
.sql .sql
.insert( .insert(
@@ -572,6 +593,11 @@ impl Message {
} else { } else {
WEBXDC_DEFAULT_ICON.to_string() WEBXDC_DEFAULT_ICON.to_string()
}, },
document: self
.param
.get(Param::WebxdcDocument)
.unwrap_or_default()
.to_string(),
summary: self summary: self
.param .param
.get(Param::WebxdcSummary) .get(Param::WebxdcSummary)
@@ -1536,6 +1562,48 @@ sth_for_the = "future""#
Ok(()) Ok(())
} }
#[async_std::test]
async fn test_webxdc_document_name() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
// Alice creates an webxdc instance and updates document name
let alice_chat = alice.create_chat(&bob).await;
let alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?;
let sent_instance = &alice.pop_sent_msg().await;
let info = alice_instance.get_webxdc_info(&alice).await?;
assert_eq!(info.document, "".to_string());
assert_eq!(info.summary, "".to_string());
alice
.send_webxdc_status_update(
alice_instance.id,
r#"{"document":"my file", "payload":1337}"#,
"descr",
)
.await?;
let sent_update1 = &alice.pop_sent_msg().await;
let info = Message::load_from_db(&alice, alice_instance.id)
.await?
.get_webxdc_info(&alice)
.await?;
assert_eq!(info.document, "my file".to_string());
assert_eq!(info.summary, "".to_string());
// Bob receives the updates
bob.recv_msg(sent_instance).await;
let bob_instance = bob.get_last_msg().await;
bob.recv_msg(sent_update1).await;
let info = Message::load_from_db(&bob, bob_instance.id)
.await?
.get_webxdc_info(&bob)
.await?;
assert_eq!(info.document, "my file".to_string());
assert_eq!(info.summary, "".to_string());
Ok(())
}
#[async_std::test] #[async_std::test]
async fn test_webxdc_info_msg() -> Result<()> { async fn test_webxdc_info_msg() -> Result<()> {
let alice = TestContext::new_alice().await; let alice = TestContext::new_alice().await;