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