- User Metadata clean up upon receipt instead of in every rendering.

- Simpler/Faster UserDisplay renderings
- Removes co-routing use for Hashtags.
This commit is contained in:
Vitor Pamplona 2024-03-06 10:32:08 -05:00
parent da41fbb4c9
commit b8619e3b61
5 changed files with 49 additions and 109 deletions

View File

@ -310,6 +310,7 @@ class User(val pubkeyHex: String) {
info?.latestMetadata = latestMetadata
info?.updatedMetadataAt = latestMetadata.createdAt
info?.tags = latestMetadata.tags.toImmutableListOfLists()
info?.cleanBlankNames()
if (newUserInfo.lud16.isNullOrBlank()) {
info?.lud06?.let {

View File

@ -76,6 +76,7 @@ import com.vitorpamplona.amethyst.ui.note.elements.DisplayZapSplits
import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton
import com.vitorpamplona.amethyst.ui.note.elements.Reward
import com.vitorpamplona.amethyst.ui.note.elements.ShowForkInformation
import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo
import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay
import com.vitorpamplona.amethyst.ui.note.types.CommunityHeader
import com.vitorpamplona.amethyst.ui.note.types.DisplayPeopleList
@ -1121,11 +1122,8 @@ fun FirstUserInfoRow(
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
) {
Row(verticalAlignment = CenterVertically, modifier = remember { UserNameRowHeight }) {
val isRepost by
remember(baseNote) {
derivedStateOf { baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent }
}
Row(verticalAlignment = CenterVertically, modifier = UserNameRowHeight) {
val isRepost = baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent
val isCommunityPost by
remember(baseNote) {
@ -1139,9 +1137,9 @@ fun FirstUserInfoRow(
if (showAuthorPicture) {
NoteAuthorPicture(baseNote, nav, accountViewModel, Size25dp)
Spacer(HalfPadding)
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) }, textColor = textColor)
NoteUsernameDisplay(baseNote, Modifier.weight(1f), textColor = textColor)
} else {
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) }, textColor = textColor)
NoteUsernameDisplay(baseNote, Modifier.weight(1f), textColor = textColor)
}
if (isRepost) {
@ -1158,7 +1156,7 @@ fun FirstUserInfoRow(
}
}
com.vitorpamplona.amethyst.ui.note.elements.TimeAgo(baseNote)
TimeAgo(baseNote)
MoreOptionsButton(baseNote, editState, accountViewModel, nav)
}

View File

@ -29,7 +29,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
@ -72,67 +71,27 @@ fun UsernameDisplay(
fontWeight: FontWeight = FontWeight.Bold,
textColor: Color = Color.Unspecified,
) {
val npubDisplay by remember { derivedStateOf { baseUser.pubkeyDisplayHex() } }
val userMetadata by baseUser.live().userMetadataInfo.observeAsState(baseUser.info)
Crossfade(targetState = userMetadata, modifier = weight, label = "UsernameDisplay") {
if (it != null) {
UserNameDisplay(
it.bestUsername(),
it.bestDisplayName(),
npubDisplay,
it.tags,
weight,
showPlayButton,
fontWeight,
textColor,
)
val name = it?.bestDisplayName() ?: it?.bestUsername()
if (name != null) {
UserDisplay(name, it?.tags, weight, showPlayButton, fontWeight, textColor)
} else {
NPubDisplay(npubDisplay, weight, fontWeight, textColor)
NPubDisplay(baseUser, weight, fontWeight, textColor)
}
}
}
@Composable
private fun UserNameDisplay(
bestUserName: String?,
bestDisplayName: String?,
npubDisplay: String,
tags: ImmutableListOfLists<String>?,
modifier: Modifier,
showPlayButton: Boolean = true,
fontWeight: FontWeight = FontWeight.Bold,
textColor: Color = Color.Unspecified,
) {
if (bestUserName != null && bestDisplayName != null && bestDisplayName != bestUserName) {
UserAndUsernameDisplay(
bestDisplayName.trim(),
tags,
bestUserName.trim(),
modifier,
showPlayButton,
fontWeight,
textColor,
)
} else if (bestDisplayName != null) {
UserDisplay(bestDisplayName.trim(), tags, modifier, showPlayButton, fontWeight, textColor)
} else if (bestUserName != null) {
UserDisplay(bestUserName.trim(), tags, modifier, showPlayButton, fontWeight, textColor)
} else {
NPubDisplay(npubDisplay, modifier, fontWeight, textColor)
}
}
@Composable
fun NPubDisplay(
npubDisplay: String,
private fun NPubDisplay(
user: User,
modifier: Modifier,
fontWeight: FontWeight = FontWeight.Bold,
textColor: Color = Color.Unspecified,
) {
Text(
text = npubDisplay,
text = remember { user.pubkeyDisplayHex() },
fontWeight = fontWeight,
modifier = modifier,
maxLines = 1,
@ -160,41 +119,7 @@ private fun UserDisplay(
modifier = modifier,
color = textColor,
)
if (showPlayButton) {
Spacer(StdHorzSpacer)
DrawPlayName(bestDisplayName)
}
}
}
@Composable
private fun UserAndUsernameDisplay(
bestDisplayName: String,
tags: ImmutableListOfLists<String>?,
bestUserName: String,
modifier: Modifier,
showPlayButton: Boolean = true,
fontWeight: FontWeight = FontWeight.Bold,
textColor: Color = Color.Unspecified,
) {
Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
CreateTextWithEmoji(
text = bestDisplayName,
tags = tags,
fontWeight = fontWeight,
maxLines = 1,
modifier = modifier,
color = textColor,
)
/*
CreateTextWithEmoji(
text = remember { "@$bestUserName" },
tags = tags,
color = MaterialTheme.colorScheme.placeholderText,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)*/
if (showPlayButton) {
Spacer(StdHorzSpacer)
DrawPlayName(bestDisplayName)
@ -207,12 +132,7 @@ fun DrawPlayName(name: String) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
DrawPlayNameIcon { speak(name, context, lifecycleOwner) }
}
@Composable
fun DrawPlayNameIcon(onClick: () -> Unit) {
IconButton(onClick = onClick, modifier = StdButtonSizeModifier) {
IconButton(onClick = { speak(name, context, lifecycleOwner) }, modifier = StdButtonSizeModifier) {
PlayIcon(
modifier = StdButtonSizeModifier,
tint = MaterialTheme.colorScheme.placeholderText,

View File

@ -37,8 +37,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.text.AnnotatedString
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Composable
fun DisplayFollowingHashtagsInPost(
@ -50,13 +48,11 @@ fun DisplayFollowingHashtagsInPost(
var firstTag by remember(baseNote) { mutableStateOf<String?>(null) }
LaunchedEffect(key1 = userFollowState) {
launch(Dispatchers.Default) {
val followingTags = userFollowState?.user?.cachedFollowingTagSet() ?: emptySet()
val newFirstTag = baseNote.event?.firstIsTaggedHashes(followingTags)
val followingTags = userFollowState?.user?.cachedFollowingTagSet() ?: emptySet()
val newFirstTag = baseNote.event?.firstIsTaggedHashes(followingTags)
if (firstTag != newFirstTag) {
launch(Dispatchers.Main) { firstTag = newFirstTag }
}
if (firstTag != newFirstTag) {
firstTag = newFirstTag
}
}

View File

@ -429,25 +429,50 @@ class UserMetadata {
}
fun lnAddress(): String? {
return (lud16?.trim() ?: lud06?.trim())?.ifBlank { null }
return lud16 ?: lud06
}
fun bestUsername(): String? {
return name?.ifBlank { null } ?: username?.ifBlank { null }
return name ?: username
}
fun bestDisplayName(): String? {
return displayName?.ifBlank { null }
return displayName
}
fun nip05(): String? {
return nip05?.ifBlank { null }
return nip05
}
fun profilePicture(): String? {
if (picture.isNullOrBlank()) picture = null
return picture
}
fun cleanBlankNames() {
if (picture?.isNotEmpty() == true) picture = picture?.trim()
if (nip05?.isNotEmpty() == true) nip05 = nip05?.trim()
if (displayName?.isNotEmpty() == true) displayName = displayName?.trim()
if (name?.isNotEmpty() == true) name = name?.trim()
if (username?.isNotEmpty() == true) username = username?.trim()
if (lud06?.isNotEmpty() == true) lud06 = lud06?.trim()
if (lud16?.isNotEmpty() == true) lud16 = lud16?.trim()
if (banner?.isNotEmpty() == true) banner = banner?.trim()
if (website?.isNotEmpty() == true) website = website?.trim()
if (domain?.isNotEmpty() == true) domain = domain?.trim()
if (picture?.isBlank() == true) picture = null
if (nip05?.isBlank() == true) nip05 = null
if (displayName?.isBlank() == true) displayName = null
if (name?.isBlank() == true) name = null
if (username?.isBlank() == true) username = null
if (lud06?.isBlank() == true) lud06 = null
if (lud16?.isBlank() == true) lud16 = null
if (banner?.isBlank() == true) banner = null
if (website?.isBlank() == true) website = null
if (domain?.isBlank() == true) domain = null
}
}
@Stable class ImmutableListOfLists<T>(val lists: Array<Array<T>>)