diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/RelayAuthPromptHost.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/RelayAuthPromptHost.kt index 255c095abb..40df5a15aa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/RelayAuthPromptHost.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/RelayAuthPromptHost.kt @@ -51,6 +51,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.PlaceholderVerticalAlign @@ -399,7 +400,7 @@ private fun secondaryLine( ): String? { val others = purposes.filter { it !== primary } if (others.isEmpty()) return null - return stringRes(R.string.relay_auth_also_holding_back, others.size) + return pluralStringResource(R.plurals.relay_auth_also_holding_back, others.size, others.size) } /** A short label for a set of counterparties: the first person's name, or "Alice and 4 others". */ @@ -409,10 +410,39 @@ private fun counterpartyLabel( accountViewModel: AccountViewModel, ): String { val first = pubkeys.firstOrNull() ?: return "" - val name = rememberDisplayName(first, accountViewModel) + val name = rememberCounterpartyName(first, accountViewModel) return if (pubkeys.size > 1) stringRes(R.string.relay_auth_name_and_n_others, name, (pubkeys.size - 1).toString()) else name } +/** + * Like [rememberDisplayName], but never renders a bare npub. + * + * The reason sentence exists to name *a person* — "it won't serve posts from Alice". A pubkey we + * have no metadata for has no name to give, and [User.toBestDisplayName] falls back to the shortened + * npub, so the sentence became "it won't serve posts from npub1j9hlsge8…kqy003h0 unless you log in": + * a string the reader cannot recognize, dressed up as if it were a name. Falling back to the generic + * phrase says the same amount and reads as language. + * + * The dialog *title* deliberately keeps the npub ([rememberDisplayName]): it names the account whose + * identity is about to be revealed, where an unrecognizable-but-exact key still beats "someone you + * haven't loaded yet" — the user can at least match it against the account they are logged in as. + */ +@Composable +private fun rememberCounterpartyName( + pubkey: HexKey, + accountViewModel: AccountViewModel, +): String { + var user by remember(pubkey) { mutableStateOf(accountViewModel.getUserIfExists(pubkey)) } + if (user == null) { + LaunchedEffect(pubkey) { user = accountViewModel.checkGetOrCreateUser(pubkey) } + } + val loaded = user ?: return stringRes(R.string.relay_auth_someone_unloaded) + val metadata by observeUserInfo(loaded, accountViewModel) + return metadata?.info?.bestName() + ?: loaded.metadataOrNull()?.bestName() + ?: stringRes(R.string.relay_auth_someone_unloaded) +} + /** * A display name for a venue id — a public chat channel (64-hex event id), a NIP-53 live activity, * or a NIP-72 community. diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 3329e6669f..a703b1bc3e 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -1165,7 +1165,10 @@ It asks everyone to log in. Amethyst can\'t tell what it\'s holding back. someone you haven\'t loaded yet %1$s and %2$s others - It\'s also holding back %1$d other thing(s). + + It\'s also holding back %1$d other thing. + It\'s also holding back %1$d other things. + Remember for this relay Log in Not now