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