From 95f84cafb75818ad1a4a97fbf19d7e1ebb393eeb Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Wed, 23 Apr 2025 22:57:41 +0300 Subject: [PATCH] impr: show images in blogposts --- app/build.gradle.kts | 1 + .../ru/sweetbread/unn/ui/composes/Blogpost.kt | 92 ++++++++++++++++++- gradle/libs.versions.toml | 2 + 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 074c92c..d3400fa 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -116,6 +116,7 @@ dependencies { implementation(libs.ktor.client.logging) implementation(libs.ktor.client.android) implementation(libs.coil.compose) + implementation(libs.glide) implementation(libs.androidx.datastore.preferences) implementation(libs.splitties.base) 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 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 97521b8..fd0365d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ compose = "1.8.0" coreSplashscreen = "1.0.1" datastorePreferences = "1.1.5" desugar_jdk_libs = "2.1.5" +glide = "4.16.0" kotlin = "2.1.20" coreKtx = "1.16.0" junitVersion = "1.2.1" @@ -51,6 +52,7 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } ktor-client-android = { module = "io.ktor:ktor-client-android", version.ref = "ktor" } ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" } ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }