Fixing some of the old display name structure

This commit is contained in:
Vitor Pamplona
2024-03-12 17:51:27 -04:00
parent e094b56b72
commit 0dbd58d8d7
17 changed files with 91 additions and 217 deletions
@@ -81,7 +81,7 @@ class User(val pubkeyHex: String) {
override fun toString(): String = pubkeyHex override fun toString(): String = pubkeyHex
fun toBestShortFirstName(): String { fun toBestShortFirstName(): String {
val fullName = bestDisplayName() ?: bestUsername() ?: return pubkeyDisplayHex() val fullName = toBestDisplayName()
val names = fullName.split(' ') val names = fullName.split(' ')
@@ -97,23 +97,14 @@ class User(val pubkeyHex: String) {
} }
fun toBestDisplayName(): String { fun toBestDisplayName(): String {
return bestDisplayName() ?: bestUsername() ?: pubkeyDisplayHex() return info?.bestName() ?: pubkeyDisplayHex()
}
fun bestUsername(): String? {
return info?.name?.ifBlank { null } ?: info?.username?.ifBlank { null }
}
fun bestDisplayName(): String? {
return info?.displayName?.ifBlank { null }
} }
fun nip05(): String? { fun nip05(): String? {
return info?.nip05?.ifBlank { null } return info?.nip05
} }
fun profilePicture(): String? { fun profilePicture(): String? {
if (info?.picture.isNullOrBlank()) info?.picture = null
return info?.picture return info?.picture
} }
@@ -35,7 +35,7 @@ object NostrSingleUserDataSource : NostrDataSource("SingleUserFeed") {
fun createUserMetadataFilter(): List<TypedFilter>? { fun createUserMetadataFilter(): List<TypedFilter>? {
if (usersToWatch.isEmpty()) return null if (usersToWatch.isEmpty()) return null
val firstTimers = usersToWatch.filter { it.info?.latestMetadata == null }.map { it.pubkeyHex } val firstTimers = usersToWatch.filter { it.latestMetadata == null }.map { it.pubkeyHex }
if (firstTimers.isEmpty()) return null if (firstTimers.isEmpty()) return null
@@ -54,7 +54,7 @@ object NostrSingleUserDataSource : NostrDataSource("SingleUserFeed") {
fun createUserMetadataStatusReportFilter(): List<TypedFilter>? { fun createUserMetadataStatusReportFilter(): List<TypedFilter>? {
if (usersToWatch.isEmpty()) return null if (usersToWatch.isEmpty()) return null
val secondTimers = usersToWatch.filter { it.info?.latestMetadata != null } val secondTimers = usersToWatch.filter { it.latestMetadata != null }
if (secondTimers.isEmpty()) return null if (secondTimers.isEmpty()) return null
@@ -91,7 +91,7 @@ object NostrSingleUserDataSource : NostrDataSource("SingleUserFeed") {
checkNotInMainThread() checkNotInMainThread()
usersToWatch.forEach { usersToWatch.forEach {
if (it.info?.latestMetadata != null) { if (it.latestMetadata != null) {
val eose = it.latestEOSEs[relayUrl] val eose = it.latestEOSEs[relayUrl]
if (eose == null) { if (eose == null) {
it.latestEOSEs = it.latestEOSEs + Pair(relayUrl, EOSETime(time)) it.latestEOSEs = it.latestEOSEs + Pair(relayUrl, EOSETime(time))
@@ -168,7 +168,6 @@ import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.theme.replyModifier import com.vitorpamplona.amethyst.ui.theme.replyModifier
import com.vitorpamplona.amethyst.ui.theme.subtleBorder import com.vitorpamplona.amethyst.ui.theme.subtleBorder
import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent
import com.vitorpamplona.quartz.events.toImmutableListOfLists
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
@@ -1256,8 +1255,7 @@ fun Notifying(
mentions.forEachIndexed { idx, user -> mentions.forEachIndexed { idx, user ->
val innerUserState by user.live().metadata.observeAsState() val innerUserState by user.live().metadata.observeAsState()
innerUserState?.user?.let { myUser -> innerUserState?.user?.let { myUser ->
val tags = val tags = myUser.info?.tags
remember(innerUserState) { myUser.info?.latestMetadata?.tags?.toImmutableListOfLists() }
Button( Button(
shape = ButtonBorder, shape = ButtonBorder,
@@ -68,7 +68,7 @@ class NewUserMetadataViewModel : ViewModel() {
account.userProfile().let { account.userProfile().let {
// userName.value = it.bestUsername() ?: "" // userName.value = it.bestUsername() ?: ""
displayName.value = it.bestDisplayName() ?: "" displayName.value = it.info?.bestName() ?: ""
about.value = it.info?.about ?: "" about.value = it.info?.about ?: ""
picture.value = it.info?.picture ?: "" picture.value = it.info?.picture ?: ""
banner.value = it.info?.banner ?: "" banner.value = it.info?.banner ?: ""
@@ -82,7 +82,7 @@ class NewUserMetadataViewModel : ViewModel() {
mastodon.value = "" mastodon.value = ""
// TODO: Validate Telegram input, somehow. // TODO: Validate Telegram input, somehow.
it.info?.latestMetadata?.identityClaims()?.forEach { it.latestMetadata?.identityClaims()?.forEach {
when (it) { when (it) {
is TwitterIdentity -> twitter.value = it.toProofUrl() is TwitterIdentity -> twitter.value = it.toProofUrl()
is GitHubIdentity -> github.value = it.toProofUrl() is GitHubIdentity -> github.value = it.toProofUrl()
@@ -65,10 +65,10 @@ import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.encoders.Nip19Bech32 import com.vitorpamplona.quartz.encoders.Nip19Bech32
import com.vitorpamplona.quartz.encoders.Nip30CustomEmoji import com.vitorpamplona.quartz.encoders.Nip30CustomEmoji
import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChannelCreateEvent
import com.vitorpamplona.quartz.events.EmptyTagList
import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.ImmutableListOfLists import com.vitorpamplona.quartz.events.ImmutableListOfLists
import com.vitorpamplona.quartz.events.PrivateDmEvent import com.vitorpamplona.quartz.events.PrivateDmEvent
import com.vitorpamplona.quartz.events.toImmutableListOfLists
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.ImmutableMap
@@ -286,25 +286,16 @@ private fun RenderUserAsClickableText(
additionalChars: String, additionalChars: String,
nav: (String) -> Unit, nav: (String) -> Unit,
) { ) {
val userState by baseUser.live().metadata.observeAsState() val userState by baseUser.live().userMetadataInfo.observeAsState()
val route = remember { "User/${baseUser.pubkeyHex}" }
val userDisplayName by userState?.bestName()?.let {
remember(userState) { derivedStateOf { userState?.user?.toBestDisplayName() } }
val userTags by
remember(userState) {
derivedStateOf { userState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists() }
}
userDisplayName?.let {
CreateClickableTextWithEmoji( CreateClickableTextWithEmoji(
clickablePart = it, clickablePart = it,
suffix = additionalChars.ifBlank { null }, suffix = additionalChars.ifBlank { null },
maxLines = 1, maxLines = 1,
route = route, route = "User/${baseUser.pubkeyHex}",
nav = nav, nav = nav,
tags = userTags, tags = userState?.tags ?: EmptyTagList,
) )
} }
} }
@@ -661,7 +652,10 @@ fun ClickableInLineIconRenderer(
AsyncImage( AsyncImage(
model = value.url, model = value.url,
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxSize().padding(1.dp), modifier =
Modifier
.fillMaxSize()
.padding(1.dp),
) )
}, },
) )
@@ -743,7 +737,10 @@ fun InLineIconRenderer(
AsyncImage( AsyncImage(
model = value.url, model = value.url,
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxSize().padding(horizontal = 0.dp), modifier =
Modifier
.fillMaxSize()
.padding(horizontal = 0.dp),
) )
}, },
) )
@@ -858,18 +858,14 @@ private fun DisplayUserFromTag(
baseUser: User, baseUser: User,
nav: (String) -> Unit, nav: (String) -> Unit,
) { ) {
val route = remember { "User/${baseUser.pubkeyHex}" }
val hex = remember { baseUser.pubkeyDisplayHex() }
val meta by baseUser.live().userMetadataInfo.observeAsState(baseUser.info) val meta by baseUser.live().userMetadataInfo.observeAsState(baseUser.info)
Crossfade(targetState = meta, label = "DisplayUserFromTag") { Crossfade(targetState = meta, label = "DisplayUserFromTag") {
Row { Row {
val displayName = remember(it) { it?.bestDisplayName() ?: it?.bestUsername() ?: hex }
CreateClickableTextWithEmoji( CreateClickableTextWithEmoji(
clickablePart = displayName, clickablePart = remember(meta) { it?.bestName() ?: baseUser.pubkeyDisplayHex() },
maxLines = 1, maxLines = 1,
route = route, route = "User/${baseUser.pubkeyHex}",
nav = nav, nav = nav,
tags = it?.tags, tags = it?.tags,
) )
@@ -61,7 +61,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.map
import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.AccountInfo
import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
@@ -78,7 +77,6 @@ import com.vitorpamplona.amethyst.ui.theme.AccountPictureModifier
import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size10dp
import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.Size55dp
import com.vitorpamplona.quartz.encoders.decodePublicKeyAsHexOrNull import com.vitorpamplona.quartz.encoders.decodePublicKeyAsHexOrNull
import com.vitorpamplona.quartz.events.toImmutableListOfLists
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -95,7 +93,10 @@ fun AccountSwitchBottomSheet(
Column(modifier = Modifier.verticalScroll(scrollState)) { Column(modifier = Modifier.verticalScroll(scrollState)) {
Row( Row(
modifier = Modifier.fillMaxWidth().padding(Size10dp), modifier =
Modifier
.fillMaxWidth()
.padding(Size10dp),
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
@@ -103,7 +104,10 @@ fun AccountSwitchBottomSheet(
} }
accounts.forEach { acc -> DisplayAccount(acc, accountViewModel, accountStateViewModel) } accounts.forEach { acc -> DisplayAccount(acc, accountViewModel, accountStateViewModel) }
Row( Row(
modifier = Modifier.fillMaxWidth().padding(top = Size10dp, bottom = Size55dp), modifier =
Modifier
.fillMaxWidth()
.padding(top = Size10dp, bottom = Size55dp),
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
@@ -167,7 +171,8 @@ fun DisplayAccount(
baseUser?.let { baseUser?.let {
Row( Row(
modifier = modifier =
Modifier.fillMaxWidth() Modifier
.fillMaxWidth()
.clickable { accountStateViewModel.switchUser(acc) } .clickable { accountStateViewModel.switchUser(acc) }
.padding(16.dp, 16.dp), .padding(16.dp, 16.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@@ -181,7 +186,10 @@ fun DisplayAccount(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Box( Box(
modifier = Modifier.width(55.dp).padding(0.dp), modifier =
Modifier
.width(55.dp)
.padding(0.dp),
) { ) {
val automaticallyShowProfilePicture = val automaticallyShowProfilePicture =
remember { remember {
@@ -241,22 +249,17 @@ private fun AccountName(
acc: AccountInfo, acc: AccountInfo,
user: User, user: User,
) { ) {
val displayName by user.live().metadata.map { user.bestDisplayName() }.observeAsState() val info by user.live().userMetadataInfo.observeAsState()
val tags by info?.let {
user it.bestName()?.let { name ->
.live() CreateTextWithEmoji(
.metadata text = name,
.map { user.info?.latestMetadata?.tags?.toImmutableListOfLists() } tags = it.tags,
.observeAsState() maxLines = 1,
overflow = TextOverflow.Ellipsis,
displayName?.let { )
CreateTextWithEmoji( }
text = it,
tags = tags,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
} }
Text( Text(
@@ -189,7 +189,7 @@ fun ProfileContent(
profilePubHex = baseAccountUser.pubkeyHex, profilePubHex = baseAccountUser.pubkeyHex,
profileBanner = userInfo?.banner, profileBanner = userInfo?.banner,
profilePicture = userInfo?.profilePicture(), profilePicture = userInfo?.profilePicture(),
bestDisplayName = userInfo?.bestDisplayName(), bestDisplayName = userInfo?.bestName(),
tags = userInfo?.tags, tags = userInfo?.tags,
modifier = modifier, modifier = modifier,
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
@@ -374,11 +374,13 @@ private fun RenderBubble(
val bubbleModifier = val bubbleModifier =
remember { remember {
Modifier.padding(start = 10.dp, end = 5.dp, bottom = 5.dp).onSizeChanged { Modifier
if (bubbleSize.intValue != it.width) { .padding(start = 10.dp, end = 5.dp, bottom = 5.dp)
bubbleSize.intValue = it.width .onSizeChanged {
if (bubbleSize.intValue != it.width) {
bubbleSize.intValue = it.width
}
} }
}
} }
Column(modifier = bubbleModifier) { Column(modifier = bubbleModifier) {
@@ -555,7 +557,8 @@ private fun ConstrainedStatusRow(
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
modifier = modifier =
with(LocalDensity.current) { with(LocalDensity.current) {
Modifier.padding(top = Size5dp) Modifier
.padding(top = Size5dp)
.height(Size20dp) .height(Size20dp)
.widthIn( .widthIn(
bubbleSize.value.toDp(), bubbleSize.value.toDp(),
@@ -589,7 +592,10 @@ fun IncognitoBadge(baseNote: Note) {
Icon( Icon(
painter = painterResource(id = R.drawable.incognito), painter = painterResource(id = R.drawable.incognito),
null, null,
modifier = Modifier.padding(top = 1.dp).size(14.dp), modifier =
Modifier
.padding(top = 1.dp)
.size(14.dp),
tint = MaterialTheme.colorScheme.placeholderText, tint = MaterialTheme.colorScheme.placeholderText,
) )
Spacer(modifier = StdHorzSpacer) Spacer(modifier = StdHorzSpacer)
@@ -597,7 +603,10 @@ fun IncognitoBadge(baseNote: Note) {
Icon( Icon(
painter = painterResource(id = R.drawable.incognito_off), painter = painterResource(id = R.drawable.incognito_off),
null, null,
modifier = Modifier.padding(top = 1.dp).size(14.dp), modifier =
Modifier
.padding(top = 1.dp)
.size(14.dp),
tint = MaterialTheme.colorScheme.placeholderText, tint = MaterialTheme.colorScheme.placeholderText,
) )
Spacer(modifier = StdHorzSpacer) Spacer(modifier = StdHorzSpacer)
@@ -678,7 +687,7 @@ private fun RenderChangeChannelMetadataNote(note: Note) {
CreateTextWithEmoji( CreateTextWithEmoji(
text = text, text = text,
tags = remember { note.author?.info?.latestMetadata?.tags?.toImmutableListOfLists() }, tags = note.author?.info?.tags,
) )
} }
@@ -699,7 +708,7 @@ private fun RenderCreateChannelNote(note: Note) {
CreateTextWithEmoji( CreateTextWithEmoji(
text = text, text = text,
tags = remember { note.author?.info?.latestMetadata?.tags?.toImmutableListOfLists() }, tags = note.author?.info?.tags,
) )
} }
@@ -735,25 +744,17 @@ private fun WatchAndDisplayUser(
loadProfilePicture: Boolean, loadProfilePicture: Boolean,
nav: (String) -> Unit, nav: (String) -> Unit,
) { ) {
val pubkeyHex = remember { author.pubkeyHex } val route = "User/${author.pubkeyHex}"
val route = remember { "User/${author.pubkeyHex}" }
val userState by author.live().metadata.observeAsState() val userState by author.live().userMetadataInfo.observeAsState()
val userDisplayName by UserIcon(author.pubkeyHex, userState?.picture, loadProfilePicture, nav, route)
remember(userState) { derivedStateOf { userState?.user?.toBestDisplayName() } }
val userProfilePicture by userState?.let {
remember(userState) { derivedStateOf { userState?.user?.profilePicture() } } it.bestName()?.let { name ->
DisplayMessageUsername(name, it.tags, route, nav)
val userTags by
remember(userState) {
derivedStateOf { userState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists() }
} }
}
UserIcon(pubkeyHex, userProfilePicture, loadProfilePicture, nav, route)
userDisplayName?.let { DisplayMessageUsername(it, userTags, route, nav) }
} }
@Composable @Composable
@@ -771,7 +772,8 @@ private fun UserIcon(
loadProfilePicture = loadProfilePicture, loadProfilePicture = loadProfilePicture,
modifier = modifier =
remember { remember {
Modifier.width(Size25dp) Modifier
.width(Size25dp)
.height(Size25dp) .height(Size25dp)
.clip(shape = CircleShape) .clip(shape = CircleShape)
.clickable(onClick = { nav(route) }) .clickable(onClick = { nav(route) })
@@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.note
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -35,10 +34,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji
@@ -46,112 +43,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.ui.theme.lessImportantLink
import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.events.toImmutableListOfLists
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Composable
fun ReplyInformation(
replyTo: ImmutableList<Note>?,
mentions: ImmutableList<String>,
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
) {
var sortedMentions by remember { mutableStateOf<ImmutableList<User>?>(null) }
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
sortedMentions =
mentions
.mapNotNull { LocalCache.checkGetOrCreateUser(it) }
.toSet()
.sortedBy { !accountViewModel.account.userProfile().isFollowingCached(it) }
.toImmutableList()
}
}
if (sortedMentions != null) {
ReplyInformation(replyTo, sortedMentions) { nav("User/${it.pubkeyHex}") }
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun ReplyInformation(
replyTo: ImmutableList<Note>?,
sortedMentions: ImmutableList<User>?,
prefix: String = "",
onUserTagClick: (User) -> Unit,
) {
var expanded by remember { mutableStateOf((sortedMentions?.size ?: 0) <= 2) }
FlowRow {
if (sortedMentions != null && sortedMentions.isNotEmpty()) {
if (replyTo != null && replyTo.isNotEmpty()) {
val repliesToDisplay = if (expanded) sortedMentions else sortedMentions.take(2)
Text(
stringResource(R.string.replying_to),
fontSize = 13.sp,
color = MaterialTheme.colorScheme.placeholderText,
)
repliesToDisplay.forEachIndexed { idx, user ->
ReplyInfoMention(user, prefix, onUserTagClick)
if (expanded) {
if (idx < repliesToDisplay.size - 2) {
Text(
", ",
fontSize = 13.sp,
color = MaterialTheme.colorScheme.placeholderText,
)
} else if (idx < repliesToDisplay.size - 1) {
Text(
stringResource(R.string.and),
fontSize = 13.sp,
color = MaterialTheme.colorScheme.placeholderText,
)
}
} else {
if (idx < repliesToDisplay.size - 1) {
Text(
", ",
fontSize = 13.sp,
color = MaterialTheme.colorScheme.placeholderText,
)
} else if (idx < repliesToDisplay.size) {
Text(
stringResource(R.string.and),
fontSize = 13.sp,
color = MaterialTheme.colorScheme.placeholderText,
)
ClickableText(
AnnotatedString("${sortedMentions.size - 2}"),
style =
LocalTextStyle.current.copy(
color = MaterialTheme.colorScheme.lessImportantLink,
fontSize = 13.sp,
),
onClick = { expanded = true },
)
Text(
" ${stringResource(R.string.others)}",
fontSize = 13.sp,
color = MaterialTheme.colorScheme.placeholderText,
)
}
}
}
}
}
}
}
@Composable @Composable
fun ReplyInformationChannel( fun ReplyInformationChannel(
@@ -225,15 +118,11 @@ private fun ReplyInfoMention(
prefix: String, prefix: String,
onUserTagClick: (User) -> Unit, onUserTagClick: (User) -> Unit,
) { ) {
val innerUserState by user.live().metadata.observeAsState() val innerUserState by user.live().userMetadataInfo.observeAsState()
CreateClickableTextWithEmoji( CreateClickableTextWithEmoji(
clickablePart = clickablePart = "$prefix${innerUserState?.bestName()}",
remember(innerUserState) { "$prefix${innerUserState?.user?.toBestDisplayName()}" }, tags = innerUserState?.tags,
tags =
remember(innerUserState) {
innerUserState?.user?.info?.latestMetadata?.tags?.toImmutableListOfLists()
},
style = style =
LocalTextStyle.current.copy( LocalTextStyle.current.copy(
color = MaterialTheme.colorScheme.lessImportantLink, color = MaterialTheme.colorScheme.lessImportantLink,
@@ -336,7 +336,7 @@ fun LoadUserProfilePicture(
) { ) {
val userProfile by baseUser.live().userMetadataInfo.observeAsState(baseUser.info) val userProfile by baseUser.live().userMetadataInfo.observeAsState(baseUser.info)
innerContent(userProfile?.profilePicture(), userProfile?.bestDisplayName() ?: userProfile?.bestDisplayName()) innerContent(userProfile?.profilePicture(), userProfile?.bestName())
} }
@Composable @Composable
@@ -70,9 +70,9 @@ fun UsernameDisplay(
val userMetadata by baseUser.live().userMetadataInfo.observeAsState(baseUser.info) val userMetadata by baseUser.live().userMetadataInfo.observeAsState(baseUser.info)
Crossfade(targetState = userMetadata, modifier = weight, label = "UsernameDisplay") { Crossfade(targetState = userMetadata, modifier = weight, label = "UsernameDisplay") {
val name = it?.bestDisplayName() ?: it?.bestUsername() val name = it?.bestName()
if (name != null) { if (name != null) {
UserDisplay(name, it?.tags, weight, showPlayButton, fontWeight, textColor) UserDisplay(name, it.tags, weight, showPlayButton, fontWeight, textColor)
} else { } else {
NPubDisplay(baseUser, weight, fontWeight, textColor) NPubDisplay(baseUser, weight, fontWeight, textColor)
} }
@@ -132,18 +132,20 @@ fun ForkInformationRow(
) { ) {
val noteState by originalVersion.live().metadata.observeAsState() val noteState by originalVersion.live().metadata.observeAsState()
val note = noteState?.note ?: return val note = noteState?.note ?: return
val author = note.author ?: return
val route = remember(note) { routeFor(note, accountViewModel.userProfile()) } val route = remember(note) { routeFor(note, accountViewModel.userProfile()) }
if (route != null) { if (route != null) {
Row(modifier) { Row(modifier) {
val author = note.author ?: return
val meta by author.live().userMetadataInfo.observeAsState(author.info)
Text(stringResource(id = R.string.forked_from)) Text(stringResource(id = R.string.forked_from))
Spacer(modifier = StdHorzSpacer) Spacer(modifier = StdHorzSpacer)
val userMetadata by author.live().userMetadataInfo.observeAsState() val userMetadata by author.live().userMetadataInfo.observeAsState()
CreateClickableTextWithEmoji( CreateClickableTextWithEmoji(
clickablePart = userMetadata?.bestDisplayName() ?: userMetadata?.bestUsername() ?: author.pubkeyDisplayHex(), clickablePart = remember(meta) { meta?.bestName() ?: author.pubkeyDisplayHex() },
maxLines = 1, maxLines = 1,
route = route, route = route,
nav = nav, nav = nav,
@@ -144,7 +144,7 @@ private fun DisplayQuoteAuthor(
val userMetadata by userBase.live().userMetadataInfo.observeAsState() val userMetadata by userBase.live().userMetadataInfo.observeAsState()
CreateClickableTextWithEmoji( CreateClickableTextWithEmoji(
clickablePart = userMetadata?.bestDisplayName() ?: userMetadata?.bestUsername() ?: userBase.pubkeyDisplayHex(), clickablePart = userMetadata?.bestName() ?: userBase.pubkeyDisplayHex(),
maxLines = 1, maxLines = 1,
route = "User/${userBase.pubkeyHex}", route = "User/${userBase.pubkeyHex}",
nav = nav, nav = nav,
@@ -133,7 +133,7 @@ fun ShowQRDialog(
modifier = Modifier.fillMaxWidth().padding(top = 5.dp), modifier = Modifier.fillMaxWidth().padding(top = 5.dp),
) { ) {
CreateTextWithEmoji( CreateTextWithEmoji(
text = user.bestDisplayName() ?: user.bestUsername() ?: "", text = user.info?.bestName() ?: "",
tags = user.info?.tags, tags = user.info?.tags,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 18.sp, fontSize = 18.sp,
@@ -757,7 +757,7 @@ private fun RenderClassifiedsReaderForThread(
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
val sellerName = note.author?.bestDisplayName() ?: note.author?.bestUsername() val sellerName = note.author?.info?.bestName()
val msg = val msg =
if (sellerName != null) { if (sellerName != null) {
@@ -431,12 +431,8 @@ class UserMetadata {
return lud16 ?: lud06 return lud16 ?: lud06
} }
fun bestUsername(): String? { fun bestName(): String? {
return name ?: username return displayName ?: name ?: username
}
fun bestDisplayName(): String? {
return displayName
} }
fun nip05(): String? { fun nip05(): String? {