diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index 7eccf14fa..a54f19e0d 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -1,6 +1,6 @@ use anyhow::{anyhow, bail, Context, Result}; use deltachat::{ - chat::{get_chat_msgs, ChatId}, + chat::{get_chat_media, get_chat_msgs, ChatId}, chatlist::Chatlist, config::Config, contact::{may_be_valid_addr, Contact, ContactId}, @@ -31,6 +31,8 @@ use types::message::MessageObject; use types::provider_info::ProviderInfo; use types::webxdc::WebxdcMessageInfo; +use self::types::message::MessageViewtype; + #[derive(Clone, Debug)] pub struct CommandApi { pub(crate) accounts: Arc>, @@ -557,6 +559,40 @@ impl CommandApi { } Ok(contacts) } + // --------------------------------------------- + // chat + // --------------------------------------------- + + /// Returns all message IDs of the given types in a chat. + /// Typically used to show a gallery. + /// + /// The list is already sorted and starts with the oldest message. + /// Clients should not try to re-sort the list as this would be an expensive action + /// and would result in inconsistencies between clients. + async fn chat_get_media( + &self, + account_id: u32, + chat_id: u32, + message_type: MessageViewtype, + or_message_type2: Option, + or_message_type3: Option, + ) -> Result> { + let ctx = self.get_context(account_id).await?; + + let msg_type = message_type.into(); + let or_msg_type2 = or_message_type2.map_or(Viewtype::Unknown, |v| v.into()); + let or_msg_type3 = or_message_type3.map_or(Viewtype::Unknown, |v| v.into()); + + let media = get_chat_media( + &ctx, + ChatId::new(chat_id), + msg_type, + or_msg_type2, + or_msg_type3, + ) + .await?; + Ok(media.iter().map(|msg_id| msg_id.to_u32()).collect()) + } // --------------------------------------------- // webxdc diff --git a/deltachat-jsonrpc/src/api/types/message.rs b/deltachat-jsonrpc/src/api/types/message.rs index 5c860c74e..01d1f42bb 100644 --- a/deltachat-jsonrpc/src/api/types/message.rs +++ b/deltachat-jsonrpc/src/api/types/message.rs @@ -3,7 +3,9 @@ use deltachat::contact::Contact; use deltachat::context::Context; use deltachat::message::Message; use deltachat::message::MsgId; +use deltachat::message::Viewtype; use num_traits::cast::ToPrimitive; +use serde::Deserialize; use serde::Serialize; use typescript_type_def::TypeDef; @@ -20,7 +22,7 @@ pub struct MessageObject { text: Option, has_location: bool, has_html: bool, - view_type: u32, + view_type: MessageViewtype, state: u32, timestamp: i64, @@ -77,10 +79,7 @@ impl MessageObject { text: message.get_text(), has_location: message.has_location(), has_html: message.has_html(), - view_type: message - .get_viewtype() - .to_u32() - .ok_or_else(|| anyhow!("viewtype conversion to number failed"))?, + view_type: message.get_viewtype().into(), state: message .get_state() .to_u32() @@ -125,3 +124,79 @@ impl MessageObject { }) } } + +#[derive(Serialize, Deserialize, TypeDef)] +#[serde(rename = "Viewtype")] +pub enum MessageViewtype { + Unknown, + + /// Text message. + Text, + + /// Image message. + /// If the image is an animated GIF, the type `Viewtype.Gif` should be used. + Image, + + /// Animated GIF message. + Gif, + + /// Message containing a sticker, similar to image. + /// If possible, the ui should display the image without borders in a transparent way. + /// A click on a sticker will offer to install the sticker set in some future. + Sticker, + + /// Message containing an Audio file. + Audio, + + /// A voice message that was directly recorded by the user. + /// For all other audio messages, the type `Viewtype.Audio` should be used. + Voice, + + /// Video messages. + Video, + + /// Message containing any file, eg. a PDF. + File, + + /// Message is an invitation to a videochat. + VideochatInvitation, + + /// Message is an webxdc instance. + Webxdc, +} + +impl From for MessageViewtype { + fn from(viewtype: Viewtype) -> Self { + match viewtype { + Viewtype::Unknown => MessageViewtype::Unknown, + Viewtype::Text => MessageViewtype::Text, + Viewtype::Image => MessageViewtype::Image, + Viewtype::Gif => MessageViewtype::Gif, + Viewtype::Sticker => MessageViewtype::Sticker, + Viewtype::Audio => MessageViewtype::Audio, + Viewtype::Voice => MessageViewtype::Voice, + Viewtype::Video => MessageViewtype::Video, + Viewtype::File => MessageViewtype::File, + Viewtype::VideochatInvitation => MessageViewtype::VideochatInvitation, + Viewtype::Webxdc => MessageViewtype::Webxdc, + } + } +} + +impl From for Viewtype { + fn from(viewtype: MessageViewtype) -> Self { + match viewtype { + MessageViewtype::Unknown => Viewtype::Unknown, + MessageViewtype::Text => Viewtype::Text, + MessageViewtype::Image => Viewtype::Image, + MessageViewtype::Gif => Viewtype::Gif, + MessageViewtype::Sticker => Viewtype::Sticker, + MessageViewtype::Audio => Viewtype::Audio, + MessageViewtype::Voice => Viewtype::Voice, + MessageViewtype::Video => Viewtype::Video, + MessageViewtype::File => Viewtype::File, + MessageViewtype::VideochatInvitation => Viewtype::VideochatInvitation, + MessageViewtype::Webxdc => Viewtype::Webxdc, + } + } +} diff --git a/deltachat-jsonrpc/typescript/generated/client.ts b/deltachat-jsonrpc/typescript/generated/client.ts index 89aec72f1..5b3fcbeed 100644 --- a/deltachat-jsonrpc/typescript/generated/client.ts +++ b/deltachat-jsonrpc/typescript/generated/client.ts @@ -287,6 +287,18 @@ export class RawClient { return (this._transport.request('contacts_get_contacts_by_ids', [accountId, ids] as RPC.Params)) as Promise>; } + /** + * Returns all message IDs of the given types in a chat. + * Typically used to show a gallery. + * + * The list is already sorted and starts with the oldest message. + * Clients should not try to re-sort the list as this would be an expensive action + * and would result in inconsistencies between clients. + */ + public chatGetMedia(accountId: T.U32, chatId: T.U32, messageType: T.Viewtype, orMessageType2: (T.Viewtype|null), orMessageType3: (T.Viewtype|null)): Promise<(T.U32)[]> { + return (this._transport.request('chat_get_media', [accountId, chatId, messageType, orMessageType2, orMessageType3] as RPC.Params)) as Promise<(T.U32)[]>; + } + public webxdcSendStatusUpdate(accountId: T.U32, instanceMsgId: T.U32, updateStr: string, description: string): Promise { return (this._transport.request('webxdc_send_status_update', [accountId, instanceMsgId, updateStr, description] as RPC.Params)) as Promise; diff --git a/deltachat-jsonrpc/typescript/generated/types.ts b/deltachat-jsonrpc/typescript/generated/types.ts index 7e22055d6..d1000089c 100644 --- a/deltachat-jsonrpc/typescript/generated/types.ts +++ b/deltachat-jsonrpc/typescript/generated/types.ts @@ -13,9 +13,54 @@ export type ChatListItemFetchResult=(({"type":"ChatListItem";}&{"id":U32;"name": "dmChatContact":(U32|null);})|{"type":"ArchiveLink";}|({"type":"Error";}&{"id":U32;"error":string;})); export type Contact={"address":string;"color":string;"auth_name":string;"status":string;"display_name":string;"id":U32;"name":string;"profile_image":(string|null);"name_and_addr":string;"is_blocked":boolean;"is_verified":boolean;}; export type FullChat={"id":U32;"name":string;"is_protected":boolean;"profile_image":(string|null);"archived":boolean;"chat_type":U32;"is_unpromoted":boolean;"is_self_talk":boolean;"contacts":(Contact)[];"contact_ids":(U32)[];"color":string;"fresh_message_counter":Usize;"is_contact_request":boolean;"is_device_chat":boolean;"self_in_group":boolean;"is_muted":boolean;"ephemeral_timer":U32;"can_send":boolean;}; +export type Viewtype=("Unknown"| +/** + * Text message. + */ +"Text"| +/** + * Image message. + * If the image is an animated GIF, the type `Viewtype.Gif` should be used. + */ +"Image"| +/** + * Animated GIF message. + */ +"Gif"| +/** + * Message containing a sticker, similar to image. + * If possible, the ui should display the image without borders in a transparent way. + * A click on a sticker will offer to install the sticker set in some future. + */ +"Sticker"| +/** + * Message containing an Audio file. + */ +"Audio"| +/** + * A voice message that was directly recorded by the user. + * For all other audio messages, the type `Viewtype.Audio` should be used. + */ +"Voice"| +/** + * Video messages. + */ +"Video"| +/** + * Message containing any file, eg. a PDF. + */ +"File"| +/** + * Message is an invitation to a videochat. + */ +"VideochatInvitation"| +/** + * Message is an webxdc instance. + */ +"Webxdc"); export type I32=number; export type U64=number; -export type Message={"id":U32;"chat_id":U32;"from_id":U32;"quoted_text":(string|null);"quoted_message_id":(U32|null);"text":(string|null);"has_location":boolean;"has_html":boolean;"view_type":U32;"state":U32;"timestamp":I64;"sort_timestamp":I64;"received_timestamp":I64;"has_deviating_timestamp":boolean;"subject":string;"show_padlock":boolean;"is_setupmessage":boolean;"is_info":boolean;"is_forwarded":boolean;"duration":I32;"dimensions_height":I32;"dimensions_width":I32;"videochat_type":(U32|null);"videochat_url":(string|null);"override_sender_name":(string|null);"sender":Contact;"setup_code_begin":(string|null);"file":(string|null);"file_mime":(string|null);"file_bytes":U64;"file_name":(string|null);}; +export type Message={"id":U32;"chat_id":U32;"from_id":U32;"quoted_text":(string|null);"quoted_message_id":(U32|null);"text":(string|null);"has_location":boolean;"has_html":boolean;"view_type":Viewtype;"state":U32;"timestamp":I64;"sort_timestamp":I64;"received_timestamp":I64;"has_deviating_timestamp":boolean;"subject":string;"show_padlock":boolean;"is_setupmessage":boolean;"is_info":boolean;"is_forwarded":boolean;"duration":I32;"dimensions_height":I32;"dimensions_width":I32;"videochat_type":(U32|null);"videochat_url":(string|null);"override_sender_name":(string|null);"sender":Contact;"setup_code_begin":(string|null);"file":(string|null);"file_mime":(string|null);"file_bytes":U64;"file_name":(string|null);}; export type WebxdcMessageInfo={ /** * The name of the app. @@ -49,4 +94,4 @@ export type WebxdcMessageInfo={ * Implementations may offer an menu or a button to open this URL. */ "source_code_url":(string|null);}; -export type __AllTyps=[string,boolean,Record,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],U32,Account,U32,string,(ProviderInfo|null),U32,boolean,U32,Record,U32,string,(string|null),null,U32,Record,null,U32,string,null,U32,string,(string|null),U32,(string)[],Record,U32,null,U32,null,U32,(U32)[],U32,U32,Usize,U32,string,U32,U32,string,null,U32,(U32|null),(string|null),(U32|null),(ChatListEntry)[],U32,(ChatListEntry)[],Record,U32,U32,FullChat,U32,U32,null,U32,U32,null,U32,string,string,U32,U32,U32,U32,(U32)[],U32,U32,Message,U32,(U32)[],Record,U32,U32,Contact,U32,string,(string|null),U32,U32,U32,U32,U32,U32,null,U32,U32,null,U32,(Contact)[],U32,U32,(string|null),(U32)[],U32,U32,(string|null),(Contact)[],U32,(U32)[],Record,U32,U32,string,string,null,U32,U32,U32,string,U32,U32,WebxdcMessageInfo,U32,string,U32,U32]; +export type __AllTyps=[string,boolean,Record,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],U32,Account,U32,string,(ProviderInfo|null),U32,boolean,U32,Record,U32,string,(string|null),null,U32,Record,null,U32,string,null,U32,string,(string|null),U32,(string)[],Record,U32,null,U32,null,U32,(U32)[],U32,U32,Usize,U32,string,U32,U32,string,null,U32,(U32|null),(string|null),(U32|null),(ChatListEntry)[],U32,(ChatListEntry)[],Record,U32,U32,FullChat,U32,U32,null,U32,U32,null,U32,string,string,U32,U32,U32,U32,(U32)[],U32,U32,Message,U32,(U32)[],Record,U32,U32,Contact,U32,string,(string|null),U32,U32,U32,U32,U32,U32,null,U32,U32,null,U32,(Contact)[],U32,U32,(string|null),(U32)[],U32,U32,(string|null),(Contact)[],U32,(U32)[],Record,U32,U32,Viewtype,(Viewtype|null),(Viewtype|null),(U32)[],U32,U32,string,string,null,U32,U32,U32,string,U32,U32,WebxdcMessageInfo,U32,string,U32,U32];