diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 208c6f1b5..d7f215abf 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -1139,6 +1139,24 @@ void dc_set_draft (dc_context_t* context, uint32_t ch uint32_t dc_add_device_msg (dc_context_t* context, const char* label, dc_msg_t* msg); +/** + * Init device-messages and saved-messages chat. + * This function adds the device-chat and saved-messages chat + * and adds one or more welcome or update-messages. + * The ui can add messages on its own using dc_add_device_msg() - + * for ordering, either before or after or even without calling this function. + * + * Chat and message creation is done only once. + * So if the user has manually deleted things, they won't be re-created + * (however, not seen device messages are added and may re-create the device-chat). + * + * @memberof dc_context_t + * @param context The context as created by dc_context_new(). + * @return None. + */ +void dc_update_device_chats (dc_context_t* context); + + /** * Check if a device-message with a given label was ever added. * Device-messages can be added dc_add_device_msg(). diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index f1f8697b8..1a25a84a5 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -851,6 +851,21 @@ pub unsafe extern "C" fn dc_add_device_msg( .unwrap_or(0) } +#[no_mangle] +pub unsafe extern "C" fn dc_update_device_chats(context: *mut dc_context_t) { + if context.is_null() { + eprintln!("ignoring careless call to dc_update_device_chats()"); + return; + } + let ffi_context = &mut *context; + ffi_context + .with_inner(|ctx| { + ctx.update_device_chats() + .unwrap_or_log_default(ctx, "Failed to add device message") + }) + .unwrap_or(()) +} + #[no_mangle] pub unsafe extern "C" fn dc_was_device_msg_ever_added( context: *mut dc_context_t, diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 181f9ebd0..d7776d557 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -837,6 +837,9 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E msg.set_text(Some(arg1.to_string())); chat::add_device_msg(context, None, Some(&mut msg))?; } + "updatedevicechats" => { + context.update_device_chats()?; + } "listmedia" => { ensure!(sel_chat.is_some(), "No chat selected."); diff --git a/src/stock.rs b/src/stock.rs index 54ae4a23b..68eba357b 100644 --- a/src/stock.rs +++ b/src/stock.rs @@ -5,9 +5,13 @@ use std::borrow::Cow; use strum::EnumProperty; use strum_macros::EnumProperty; +use crate::chat; +use crate::constants::{Viewtype, DC_CONTACT_ID_SELF}; use crate::contact::*; use crate::context::Context; use crate::error::Error; +use crate::message::Message; +use crate::stock::StockMessage::{DeviceMessagesHint, WelcomeMessage}; /// Stock strings /// @@ -116,8 +120,29 @@ pub enum StockMessage { DeviceMessages = 68, #[strum(props(fallback = "Saved messages"))] SavedMessages = 69, + + #[strum(props( + fallback = "Messages in this chat are generated locally by your Delta Chat app. \ + Its makers use it to inform about app updates and problems during usage." + ))] + DeviceMessagesHint = 70, + + #[strum(props(fallback = "Welcome to Delta Chat! – \ + Delta Chat looks and feels like other popular messenger apps, \ + but does not involve centralized control, \ + tracking or selling you, friends, colleagues or family out to large organizations.\n\n\ + Technically, Delta Chat is an email application with a modern chat interface. \ + Email in a new dress if you will 👻\n\n\ + Use Delta Chat with anyone out of billions of people: just use their e-mail address. \ + Recipients don't need to install Delta Chat, visit websites or sign up anywhere - \ + however, of course, if they like, you may point them to 👉 https://get.delta.chat"))] + WelcomeMessage = 71, } +/* +" +*/ + impl StockMessage { /// Default untranslated strings for stock messages. /// @@ -264,6 +289,27 @@ impl Context { } } } + + pub fn update_device_chats(&self) -> Result<(), Error> { + // create saved-messages chat; + // we do this only once, if the user has deleted the chat, he can recreate it manually. + if !self.sql.get_raw_config_bool(&self, "self-chat-added") { + self.sql + .set_raw_config_bool(&self, "self-chat-added", true)?; + chat::create_by_contact_id(&self, DC_CONTACT_ID_SELF)?; + } + + // add welcome-messages. by the label, this is done only once, + // if the user has deleted the message or the chat, it is not added again. + let mut msg = Message::new(Viewtype::Text); + msg.text = Some(self.stock_str(DeviceMessagesHint).to_string()); + chat::add_device_msg(&self, Some("core-about-device-chat"), Some(&mut msg))?; + + let mut msg = Message::new(Viewtype::Text); + msg.text = Some(self.stock_str(WelcomeMessage).to_string()); + chat::add_device_msg(&self, Some("core-welcome"), Some(&mut msg))?; + Ok(()) + } } #[cfg(test)] @@ -273,6 +319,7 @@ mod tests { use crate::constants::DC_CONTACT_ID_SELF; + use crate::chatlist::Chatlist; use num_traits::ToPrimitive; #[test] @@ -428,4 +475,22 @@ mod tests { "Group name changed from \"Some chat\" to \"Other chat\" by Alice (alice@example.com)." ) } + + #[test] + fn test_update_device_chats() { + let t = dummy_context(); + t.ctx.update_device_chats().ok(); + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 2); + + chat::delete(&t.ctx, chats.get_chat_id(0)).ok(); + chat::delete(&t.ctx, chats.get_chat_id(1)).ok(); + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 0); + + // a subsequent call to update_device_chats() must not re-add manally deleted messages or chats + t.ctx.update_device_chats().ok(); + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 0); + } }