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

MSC2530: added the ability to send media with captions #3226

Merged
merged 23 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
46a5f0c
ffi: Expose filename and formatted body fields for media captions
SpiritCroc Dec 30, 2023
64aa264
Merge remote-tracking branch 'origin/main'
surakin Mar 11, 2024
705adfe
Merge remote-tracking branch 'origin/main'
surakin Mar 13, 2024
a4301c6
Merge remote-tracking branch 'origin/main'
surakin Mar 14, 2024
ed39ed5
MSC2530: added the ability to send media with captions
surakin Mar 16, 2024
7aa59a6
signoff
surakin Mar 16, 2024
9bdd989
fixing the import messup
surakin Mar 16, 2024
064b7e0
Merge remote-tracking branch 'upstream/main' into msc2530
surakin Mar 16, 2024
0ba1afb
Merge branch 'matrix-org:main' into msc2530
surakin Mar 16, 2024
7a7546e
Merge branch 'msc2530' of github.com:surakin/matrix-rust-sdk into msc…
surakin Mar 16, 2024
e21a0d2
fix missing parameters in documentation
surakin Mar 17, 2024
e165e1c
fix formatting
surakin Mar 17, 2024
74ca821
move optional parameters to the end
surakin Mar 17, 2024
24931fe
more formatting fixes
surakin Mar 17, 2024
4c6fa67
more formatting fixes
surakin Mar 17, 2024
76d58dc
rename url parameter to filename in send_attachment and helpers
surakin Mar 17, 2024
3ab9e1a
fix send_attachment documentation example
surakin Mar 17, 2024
1798315
move caption and formatted_caption into attachmentconfig
surakin Mar 18, 2024
053a656
fix formatting
surakin Mar 18, 2024
79fb2c6
fix formatting
surakin Mar 18, 2024
91816e3
fix formatting (hopefully the last one)
surakin Mar 18, 2024
9f89e2d
updated stale comments
surakin Mar 19, 2024
58529c3
simplify attachment message comments
surakin Mar 19, 2024
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
36 changes: 25 additions & 11 deletions bindings/matrix-sdk-ffi/src/timeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use ruma::{
receipt::ReceiptThread,
relation::Annotation,
room::message::{
ForwardThread, LocationMessageEventContent, MessageType,
RoomMessageEventContentWithoutRelation,
FormattedBody as RumaFormattedBody, ForwardThread, LocationMessageEventContent,
MessageType, RoomMessageEventContentWithoutRelation
},
AnyMessageLikeEventContent,
},
Expand All @@ -56,14 +56,14 @@ use crate::{
client::ProgressWatcher,
error::{ClientError, RoomError},
helpers::unwrap_or_clone_arc,
ruma::{AssetType, AudioInfo, FileInfo, ImageInfo, PollKind, ThumbnailInfo, VideoInfo},
ruma::{AssetType, AudioInfo, FileInfo, FormattedBody, ImageInfo, PollKind, ThumbnailInfo, VideoInfo},
task_handle::TaskHandle,
RUNTIME,
};

mod content;
use self::content::{Reaction, ReactionSenderData, TimelineItemContent};

pub use self::content::{Reaction, ReactionSenderData, TimelineItemContent};
mod content;

