1
Fork 0
mirror of https://github.com/Steffo99/twom.git synced 2024-11-21 23:54:26 +00:00

Image refactors and improvements

This commit is contained in:
Steffo 2024-01-30 04:30:56 +01:00
parent deb0b8be61
commit ed5d6a0633
Signed by: steffo
GPG key ID: 5ADA3868646C3FC0
7 changed files with 99 additions and 60 deletions

View file

@ -11,7 +11,9 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@Composable @Composable
@Preview(widthDp = 40, heightDp = 40) @Preview(name = "Regular", widthDp = 40, heightDp = 40)
@Preview(name = "Double font scale", widthDp = 40, heightDp = 40, fontScale = 2f)
@Preview(name = "Quadruple font scale", widthDp = 40, heightDp = 40, fontScale = 4f)
fun AvatarImage( fun AvatarImage(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
bitmap: ImageBitmap? = null, bitmap: ImageBitmap? = null,

View file

@ -16,7 +16,9 @@ import eu.steffo.twom.utils.BitmapUtilities
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
@Preview(widthDp = 40, heightDp = 40) @Preview(name = "Regular", widthDp = 40, heightDp = 40)
@Preview(name = "Double font scale", widthDp = 40, heightDp = 40, fontScale = 2f)
@Preview(name = "Quadruple font scale", widthDp = 40, heightDp = 40, fontScale = 4f)
fun AvatarPicker( fun AvatarPicker(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
fallbackText: String = "?", fallbackText: String = "?",
@ -31,10 +33,7 @@ fun AvatarPicker(
rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) ImageSelect@{ rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) ImageSelect@{
it ?: return@ImageSelect it ?: return@ImageSelect
val rawBitmap = BitmapUtilities.getRawBitmap(resolver, it) ?: return@ImageSelect val correctedBitmap = BitmapUtilities.getCorrectedBitmap(resolver, it)
val orientation = BitmapUtilities.getOrientation(resolver, it) ?: return@ImageSelect
val correctedBitmap = BitmapUtilities.squareAndOrient(rawBitmap, orientation)
onPick(correctedBitmap) onPick(correctedBitmap)
} }

View file

@ -1,22 +1,14 @@
package eu.steffo.twom.composables.avatar package eu.steffo.twom.composables.avatar
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Log
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import eu.steffo.twom.composables.matrix.LocalSession
import java.io.File
@Composable @Composable
@Preview(widthDp = 40, heightDp = 40) @Preview(name = "Regular", widthDp = 40, heightDp = 40)
@Preview(name = "Double font scale", widthDp = 40, heightDp = 40, fontScale = 2f)
@Preview(name = "Quadruple font scale", widthDp = 40, heightDp = 40, fontScale = 4f)
fun AvatarURL( fun AvatarURL(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
url: String? = "", url: String? = "",
@ -24,49 +16,9 @@ fun AvatarURL(
contentDescription: String = "", contentDescription: String = "",
alpha: Float = 1.0f, alpha: Float = 1.0f,
) { ) {
val session = LocalSession.current
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
LaunchedEffect(session, url) GetAvatar@{
if (session == null) {
Log.d("AvatarURL", "Not doing anything, session is null.")
bitmap = null
return@GetAvatar
}
if (url == null) {
Log.d("AvatarURL", "URL is null, not downloading anything.")
bitmap = null
return@GetAvatar
}
if (url.isEmpty()) {
Log.d("AvatarURL", "URL is a zero-length string, not downloading anything.")
bitmap = null
return@GetAvatar
}
Log.d("AvatarURL", "Downloading avatar at: $url")
lateinit var avatarFile: File
try {
avatarFile = session.fileService().downloadFile(
fileName = "avatar",
url = url,
mimeType = null,
elementToDecrypt = null,
)
} catch (e: Throwable) {
Log.e("AvatarURL", "Unable to download avatar at: $url", e)
return@GetAvatar
}
// TODO: Should I check the MIME type? And the size of the image?
// FIXME: I feel this might be a race condition...
Log.d("AvatarURL", "File for $url is: $avatarFile")
bitmap = BitmapFactory.decodeFile(avatarFile.absolutePath)
}
AvatarImage( AvatarImage(
modifier = modifier, modifier = modifier,
bitmap = bitmap?.asImageBitmap(), bitmap = bitmapFromMatrixFile(url)?.asImageBitmap(),
fallbackText = fallbackText, fallbackText = fallbackText,
contentDescription = contentDescription, contentDescription = contentDescription,
alpha = alpha, alpha = alpha,

View file

@ -7,7 +7,9 @@ import org.matrix.android.sdk.api.session.user.model.User
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
@Composable @Composable
@Preview(widthDp = 40, heightDp = 40) @Preview(name = "Regular", widthDp = 40, heightDp = 40)
@Preview(name = "Double font scale", widthDp = 40, heightDp = 40, fontScale = 2f)
@Preview(name = "Quadruple font scale", widthDp = 40, heightDp = 40, fontScale = 4f)
fun AvatarUser( fun AvatarUser(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
user: User? = null, user: User? = null,

View file

@ -12,7 +12,9 @@ import androidx.compose.ui.tooling.preview.Preview
import eu.steffo.twom.composables.matrix.LocalSession import eu.steffo.twom.composables.matrix.LocalSession
@Composable @Composable
@Preview(widthDp = 40, heightDp = 40) @Preview(name = "Regular", widthDp = 40, heightDp = 40)
@Preview(name = "Double font scale", widthDp = 40, heightDp = 40, fontScale = 2f)
@Preview(name = "Quadruple font scale", widthDp = 40, heightDp = 40, fontScale = 4f)
fun AvatarUserId( fun AvatarUserId(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
userId: String = "", userId: String = "",

View file

@ -0,0 +1,76 @@
package eu.steffo.twom.composables.avatar
import android.graphics.Bitmap
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.core.net.toUri
import eu.steffo.twom.composables.matrix.LocalSession
import eu.steffo.twom.utils.BitmapUtilities
import kotlinx.coroutines.CancellationException
import org.matrix.android.sdk.api.util.md5
import java.io.File
const val TAG = "bitmapFromMatrixFile"
@Composable
fun bitmapFromMatrixFile(url: String? = null): Bitmap? {
val session = LocalSession.current
val resolver = LocalContext.current.contentResolver
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
Log.v(TAG, "Compositing: $url")
// LaunchedEffect does not behave as expected: sometimes, the effect is cancelled, but not relaunched!
LaunchedEffect(session, url) Fetch@{
Log.v(TAG, "Launching: $url")
if (session == null) {
Log.d(TAG, "Session is null, clearing bitmap.")
bitmap = null
return@Fetch
}
if (url == null) {
Log.d(TAG, "URL is null, clearing bitmap.")
bitmap = null
return@Fetch
}
if (url.isEmpty()) {
Log.d(TAG, "URL is a zero-length string, clearing bitmap.")
bitmap = null
return@Fetch
}
Log.i(TAG, "Downloading file at: $url")
lateinit var avatarFile: File
try {
avatarFile = session.fileService().downloadFile(
fileName = url.md5(),
url = url,
mimeType = null,
elementToDecrypt = null,
)
} catch (e: CancellationException) {
// This makes sure no corrupt image is displayed, at least
Log.i(TAG, "Cancelled download of file at: $url", e)
bitmap = null
return@Fetch
} catch (e: Throwable) {
Log.e(TAG, "Unable to download file at: $url", e)
bitmap = null
return@Fetch
}
Log.d(TAG, "File for $url is: $avatarFile")
bitmap = BitmapUtilities.getCorrectedBitmap(resolver, avatarFile.toUri())
}
return bitmap
}

View file

@ -106,6 +106,12 @@ class BitmapUtilities {
) )
} }
fun getCorrectedBitmap(resolver: ContentResolver, uri: Uri): Bitmap? {
val rawBitmap = getRawBitmap(resolver, uri) ?: return null
val orientation = getOrientation(resolver, uri) ?: return null
return squareAndOrient(rawBitmap, orientation)
}
fun bitmapToCache(id: String, bitmap: Bitmap): File { fun bitmapToCache(id: String, bitmap: Bitmap): File {
val file = File.createTempFile("bitmap_$id", ".jpg") val file = File.createTempFile("bitmap_$id", ".jpg")
file.outputStream().use { file.outputStream().use {