From d0347426c327de07881713c07d5a3973f9d08ed2 Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Wed, 23 Apr 2025 19:57:41 +0300 Subject: [PATCH] impr: show images in blogposts --- .../ru/sweetbread/unn/ui/composes/Blogpost.kt | 92 ++++++++++++++++++- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/ru/sweetbread/unn/ui/composes/Blogpost.kt b/app/src/main/java/ru/sweetbread/unn/ui/composes/Blogpost.kt index f70bea2..3ec3825 100644 --- a/app/src/main/java/ru/sweetbread/unn/ui/composes/Blogpost.kt +++ b/app/src/main/java/ru/sweetbread/unn/ui/composes/Blogpost.kt @@ -5,8 +5,12 @@ package ru.sweetbread.unn.ui.composes +import android.graphics.drawable.Drawable +import android.text.Html +import android.text.method.LinkMovementMethod import android.text.util.Linkify import android.util.Log +import android.widget.TextView import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -43,11 +47,11 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.text.HtmlCompat import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodel.compose.viewModel +import coil.ImageLoader import coil.compose.AsyncImage -import com.google.android.material.textview.MaterialTextView +import coil.request.ImageRequest import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -196,8 +200,10 @@ fun PostItem(modifier: Modifier = Modifier, post: Post, extended: Boolean = fals val linkColor = MaterialTheme.colorScheme.primary.toArgb() AndroidView( + modifier = Modifier, factory = { - MaterialTextView(it).apply { + TextView(it).apply { + movementMethod = LinkMovementMethod.getInstance() autoLinkMask = Linkify.WEB_URLS linksClickable = true setTextColor(textColor) @@ -206,7 +212,12 @@ fun PostItem(modifier: Modifier = Modifier, post: Post, extended: Boolean = fals }, update = { it.maxLines = if (extended) Int.MAX_VALUE else 5 - it.text = HtmlCompat.fromHtml(html, 0) + it.text = Html.fromHtml( + html, + Html.FROM_HTML_MODE_LEGACY, + CoilImageGetter(it), + null + ) } ) @@ -257,4 +268,77 @@ fun PostItemPreview() { ) } } +} + + +class CoilImageGetter( + private val textView: TextView, + private val maxImageWidth: Int = textView.width +) : Html.ImageGetter { + + override fun getDrawable(source: String): Drawable { + val urlDrawable = UrlDrawable() + + if (maxImageWidth <= 0) + textView.post { updateImage(source, urlDrawable, textView.width) } + else + updateImage(source, urlDrawable, maxImageWidth) + + return urlDrawable + } + + private fun updateImage(source: String, urlDrawable: UrlDrawable, maxWidth: Int) { + val imageLoader = ImageLoader.Builder(textView.context) + .build() + + val request = ImageRequest.Builder(textView.context) + .data(source) + .target { drawable -> + val (scaledWidth, scaledHeight) = calculateScaledSize( + drawable.intrinsicWidth, + drawable.intrinsicHeight, + maxWidth + ) + + drawable.setBounds(0, 0, scaledWidth, scaledHeight) + urlDrawable.drawable = drawable + urlDrawable.setBounds(0, 0, scaledWidth, scaledHeight) + + textView.text = textView.text + } + .build() + + imageLoader.enqueue(request) + } + + private fun calculateScaledSize( + originalWidth: Int, + originalHeight: Int, + maxWidth: Int + ): Pair { + if (originalWidth <= maxWidth) + return Pair(originalWidth, originalHeight) + + val ratio = maxWidth.toFloat() / originalWidth.toFloat() + return Pair( + maxWidth, + (originalHeight * ratio).toInt() + ) + } +} + +class UrlDrawable() : Drawable() { + var drawable: Drawable? = null + set(value) { + field = value + invalidateSelf() + } + + override fun draw(canvas: android.graphics.Canvas) { + drawable?.draw(canvas) + } + + override fun setAlpha(alpha: Int) {} + override fun setColorFilter(colorFilter: android.graphics.ColorFilter?) {} + override fun getOpacity(): Int = android.graphics.PixelFormat.TRANSLUCENT } \ No newline at end of file