Allows Base64 images on profiles.
This commit is contained in:
@@ -1,7 +1,13 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.components
|
package com.vitorpamplona.amethyst.ui.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.net.Uri
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -11,9 +17,19 @@ import androidx.compose.ui.graphics.FilterQuality
|
|||||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.core.graphics.drawable.toDrawable
|
||||||
|
import coil.ImageLoader
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.compose.AsyncImagePainter
|
import coil.compose.AsyncImagePainter
|
||||||
import coil.compose.rememberAsyncImagePainter
|
import coil.compose.rememberAsyncImagePainter
|
||||||
|
import coil.decode.DataSource
|
||||||
|
import coil.fetch.DrawableResult
|
||||||
|
import coil.fetch.FetchResult
|
||||||
|
import coil.fetch.Fetcher
|
||||||
|
import coil.request.ImageRequest
|
||||||
|
import coil.request.Options
|
||||||
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
|
import java.util.Base64
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RobohashAsyncImage(
|
fun RobohashAsyncImage(
|
||||||
@@ -67,19 +83,40 @@ fun RobohashFallbackAsyncImage(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (model != null && loadProfilePicture) {
|
if (model != null && loadProfilePicture) {
|
||||||
AsyncImage(
|
val isBase64 by remember {
|
||||||
model = model,
|
derivedStateOf {
|
||||||
contentDescription = contentDescription,
|
model.startsWith("data:image/jpeg;base64,")
|
||||||
modifier = modifier,
|
}
|
||||||
placeholder = painter,
|
}
|
||||||
fallback = painter,
|
|
||||||
error = painter,
|
if (isBase64) {
|
||||||
alignment = alignment,
|
val painter = rememberAsyncImagePainter(
|
||||||
contentScale = contentScale,
|
model = Base64Requester.imageRequest(context, model)
|
||||||
alpha = alpha,
|
)
|
||||||
colorFilter = colorFilter,
|
|
||||||
filterQuality = filterQuality
|
Image(
|
||||||
)
|
painter = painter,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = modifier,
|
||||||
|
alignment = alignment,
|
||||||
|
contentScale = contentScale,
|
||||||
|
colorFilter = colorFilter
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AsyncImage(
|
||||||
|
model = model,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
modifier = modifier,
|
||||||
|
placeholder = painter,
|
||||||
|
fallback = painter,
|
||||||
|
error = painter,
|
||||||
|
alignment = alignment,
|
||||||
|
contentScale = contentScale,
|
||||||
|
alpha = alpha,
|
||||||
|
colorFilter = colorFilter,
|
||||||
|
filterQuality = filterQuality
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Image(
|
Image(
|
||||||
painter = painter,
|
painter = painter,
|
||||||
@@ -118,3 +155,45 @@ fun RobohashAsyncImageProxy(
|
|||||||
loadProfilePicture = loadProfilePicture
|
loadProfilePicture = loadProfilePicture
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Base64Requester {
|
||||||
|
fun imageRequest(context: Context, message: String): ImageRequest {
|
||||||
|
return ImageRequest
|
||||||
|
.Builder(context)
|
||||||
|
.data(message)
|
||||||
|
.fetcherFactory(Base64Fetcher.Factory)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
class Base64Fetcher(
|
||||||
|
private val options: Options,
|
||||||
|
private val data: Uri
|
||||||
|
) : Fetcher {
|
||||||
|
|
||||||
|
override suspend fun fetch(): FetchResult {
|
||||||
|
checkNotInMainThread()
|
||||||
|
|
||||||
|
val base64String = data.toString().removePrefix("data:image/jpeg;base64,")
|
||||||
|
|
||||||
|
val byteArray = Base64.getDecoder().decode(base64String)
|
||||||
|
val bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
|
||||||
|
|
||||||
|
if (bitmap == null) {
|
||||||
|
throw Exception("Unable to load base64 $base64String")
|
||||||
|
}
|
||||||
|
|
||||||
|
return DrawableResult(
|
||||||
|
drawable = bitmap.toDrawable(options.context.resources),
|
||||||
|
isSampled = false,
|
||||||
|
dataSource = DataSource.MEMORY
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Factory : Fetcher.Factory<Uri> {
|
||||||
|
override fun create(data: Uri, options: Options, imageLoader: ImageLoader): Fetcher {
|
||||||
|
return Base64Fetcher(options, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user