feat(wallet): dashboard polish — top-5 transactions, switch-wallet flow, drop relay backup status list (port wisp #571, #572)
- Dashboard footer lists the 5 most recent transactions instead of 1 - Delete wallet replaced by a switch-wallet flow: disconnect to use the default wallet or restore another; copy clarifies funds stay safe - NWC dashboard parity + wallet settings cleanup - Spark settings no longer render the per-relay backup status list
This commit is contained in:
@@ -51,6 +51,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@@ -126,6 +127,7 @@ import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.compose.ui.res.painterResource
|
||||
@@ -829,6 +831,50 @@ private fun WalletConnectionContent(
|
||||
)
|
||||
}
|
||||
|
||||
if (showScanner) {
|
||||
// Dialog overlay matches the iOS "Scan QR" button on the NWC
|
||||
// entry sheet — opens the camera in-place, on success closes
|
||||
// the dialog and seeds the connection-string field. Stripping
|
||||
// `nostr+walletconnect://` is intentionally left to the scan
|
||||
// value: many wallet apps QR-encode the full URI, and that's
|
||||
// what the connect step expects.
|
||||
androidx.compose.ui.window.Dialog(
|
||||
onDismissRequest = { showScanner = false }
|
||||
) {
|
||||
androidx.compose.material3.Surface(
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
color = MaterialTheme.colorScheme.surface,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
stringResource(R.string.wallet_scan_qr_code),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Spacer(Modifier.height(12.dp))
|
||||
com.darkwisp.app.ui.component.QrScanner(
|
||||
onResult = { value ->
|
||||
showScanner = false
|
||||
onConnectionStringChange(value.trim())
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(320.dp),
|
||||
promptText = stringResource(R.string.wallet_point_camera)
|
||||
)
|
||||
Spacer(Modifier.height(12.dp))
|
||||
TextButton(onClick = { showScanner = false }) {
|
||||
Text(stringResource(R.string.btn_cancel))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (walletState is WalletState.Error) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
@@ -1263,7 +1309,13 @@ private fun WalletHomeContent(
|
||||
}
|
||||
|
||||
// ── Lightning address pill ─────────────────────────────────
|
||||
if (walletMode == WalletMode.SPARK && lightningAddress != null) {
|
||||
// Shown for any wallet mode that carries a lud16 — Spark wallets
|
||||
// expose one via the Breez SDK; NWC URIs may include `lud16=...`
|
||||
// which connectNwcWallet copies into `lightningAddress`. The old
|
||||
// NWC-only logo + "Nostr Wallet Connect" footer below the balance
|
||||
// was redundant (the dashboard header already brands the mode),
|
||||
// so it's removed.
|
||||
if (!lightningAddress.isNullOrBlank()) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Surface(
|
||||
modifier = Modifier.clickable {
|
||||
@@ -1290,7 +1342,9 @@ private fun WalletHomeContent(
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (walletMode == WalletMode.SPARK && lightningAddress == null) {
|
||||
} else if (walletMode == WalletMode.SPARK) {
|
||||
// Spark-only setup CTA. NWC users can't register an address
|
||||
// from inside Wisp — it comes from the NWC URI or not at all.
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Surface(
|
||||
modifier = Modifier.clickable(onClick = onSetupAddress),
|
||||
@@ -1316,28 +1370,6 @@ private fun WalletHomeContent(
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (walletMode == WalletMode.NWC) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_nwc_logo),
|
||||
contentDescription = "NWC",
|
||||
modifier = Modifier.height(16.dp),
|
||||
colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(
|
||||
MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
)
|
||||
Spacer(Modifier.width(6.dp))
|
||||
Text(
|
||||
stringResource(R.string.wallet_nwc_title),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Send / Receive ─────────────────────────────────────────
|
||||
@@ -1396,7 +1428,20 @@ private fun WalletHomeContent(
|
||||
HorizontalDivider(
|
||||
color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)
|
||||
)
|
||||
recentTransactions.take(1).forEach { tx ->
|
||||
// Match iOS — show recent transactions inline, "View all"
|
||||
// expands to the full screen. Row count scales with the
|
||||
// device's available height so a compact phone (e.g.
|
||||
// ~640dp tall) doesn't crowd out the balance + Send/
|
||||
// Receive controls, while bigger displays still get up
|
||||
// to 5 rows like iOS.
|
||||
val screenHeightDp = LocalConfiguration.current.screenHeightDp
|
||||
val txCount = when {
|
||||
screenHeightDp >= 800 -> 5
|
||||
screenHeightDp >= 720 -> 4
|
||||
screenHeightDp >= 640 -> 3
|
||||
else -> 2
|
||||
}
|
||||
recentTransactions.take(txCount).forEach { tx ->
|
||||
TransactionRow(tx, profileLookup, balanceDisplay)
|
||||
}
|
||||
}
|
||||
@@ -3391,150 +3436,28 @@ private fun WalletSettingsContent(
|
||||
Text(if (isDefaultWallet) "View Recovery Phrase" else "Backup Recovery Phrase")
|
||||
}
|
||||
|
||||
if (!isDefaultWallet) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Spacer(Modifier.height(8.dp))
|
||||
|
||||
OutlinedButton(
|
||||
onClick = onBackupToRelay,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Icon(Icons.Default.CloudUpload, contentDescription = null, modifier = Modifier.size(18.dp))
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text("Backup to Nostr Relays")
|
||||
}
|
||||
// Relay backup is offered for both default and non-default
|
||||
// Spark wallets — matches iOS. For default wallets the nsec
|
||||
// is already the canonical backup; offering relay backup
|
||||
// here is belt-and-braces for users who want it.
|
||||
OutlinedButton(
|
||||
onClick = onBackupToRelay,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Icon(Icons.Default.CloudUpload, contentDescription = null, modifier = Modifier.size(18.dp))
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text("Backup to Nostr Relays")
|
||||
}
|
||||
|
||||
// Relay backup status section (when logged in). Skipped for default
|
||||
// wallets — the nsec already serves as their backup.
|
||||
if (isLoggedIn && !isDefaultWallet) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
"Relay Backup Status",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
IconButton(
|
||||
onClick = onCheckRelayBackups,
|
||||
enabled = !relayBackupCheckLoading
|
||||
) {
|
||||
if (relayBackupCheckLoading) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(18.dp),
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
Icons.Default.Refresh,
|
||||
contentDescription = "Check relay backups",
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (relayBackupStatuses.isNotEmpty()) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant
|
||||
)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(12.dp)) {
|
||||
relayBackupStatuses.forEach { info ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(8.dp)
|
||||
.background(
|
||||
if (info.hasBackup) Color(0xFF4CAF50) else Color(0xFF9E9E9E),
|
||||
CircleShape
|
||||
)
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
info.relayUrl.removePrefix("wss://").removePrefix("ws://"),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(8.dp))
|
||||
|
||||
var showDeleteDialog by remember { mutableStateOf(false) }
|
||||
|
||||
TextButton(
|
||||
onClick = { showDeleteDialog = true },
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = Color(0xFFD32F2F)),
|
||||
enabled = deleteBackupStatus !is DeleteBackupStatus.InProgress
|
||||
) {
|
||||
if (deleteBackupStatus is DeleteBackupStatus.InProgress) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(16.dp),
|
||||
strokeWidth = 2.dp,
|
||||
color = Color(0xFFD32F2F)
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
}
|
||||
Text("Delete Relay Backup")
|
||||
}
|
||||
|
||||
if (deleteBackupStatus is DeleteBackupStatus.Success) {
|
||||
Text(
|
||||
"Backup deleted",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
} else if (deleteBackupStatus is DeleteBackupStatus.Error) {
|
||||
Text(
|
||||
deleteBackupStatus.message,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
|
||||
if (showDeleteDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showDeleteDialog = false },
|
||||
title = { Text("Delete Relay Backup?") },
|
||||
text = {
|
||||
Text("This will delete your wallet backup from your relays. Make sure you have your recovery phrase saved elsewhere.")
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
showDeleteDialog = false
|
||||
onDeleteRelayBackup()
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = Color(0xFFD32F2F))
|
||||
) {
|
||||
Text("Delete")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showDeleteDialog = false }) {
|
||||
Text("Cancel")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Relay backup status list intentionally omitted — iOS doesn't
|
||||
// surface a per-relay backup display, and the majority of users
|
||||
// will use the default Spark wallet (which doesn't need relay
|
||||
// backup since the nsec is the canonical backup). Non-default
|
||||
// wallets can still tap "Backup to Nostr Relays" above; the
|
||||
// status / delete plumbing in WalletViewModel stays alive in
|
||||
// case we want to surface it again later.
|
||||
}
|
||||
|
||||
// Disclaimer
|
||||
@@ -3556,22 +3479,68 @@ private fun WalletSettingsContent(
|
||||
|
||||
Spacer(Modifier.height(32.dp))
|
||||
|
||||
Button(
|
||||
onClick = onDeleteWallet,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = if (isDefaultWallet) ButtonDefaults.buttonColors()
|
||||
else ButtonDefaults.buttonColors(
|
||||
// iOS treats both the default-Spark "Switch" and the NWC
|
||||
// "Disconnect" cases as quiet, recoverable affordances — a
|
||||
// card row with red text + swap icon plus a caption. Only the
|
||||
// truly destructive Delete (non-default Spark whose seed can't
|
||||
// be re-derived from nsec) keeps the filled-red CTA so the user
|
||||
// notices the irreversibility.
|
||||
val isRecoverable = walletMode == WalletMode.NWC || isDefaultWallet
|
||||
if (isRecoverable) {
|
||||
Text(
|
||||
stringResource(R.string.wallet_disconnect_section),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 4.dp, bottom = 6.dp)
|
||||
)
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onDeleteWallet),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.SwapHoriz,
|
||||
contentDescription = null,
|
||||
tint = Color(0xFFFF3B30),
|
||||
modifier = Modifier.size(22.dp)
|
||||
)
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Text(
|
||||
stringResource(R.string.wallet_switch_wallet),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = Color(0xFFFF3B30)
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
stringResource(R.string.wallet_switch_wallet_caption),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = 4.dp)
|
||||
)
|
||||
} else {
|
||||
Button(
|
||||
onClick = onDeleteWallet,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0xFFD32F2F),
|
||||
contentColor = Color.White
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
when {
|
||||
walletMode == WalletMode.NWC -> "Disconnect"
|
||||
isDefaultWallet -> stringResource(R.string.wallet_switch_wallet)
|
||||
else -> "Delete Wallet"
|
||||
}
|
||||
)
|
||||
) {
|
||||
Text("Delete Wallet")
|
||||
}
|
||||
}
|
||||
|
||||
// Footer
|
||||
@@ -3918,18 +3887,20 @@ private fun DeleteWalletConfirmContent(
|
||||
) {
|
||||
Spacer(Modifier.height(32.dp))
|
||||
|
||||
// Confirmation page uses the same iOS-red `#FF3B30` for all
|
||||
// three flows (default-switch, NWC-disconnect, non-default
|
||||
// delete) so the user doesn't see one orange and one red CTA
|
||||
// for what's the same conceptual action — "stop using this
|
||||
// wallet." Matches the iOS-red used on the entry-point card.
|
||||
val accent = Color(0xFFFF3B30)
|
||||
Icon(
|
||||
if (isDefault) Icons.Default.SwapHoriz else Icons.Default.Close,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(64.dp)
|
||||
.background(
|
||||
(if (isDefault) MaterialTheme.colorScheme.primary else Color(0xFFD32F2F))
|
||||
.copy(alpha = 0.1f),
|
||||
CircleShape
|
||||
)
|
||||
.background(accent.copy(alpha = 0.1f), CircleShape)
|
||||
.padding(16.dp),
|
||||
tint = if (isDefault) MaterialTheme.colorScheme.primary else Color(0xFFD32F2F)
|
||||
tint = accent
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(24.dp))
|
||||
@@ -3941,7 +3912,7 @@ private fun DeleteWalletConfirmContent(
|
||||
else -> "Delete Wallet"
|
||||
},
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
color = if (isDefault) MaterialTheme.colorScheme.onSurface else Color(0xFFD32F2F)
|
||||
color = if (isDefault) MaterialTheme.colorScheme.onSurface else accent
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
@@ -3963,7 +3934,7 @@ private fun DeleteWalletConfirmContent(
|
||||
Text(
|
||||
"Make sure you have backed up your recovery phrase before proceeding.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = Color(0xFFD32F2F),
|
||||
color = accent,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
@@ -3984,11 +3955,10 @@ private fun DeleteWalletConfirmContent(
|
||||
onClick = onDelete,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
enabled = isNwc || isDefault || confirmText == "DELETE",
|
||||
colors = if (isDefault) ButtonDefaults.buttonColors()
|
||||
else ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0xFFD32F2F),
|
||||
contentColor = Color.White
|
||||
)
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = accent,
|
||||
contentColor = Color.White
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
when {
|
||||
@@ -4723,11 +4693,21 @@ private fun WalletInfoRow(
|
||||
.padding(vertical = 6.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// Fixed-width label column so values across rows align to the
|
||||
// same x-coordinate regardless of label length, and the value
|
||||
// text always has a stable container to ellipsize within.
|
||||
// Without this, "Lightning address" pushes its value column 30dp
|
||||
// to the right of "Relay" — the iOS settings panel uses the
|
||||
// same column-aligned layout.
|
||||
Text(
|
||||
label,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.weight(1f)
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.widthIn(min = 110.dp)
|
||||
.padding(end = 12.dp)
|
||||
)
|
||||
Text(
|
||||
value,
|
||||
@@ -4735,7 +4715,8 @@ private fun WalletInfoRow(
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.weight(2f)
|
||||
textAlign = TextAlign.End,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
if (onCopy != null) {
|
||||
Spacer(Modifier.width(8.dp))
|
||||
|
||||
@@ -880,6 +880,18 @@ class WalletViewModel(
|
||||
if (provider === nwcRepo) {
|
||||
launch { nwcRepo.fetchNodeInfo() }
|
||||
}
|
||||
// Once the wallet finishes connecting, leave the setup
|
||||
// screen and land on Home — otherwise currentPage stays
|
||||
// at NwcSetup/SparkSetup and the Scaffold's "Wallet"
|
||||
// TopAppBar keeps showing over the dashboard. Guarded
|
||||
// to the setup pages so a connect-during-navigation
|
||||
// doesn't pop the user out of an unrelated sub-page.
|
||||
val page = _currentPage.value
|
||||
if (page is WalletPage.NwcSetup || page is WalletPage.SparkSetup) {
|
||||
pageStack.clear()
|
||||
pageStack.add(WalletPage.Home)
|
||||
_currentPage.value = WalletPage.Home
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -937,16 +949,18 @@ class WalletViewModel(
|
||||
|
||||
// Suppress the auto-create on the next navigateHome — the user
|
||||
// explicitly disconnected to choose a different wallet. They'll land
|
||||
// on the SparkSetup screen with the three options. Persist so the
|
||||
// choice survives app restarts.
|
||||
// on the wallet-mode picker (Spark vs NWC), matching iOS. Persist
|
||||
// so the choice survives app restarts.
|
||||
skipAutoCreate = true
|
||||
walletModeRepo.setAutoCreateSkipped(true)
|
||||
|
||||
pageStack.clear()
|
||||
pageStack.add(WalletPage.Home)
|
||||
if (wasSpark && keyRepo.hasKeypair()) {
|
||||
pageStack.add(WalletPage.SparkSetup)
|
||||
_currentPage.value = WalletPage.SparkSetup
|
||||
// Drop the user at the top-level wallet picker so they can
|
||||
// re-enter via Spark or NWC, not just Spark. iOS does the
|
||||
// same — Switch is a true "start over" affordance.
|
||||
_currentPage.value = WalletPage.Home
|
||||
} else {
|
||||
_currentPage.value = WalletPage.Home
|
||||
}
|
||||
|
||||
@@ -868,7 +868,9 @@
|
||||
<string name="wallet_generate_invoice">Generate invoice</string>
|
||||
<string name="wallet_use_default">Use my default wallet</string>
|
||||
<string name="wallet_default_subtitle">Derived from your Nostr key — no extra backup needed.</string>
|
||||
<string name="wallet_switch_wallet">Switch Wallet</string>
|
||||
<string name="wallet_switch_wallet">Switch to a different wallet</string>
|
||||
<string name="wallet_switch_wallet_body">Disconnect this wallet so you can use your default wallet or restore a different one. Your funds stay safe — you can reconnect this wallet anytime by entering its recovery phrase.</string>
|
||||
<string name="wallet_disconnect_section">Disconnect Wallet</string>
|
||||
<string name="wallet_switch_wallet_caption">Your default wallet is linked to your key and can always be restored. Switching connects a different wallet instead.</string>
|
||||
<string name="wallet_default_seed_info">This wallet is derived from your Nostr key, so the phrase below is just for export to other wallet apps. You don\'t need to back it up — your nsec is the backup.</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user