#[derive(uniffi::Object)]
#[repr(transparent)]
Expand Down Expand Up @@ -106,12 +106,18 @@ impl Timeline {

async fn send_attachment(
&self,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: String,
mime_type: Mime,
attachment_config: AttachmentConfig,
progress_watcher: Option<Box<dyn ProgressWatcher>>,
) -> Result<(), RoomError> {
let request = self.inner.send_attachment(url, mime_type, attachment_config);
let formatted: Option<RumaFormattedBody> = match formatted {
Some(p) => Some(RumaFormattedBody::from(p)),
None => None
};
let request = self.inner.send_attachment(caption, formatted, url, mime_type, attachment_config);
if let Some(progress_watcher) = progress_watcher {
let mut subscriber = request.subscribe_to_send_progress();
RUNTIME.spawn(async move {
Expand Down Expand Up @@ -215,6 +221,8 @@ impl Timeline {

pub fn send_image(
self: Arc<Self>,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: String,
thumbnail_url: Option<String>,
image_info: ImageInfo,
Expand All @@ -240,12 +248,14 @@ impl Timeline {
_ => AttachmentConfig::new().info(attachment_info),
};

self.send_attachment(url, mime_type, attachment_config, progress_watcher).await
self.send_attachment(caption, formatted, url, mime_type, attachment_config, progress_watcher).await
}))
}

pub fn send_video(
self: Arc<Self>,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: String,
thumbnail_url: Option<String>,
video_info: VideoInfo,
Expand All @@ -271,12 +281,14 @@ impl Timeline {
_ => AttachmentConfig::new().info(attachment_info),
};

self.send_attachment(url, mime_type, attachment_config, progress_watcher).await
self.send_attachment(caption, formatted, url, mime_type, attachment_config, progress_watcher).await
}))
}

pub fn send_audio(
self: Arc<Self>,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: String,
audio_info: AudioInfo,
progress_watcher: Option<Box<dyn ProgressWatcher>>,
Expand All @@ -293,12 +305,14 @@ impl Timeline {
let attachment_info = AttachmentInfo::Audio(base_audio_info);
let attachment_config = AttachmentConfig::new().info(attachment_info);

self.send_attachment(url, mime_type, attachment_config, progress_watcher).await
self.send_attachment(caption, formatted, url, mime_type, attachment_config, progress_watcher).await
}))
}

pub fn send_voice_message(
self: Arc<Self>,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: String,
audio_info: AudioInfo,
waveform: Vec<u16>,
Expand All @@ -317,7 +331,7 @@ impl Timeline {
AttachmentInfo::Voice { audio_info: base_audio_info, waveform: Some(waveform) };
let attachment_config = AttachmentConfig::new().info(attachment_info);

self.send_attachment(url, mime_type, attachment_config, progress_watcher).await
self.send_attachment(caption, formatted, url, mime_type, attachment_config, progress_watcher).await
}))
}

Expand All @@ -339,7 +353,7 @@ impl Timeline {
let attachment_info = AttachmentInfo::File(base_file_info);
let attachment_config = AttachmentConfig::new().info(attachment_info);

self.send_attachment(url, mime_type, attachment_config, progress_watcher).await
self.send_attachment(None, None, url, mime_type, attachment_config, progress_watcher).await
}))
}

Expand Down
13 changes: 10 additions & 3 deletions crates/matrix-sdk-ui/src/timeline/futures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ use eyeball::{SharedObservable, Subscriber};
use matrix_sdk::{attachment::AttachmentConfig, TransmissionProgress};
use matrix_sdk_base::boxed_into_future;
use mime::Mime;
use ruma::events::room::message::FormattedBody;
use tracing::{Instrument as _, Span};

use super::{Error, Timeline};

