Providing a thumbnail when sending a media is now optional.
This commit is contained in:
@@ -100,9 +100,9 @@ interface MatrixRoom : Closeable {
|
||||
|
||||
suspend fun redactEvent(eventId: EventId, reason: String? = null): Result<Unit>
|
||||
|
||||
suspend fun sendImage(file: File, thumbnailFile: File, imageInfo: ImageInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
|
||||
suspend fun sendImage(file: File, thumbnailFile: File?, imageInfo: ImageInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
|
||||
|
||||
suspend fun sendVideo(file: File, thumbnailFile: File, videoInfo: VideoInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
|
||||
suspend fun sendVideo(file: File, thumbnailFile: File?, videoInfo: VideoInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
|
||||
|
||||
suspend fun sendAudio(file: File, audioInfo: AudioInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
|
||||
|
||||
|
||||
@@ -360,15 +360,25 @@ class RustMatrixRoom(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendImage(file: File, thumbnailFile: File, imageInfo: ImageInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> {
|
||||
return sendAttachment(listOf(file, thumbnailFile)) {
|
||||
innerTimeline.sendImage(file.path, thumbnailFile.path, imageInfo.map(), progressCallback?.toProgressWatcher())
|
||||
override suspend fun sendImage(
|
||||
file: File,
|
||||
thumbnailFile: File?,
|
||||
imageInfo: ImageInfo,
|
||||
progressCallback: ProgressCallback?,
|
||||
): Result<MediaUploadHandler> {
|
||||
return sendAttachment(listOfNotNull(file, thumbnailFile)) {
|
||||
innerTimeline.sendImage(file.path, thumbnailFile?.path, imageInfo.map(), progressCallback?.toProgressWatcher())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendVideo(file: File, thumbnailFile: File, videoInfo: VideoInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> {
|
||||
return sendAttachment(listOf(file, thumbnailFile)) {
|
||||
innerTimeline.sendVideo(file.path, thumbnailFile.path, videoInfo.map(), progressCallback?.toProgressWatcher())
|
||||
override suspend fun sendVideo(
|
||||
file: File,
|
||||
thumbnailFile: File?,
|
||||
videoInfo: VideoInfo,
|
||||
progressCallback: ProgressCallback?,
|
||||
): Result<MediaUploadHandler> {
|
||||
return sendAttachment(listOfNotNull(file, thumbnailFile)) {
|
||||
innerTimeline.sendVideo(file.path, thumbnailFile?.path, videoInfo.map(), progressCallback?.toProgressWatcher())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -299,14 +299,14 @@ class FakeMatrixRoom(
|
||||
|
||||
override suspend fun sendImage(
|
||||
file: File,
|
||||
thumbnailFile: File,
|
||||
thumbnailFile: File?,
|
||||
imageInfo: ImageInfo,
|
||||
progressCallback: ProgressCallback?
|
||||
): Result<MediaUploadHandler> = fakeSendMedia(progressCallback)
|
||||
|
||||
override suspend fun sendVideo(
|
||||
file: File,
|
||||
thumbnailFile: File,
|
||||
thumbnailFile: File?,
|
||||
videoInfo: VideoInfo,
|
||||
progressCallback: ProgressCallback?
|
||||
): Result<MediaUploadHandler> = fakeSendMedia(
|
||||
|
||||
@@ -101,7 +101,6 @@ class MediaSender @Inject constructor(
|
||||
progressCallback = progressCallback
|
||||
)
|
||||
}
|
||||
|
||||
is MediaUploadInfo.Video -> {
|
||||
sendVideo(
|
||||
file = uploadInfo.file,
|
||||
|
||||
@@ -26,8 +26,8 @@ sealed interface MediaUploadInfo {
|
||||
|
||||
val file: File
|
||||
|
||||
data class Image(override val file: File, val imageInfo: ImageInfo, val thumbnailFile: File) : MediaUploadInfo
|
||||
data class Video(override val file: File, val videoInfo: VideoInfo, val thumbnailFile: File) : MediaUploadInfo
|
||||
data class Image(override val file: File, val imageInfo: ImageInfo, val thumbnailFile: File?) : MediaUploadInfo
|
||||
data class Video(override val file: File, val videoInfo: VideoInfo, val thumbnailFile: File?) : MediaUploadInfo
|
||||
data class Audio(override val file: File, val audioInfo: AudioInfo) : MediaUploadInfo
|
||||
data class VoiceMessage(override val file: File, val audioInfo: AudioInfo, val waveform: List<Float>) : MediaUploadInfo
|
||||
data class AnyFile(override val file: File, val fileInfo: FileInfo) : MediaUploadInfo
|
||||
|
||||
@@ -137,7 +137,7 @@ class AndroidMediaPreProcessor @Inject constructor(
|
||||
resizeMode = ResizeMode.Approximate(IMAGE_SCALE_REF_SIZE, IMAGE_SCALE_REF_SIZE),
|
||||
orientation = orientation,
|
||||
).getOrThrow()
|
||||
val thumbnailResult: ThumbnailResult = thumbnailFactory.createImageThumbnail(compressionResult.file)
|
||||
val thumbnailResult = thumbnailFactory.createImageThumbnail(compressionResult.file)
|
||||
val imageInfo = compressionResult.toImageInfo(
|
||||
mimeType = mimeType,
|
||||
thumbnailResult = thumbnailResult
|
||||
@@ -146,13 +146,13 @@ class AndroidMediaPreProcessor @Inject constructor(
|
||||
return MediaUploadInfo.Image(
|
||||
file = compressionResult.file,
|
||||
imageInfo = imageInfo,
|
||||
thumbnailFile = thumbnailResult.file
|
||||
thumbnailFile = thumbnailResult?.file
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun processImageWithoutCompression(): MediaUploadInfo {
|
||||
val file = copyToTmpFile(uri)
|
||||
val thumbnailResult: ThumbnailResult = thumbnailFactory.createImageThumbnail(file)
|
||||
val thumbnailResult = thumbnailFactory.createImageThumbnail(file)
|
||||
val imageInfo = contentResolver.openInputStream(uri).use { input ->
|
||||
val bitmap = BitmapFactory.decodeStream(input, null, null)!!
|
||||
ImageInfo(
|
||||
@@ -160,16 +160,16 @@ class AndroidMediaPreProcessor @Inject constructor(
|
||||
height = bitmap.height.toLong(),
|
||||
mimetype = mimeType,
|
||||
size = file.length(),
|
||||
thumbnailInfo = thumbnailResult.info,
|
||||
thumbnailInfo = thumbnailResult?.info,
|
||||
thumbnailSource = null,
|
||||
blurhash = thumbnailResult.blurhash,
|
||||
blurhash = thumbnailResult?.blurhash,
|
||||
)
|
||||
}
|
||||
removeSensitiveImageMetadata(file)
|
||||
return MediaUploadInfo.Image(
|
||||
file = file,
|
||||
imageInfo = imageInfo,
|
||||
thumbnailFile = thumbnailResult.file
|
||||
thumbnailFile = thumbnailResult?.file
|
||||
)
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ class AndroidMediaPreProcessor @Inject constructor(
|
||||
return MediaUploadInfo.Video(
|
||||
file = resultFile,
|
||||
videoInfo = videoInfo,
|
||||
thumbnailFile = thumbnailInfo.file
|
||||
thumbnailFile = thumbnailInfo?.file
|
||||
)
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ class AndroidMediaPreProcessor @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractVideoMetadata(file: File, mimeType: String?, thumbnailResult: ThumbnailResult): VideoInfo =
|
||||
private fun extractVideoMetadata(file: File, mimeType: String?, thumbnailResult: ThumbnailResult?): VideoInfo =
|
||||
MediaMetadataRetriever().runAndRelease {
|
||||
setDataSource(context, Uri.fromFile(file))
|
||||
VideoInfo(
|
||||
@@ -244,10 +244,10 @@ class AndroidMediaPreProcessor @Inject constructor(
|
||||
height = extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toLong() ?: 0L,
|
||||
mimetype = mimeType,
|
||||
size = file.length(),
|
||||
thumbnailInfo = thumbnailResult.info,
|
||||
thumbnailInfo = thumbnailResult?.info,
|
||||
// Will be computed by the rust sdk
|
||||
thumbnailSource = null,
|
||||
blurhash = thumbnailResult.blurhash,
|
||||
blurhash = thumbnailResult?.blurhash,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -257,15 +257,15 @@ class AndroidMediaPreProcessor @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun ImageCompressionResult.toImageInfo(mimeType: String, thumbnailResult: ThumbnailResult) = ImageInfo(
|
||||
private fun ImageCompressionResult.toImageInfo(mimeType: String, thumbnailResult: ThumbnailResult?) = ImageInfo(
|
||||
width = width.toLong(),
|
||||
height = height.toLong(),
|
||||
mimetype = mimeType,
|
||||
size = size,
|
||||
thumbnailInfo = thumbnailResult.info,
|
||||
thumbnailInfo = thumbnailResult?.info,
|
||||
// Will be computed by the rust sdk
|
||||
thumbnailSource = null,
|
||||
blurhash = thumbnailResult.blurhash,
|
||||
blurhash = thumbnailResult?.blurhash,
|
||||
)
|
||||
|
||||
private fun MediaMetadataRetriever.extractDuration(): Duration {
|
||||
|
||||
@@ -61,7 +61,7 @@ class ThumbnailFactory @Inject constructor(
|
||||
) {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
suspend fun createImageThumbnail(file: File): ThumbnailResult {
|
||||
suspend fun createImageThumbnail(file: File): ThumbnailResult? {
|
||||
return createThumbnail { cancellationSignal ->
|
||||
// This API works correctly with GIF
|
||||
if (sdkIntProvider.isAtLeast(Build.VERSION_CODES.Q)) {
|
||||
@@ -80,7 +80,7 @@ class ThumbnailFactory @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createVideoThumbnail(file: File): ThumbnailResult {
|
||||
suspend fun createVideoThumbnail(file: File): ThumbnailResult? {
|
||||
return createThumbnail {
|
||||
MediaMetadataRetriever().runAndRelease {
|
||||
setDataSource(context, file.toUri())
|
||||
@@ -89,32 +89,33 @@ class ThumbnailFactory @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createThumbnail(bitmapFactory: (CancellationSignal) -> Bitmap?): ThumbnailResult = suspendCancellableCoroutine { continuation ->
|
||||
private suspend fun createThumbnail(bitmapFactory: (CancellationSignal) -> Bitmap?): ThumbnailResult? = suspendCancellableCoroutine { continuation ->
|
||||
val cancellationSignal = CancellationSignal()
|
||||
continuation.invokeOnCancellation {
|
||||
cancellationSignal.cancel()
|
||||
}
|
||||
val bitmapThumbnail: Bitmap? = bitmapFactory(cancellationSignal)
|
||||
if (bitmapThumbnail == null) {
|
||||
continuation.resume(null)
|
||||
return@suspendCancellableCoroutine
|
||||
}
|
||||
val thumbnailFile = context.createTmpFile(extension = "jpeg")
|
||||
thumbnailFile.outputStream().use { outputStream ->
|
||||
bitmapThumbnail?.compress(Bitmap.CompressFormat.JPEG, 80, outputStream)
|
||||
}
|
||||
val blurhash = bitmapThumbnail?.let {
|
||||
BlurHash.encode(it, 3, 3)
|
||||
bitmapThumbnail.compress(Bitmap.CompressFormat.JPEG, 80, outputStream)
|
||||
}
|
||||
val blurhash = BlurHash.encode(bitmapThumbnail, 3, 3)
|
||||
val thumbnailResult = ThumbnailResult(
|
||||
file = thumbnailFile,
|
||||
info = ThumbnailInfo(
|
||||
height = bitmapThumbnail?.height?.toLong(),
|
||||
width = bitmapThumbnail?.width?.toLong(),
|
||||
height = bitmapThumbnail.height.toLong(),
|
||||
width = bitmapThumbnail.width.toLong(),
|
||||
mimetype = MimeTypes.Jpeg,
|
||||
size = thumbnailFile.length()
|
||||
),
|
||||
blurhash = blurhash
|
||||
)
|
||||
bitmapThumbnail?.recycle()
|
||||
bitmapThumbnail.recycle()
|
||||
continuation.resume(thumbnailResult)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user