diff --git a/app/src/main/java/ru/risdeveau/pixeldragon/ui/item/Image.kt b/app/src/main/java/ru/risdeveau/pixeldragon/ui/item/Image.kt new file mode 100755 index 0000000..87d3c25 --- /dev/null +++ b/app/src/main/java/ru/risdeveau/pixeldragon/ui/item/Image.kt @@ -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") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Rooms.kt b/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Rooms.kt index 19a62ee..16c0d41 100755 --- a/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Rooms.kt +++ b/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Rooms.kt @@ -18,7 +18,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -31,22 +30,15 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.dp 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.launch import kotlinx.coroutines.withContext import ru.risdeveau.pixeldragon.api.getRoom import ru.risdeveau.pixeldragon.api.getRooms -import ru.risdeveau.pixeldragon.api.mxcToUrl import ru.risdeveau.pixeldragon.db.Room -import ru.risdeveau.pixeldragon.token -import splitties.init.appCtx +import ru.risdeveau.pixeldragon.ui.item.MXCImage @Composable fun RoomList(modifier: Modifier = Modifier, navController: NavController) { @@ -111,7 +103,8 @@ fun RoomItem(modifier: Modifier = Modifier, rid: String, navController: NavContr } .padding(8.dp) ) { - SubcomposeAsyncImage( + MXCImage( + room!!.avatarUrl ?: "", modifier = Modifier .padding(end = 4.dp) .height(52.dp) @@ -121,21 +114,7 @@ fun RoomItem(modifier: Modifier = Modifier, rid: String, navController: NavContr it.clip(RoundedCornerShape(12.dp)) else 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 { Text(