pub struct SendAttachment<'a> {
timeline: &'a Timeline,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: String,
mime_type: Mime,
config: AttachmentConfig,
Expand All @@ -20,12 +23,16 @@ pub struct SendAttachment<'a> {
impl<'a> SendAttachment<'a> {
pub(crate) fn new(
timeline: &'a Timeline,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: String,
mime_type: Mime,
config: AttachmentConfig,
) -> Self {
Self {
timeline,
caption,
formatted,
url,
mime_type,
config,
Expand All @@ -47,9 +54,9 @@ impl<'a> IntoFuture for SendAttachment<'a> {
boxed_into_future!(extra_bounds: 'a);

fn into_future(self) -> Self::IntoFuture {
let Self { timeline, url, mime_type, config, tracing_span, send_progress } = self;
let Self { timeline, caption, formatted, url, mime_type, config, tracing_span, send_progress } = self;
let fut = async move {
let body = Path::new(&url)
let urlbody = Path::new(&url)
.file_name()
.ok_or(Error::InvalidAttachmentFileName)?
.to_str()
Expand All @@ -58,7 +65,7 @@ impl<'a> IntoFuture for SendAttachment<'a> {

timeline
.room()
.send_attachment(body, &mime_type, data, config)
.send_attachment(caption, formatted, urlbody, &mime_type, data, config)
.with_send_progress_observable(send_progress)
.await
.map_err(|_| Error::FailedSendingAttachment)?;
Expand Down
11 changes: 8 additions & 3 deletions crates/matrix-sdk-ui/src/timeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ use ruma::{
relation::Annotation,
room::{
message::{
AddMentions, ForwardThread, OriginalRoomMessageEvent, ReplacementMetadata,
RoomMessageEventContent, RoomMessageEventContentWithoutRelation,
AddMentions, FormattedBody, ForwardThread, OriginalRoomMessageEvent, ReplacementMetadata, RoomMessageEventContent, RoomMessageEventContentWithoutRelation
},
redaction::RoomRedactionEventContent,
},
Expand Down Expand Up @@ -513,6 +512,10 @@ impl Timeline {
///
/// # Arguments
///
/// * `caption` - The url for the file to be sent
///
/// * `formatted` - The url for the file to be sent
///
/// * `url` - The url for the file to be sent
///
/// * `mime_type` - The attachment's mime type
Expand All @@ -523,11 +526,13 @@ impl Timeline {
#[instrument(skip_all)]
pub fn send_attachment(
&self,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: String,
mime_type: Mime,
config: AttachmentConfig,
) -> SendAttachment<'_> {
SendAttachment::new(self, url, mime_type, config)
SendAttachment::new(self, caption, formatted, url, mime_type, config)
}

/// Retry sending a message that previously failed to send.
Expand Down
2 changes: 2 additions & 0 deletions crates/matrix-sdk/src/attachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ impl Default for AttachmentConfig {
/// if let Some(room) = client.get_room(&room_id) {
/// room.send_attachment(
/// "My favorite cat",
/// None,
/// "my_favorite_cat.jpg",
/// &mime::IMAGE_JPEG,
/// image,
/// config,
Expand Down
33 changes: 23 additions & 10 deletions crates/matrix-sdk/src/encryption/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ use ruma::{
assign,
events::room::{
message::{
AudioMessageEventContent, FileInfo, FileMessageEventContent, ImageMessageEventContent,
MessageType, VideoInfo, VideoMessageEventContent,
AudioMessageEventContent, FileInfo, FileMessageEventContent, FormattedBody,
ImageMessageEventContent, MessageType, VideoInfo, VideoMessageEventContent
},
ImageInfo, MediaSource, ThumbnailInfo,
},
Expand Down Expand Up @@ -298,10 +298,13 @@ impl Client {
}

/// Encrypt and upload the file to be read from `reader` and construct an
/// attachment message with `body`, `content_type`, `info` and `thumbnail`.
/// attachment message with `body`, `content_type`, `info` and `thumbnail`,
/// optionanly with `formatted` and `filename`.
surakin marked this conversation as resolved.
Show resolved Hide resolved
pub(crate) async fn prepare_encrypted_attachment_message(
&self,
body: &str,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: &str,
content_type: &mime::Mime,
data: Vec<u8>,
info: Option<AttachmentInfo>,
Expand All @@ -321,6 +324,15 @@ impl Client {
let ((thumbnail_source, thumbnail_info), file) =
try_join(upload_thumbnail, upload_attachment).await?;

let body: &str = match &caption {
Some(p) => p,
None => url,
};
let filename = match &caption {
Some(p) => Some(String::from(p)),
None => None
};

Ok(match content_type.type_() {
mime::IMAGE => {
let info = assign!(info.map(ImageInfo::from).unwrap_or_default(), {
Expand All @@ -329,7 +341,9 @@ impl Client {
thumbnail_info
});
let content = assign!(ImageMessageEventContent::encrypted(body.to_owned(), file), {
info: Some(Box::new(info))
info: Some(Box::new(info)),
formatted: formatted,
filename: filename
surakin marked this conversation as resolved.
Show resolved Hide resolved
});
MessageType::Image(content)
}
Expand Down Expand Up @@ -1435,29 +1449,28 @@ impl Encryption {

#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
use std::time::Duration;

use matrix_sdk_base::SessionMeta;
use matrix_sdk_test::{
async_test, test_json, GlobalAccountDataTestEvent, JoinedRoomBuilder, StateTestEvent,
SyncResponseBuilder, DEFAULT_TEST_ROOM_ID,
async_test, DEFAULT_TEST_ROOM_ID, GlobalAccountDataTestEvent, JoinedRoomBuilder, StateTestEvent,
SyncResponseBuilder, test_json,
};
use ruma::{
device_id, event_id,
events::{reaction::ReactionEventContent, relation::Annotation},
user_id,
};
use serde_json::json;
use std::time::Duration;
use wiremock::{
matchers::{header, method, path_regex},
Mock, MockServer, ResponseTemplate,
};

use crate::{
Client,
config::RequestConfig,
matrix_auth::{MatrixSession, MatrixSessionTokens},
test_utils::logged_in_client,
Client,
};

#[async_test]
Expand Down
40 changes: 31 additions & 9 deletions crates/matrix-sdk/src/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ use ruma::{
assign,
events::room::{
message::{
self, AudioInfo, AudioMessageEventContent, FileInfo, FileMessageEventContent,
ImageMessageEventContent, MessageType, UnstableAudioDetailsContentBlock,
UnstableVoiceContentBlock, VideoInfo, VideoMessageEventContent,
self, AudioInfo, AudioMessageEventContent, FileInfo, FileMessageEventContent,
FormattedBody, ImageMessageEventContent, MessageType, UnstableAudioDetailsContentBlock,
UnstableVoiceContentBlock, VideoInfo, VideoMessageEventContent
},
ImageInfo, MediaSource, ThumbnailInfo,
},
Expand Down Expand Up @@ -437,10 +437,13 @@ impl Media {
}

/// Upload the file bytes in `data` and construct an attachment
/// message with `body`, `content_type`, `info` and `thumbnail`.
/// message with `body`, `content_type`, `info` and `thumbnail`,
/// optionally with `formatted` and `filename`.
surakin marked this conversation as resolved.
Show resolved Hide resolved
pub(crate) async fn prepare_attachment_message(
&self,
body: &str,
caption: Option<String>,
formatted: Option<FormattedBody>,
url: &str,
content_type: &Mime,
data: Vec<u8>,
info: Option<AttachmentInfo>,
Expand All @@ -459,6 +462,14 @@ impl Media {
let ((thumbnail_source, thumbnail_info), response) =
try_join(upload_thumbnail, upload_attachment).await?;

let body: &str = match &caption {
Some(p) => p,
None => url,
};
let filename = match &caption {
Some(_) => Some(String::from(url)),
None => None
};
let url = response.content_uri;

Ok(match content_type.type_() {
Expand All @@ -469,12 +480,17 @@ impl Media {
thumbnail_info,
});
MessageType::Image(
ImageMessageEventContent::plain(body.to_owned(), url).info(Box::new(info)),
ImageMessageEventContent::plain(body.to_owned(), url)
.info(Box::new(info))
.filename(filename)
.formatted(formatted),
)
}
mime::AUDIO => {
let audio_message_event_content =
message::AudioMessageEventContent::plain(body.to_owned(), url);
message::AudioMessageEventContent::plain(body.to_owned(), url)
.filename(filename)
.formatted(formatted);
MessageType::Audio(update_audio_message_event(
audio_message_event_content,
content_type,
Expand All @@ -488,7 +504,10 @@ impl Media {
thumbnail_info
});
MessageType::Video(
VideoMessageEventContent::plain(body.to_owned(), url).info(Box::new(info)),
VideoMessageEventContent::plain(body.to_owned(), url)
.info(Box::new(info))
.filename(filename)
.formatted(formatted)
)
}
_ => {
Expand All @@ -498,7 +517,10 @@ impl Media {
thumbnail_info
});
MessageType::File(
FileMessageEventContent::plain(body.to_owned(), url).info(Box::new(info)),
FileMessageEventContent::plain(body.to_owned(), url)
.info(Box::new(info))
.filename(filename)
.formatted(formatted),
)
}
})
Expand Down
Loading
Loading