mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-17 20:40:07 +03:00
Media : start to refact renderer to be more generic
This commit is contained in:
parent
f9ca8f35bc
commit
7c4ac7b53a
5 changed files with 112 additions and 100 deletions
|
@ -2,12 +2,11 @@ package im.vector.riotredesign.features.home.room.detail.timeline
|
||||||
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.features.media.MessageImageRenderer
|
import im.vector.riotredesign.features.media.MediaContentRenderer
|
||||||
|
|
||||||
class MessageImageItem(
|
class MessageImageItem(
|
||||||
private val messageContent: MessageImageContent,
|
private val mediaData: MediaContentRenderer.Data,
|
||||||
informationData: MessageInformationData
|
informationData: MessageInformationData
|
||||||
) : AbsMessageItem(informationData, R.layout.item_timeline_event_image_message) {
|
) : AbsMessageItem(informationData, R.layout.item_timeline_event_image_message) {
|
||||||
|
|
||||||
|
@ -18,7 +17,7 @@ class MessageImageItem(
|
||||||
|
|
||||||
override fun bind() {
|
override fun bind() {
|
||||||
super.bind()
|
super.bind()
|
||||||
MessageImageRenderer.render(messageContent, imageView)
|
MediaContentRenderer.render(mediaData, MediaContentRenderer.Mode.THUMBNAIL, imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.MessageImageContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
||||||
import im.vector.riotredesign.core.extensions.localDateTime
|
import im.vector.riotredesign.core.extensions.localDateTime
|
||||||
|
import im.vector.riotredesign.features.media.MediaContentRenderer
|
||||||
|
|
||||||
class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatter) {
|
class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatter) {
|
||||||
|
|
||||||
|
@ -28,12 +29,12 @@ class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatte
|
||||||
val nextDate = nextEvent?.root?.localDateTime()
|
val nextDate = nextEvent?.root?.localDateTime()
|
||||||
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate()
|
||||||
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60))
|
||||||
?: false
|
?: false
|
||||||
|
|
||||||
if (addDaySeparator
|
if (addDaySeparator
|
||||||
|| nextRoomMember != roomMember
|
|| nextRoomMember != roomMember
|
||||||
|| nextEvent?.root?.type != EventType.MESSAGE
|
|| nextEvent?.root?.type != EventType.MESSAGE
|
||||||
|| isNextMessageReceivedMoreThanOneHourAgo) {
|
|| isNextMessageReceivedMoreThanOneHourAgo) {
|
||||||
messagesDisplayedWithInformation.add(event.root.eventId)
|
messagesDisplayedWithInformation.add(event.root.eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +52,19 @@ class MessageItemFactory(private val timelineDateFormatter: TimelineDateFormatte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildImageMessageItem(messageContent: MessageImageContent, informationData: MessageInformationData): MessageImageItem? {
|
private fun buildImageMessageItem(messageContent: MessageImageContent,
|
||||||
return MessageImageItem(messageContent, informationData)
|
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,
|
private fun buildTextMessageItem(messageContent: MessageTextContent,
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,16 +1,17 @@
|
||||||
package im.vector.matrix.android.api.session.room.model.message
|
package im.vector.matrix.android.api.session.room.model.message
|
||||||
|
|
||||||
|
import android.media.ExifInterface
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class ImageInfo(
|
data class ImageInfo(
|
||||||
@Json(name = "mimetype") val mimeType: String,
|
@Json(name = "mimetype") val mimeType: String,
|
||||||
@Json(name = "w") val width: Int,
|
@Json(name = "w") val width: Int = 0,
|
||||||
@Json(name = "h") val height: Int,
|
@Json(name = "h") val height: Int = 0,
|
||||||
@Json(name = "size") val size: Int,
|
@Json(name = "size") val size: Int = 0,
|
||||||
@Json(name = "rotation") val rotation: Int? = null,
|
@Json(name = "rotation") val rotation: Int = 0,
|
||||||
@Json(name = "orientation") val orientation: Int? = null,
|
@Json(name = "orientation") val orientation: Int = ExifInterface.ORIENTATION_NORMAL,
|
||||||
@Json(name = "thumbnail_info") val thumbnailInfo: ThumbnailInfo? = null,
|
@Json(name = "thumbnail_info") val thumbnailInfo: ThumbnailInfo? = null,
|
||||||
@Json(name = "thumbnail_url") val thumbnailUrl: String? = null
|
@Json(name = "thumbnail_url") val thumbnailUrl: String? = null
|
||||||
)
|
)
|
Loading…
Add table
Reference in a new issue