From bb56bf6a7357016dc4f1b42a8107ec0fa434ec74 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 19:57:06 +0000 Subject: [PATCH] feat(nip46): show a connected app's relays on its detail screen The list row's "N relays" count wasn't inspectable, so a user debugging why the signer holds a background relay connection couldn't see which relays an app uses. Add a Relays section to the (already tap-through) detail screen listing each relay URL, with a note that Amethyst keeps a background connection to each while the app stays connected. Apps that brought no relays of their own (the bunker flow) show that they ride the account's inbox relays and add no extra connection. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015FHr2mu5SiHwYNR7evYUuF --- .../napplets/ConnectedAppDetailScreen.kt | 55 +++++++++++++++++++ amethyst/src/main/res/values/strings.xml | 3 + 2 files changed, 58 insertions(+) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppDetailScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppDetailScreen.kt index fd4c256ef2..d212c82f69 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppDetailScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppDetailScreen.kt @@ -189,6 +189,12 @@ fun ConnectedAppDetailScreen( AppIdentityHeader(current) } + // Relays this remote client is reached on — the whole reason it costs a background + // connection, so surface them for debugging relay footprint. + if (nip46Client != null) { + Nip46RelaysSection(nip46Info?.relays.orEmpty()) + } + // Signing trust level section if (current.signerPolicy != null) { SectionHeader(stringResource(R.string.napplet_connected_app_trust_level)) @@ -284,6 +290,55 @@ fun ConnectedAppDetailScreen( } } +/** + * Lists the relays a NIP-46 remote client is reached on. When the client brought its own relays + * (the `nostrconnect://` flow) each one is a background connection Amethyst keeps open while the app + * stays connected — exactly what a user debugging relay footprint wants to see. An empty set means + * the client talks over the account's inbox relays (the bunker flow), so it adds no extra connection. + */ +@Composable +private fun Nip46RelaysSection(relays: Set) { + SectionHeader(stringResource(R.string.nip46_signer_app_relays_title)) + Surface( + color = MaterialTheme.colorScheme.surfaceVariant, + shape = MaterialTheme.shapes.medium, + modifier = Modifier.fillMaxWidth(), + ) { + Column(modifier = Modifier.padding(vertical = 12.dp, horizontal = 16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { + if (relays.isEmpty()) { + Text( + stringResource(R.string.nip46_signer_app_relays_inbox), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } else { + relays.forEach { relay -> + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) { + Icon( + MaterialSymbols.Dns, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(18.dp), + ) + Text( + relay, + style = MaterialTheme.typography.bodyMedium, + fontFamily = FontFamily.Monospace, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } + Text( + stringResource(R.string.nip46_signer_app_relays_own_hint), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } + } +} + @Composable private fun Nip46AppHeader( title: String, diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index e7a359080e..738c801203 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -930,6 +930,9 @@ Manage connected apps No apps are connected to your signer yet.\n\nScan or paste an app\'s code to connect it. Connected apps appear here, and idle ones are removed automatically after a week. used %1$s + Relays + Signs over your inbox relays — this app brought none of its own, so it keeps no extra background connection. + Amethyst holds a background connection to each of these while this app stays connected. Forget the app to drop them. %1$d relay %1$d relays