Media : start to refact renderer to be more generic

This commit is contained in:
ganfra 2019-01-23 20:29:47 +01:00
parent f9ca8f35bc
commit 7c4ac7b53a
5 changed files with 112 additions and 100 deletions

View file

@ -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)
}

View file

@ -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,

View file

@ -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<Int, Int> {
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)
}
}

View file

@ -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<Int, Int> {
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)
}
}

View file

@ -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
)