Improves rendering of chat messages when scrolling.

This commit is contained in:
Vitor Pamplona
2023-06-21 10:23:49 -04:00
parent fbe0f584af
commit 6fe66986be
4 changed files with 137 additions and 84 deletions
@@ -502,35 +502,49 @@ private fun StatusRow(
onWantsToReply: (Note) -> Unit
) {
val grayTint = MaterialTheme.colors.placeholderText
val time = remember { baseNote.createdAt() ?: 0 }
Row(verticalAlignment = Alignment.CenterVertically) {
ChatTimeAgo(time)
RelayBadges(baseNote)
Spacer(modifier = DoubleHorzSpacer)
Column() {
Row(verticalAlignment = Alignment.CenterVertically) {
ChatTimeAgo(baseNote)
RelayBadges(baseNote)
Spacer(modifier = DoubleHorzSpacer)
}
}
Row(verticalAlignment = Alignment.CenterVertically) {
LikeReaction(baseNote, grayTint, accountViewModel)
Spacer(modifier = StdHorzSpacer)
ZapReaction(baseNote, grayTint, accountViewModel)
Spacer(modifier = StdHorzSpacer)
ReplyReaction(baseNote, grayTint, accountViewModel, showCounter = false, iconSize = Size16dp) {
onWantsToReply(baseNote)
Column() {
Row(verticalAlignment = Alignment.CenterVertically) {
LikeReaction(baseNote, grayTint, accountViewModel)
Spacer(modifier = StdHorzSpacer)
ZapReaction(baseNote, grayTint, accountViewModel)
Spacer(modifier = StdHorzSpacer)
ReplyReaction(
baseNote,
grayTint,
accountViewModel,
showCounter = false,
iconSize = Size16dp
) {
onWantsToReply(baseNote)
}
}
}
}
@Composable
fun ChatTimeAgo(time: Long) {
fun ChatTimeAgo(baseNote: Note) {
val context = LocalContext.current
val timeStr = remember { timeAgoShort(time, context = context) }
val timeStr by remember(baseNote) {
derivedStateOf {
timeAgoShort(baseNote.createdAt() ?: 0, context = context)
}
}
Text(
timeStr,
text = timeStr,
color = MaterialTheme.colors.placeholderText,
fontSize = 12.sp
fontSize = 12.sp,
maxLines = 1
)
}
@@ -159,7 +159,6 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toImmutableSet
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import nostr.postr.toNpub
import java.io.File
import java.math.BigDecimal
@@ -1282,8 +1281,14 @@ fun DisplayPeopleList(
members.take(3)
}
val name by remember {
derivedStateOf {
"#${noteEvent.dTag()}"
}
}
Text(
text = "#${noteEvent.dTag()}",
text = name,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -1385,7 +1390,7 @@ private fun RenderBadgeAward(
}
if (awardees.size > 100) {
Text(" and ${awardees.size - 100} others")
Text(" and ${awardees.size - 100} others", maxLines = 1)
}
}
@@ -1427,7 +1432,8 @@ private fun RenderReaction(
if (note.event?.content() == "+") "" else note.event?.content() ?: ""
Text(
text = refactorReactionText
text = refactorReactionText,
maxLines = 1
)
}
@@ -1778,7 +1784,8 @@ private fun FirstUserInfoRow(
Text(
" ${stringResource(id = R.string.boosted)}",
fontWeight = FontWeight.Bold,
color = MaterialTheme.colors.placeholderText
color = MaterialTheme.colors.placeholderText,
maxLines = 1
)
} else {
DisplayFollowingHashtagsInPost(eventNote, accountViewModel, nav)
@@ -1832,7 +1839,7 @@ fun TimeAgo(time: Long) {
}
Text(
timeStr,
text = timeStr,
color = MaterialTheme.colors.placeholderText,
maxLines = 1
)
@@ -1990,54 +1997,78 @@ fun DisplayHighlight(
nav
)
var userBase by remember { mutableStateOf<User?>(null) }
authorHex?.let {
DisplayQuoteAuthor(authorHex, url, nav)
}
}
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
if (authorHex != null) {
@Composable
@OptIn(ExperimentalLayoutApi::class)
private fun DisplayQuoteAuthor(
authorHex: String,
url: String?,
nav: (String) -> Unit
) {
var userBase by remember { mutableStateOf<User?>(LocalCache.getUserIfExists(authorHex)) }
if (userBase == null) {
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
userBase = LocalCache.checkGetOrCreateUser(authorHex)
}
}
}
FlowRow() {
authorHex?.let { authorHex ->
userBase?.let { userBase ->
val userState by userBase.live().metadata.observeAsState()
val route = remember { "User/${userBase.pubkeyHex}" }
val userDisplayName = remember(userState) { userState?.user?.toBestDisplayName() }
val userTags = remember(userState) { userState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists() }
if (userDisplayName != null) {
CreateClickableTextWithEmoji(
clickablePart = userDisplayName,
suffix = " ",
tags = userTags,
route = route,
nav = nav
)
}
}
Row() {
userBase?.let { userBase ->
LoadAndDisplayUser(userBase, nav)
}
url?.let { url ->
val validatedUrl = remember {
try {
URL(url)
} catch (e: Exception) {
Log.w("Note Compose", "Invalid URI: $url")
null
}
}
validatedUrl?.host?.let { host ->
Text("on ")
ClickableUrl(urlText = host, url = url)
}
LoadAndDisplayUrl(url)
}
}
}
@Composable
private fun LoadAndDisplayUrl(url: String) {
val validatedUrl = remember {
try {
URL(url)
} catch (e: Exception) {
Log.w("Note Compose", "Invalid URI: $url")
null
}
}
validatedUrl?.host?.let { host ->
Text(remember { "on " }, maxLines = 1)
ClickableUrl(urlText = host, url = url)
}
}
@Composable
private fun LoadAndDisplayUser(
userBase: User,
nav: (String) -> Unit
) {
val userState by userBase.live().metadata.observeAsState()
val route = remember { "User/${userBase.pubkeyHex}" }
val userDisplayName = remember(userState) { userState?.user?.toBestDisplayName() }
val userTags =
remember(userState) { userState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists() }
if (userDisplayName != null) {
CreateClickableTextWithEmoji(
clickablePart = userDisplayName,
suffix = " ",
tags = userTags,
route = route,
nav = nav
)
}
}
@Composable
fun DisplayFollowingHashtagsInPost(
noteEvent: EventInterface,
@@ -2071,7 +2102,8 @@ fun DisplayFollowingHashtagsInPost(
color = MaterialTheme.colors.primary.copy(
alpha = 0.52f
)
)
),
maxLines = 1
)
}
}
@@ -2120,7 +2152,8 @@ fun DisplayPoW(
alpha = 0.52f
),
fontSize = 14.sp,
fontWeight = FontWeight.Bold
fontWeight = FontWeight.Bold,
maxLines = 1
)
}
@@ -2214,7 +2247,8 @@ private fun RenderPledgeAmount(
Text(
text = reward,
color = MaterialTheme.colors.placeholderText
color = MaterialTheme.colors.placeholderText,
maxLines = 1
)
}
@@ -2421,7 +2455,7 @@ fun AudioTrackHeader(noteEvent: AudioTrackEvent, accountViewModel: AccountViewMo
var participantUsers by remember { mutableStateOf<List<Pair<Participant, User>>>(emptyList()) }
LaunchedEffect(key1 = participants) {
withContext(Dispatchers.IO) {
launch(Dispatchers.IO) {
participantUsers = participants.mapNotNull { part -> LocalCache.checkGetOrCreateUser(part.key)?.let { Pair(part, it) } }
}
}
@@ -2925,7 +2959,7 @@ private fun FollowingIcon(iconSize: Dp) {
val myIconBackgroundModifier = remember {
Modifier
.clip(CircleShape)
.fillMaxSize(0.6f)
.size(iconSize.times(0.6f))
.drawBehind { drawRect(backgroundColor) }
}
@@ -62,7 +62,8 @@ private fun UserNameDisplay(
CreateTextWithEmoji(
text = bestDisplayName,
tags = tags,
fontWeight = FontWeight.Bold
fontWeight = FontWeight.Bold,
maxLines = 1
)
CreateTextWithEmoji(
text = remember { "@$bestUserName" },
@@ -656,43 +656,47 @@ private fun LiveChannelActionOptions(
}
}
val accountState by accountViewModel.accountLiveData.observeAsState()
val isFollowing by remember(accountState) {
val isLive by remember(channel) {
derivedStateOf {
accountState?.account?.followingChannels?.contains(channel.idHex) ?: false
}
}
val status by remember {
derivedStateOf {
channel.info?.status()
channel.info?.status() == "live"
}
}
if (isMe) {
// EditButton(accountViewModel, channel)
} else {
LocalCache.addressables[channel.idHex]?.let {
if (status == "live") {
Text(
text = "LIVE",
color = Color.White,
fontWeight = FontWeight.Bold,
modifier = Modifier
.clip(SmallBorder)
.drawBehind { drawRect(Color.Red) }
.padding(horizontal = 5.dp)
)
val note = remember(channel.idHex) {
LocalCache.getNoteIfExists(channel.idHex)
}
note?.let {
if (isLive) {
LiveFlag()
Spacer(modifier = StdHorzSpacer)
}
LikeReaction(it, MaterialTheme.colors.onSurface, accountViewModel)
LikeReaction(baseNote = it, grayTint = MaterialTheme.colors.onSurface, accountViewModel = accountViewModel)
Spacer(modifier = StdHorzSpacer)
ZapReaction(baseNote = it, grayTint = MaterialTheme.colors.onSurface, accountViewModel = accountViewModel)
}
}
}
@Composable
private fun LiveFlag() {
Text(
text = "LIVE",
color = Color.White,
fontWeight = FontWeight.Bold,
modifier = remember {
Modifier
.clip(SmallBorder)
.drawBehind { drawRect(Color.Red) }
.padding(horizontal = 5.dp)
}
)
}
@Composable
private fun NoteCopyButton(
note: Channel