Skip to content
Open
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
21 changes: 15 additions & 6 deletions deltachat-jsonrpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use types::chat::FullChat;
use types::contact::{ContactObject, VcardContact};
use types::events::Event;
use types::http::HttpResponse;
use types::message::{MessageData, MessageObject, MessageReadReceipt};
use types::message::{DeviceMessageData, MessageData, MessageObject, MessageReadReceipt};
use types::notify_state::JsonrpcNotifyState;
use types::provider_info::ProviderInfo;
use types::reactions::JsonrpcReactions;
Expand Down Expand Up @@ -1229,18 +1229,27 @@ impl CommandApi {
&self,
account_id: u32,
label: String,
msg: Option<MessageData>,
msg: Option<DeviceMessageData>,
) -> Result<Option<u32>> {
let ctx = self.get_context(account_id).await?;
if let Some(msg) = msg {
let mut message = msg.create_message(&ctx).await?;
let message_id =
deltachat::chat::add_device_msg(&ctx, Some(&label), Some(&mut message)).await?;
let mut message = msg.message_data.create_message(&ctx).await?;
if let Some(state) = msg.message_state {
deltachat::chat::set_device_msg_state(&mut message, state.into());
}
let message_id = deltachat::chat::add_device_msg_with_importance(
&ctx,
Some(&label),
Some(&mut message),
false,
)
.await?;
if !message_id.is_unset() {
return Ok(Some(message_id.to_u32()));
}
} else {
deltachat::chat::add_device_msg(&ctx, Some(&label), None).await?;
deltachat::chat::add_device_msg_with_importance(&ctx, Some(&label), None, false)
.await?;
}
Ok(None)
}
Expand Down
36 changes: 36 additions & 0 deletions deltachat-jsonrpc/src/api/types/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,42 @@ impl MessageData {
}
}

#[derive(Deserialize, Serialize, TypeDef, schemars::JsonSchema)]
#[repr(u32)]
pub enum DeviceMessageState {
// Variants that are not really wanted for device messages are omitted,
// to avoid misuse.

// Undefined,
InFresh,
InNoticed,
// InSeen,
// OutDraft,
// OutPending,
// OutFailed,
// OutDelivered,
// OutMdnRcvd,
}

impl From<DeviceMessageState> for deltachat::message::MessageState {
fn from(message_state: DeviceMessageState) -> Self {
use deltachat::message::MessageState;
match message_state {
DeviceMessageState::InFresh => MessageState::InFresh,
DeviceMessageState::InNoticed => MessageState::InNoticed,
}
}
}

#[derive(Deserialize, Serialize, TypeDef, schemars::JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct DeviceMessageData {
#[serde(flatten)]
pub message_data: MessageData,
#[serde(default)]
pub message_state: Option<DeviceMessageState>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can't this be replaced with a bool flag noticed? Why do we need a new enum with 3 variants (InSeen also)? If adding a message as InNoticed doesn't work, i.e. Core still emits IncomingMsg, that should be fixed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

TBH I still haven't fully grasped the concept of noticed vs. seen.

If what we actually want is noticed, then I can remove "seen". But I would keep it as an enum, for clarity, consistency with the Message struct, and flexibility.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

InSeen means "actually seen/read", so an MDN can be sent (this isn't relevant to device messages though). InNoticed means "the user has opened the chat or read some later chat messages", so the user has had a chance to see the message on this or another device and no new notification is needed. As we don't want to trigger a notification, InNoticed should already work.

As for enum, this is minor, but anyway DeviceMessageState is inconsistent with enum MessageState because it doesn't list the same variants and with a bool flag there will be less code i guess.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

OK, I removed the InSeen variant.

}

#[derive(Serialize, TypeDef, schemars::JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct MessageReadReceipt {
Expand Down
16 changes: 15 additions & 1 deletion src/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4810,10 +4810,20 @@ pub(crate) async fn get_chat_id_by_grpid(
.await
}

/// Intended to be used only for messages passed to
/// [`add_device_msg_with_importance`].
pub fn set_device_msg_state(msg: &mut Message, state: MessageState) {
msg.state = state;
}

/// Adds a message to device chat.
///
/// Optional `label` can be provided to ensure that message is added only once.
/// If `important` is true, a notification will be sent.
///
/// If message state is [`MessageState::Undefined`],
/// the message will be added to the DB as [`MessageState::InFresh`].
/// To set message state, you may utilize [`set_device_msg_state`].
#[expect(clippy::arithmetic_side_effects)]
pub async fn add_device_msg_with_importance(
context: &Context,
Expand Down Expand Up @@ -4850,7 +4860,11 @@ pub async fn add_device_msg_with_importance(
msg.timestamp_sort = last_msg_time + 1;
}
prepare_msg_blob(context, msg).await?;
let state = MessageState::InFresh;
let state = if msg.state == MessageState::Undefined {
MessageState::InFresh
} else {
msg.state
};
let row_id = context
.sql
.insert(
Expand Down
9 changes: 9 additions & 0 deletions src/chat/chat_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,7 @@ async fn test_add_device_msg_unlabelled() {

// add two device-messages
let mut msg1 = Message::new_text("first message".to_string());
msg1.state = MessageState::InNoticed;
let msg1_id = add_device_msg(&t, None, Some(&mut msg1)).await;
assert!(msg1_id.is_ok());

Expand All @@ -869,12 +870,20 @@ async fn test_add_device_msg_unlabelled() {
assert_eq!(msg1.text, "first message");
assert_eq!(msg1.from_id, ContactId::DEVICE);
assert_eq!(msg1.to_id, ContactId::SELF);
assert_eq!(msg1.get_state(), MessageState::InNoticed);
Comment thread
WofWca marked this conversation as resolved.
assert!(
t.evtracker
.get_matching_opt(&t, |e| matches!(e, EventType::IncomingMsg { .. }))
.await
.is_none()
);
assert!(!msg1.is_info());

let msg2 = message::Message::load_from_db(&t, msg2_id.unwrap()).await;
assert!(msg2.is_ok());
let msg2 = msg2.unwrap();
assert_eq!(msg2.text, "second message");
assert_eq!(msg2.get_state(), MessageState::InFresh);

// check device chat
assert_eq!(msg2.chat_id.get_msg_cnt(&t).await.unwrap(), 2);
Expand Down
Loading