From bd9229bb645a823474921bf29772f6cc691f130d Mon Sep 17 00:00:00 2001 From: dankito Date: Thu, 12 Sep 2024 11:05:07 +0200 Subject: [PATCH] Saving retrieved images to disk on Android and Desktop --- .../net/codinux/banking/ui/MainActivity.kt | 3 ++ .../ui/service/ImageService.android.kt | 37 ++++++++++++++++++- .../banking/ui/composables/BankIcon.kt | 5 +-- .../ui/service/ImageService.desktop.kt | 30 ++++++++++++++- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/MainActivity.kt b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/MainActivity.kt index 25440e7..7eb44dd 100644 --- a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/MainActivity.kt @@ -9,11 +9,14 @@ import app.cash.sqldelight.async.coroutines.synchronous import app.cash.sqldelight.driver.android.AndroidSqliteDriver import net.codinux.banking.dataaccess.BankmeisterDb import net.codinux.banking.ui.config.DI +import net.codinux.banking.ui.service.ImageService class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + ImageService.context = this.applicationContext + DI.setRepository(AndroidSqliteDriver(BankmeisterDb.Schema.synchronous(), this, "Bankmeister.db")) setContent { diff --git a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/service/ImageService.android.kt b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/service/ImageService.android.kt index 97a2010..f64030d 100644 --- a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/service/ImageService.android.kt +++ b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/service/ImageService.android.kt @@ -1,12 +1,45 @@ package net.codinux.banking.ui.service +import android.content.Context import android.graphics.BitmapFactory import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap +import net.codinux.log.Log +import java.io.File import java.net.URL +import java.security.MessageDigest + + +object ImageService { + + lateinit var context: Context + +} + +private val cacheDir by lazy { File(ImageService.context.cacheDir, "imageCache").also { it.mkdirs() } } + +private val messageDigest = MessageDigest.getInstance("SHA-256") actual fun createImageBitmap(imageBytes: ByteArray): ImageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size).asImageBitmap() -actual suspend fun fetchBytesFromUrl(url: String): ByteArray = - URL(url).openStream().buffered().use { it.readBytes() } \ No newline at end of file +actual suspend fun fetchBytesFromUrl(url: String): ByteArray { + var imageFile: File? = null + try { + val urlHash = messageDigest.digest(url.toByteArray()) + .joinToString("") { "%02x".format(it) } + imageFile = File(cacheDir, urlHash) + + if (imageFile.exists()) { + return imageFile.readBytes() + } + } catch (e: Throwable) { + Log.error(e) { "Could not create SHA-256 or read image bytes from file for url '$url'" } + } + + val imageBytes = URL(url).openStream().buffered().use { it.readBytes() } + + imageFile?.writeBytes(imageBytes) + + return imageBytes +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt index 2e723a5..1808961 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt @@ -5,10 +5,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.material.Icon import androidx.compose.material.LocalContentAlpha import androidx.compose.material.LocalContentColor -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector diff --git a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/service/ImageService.desktop.kt b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/service/ImageService.desktop.kt index 3b66d18..52b0434 100644 --- a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/service/ImageService.desktop.kt +++ b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/service/ImageService.desktop.kt @@ -2,11 +2,37 @@ package net.codinux.banking.ui.service import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.toComposeImageBitmap +import net.codinux.log.Log import org.jetbrains.skia.Image +import java.io.File import java.net.URL +import java.security.MessageDigest + + +private val cacheDir = File("data/imageCache").also { it.mkdirs() } + +private val messageDigest = MessageDigest.getInstance("SHA-256") actual fun createImageBitmap(imageBytes: ByteArray): ImageBitmap = Image.makeFromEncoded(imageBytes).toComposeImageBitmap() -actual suspend fun fetchBytesFromUrl(url: String): ByteArray = - URL(url).openStream().buffered().use { it.readAllBytes() } \ No newline at end of file +actual suspend fun fetchBytesFromUrl(url: String): ByteArray { + var imageFile: File? = null + try { + val urlHash = messageDigest.digest(url.toByteArray()) + .joinToString("") { "%02x".format(it) } + imageFile = File(cacheDir, urlHash) + + if (imageFile.exists()) { + return imageFile.readBytes() + } + } catch (e: Throwable) { + Log.error(e) { "Could not create SHA-256 or read image bytes from file for url '$url'" } + } + + val imageBytes = URL(url).openStream().buffered().use { it.readAllBytes() } + + imageFile?.writeBytes(imageBytes) + + return imageBytes +} \ No newline at end of file