fix(cashu): keep Verify on current mints; reorder settings hub

- Restore the per-mint Verify button + reachability status on the already-added
  mints list. Verify is now in BOTH places: the current mints and the
  Matching/Popular suggestions (it was meant to be added to suggestions, not
  moved off the current list).
- Settings hub order: My mints → Mint recommendations → Recover from seed →
  Danger Zone, so the occasional recovery action sits last before the
  destructive section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SXRAunSJS2dBx7B79qTMew
This commit is contained in:
Claude
2026-06-17 22:32:13 +00:00
parent c340fd05cf
commit d56f3a675d
2 changed files with 66 additions and 26 deletions
@@ -163,27 +163,67 @@ fun AddCashuWalletScreen(
)
Spacer(modifier = Modifier.height(8.dp))
val verifications by viewModel.mintVerifications.collectAsState()
mints.forEachIndexed { index, mint ->
val verifyState = verifications[mint.trim().trimEnd('/')]
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
) {
Row(
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = mint,
modifier = Modifier.weight(1f),
style = MaterialTheme.typography.bodyMedium,
)
IconButton(onClick = { mints.removeAt(index) }) {
Icon(
symbol = MaterialSymbols.Delete,
contentDescription = stringRes(R.string.cashu_remove_mint),
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colorScheme.error,
Column(modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = mint,
modifier = Modifier.weight(1f),
style = MaterialTheme.typography.bodyMedium,
)
OutlinedButton(
onClick = { viewModel.verifyMint(mint) },
enabled = verifyState !is MintPingState.Pinging,
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 0.dp),
modifier = Modifier.height(32.dp),
) {
if (verifyState is MintPingState.Pinging) {
CircularProgressIndicator(modifier = Modifier.size(14.dp), strokeWidth = 2.dp)
} else {
Text(
stringRes(R.string.cashu_verify),
style = MaterialTheme.typography.labelMedium,
)
}
}
IconButton(onClick = { mints.removeAt(index) }) {
Icon(
symbol = MaterialSymbols.Delete,
contentDescription = stringRes(R.string.cashu_remove_mint),
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colorScheme.error,
)
}
}
when (val vs = verifyState) {
is MintPingState.Ok -> {
Text(
text =
if (vs.name.isNullOrBlank()) {
stringRes(R.string.cashu_mint_reachable)
} else {
stringRes(R.string.cashu_mint_reachable_named, vs.name)
},
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(bottom = 4.dp),
)
}
is MintPingState.Failed -> {
Text(
text = stringRes(R.string.cashu_mint_unreachable, vs.message),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(bottom = 4.dp),
)
}
else -> Unit
}
}
}
@@ -285,7 +325,6 @@ fun AddCashuWalletScreen(
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Spacer(modifier = Modifier.height(4.dp))
val verifications by viewModel.mintVerifications.collectAsState()
MintSuggestionList(
suggestions = suggestions,
accountViewModel = accountViewModel,
@@ -131,10 +131,20 @@ fun CashuWalletSettingsScreen(
)
}
item {
SettingsRow(
icon = MaterialSymbols.ThumbUp,
title = stringRes(R.string.cashu_settings_my_recommendations),
subtitle = stringRes(R.string.cashu_settings_recommendations_subtitle),
onClick = { nav.nav(Route.CashuMintRecommendations) },
)
}
// NUT-09 recovery: ask every mint in our list which blind
// signatures it has previously issued for our seed and
// republish them as fresh kind:7375 events. Useful after a
// device loss or rogue-relay NIP-09 of our token events.
// device loss or rogue-relay NIP-09 of our token events. Kept
// last before the Danger Zone as an occasional maintenance action.
item {
val restoreState by viewModel.restoreState.collectAsState()
val restoreSubtitle =
@@ -167,15 +177,6 @@ fun CashuWalletSettingsScreen(
)
}
item {
SettingsRow(
icon = MaterialSymbols.ThumbUp,
title = stringRes(R.string.cashu_settings_my_recommendations),
subtitle = stringRes(R.string.cashu_settings_recommendations_subtitle),
onClick = { nav.nav(Route.CashuMintRecommendations) },
)
}
// Destructive actions — only meaningful when a wallet exists.
if (walletEvent != null) {
item {