diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MaxUploadSizeProvider.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MaxUploadSizeProvider.kt index a5462a6caf..e6b9c7f026 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MaxUploadSizeProvider.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MaxUploadSizeProvider.kt @@ -12,5 +12,6 @@ package io.element.android.libraries.mediaupload.api * Provides the maximum upload size allowed by the Matrix server. */ fun interface MaxUploadSizeProvider { + /** Returns the maximum size in bytes a single upload may have, as advertised by the homeserver. */ suspend fun getMaxUploadSize(): Result } diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaOptimizationConfigProvider.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaOptimizationConfigProvider.kt index 976a7057f2..60dbf353eb 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaOptimizationConfigProvider.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaOptimizationConfigProvider.kt @@ -8,6 +8,10 @@ package io.element.android.libraries.mediaupload.api +/** + * Resolves how aggressively media should be compressed, combining the user's own preferences with the app defaults. + */ fun interface MediaOptimizationConfigProvider { + /** Returns the configuration to pass to the pre-processing and sending calls. */ suspend fun get(): MediaOptimizationConfig } diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaPreProcessor.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaPreProcessor.kt index c2bf1e5f5d..a51ebc17b9 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaPreProcessor.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaPreProcessor.kt @@ -10,10 +10,18 @@ package io.element.android.libraries.mediaupload.api import android.net.Uri +/** + * Prepares a media file for upload: resizing, transcoding and stripping metadata that would leak information about the sender. + */ interface MediaPreProcessor { /** * Given a [uri] and [mimeType], pre-processes the media before it's uploaded, resizing, transcoding, and removing sensitive info from its metadata. * If [deleteOriginal] is `true`, the file reference by the [uri] will be automatically deleted too when this process finishes. + * + * @param uri the media to process. + * @param mimeType the MIME type of that media. + * @param deleteOriginal whether to delete the source file once processing is done. + * @param mediaOptimizationConfig how aggressively the media should be compressed. * @return a [Result] with the [MediaUploadInfo] containing all the info needed to begin the upload. */ suspend fun process( diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt index 6cca73935e..808575f9e6 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt @@ -13,31 +13,62 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline +/** + * Creates a [MediaSender] for the room of the current room scope; see [MediaSenderRoomFactory] when the room is not in scope. + */ fun interface MediaSenderFactory { /** * Create a [MediaSender] for the given [Timeline.Mode], in the Room Scope. + * + * @param timelineMode the timeline the media should be sent to, which matters for threads in particular. */ fun create( timelineMode: Timeline.Mode, ): MediaSender } +/** + * Creates a [MediaSender] for an explicitly given room, used outside the room scope, for instance when sharing into a room. + */ fun interface MediaSenderRoomFactory { /** * Create a [MediaSender] for the given [JoinedRoom], with timeline mode Live. + * + * @param room the room the media should be sent to. */ fun create( room: JoinedRoom, ): MediaSender } +/** + * Sends media to a room, taking care of the pre-processing the timeline API does not do: resizing, transcoding and stripping metadata. + * + * Sending is a two-step process, and the steps can be used separately so the UI can show a preview between them. + * The temporary files produced by pre-processing are only released by [cleanUp]. + */ interface MediaSender { + /** + * Resizes, transcodes and strips the metadata of a media file without sending anything yet. + * + * @param uri the media picked by the user. + * @param mimeType the MIME type of that media. + * @param mediaOptimizationConfig how aggressively the media should be compressed. + */ suspend fun preProcessMedia( uri: Uri, mimeType: String, mediaOptimizationConfig: MediaOptimizationConfig, ): Result + /** + * Sends media that has already gone through [preProcessMedia]. + * + * @param mediaUploadInfo the result of the pre-processing step. + * @param caption the text shown along with the media, or `null` for none. + * @param formattedCaption the caption as HTML, or `null` to send it unformatted. + * @param inReplyToEventId the event this message replies to, or `null` if it is not a reply. + */ suspend fun sendPreProcessedMedia( mediaUploadInfo: MediaUploadInfo, caption: String?, @@ -45,6 +76,16 @@ interface MediaSender { inReplyToEventId: EventId?, ): Result + /** + * Pre-processes and sends a media file in one go, suspending until the upload finishes. + * + * @param uri the media picked by the user. + * @param mimeType the MIME type of that media. + * @param caption the text shown along with the media, or `null` for none. + * @param formattedCaption the caption as HTML, or `null` to send it unformatted. + * @param inReplyToEventId the event this message replies to, or `null` if it is not a reply. + * @param mediaOptimizationConfig how aggressively the media should be compressed. + */ suspend fun sendMedia( uri: Uri, mimeType: String, @@ -54,6 +95,14 @@ interface MediaSender { mediaOptimizationConfig: MediaOptimizationConfig, ): Result + /** + * Sends a recorded voice message, which is never compressed and carries a waveform instead of a caption. + * + * @param uri the recorded audio file. + * @param mimeType the MIME type of that recording. + * @param waveForm the amplitudes used to draw the waveform. + * @param inReplyToEventId the event this message replies to, or `null` if it is not a reply. + */ suspend fun sendVoiceMessage( uri: Uri, mimeType: String, @@ -61,6 +110,14 @@ interface MediaSender { inReplyToEventId: EventId? = null, ): Result + /** + * Sends several already pre-processed media items as a single gallery message. + * + * @param mediaUploadInfos the pre-processed items, in the order they should appear. + * @param caption the text shown along with the gallery, or `null` for none. + * @param formattedCaption the caption as HTML, or `null` to send it unformatted. + * @param inReplyToEventId the event this message replies to, or `null` if it is not a reply. + */ suspend fun sendGallery( mediaUploadInfos: List, caption: String?, @@ -68,5 +125,6 @@ interface MediaSender { inReplyToEventId: EventId?, ): Result + /** Deletes the temporary files produced by pre-processing; must be called even when nothing was ultimately sent. */ fun cleanUp() }