diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml index 15e2fc2fbb..04ed7fcc55 100644 --- a/library/ui-styles/src/main/res/values/dimens.xml +++ b/library/ui-styles/src/main/res/values/dimens.xml @@ -44,6 +44,7 @@ 8dp + 160dp 56dp diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/PreviewUrlData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/PreviewUrlData.kt index 33fc8b052b..bfba43a82d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/PreviewUrlData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/PreviewUrlData.kt @@ -47,5 +47,9 @@ data class PreviewUrlData( // Value of field "og:description" val description: String?, // Value of field "og:image" - val mxcUrl: String? + val mxcUrl: String?, + // Value of field "og:image:width" + val imageWidth: Int?, + // Value of field "og:image:height" + val imageHeight: Int? ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 1f45ac2a75..7a2511feac 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -56,7 +56,7 @@ internal class RealmSessionStoreMigration @Inject constructor( ) : RealmMigration { companion object { - const val SESSION_STORE_SCHEMA_VERSION = 21L + const val SESSION_STORE_SCHEMA_VERSION = 22L } /** @@ -90,6 +90,7 @@ internal class RealmSessionStoreMigration @Inject constructor( if (oldVersion <= 18) migrateTo19(realm) if (oldVersion <= 19) migrateTo20(realm) if (oldVersion <= 20) migrateTo21(realm) + if (oldVersion <= 21) migrateTo22(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -445,4 +446,15 @@ internal class RealmSessionStoreMigration @Inject constructor( } } } + + private fun migrateTo22(realm: DynamicRealm) { + Timber.d("Step 21 -> 22") + + realm.schema.get("PreviewUrlCacheEntity") + ?.addField(PreviewUrlCacheEntityFields.IMAGE_WIDTH, Int::class.java) + ?.setNullable(PreviewUrlCacheEntityFields.IMAGE_WIDTH, true) + ?.addField(PreviewUrlCacheEntityFields.IMAGE_HEIGHT, Int::class.java) + ?.setNullable(PreviewUrlCacheEntityFields.IMAGE_HEIGHT, true) + } + } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PreviewUrlCacheEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PreviewUrlCacheEntity.kt index b1e0b64405..f19d70a1f2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PreviewUrlCacheEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PreviewUrlCacheEntity.kt @@ -28,7 +28,8 @@ internal open class PreviewUrlCacheEntity( var title: String? = null, var description: String? = null, var mxcUrl: String? = null, - + var imageWidth: Int? = null, + var imageHeight: Int? = null, var lastUpdatedTimestamp: Long = 0L ) : RealmObject() { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt index e707c2351c..32bcf3f7ca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt @@ -48,8 +48,8 @@ internal class DefaultGetPreviewUrlTask @Inject constructor( override suspend fun execute(params: GetPreviewUrlTask.Params): PreviewUrlData { return when (params.cacheStrategy) { - CacheStrategy.NoCache -> doRequest(params.url, params.timestamp) - is CacheStrategy.TtlCache -> doRequestWithCache( + CacheStrategy.NoCache -> doRequest(params.url, params.timestamp) + is CacheStrategy.TtlCache -> doRequestWithCache( params.url, params.timestamp, params.cacheStrategy.validityDurationInMillis, @@ -77,7 +77,9 @@ internal class DefaultGetPreviewUrlTask @Inject constructor( siteName = (get("og:site_name") as? String)?.unescapeHtml(), title = (get("og:title") as? String)?.unescapeHtml(), description = (get("og:description") as? String)?.unescapeHtml(), - mxcUrl = get("og:image") as? String + mxcUrl = get("og:image") as? String, + imageHeight = (get("og:image:height") as? Double)?.toInt(), + imageWidth = (get("og:image:width") as? Double)?.toInt(), ) } @@ -114,7 +116,8 @@ internal class DefaultGetPreviewUrlTask @Inject constructor( previewUrlCacheEntity.title = data.title previewUrlCacheEntity.description = data.description previewUrlCacheEntity.mxcUrl = data.mxcUrl - + previewUrlCacheEntity.imageHeight = data.imageHeight + previewUrlCacheEntity.imageWidth = data.imageWidth previewUrlCacheEntity.lastUpdatedTimestamp = Date().time } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/PreviewUrlMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/PreviewUrlMapper.kt index dd1a9ead26..551dc29b92 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/PreviewUrlMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/PreviewUrlMapper.kt @@ -27,5 +27,7 @@ internal fun PreviewUrlCacheEntity.toDomain() = PreviewUrlData( siteName = siteName, title = title, description = description, - mxcUrl = mxcUrl + mxcUrl = mxcUrl, + imageWidth = imageWidth, + imageHeight = imageHeight ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt index 60fe1a4b2c..157749ab74 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt @@ -83,12 +83,7 @@ abstract class MessageTextItem : AbsMessageItem() { safePreviewUrlRetriever.addListener(attributes.informationData.eventId, previewUrlViewUpdater) } holder.previewUrlView.delegate = previewUrlCallback - val urlPreviewBackgroundColor = if (attributes.informationData.messageLayout is TimelineMessageLayout.Bubble) { - Color.TRANSPARENT - } else { - ThemeUtils.getColor(holder.view.context, R.attr.vctr_system) - } - holder.previewUrlView.setCardBackgroundColor(urlPreviewBackgroundColor) + holder.previewUrlView.render(attributes.informationData.messageLayout) if (useBigFont) { holder.messageView.textSize = 44F diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt index e41f62c373..905d420463 100755 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt @@ -17,14 +17,20 @@ package im.vector.app.features.home.room.detail.timeline.url import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Color import android.util.AttributeSet import android.view.View import androidx.core.view.isVisible import com.google.android.material.card.MaterialCardView import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide +import im.vector.app.core.glide.GlideApp +import im.vector.app.core.utils.DimensionConverter import im.vector.app.databinding.ViewUrlPreviewBinding import im.vector.app.features.home.room.detail.timeline.TimelineEventController +import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout +import im.vector.app.features.home.room.detail.timeline.view.TimelineMessageLayoutRenderer import im.vector.app.features.media.ImageContentRenderer import im.vector.app.features.themes.ThemeUtils import org.matrix.android.sdk.api.extensions.orFalse @@ -37,7 +43,7 @@ class PreviewUrlView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : MaterialCardView(context, attrs, defStyleAttr), View.OnClickListener { +) : MaterialCardView(context, attrs, defStyleAttr), View.OnClickListener, TimelineMessageLayoutRenderer { private lateinit var views: ViewUrlPreviewBinding @@ -75,6 +81,22 @@ class PreviewUrlView @JvmOverloads constructor( } } + override fun render(messageLayout: TimelineMessageLayout) { + when (messageLayout) { + is TimelineMessageLayout.Default -> { + val backgroundColor = ThemeUtils.getColor(context, R.attr.vctr_system) + setCardBackgroundColor(backgroundColor) + val guidelineBegin = DimensionConverter(resources).dpToPx(8) + views.urlPreviewStartGuideline.setGuidelineBegin(guidelineBegin) + } + is TimelineMessageLayout.Bubble -> { + setCardBackgroundColor(Color.TRANSPARENT) + rippleColor = ColorStateList.valueOf(Color.TRANSPARENT) + views.urlPreviewStartGuideline.setGuidelineBegin(0) + } + } + } + override fun onClick(v: View?) { when (val finalState = state) { is PreviewUrlUiState.Data -> delegate?.onPreviewUrlClicked(finalState.url) @@ -126,7 +148,7 @@ class PreviewUrlView @JvmOverloads constructor( isVisible = true views.urlPreviewTitle.setTextOrHide(previewUrlData.title) - views.urlPreviewImage.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, views.urlPreviewImage) }.orFalse() + views.urlPreviewImage.isVisible = imageContentRenderer.render(previewUrlData, views.urlPreviewImage) views.urlPreviewDescription.setTextOrHide(previewUrlData.description) views.urlPreviewDescription.maxLines = when { previewUrlData.mxcUrl != null -> 2 diff --git a/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt b/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt index be9d24272d..65c99362b9 100644 --- a/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/media/ImageContentRenderer.kt @@ -44,6 +44,7 @@ import im.vector.app.core.utils.DimensionConverter import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.content.ContentUrlResolver +import org.matrix.android.sdk.api.session.media.PreviewUrlData import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt import timber.log.Timber import java.io.File @@ -61,6 +62,9 @@ interface AttachmentData : Parcelable { val allowNonMxcUrls: Boolean } +private const val URL_PREVIEW_IMAGE_MIN_FULL_WIDTH_PX = 600 +private const val URL_PREVIEW_IMAGE_MIN_FULL_HEIGHT_PX = 315 + class ImageContentRenderer @Inject constructor(private val localFilesHelper: LocalFilesHelper, private val activeSessionHolder: ActiveSessionHolder, private val dimensionConverter: DimensionConverter) { @@ -89,12 +93,20 @@ class ImageContentRenderer @Inject constructor(private val localFilesHelper: Loc /** * For url preview */ - fun render(mxcUrl: String, imageView: ImageView): Boolean { + fun render(previewUrlData: PreviewUrlData, imageView: ImageView): Boolean { val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() - val imageUrl = contentUrlResolver.resolveFullSize(mxcUrl) ?: return false - + val imageUrl = contentUrlResolver.resolveFullSize(previewUrlData.mxcUrl) ?: return false + val maxHeight = dimensionConverter.resources.getDimensionPixelSize(R.dimen.preview_url_view_image_max_height) + val height = previewUrlData.imageHeight ?: URL_PREVIEW_IMAGE_MIN_FULL_HEIGHT_PX + val width = previewUrlData.imageWidth ?: URL_PREVIEW_IMAGE_MIN_FULL_WIDTH_PX + if (height < URL_PREVIEW_IMAGE_MIN_FULL_HEIGHT_PX || width < URL_PREVIEW_IMAGE_MIN_FULL_WIDTH_PX) { + imageView.scaleType = ImageView.ScaleType.CENTER_INSIDE + } else { + imageView.scaleType = ImageView.ScaleType.CENTER_CROP + } GlideApp.with(imageView) .load(imageUrl) + .override(width, height.coerceAtMost(maxHeight)) .into(imageView) return true } diff --git a/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml b/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml index 4bb612fedf..e2a11c7926 100644 --- a/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml +++ b/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml @@ -17,12 +17,11 @@ + tools:visibility="visible" /> diff --git a/vector/src/main/res/layout/view_url_preview.xml b/vector/src/main/res/layout/view_url_preview.xml index ff4ab1ed9a..e9774207ca 100644 --- a/vector/src/main/res/layout/view_url_preview.xml +++ b/vector/src/main/res/layout/view_url_preview.xml @@ -1,79 +1,102 @@ - + + + + android:orientation="vertical" + app:layout_constraintGuide_begin="8dp" /> - + + + - \ No newline at end of file