From 7c4ac7b53ac83e8e2a1c191c97c7df4ae9b30d75 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 23 Jan 2019 20:29:47 +0100 Subject: [PATCH] Media : start to refact renderer to be more generic --- .../room/detail/timeline/MessageImageItem.kt | 7 +- .../detail/timeline/MessageItemFactory.kt | 24 ++++-- .../features/media/MediaContentRenderer.kt | 85 +++++++++++++++++++ .../features/media/MessageImageRenderer.kt | 85 ------------------- .../session/room/model/message/ImageInfo.kt | 11 +-- 5 files changed, 112 insertions(+), 100 deletions(-) create mode 100644 app/src/main/java/im/vector/riotredesign/features/media/MediaContentRenderer.kt delete mode 100644 app/src/main/java/im/vector/riotredesign/features/media/MessageImageRenderer.kt diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageImageItem.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageImageItem.kt index bc7368f611..b273cd4f4a 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageImageItem.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageImageItem.kt @@ -2,12 +2,11 @@ package im.vector.riotredesign.features.home.room.detail.timeline import android.widget.ImageView import android.widget.TextView -import im.vector.matrix.android.api.session.room.model.message.MessageImageContent import im.vector.riotredesign.R -import im.vector.riotredesign.features.media.MessageImageRenderer +import im.vector.riotredesign.features.media.MediaContentRenderer class MessageImageItem( - private val messageContent: MessageImageContent, + private val mediaData: MediaContentRenderer.Data, informationData: MessageInformationData ) : AbsMessageItem(informationData, R.layout.item_timeline_event_image_message) { @@ -18,7 +17,7 @@ class MessageImageItem( override fun bind() { super.bind() - MessageImageRenderer.render(messageContent, imageView) + MediaContentRenderer.render(mediaData, MediaContentRenderer.Mode.THUMBNAIL, imageView) } diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageItemFactory.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageItemFactory.kt index 8168be1c28..4264647801 100644 --- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageItemFactory.kt +++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/MessageItemFactory.kt @@ -11,6 +11,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.model.message.MessageImageContent import im.vector.matrix.android.api.session.room.model.message.MessageTextContent import im.vector.riotredesign.core.extensions.localDateTime +import im.vector.riotredesign.features.media.MediaContentRenderer class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatter) { @@ -28,12 +29,12 @@ class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatte val nextDate = nextEvent?.root?.localDateTime() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60)) - ?: false + ?: false if (addDaySeparator - || nextRoomMember != roomMember - || nextEvent?.root?.type != EventType.MESSAGE - || isNextMessageReceivedMoreThanOneHourAgo) { + || nextRoomMember != roomMember + || nextEvent?.root?.type != EventType.MESSAGE + || isNextMessageReceivedMoreThanOneHourAgo) { messagesDisplayedWithInformation.add(event.root.eventId) } @@ -51,8 +52,19 @@ class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatte } } - private fun buildImageMessageItem(messageContent: MessageImageContent, informationData: MessageInformationData): MessageImageItem? { - return MessageImageItem(messageContent, informationData) + private fun buildImageMessageItem(messageContent: MessageImageContent, + informationData: MessageInformationData): MessageImageItem? { + // TODO : manage maxHeight/maxWidth + val data = MediaContentRenderer.Data( + url = messageContent.url, + height = messageContent.info.height, + maxHeight = 800, + width = messageContent.info.width, + maxWidth = 800, + rotation = messageContent.info.rotation, + orientation = messageContent.info.orientation + ) + return MessageImageItem(data, informationData) } private fun buildTextMessageItem(messageContent: MessageTextContent, diff --git a/app/src/main/java/im/vector/riotredesign/features/media/MediaContentRenderer.kt b/app/src/main/java/im/vector/riotredesign/features/media/MediaContentRenderer.kt new file mode 100644 index 0000000000..e9deb18226 --- /dev/null +++ b/app/src/main/java/im/vector/riotredesign/features/media/MediaContentRenderer.kt @@ -0,0 +1,85 @@ +package im.vector.riotredesign.features.media + +import android.media.ExifInterface +import android.widget.ImageView +import im.vector.matrix.android.api.Matrix +import im.vector.matrix.android.api.session.content.ContentUrlResolver +import im.vector.riotredesign.core.glide.GlideApp + +object MediaContentRenderer { + + data class Data( + val url: String?, + val height: Int, + val maxHeight: Int, + val width: Int, + val maxWidth: Int = width, + val orientation: Int, + val rotation: Int + ) + + enum class Mode { + FULL_SIZE, + THUMBNAIL + } + + fun render(data: Data, mode: Mode, imageView: ImageView) { + val (width, height) = processSize(data, mode) + imageView.layoutParams.height = height + imageView.layoutParams.width = width + + val contentUrlResolver = Matrix.getInstance().currentSession.contentUrlResolver() + val resolvedUrl = when (mode) { + Mode.FULL_SIZE -> contentUrlResolver.resolveFullSize(data.url) + Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE) + } + ?: return + + GlideApp + .with(imageView) + .load(resolvedUrl) + .thumbnail(0.3f) + .into(imageView) + } + + private fun processSize(data: Data, mode: Mode): Pair { + val maxImageWidth = data.maxWidth + val maxImageHeight = data.maxHeight + val rotationAngle = data.rotation + val orientation = data.orientation + var width = data.width + var height = data.height + var finalHeight = -1 + var finalWidth = -1 + + // if the image size is known + // compute the expected height + if (width > 0 && height > 0) { + // swap width and height if the image is side oriented + if (rotationAngle == 90 || rotationAngle == 270) { + val tmp = width + width = height + height = tmp + } else if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || orientation == ExifInterface.ORIENTATION_ROTATE_270) { + val tmp = width + width = height + height = tmp + } + if (mode == Mode.FULL_SIZE) { + finalHeight = height + finalWidth = width + } else { + finalHeight = Math.min(maxImageWidth * height / width, maxImageHeight) + finalWidth = finalHeight * width / height + } + } + // ensure that some values are properly initialized + if (finalHeight < 0) { + finalHeight = maxImageHeight + } + if (finalWidth < 0) { + finalWidth = maxImageWidth + } + return Pair(finalWidth, finalHeight) + } +} \ No newline at end of file diff --git a/app/src/main/java/im/vector/riotredesign/features/media/MessageImageRenderer.kt b/app/src/main/java/im/vector/riotredesign/features/media/MessageImageRenderer.kt deleted file mode 100644 index 7b437ef922..0000000000 --- a/app/src/main/java/im/vector/riotredesign/features/media/MessageImageRenderer.kt +++ /dev/null @@ -1,85 +0,0 @@ -package im.vector.riotredesign.features.media - -import android.content.Context -import android.graphics.Point -import android.media.ExifInterface -import android.view.WindowManager -import android.widget.ImageView -import im.vector.matrix.android.api.Matrix -import im.vector.matrix.android.api.session.content.ContentUrlResolver -import im.vector.matrix.android.api.session.room.model.message.MessageImageContent -import im.vector.riotredesign.core.glide.GlideApp - -object MessageImageRenderer { - - fun render(messageContent: MessageImageContent, imageView: ImageView) { - val (maxImageWidth, maxImageHeight) = computeMaxSize(imageView.context) - val imageInfo = messageContent.info - val rotationAngle = imageInfo.rotation ?: 0 - val orientation = imageInfo.orientation ?: ExifInterface.ORIENTATION_NORMAL - var width = imageInfo.width - var height = imageInfo.height - - var finalHeight = -1 - var finalWidth = -1 - - // if the image size is known - // compute the expected height - if (width > 0 && height > 0) { - // swap width and height if the image is side oriented - if (rotationAngle == 90 || rotationAngle == 270) { - val tmp = width - width = height - height = tmp - } else if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || orientation == ExifInterface.ORIENTATION_ROTATE_270) { - val tmp = width - width = height - height = tmp - } - finalHeight = Math.min(maxImageWidth * height / width, maxImageHeight) - finalWidth = finalHeight * width / height - } - // ensure that some values are properly initialized - if (finalHeight < 0) { - finalHeight = maxImageHeight - } - if (finalWidth < 0) { - finalWidth = maxImageWidth - } - imageView.layoutParams.height = finalHeight - imageView.layoutParams.width = finalWidth - - val contentUrlResolver = Matrix.getInstance().currentSession.contentUrlResolver() - val resolvedUrl = contentUrlResolver.resolveThumbnail( - messageContent.url, - finalWidth, - finalHeight, - ContentUrlResolver.ThumbnailMethod.SCALE - ) ?: return - - GlideApp - .with(imageView) - .load(resolvedUrl) - .into(imageView) - } - - private fun computeMaxSize(context: Context): Pair { - val size = Point(0, 0) - val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager - wm.defaultDisplay.getSize(size) - val screenWidth = size.x - val screenHeight = size.y - val maxImageWidth: Int - val maxImageHeight: Int - // landscape / portrait - if (screenWidth < screenHeight) { - maxImageWidth = Math.round(screenWidth * 0.6f) - maxImageHeight = Math.round(screenHeight * 0.4f) - } else { - maxImageWidth = Math.round(screenWidth * 0.4f) - maxImageHeight = Math.round(screenHeight * 0.6f) - } - return Pair(maxImageWidth, maxImageHeight) - } - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ImageInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ImageInfo.kt index 8c58f6bbc5..f4c698c18b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ImageInfo.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/ImageInfo.kt @@ -1,16 +1,17 @@ package im.vector.matrix.android.api.session.room.model.message +import android.media.ExifInterface import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class ImageInfo( @Json(name = "mimetype") val mimeType: String, - @Json(name = "w") val width: Int, - @Json(name = "h") val height: Int, - @Json(name = "size") val size: Int, - @Json(name = "rotation") val rotation: Int? = null, - @Json(name = "orientation") val orientation: Int? = null, + @Json(name = "w") val width: Int = 0, + @Json(name = "h") val height: Int = 0, + @Json(name = "size") val size: Int = 0, + @Json(name = "rotation") val rotation: Int = 0, + @Json(name = "orientation") val orientation: Int = ExifInterface.ORIENTATION_NORMAL, @Json(name = "thumbnail_info") val thumbnailInfo: ThumbnailInfo? = null, @Json(name = "thumbnail_url") val thumbnailUrl: String? = null ) \ No newline at end of file