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:
parent
deb0b8be61
commit
ed5d6a0633
7 changed files with 99 additions and 60 deletions
|
@ -11,7 +11,9 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
||||
@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(
|
||||
modifier: Modifier = Modifier,
|
||||
bitmap: ImageBitmap? = null,
|
||||
|
|
|
@ -16,7 +16,9 @@ import eu.steffo.twom.utils.BitmapUtilities
|
|||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@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(
|
||||
modifier: Modifier = Modifier,
|
||||
fallbackText: String = "?",
|
||||
|
@ -31,10 +33,7 @@ fun AvatarPicker(
|
|||
rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) ImageSelect@{
|
||||
it ?: return@ImageSelect
|
||||
|
||||
val rawBitmap = BitmapUtilities.getRawBitmap(resolver, it) ?: return@ImageSelect
|
||||
val orientation = BitmapUtilities.getOrientation(resolver, it) ?: return@ImageSelect
|
||||
|
||||
val correctedBitmap = BitmapUtilities.squareAndOrient(rawBitmap, orientation)
|
||||
val correctedBitmap = BitmapUtilities.getCorrectedBitmap(resolver, it)
|
||||
|
||||
onPick(correctedBitmap)
|
||||
}
|
||||
|
|
|
@ -1,22 +1,14 @@
|
|||
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.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.graphics.asImageBitmap
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import eu.steffo.twom.composables.matrix.LocalSession
|
||||
import java.io.File
|
||||
|
||||
@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(
|
||||
modifier: Modifier = Modifier,
|
||||
url: String? = "",
|
||||
|
@ -24,49 +16,9 @@ fun AvatarURL(
|
|||
contentDescription: String = "",
|
||||
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(
|
||||
modifier = modifier,
|
||||
bitmap = bitmap?.asImageBitmap(),
|
||||
bitmap = bitmapFromMatrixFile(url)?.asImageBitmap(),
|
||||
fallbackText = fallbackText,
|
||||
contentDescription = contentDescription,
|
||||
alpha = alpha,
|
||||
|
|
|
@ -7,7 +7,9 @@ import org.matrix.android.sdk.api.session.user.model.User
|
|||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
|
||||
@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(
|
||||
modifier: Modifier = Modifier,
|
||||
user: User? = null,
|
||||
|
|
|
@ -12,7 +12,9 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import eu.steffo.twom.composables.matrix.LocalSession
|
||||
|
||||
@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(
|
||||
modifier: Modifier = Modifier,
|
||||
userId: String = "",
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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 {
|
||||
val file = File.createTempFile("bitmap_$id", ".jpg")
|
||||
file.outputStream().use {
|
||||
|
|
Loading…
Reference in a new issue