ref: add MXCImage

This commit is contained in:
2025-06-05 20:08:31 +03:00
parent 7a2567f019
commit 8ac9ccfaca
2 changed files with 86 additions and 25 deletions
@@ -0,0 +1,82 @@
/*
* Created by sweetbread
* Copyright (c) 2025. All rights reserved.
*/
package ru.risdeveau.pixeldragon.ui.item
import android.annotation.SuppressLint
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Warning
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import coil3.compose.AsyncImagePainter
import coil3.compose.rememberAsyncImagePainter
import coil3.network.NetworkHeaders
import coil3.network.httpHeaders
import coil3.request.ImageRequest
import ru.risdeveau.pixeldragon.api.mxcToUrl
import ru.risdeveau.pixeldragon.token
import splitties.init.appCtx
@SuppressLint("StateFlowValueCalledInComposition")
@Composable
fun MXCImage(
mxcUrl: String,
modifier: Modifier = Modifier,
contentDescription: String = ""
) {
data class ImageLoadState(
val isLoading: Boolean = false,
val isSuccess: Boolean = false,
val error: Throwable? = null
)
val loadState = remember { mutableStateOf(ImageLoadState()) }
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(appCtx)
.data(mxcToUrl(mxcUrl))
.httpHeaders(
NetworkHeaders.Builder()
.set("Authorization", "Bearer $token")
.set("Cache-Control", "max-age=86400")
.build()
)
.build(),
onState = { state ->
loadState.value = when (state) {
is AsyncImagePainter.State.Loading -> ImageLoadState(isLoading = true)
is AsyncImagePainter.State.Success -> ImageLoadState(isSuccess = true)
is AsyncImagePainter.State.Error -> ImageLoadState(error = state.result.throwable)
else -> ImageLoadState()
}
}
)
Box(
modifier = modifier,
contentAlignment = Alignment.Center
) {
Image(
painter = painter,
contentDescription = contentDescription,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
if (loadState.value.isLoading) {
CircularProgressIndicator()
} else if (loadState.value.error != null) {
Icon(Icons.Outlined.Warning, "Error")
}
}
}
@@ -18,7 +18,6 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -31,22 +30,15 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
import coil3.compose.SubcomposeAsyncImage
import coil3.network.NetworkHeaders
import coil3.network.httpHeaders
import coil3.request.ImageRequest
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import ru.risdeveau.pixeldragon.api.getRoom import ru.risdeveau.pixeldragon.api.getRoom
import ru.risdeveau.pixeldragon.api.getRooms import ru.risdeveau.pixeldragon.api.getRooms
import ru.risdeveau.pixeldragon.api.mxcToUrl
import ru.risdeveau.pixeldragon.db.Room import ru.risdeveau.pixeldragon.db.Room
import ru.risdeveau.pixeldragon.token import ru.risdeveau.pixeldragon.ui.item.MXCImage
import splitties.init.appCtx
@Composable @Composable
fun RoomList(modifier: Modifier = Modifier, navController: NavController) { fun RoomList(modifier: Modifier = Modifier, navController: NavController) {
@@ -111,7 +103,8 @@ fun RoomItem(modifier: Modifier = Modifier, rid: String, navController: NavContr
} }
.padding(8.dp) .padding(8.dp)
) { ) {
SubcomposeAsyncImage( MXCImage(
room!!.avatarUrl ?: "",
modifier = Modifier modifier = Modifier
.padding(end = 4.dp) .padding(end = 4.dp)
.height(52.dp) .height(52.dp)
@@ -121,21 +114,7 @@ fun RoomItem(modifier: Modifier = Modifier, rid: String, navController: NavContr
it.clip(RoundedCornerShape(12.dp)) it.clip(RoundedCornerShape(12.dp))
else else
it.clip(CircleShape) it.clip(CircleShape)
}, }
model = ImageRequest.Builder(appCtx)
.data(mxcToUrl(room!!.avatarUrl ?: ""))
.httpHeaders(
NetworkHeaders.Builder()
.set("Authorization", "Bearer $token")
.set("Cache-Control", "max-age=86400")
.build()
)
.build(),
contentDescription = room!!.roomId,
contentScale = ContentScale.Crop,
loading = {
CircularProgressIndicator()
}
) )
Column { Column {
Text( Text(