Moving clickable to Row and not AsyncImage because it's faster

This commit is contained in:
Vitor Pamplona
2023-05-06 19:19:57 -04:00
parent fdca0af97b
commit bba45dd0a7
3 changed files with 162 additions and 110 deletions
@@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.ui.note
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -54,7 +55,6 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
val accountState by accountViewModel.accountLiveData.observeAsState()
val account = accountState?.account ?: return
val noteEvent = note?.event
var popupExpanded by remember { mutableStateOf(false) }
if (note == null) {
@@ -160,12 +160,7 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
}
Row(Modifier.fillMaxWidth()) {
Box(
modifier = Modifier
.width(65.dp)
.padding(0.dp)
) {
}
Spacer(modifier = Modifier.width(65.dp))
NoteCompose(
baseNote = multiSetCard.note,
@@ -216,14 +211,16 @@ private fun AuthorPictureAndComment(
var content by remember { mutableStateOf<Pair<User, String?>>(Pair(author, null)) }
LaunchedEffect(key1 = zapRequest.idHex) {
(zapRequest.event as? LnZapRequestEvent)?.let {
val decryptedContent = accountViewModel.decryptZap(zapRequest)
if (decryptedContent != null) {
val author = LocalCache.getOrCreateUser(decryptedContent.pubKey)
content = Pair(author, decryptedContent.content)
} else {
if (!zapRequest.event?.content().isNullOrBlank()) {
content = Pair(author, zapRequest.event?.content())
withContext(Dispatchers.IO) {
(zapRequest.event as? LnZapRequestEvent)?.let {
val decryptedContent = accountViewModel.decryptZap(zapRequest)
if (decryptedContent != null) {
val author = LocalCache.getOrCreateUser(decryptedContent.pubKey)
content = Pair(author, decryptedContent.content)
} else {
if (!zapRequest.event?.content().isNullOrBlank()) {
content = Pair(author, zapRequest.event?.content())
}
}
}
}
@@ -246,10 +243,14 @@ private fun AuthorPictureAndComment(
Modifier
}
Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
Row(
modifier = modifier.clickable {
navController.navigate("User/${author.pubkeyHex}")
},
verticalAlignment = Alignment.CenterVertically
) {
FastNoteAuthorPicture(
author = author,
navController = navController,
userAccount = accountUser,
size = 35.dp
)
@@ -294,7 +295,6 @@ fun AuthorGallery(
@Composable
fun FastNoteAuthorPicture(
author: User,
navController: NavController,
userAccount: User,
size: Dp,
pictureModifier: Modifier = Modifier
@@ -303,14 +303,12 @@ fun FastNoteAuthorPicture(
val user = userState?.user ?: return
val showFollowingMark = userAccount.isFollowingCached(user) || user === userAccount
UserPicture(
userHex = user.pubkeyHex,
userPicture = user.profilePicture(),
showFollowingMark = showFollowingMark,
size = size,
modifier = pictureModifier,
onClick = {
navController.navigate("User/${user.pubkeyHex}")
}
modifier = pictureModifier
)
}
@@ -42,6 +42,7 @@ import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.get
import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.compose.AsyncImagePainter
import com.google.accompanist.flowlayout.FlowRow
import com.vitorpamplona.amethyst.NotificationCache
import com.vitorpamplona.amethyst.R
@@ -99,7 +100,7 @@ fun NoteCompose(
Log.d("Time", "Note Compose in $elapsed for ${baseNote.idHex} ${baseNote.event?.kind()} ${baseNote.event?.content()?.split("\n")?.get(0)?.take(100)}")
}
@OptIn(ExperimentalFoundationApi::class)
@OptIn(ExperimentalFoundationApi::class, ExperimentalTime::class)
@Composable
fun NoteComposeInner(
baseNote: Note,
@@ -199,12 +200,14 @@ fun NoteComposeInner(
}
Column(
modifier = modifier.combinedClickable(
onClick = {
routeFor(note, loggedIn)?.let { navController.navigate(it) }
},
onLongClick = { popupExpanded = true }
).background(backgroundColor)
modifier = modifier
.combinedClickable(
onClick = {
routeFor(note, loggedIn)?.let { navController.navigate(it) }
},
onLongClick = { popupExpanded = true }
)
.background(backgroundColor)
) {
Row(
modifier = Modifier
@@ -222,20 +225,26 @@ fun NoteComposeInner(
modifier = Modifier
.padding(start = if (!isBoostedNote && !isQuotedNote) 10.dp else 0.dp)
) {
FirstUserInfoRow(
baseNote = baseNote,
showAuthorPicture = isQuotedNote,
account = account,
accountViewModel = accountViewModel,
navController = navController
)
val (value, elapsed1) = measureTimedValue {
FirstUserInfoRow(
baseNote = baseNote,
showAuthorPicture = isQuotedNote,
account = account,
accountViewModel = accountViewModel,
navController = navController
)
}
Log.d("Time", "$elapsed1 Line 1 of each post ${noteEvent.content()}")
if (noteEvent !is RepostEvent && !makeItShort && !isQuotedNote) {
SecondUserInfoRow(
note,
account,
navController
)
val (value, elapsed2) = measureTimedValue {
SecondUserInfoRow(
note,
account,
navController
)
}
Log.d("Time", "$elapsed2 Line 2 of each post")
}
Spacer(modifier = Modifier.height(2.dp))
@@ -543,34 +552,46 @@ private fun RenderBadgeAward(
if (note.replyTo.isNullOrEmpty()) return
val noteEvent = note.event as? BadgeAwardEvent ?: return
var awardees by remember { mutableStateOf<List<User>>(listOf()) }
Text(text = stringResource(R.string.award_granted_to))
FlowRow(modifier = Modifier.padding(top = 5.dp)) {
noteEvent.awardees()
.map { LocalCache.getOrCreateUser(it) }
.forEach {
UserPicture(
user = it,
navController = navController,
userAccount = accountViewModel.userProfile(),
size = 35.dp
)
/*
LaunchedEffect(key1 = note) {
withContext(Dispatchers.IO) {
awardees = noteEvent.awardees().mapNotNull { hex ->
LocalCache.checkGetOrCreateUser(hex)
}
}
}
}
note.replyTo?.firstOrNull()?.let {
NoteCompose(
it,
modifier = Modifier,
isBoostedNote = false,
isQuotedNote = true,
unPackReply = false,
parentBackgroundColor = backgroundColor,
accountViewModel = accountViewModel,
navController = navController
)
}
FlowRow(modifier = Modifier.padding(top = 5.dp)) {
awardees.forEach { user ->
Row(modifier = Modifier.clickable {
navController.navigate("User/${user.pubkeyHex}")
},
verticalAlignment = Alignment.CenterVertically
) {
UserPicture(
baseUser = user,
baseUserAccount = accountViewModel.userProfile(),
size = 35.dp
)
}
}
}
note.replyTo?.firstOrNull()?.let {
NoteCompose(
it,
modifier = Modifier,
isBoostedNote = false,
isQuotedNote = true,
unPackReply = false,
parentBackgroundColor = backgroundColor,
accountViewModel = accountViewModel,
navController = navController
)
}*/
ReactionsRow(note, accountViewModel, navController)
@@ -762,34 +783,30 @@ private fun FirstUserInfoRow(
navController: NavController
) {
var moreActionsExpanded by remember { mutableStateOf(false) }
val context = LocalContext.current.applicationContext
val eventNote = baseNote.event ?: return
val time = baseNote.createdAt() ?: return
val loggedIn = account.userProfile()
Row(verticalAlignment = Alignment.CenterVertically) {
if (showAuthorPicture) {
NoteAuthorPicture(baseNote, navController, account.userProfile(), 25.dp)
NoteAuthorPicture(baseNote, navController, loggedIn, 25.dp)
Spacer(Modifier.padding(horizontal = 5.dp))
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
} else {
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
}
if (baseNote.event is RepostEvent) {
if (eventNote is RepostEvent) {
Text(
" ${stringResource(id = R.string.boosted)}",
fontWeight = FontWeight.Bold,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
} else {
baseNote.event?.let {
DisplayFollowingHashtagsInPost(it, account, navController)
}
DisplayFollowingHashtagsInPost(eventNote, account, navController)
}
Text(
timeAgo(baseNote.createdAt(), context = context),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
maxLines = 1
)
TimeAgo(time)
IconButton(
modifier = Modifier.size(24.dp),
@@ -812,6 +829,25 @@ private fun FirstUserInfoRow(
}
}
@Composable
fun TimeAgo(time: Long) {
val context = LocalContext.current
var timeStr by remember { mutableStateOf("") }
LaunchedEffect(key1 = time) {
withContext(Dispatchers.IO) {
timeStr = timeAgo(time, context = context)
}
}
Text(
timeStr,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
maxLines = 1
)
}
@Composable
private fun DrawAuthorImages(baseNote: Note, loggedIn: User, navController: NavController) {
val baseChannel = baseNote.channel()
@@ -963,7 +999,7 @@ fun DisplayFollowingHashtagsInPost(
) {
var firstTag by remember { mutableStateOf<String?>(null) }
LaunchedEffect(key1 = noteEvent) {
LaunchedEffect(key1 = noteEvent.id()) {
withContext(Dispatchers.IO) {
firstTag = noteEvent.firstIsTaggedHashes(account.followingTagSet())
}
@@ -1102,7 +1138,24 @@ fun DisplayReward(
fun BadgeDisplay(baseNote: Note) {
val background = MaterialTheme.colors.background
val badgeData = baseNote.event as? BadgeDefinitionEvent ?: return
var backgroundFromImage by remember { mutableStateOf(background) }
val image = badgeData.image()
val name = badgeData.name()
val description = badgeData.description()
var backgroundFromImage by remember { mutableStateOf(Pair(background, background)) }
var imageResult by remember { mutableStateOf<AsyncImagePainter.State.Success?>(null) }
LaunchedEffect(key1 = imageResult) {
withContext(Dispatchers.IO) {
imageResult?.let {
val backgroundColor = it.result.drawable.toBitmap(200, 200).copy(Bitmap.Config.ARGB_8888, false).get(0, 199)
val colorFromImage = Color(backgroundColor)
val textBackground = if (colorFromImage.luminance() > 0.5) lightColors().onBackground else darkColors().onBackground
backgroundFromImage = Pair(colorFromImage, textBackground)
}
}
}
Row(
modifier = Modifier
@@ -1113,26 +1166,25 @@ fun BadgeDisplay(baseNote: Note) {
MaterialTheme.colors.primary.copy(alpha = 0.32f),
CutCornerShape(20)
)
.background(backgroundFromImage)
.background(backgroundFromImage.first)
) {
Column {
badgeData.image()?.let {
image.let {
AsyncImage(
model = it,
contentDescription = stringResource(
R.string.badge_award_image_for,
it
name ?: ""
),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth(),
onSuccess = {
val backgroundColor = it.result.drawable.toBitmap(200, 200).copy(Bitmap.Config.ARGB_8888, false).get(0, 199)
backgroundFromImage = Color(backgroundColor)
imageResult = it
}
)
}
badgeData.name()?.let {
name?.let {
Text(
text = it,
style = MaterialTheme.typography.body1,
@@ -1140,11 +1192,11 @@ fun BadgeDisplay(baseNote: Note) {
modifier = Modifier
.fillMaxWidth()
.padding(start = 10.dp, end = 10.dp),
color = if (backgroundFromImage.luminance() > 0.5) lightColors().onBackground else darkColors().onBackground
color = backgroundFromImage.second
)
}
badgeData.description()?.let {
description?.let {
Text(
text = it,
style = MaterialTheme.typography.caption,
@@ -1499,6 +1551,7 @@ fun UserPicture(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun UserPicture(
baseUser: User,
@@ -1516,27 +1569,38 @@ fun UserPicture(
val showFollowingMark = accountUser.isFollowingCached(user) || user == accountUser
UserPicture(
userHex = user.pubkeyHex,
userPicture = user.profilePicture(),
showFollowingMark = showFollowingMark,
size = size,
modifier = modifier,
onClick = onClick?.let { { it(user) } },
onLongClick = onLongClick?.let { { it(user) } }
)
Row(
modifier = Modifier
.run {
if (onClick != null && onLongClick != null) {
this.combinedClickable(
onClick = { onClick(user) },
onLongClick = { onLongClick(user) }
)
} else if (onClick != null) {
this.clickable(onClick = { onClick(user) })
} else {
this
}
}
) {
UserPicture(
userHex = user.pubkeyHex,
userPicture = user.profilePicture(),
showFollowingMark = showFollowingMark,
size = size,
modifier = modifier
)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun UserPicture(
userHex: String,
userPicture: String?,
showFollowingMark: Boolean,
size: Dp,
modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null,
onLongClick: (() -> Unit)? = null
modifier: Modifier = Modifier
) {
Box(
Modifier
@@ -1552,16 +1616,6 @@ fun UserPicture(
.height(size)
.clip(shape = CircleShape)
.background(MaterialTheme.colors.background)
.run {
if (onClick != null && onLongClick != null) {
this.combinedClickable(onClick = onClick, onLongClick = onLongClick)
} else if (onClick != null) {
this.clickable(onClick = onClick)
} else {
this
}
}
)
if (showFollowingMark) {
@@ -175,7 +175,7 @@ private fun FeedLoaded(
)
}
}
Log.d("Time", "${item.javaClass.simpleName} Feed in $elapsed")
Log.d("Time", "${item.javaClass.simpleName} Feed in $elapsed ${item.id()}")
}
}
}