From d2cf09e5e1541848516f34de3855c4eea3551fca Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 8 Apr 2026 18:01:13 +0000 Subject: [PATCH 1/5] feat: move lightning address and payment targets to wallet screen - Add lightning address field with save button to WalletScreen - Add payment targets navigation row to WalletScreen - Remove lightning address field from profile editor (NewUserMetadataScreen) - Remove payment targets entry from AllSettings - Extend WalletViewModel to load/save the lightning address via userMetadata https://claude.ai/code/session_017NPhwCnSzCuMn9sTX3ca37 --- .../ui/actions/NewUserMetadataScreen.kt | 16 --- .../ui/actions/NewUserMetadataViewModel.kt | 8 -- .../loggedIn/settings/AllSettingsScreen.kt | 8 -- .../ui/screen/loggedIn/wallet/WalletScreen.kt | 125 +++++++++++++++--- .../screen/loggedIn/wallet/WalletViewModel.kt | 38 +++++- 5 files changed, 138 insertions(+), 57 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt index 33722468d..b4ad1a4e6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt @@ -227,22 +227,6 @@ fun NewUserMetadataScreen( Spacer(modifier = Modifier.height(10.dp)) - OutlinedTextField( - label = { Text(text = stringRes(R.string.lightning_address)) }, - modifier = Modifier.fillMaxWidth(), - value = postViewModel.lnAddress.value, - onValueChange = { postViewModel.lnAddress.value = it }, - placeholder = { - Text( - text = "me@mylightningnode.com", - color = MaterialTheme.colorScheme.placeholderText, - ) - }, - singleLine = true, - ) - - Spacer(modifier = Modifier.height(10.dp)) - OutlinedTextField( label = { Text(text = stringRes(R.string.nip_05) + " (NIP-05)") }, modifier = Modifier.fillMaxWidth(), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt index c5ea8056f..80db28a2d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt @@ -57,8 +57,6 @@ class NewUserMetadataViewModel : ViewModel() { val website = mutableStateOf("") val pronouns = mutableStateOf("") val nip05 = mutableStateOf("") - val lnAddress = mutableStateOf("") - val lnURL = mutableStateOf("") val twitter = mutableStateOf("") val github = mutableStateOf("") @@ -82,8 +80,6 @@ class NewUserMetadataViewModel : ViewModel() { website.value = it.info.website ?: "" pronouns.value = it.info.pronouns ?: "" nip05.value = it.info.nip05 ?: "" - lnAddress.value = it.info.lud16 ?: "" - lnURL.value = it.info.lud06 ?: "" } twitter.value = "" @@ -121,8 +117,6 @@ class NewUserMetadataViewModel : ViewModel() { pronouns = pronouns.value, about = about.value, nip05 = nip05.value, - lnAddress = lnAddress.value, - lnURL = lnURL.value, ) val identities = @@ -146,8 +140,6 @@ class NewUserMetadataViewModel : ViewModel() { banner.value = "" website.value = "" nip05.value = "" - lnAddress.value = "" - lnURL.value = "" twitter.value = "" github.value = "" mastodon.value = "" diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt index fad9ebf31..c501ac432 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt @@ -29,7 +29,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.AccountBalanceWallet import androidx.compose.material.icons.outlined.Bolt import androidx.compose.material.icons.outlined.CloudUpload import androidx.compose.material.icons.outlined.DeleteForever @@ -122,13 +121,6 @@ fun AllSettingsScreen( onClick = { nav.nav(Route.EditMediaServers) }, ) HorizontalDivider() - SettingsNavigationRow( - title = R.string.payment_targets, - icon = Icons.Outlined.AccountBalanceWallet, - tint = tint, - onClick = { nav.nav(Route.EditPaymentTargets) }, - ) - HorizontalDivider() SettingsNavigationRow( title = R.string.reactions, icon = Icons.Outlined.FavoriteBorder, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt index 8ef787815..10aecc411 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt @@ -30,22 +30,28 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.List import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowUpward +import androidx.compose.material.icons.outlined.AccountBalanceWallet import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -64,6 +70,7 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.ui.theme.placeholderText import java.text.NumberFormat @OptIn(ExperimentalMaterial3Api::class) @@ -73,10 +80,14 @@ fun WalletScreen( nav: INav, ) { val walletViewModel: WalletViewModel = viewModel() - walletViewModel.init(accountViewModel.account) + walletViewModel.init(accountViewModel) val hasWallet by walletViewModel.hasWalletSetup.collectAsState() + LaunchedEffect(accountViewModel) { + walletViewModel.loadLnAddress() + } + Scaffold( topBar = { TopAppBar( @@ -92,30 +103,36 @@ fun WalletScreen( ) }, ) { padding -> - if (!hasWallet) { - NoWalletSetup( - modifier = Modifier.padding(padding), - nav = nav, - ) - } else { - WalletHomeContent( - walletViewModel = walletViewModel, - modifier = Modifier.padding(padding), - nav = nav, - ) + Column( + modifier = + Modifier + .padding(padding) + .fillMaxSize() + .verticalScroll(rememberScrollState()), + ) { + if (!hasWallet) { + NoWalletSetup(nav = nav) + } else { + WalletHomeContent( + walletViewModel = walletViewModel, + nav = nav, + ) + } + + HorizontalDivider() + LightningAddressSection(walletViewModel = walletViewModel) + HorizontalDivider() + PaymentTargetsRow(nav = nav) } } } @Composable -private fun NoWalletSetup( - modifier: Modifier, - nav: INav, -) { +private fun NoWalletSetup(nav: INav) { Column( modifier = - modifier - .fillMaxSize() + Modifier + .fillMaxWidth() .padding(32.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, @@ -142,7 +159,6 @@ private fun NoWalletSetup( @Composable private fun WalletHomeContent( walletViewModel: WalletViewModel, - modifier: Modifier, nav: INav, ) { val balance by walletViewModel.balanceSats.collectAsState() @@ -157,8 +173,8 @@ private fun WalletHomeContent( Column( modifier = - modifier - .fillMaxSize() + Modifier + .fillMaxWidth() .padding(24.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { @@ -206,7 +222,7 @@ private fun WalletHomeContent( ) } - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.height(32.dp)) // Action buttons Row( @@ -276,3 +292,68 @@ private fun WalletHomeContent( Spacer(modifier = Modifier.height(24.dp)) } } + +@Composable +private fun LightningAddressSection(walletViewModel: WalletViewModel) { + val lnAddress by walletViewModel.lnAddress.collectAsState() + + Column( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + Text( + text = stringRes(R.string.lightning_address), + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.SemiBold, + ) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + OutlinedTextField( + value = lnAddress, + onValueChange = { walletViewModel.updateLnAddress(it) }, + modifier = Modifier.weight(1f), + placeholder = { + Text( + text = "me@mylightningnode.com", + color = MaterialTheme.colorScheme.placeholderText, + ) + }, + singleLine = true, + ) + TextButton(onClick = { walletViewModel.saveLnAddress() }) { + Text(text = stringRes(R.string.save)) + } + } + } +} + +@Composable +private fun PaymentTargetsRow(nav: INav) { + Row( + modifier = + Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + imageVector = Icons.Outlined.AccountBalanceWallet, + contentDescription = null, + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colorScheme.onBackground, + ) + Spacer(modifier = Modifier.width(16.dp)) + Text( + text = stringRes(R.string.payment_targets), + style = MaterialTheme.typography.bodyLarge, + ) + } + TextButton(onClick = { nav.nav(Route.EditPaymentTargets) }) { + Text(text = stringRes(R.string.manage)) + } + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt index 7737923a0..2c22a44a6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip47WalletConnect.rpc.GetBalanceMethod import com.vitorpamplona.quartz.nip47WalletConnect.rpc.GetBalanceSuccessResponse import com.vitorpamplona.quartz.nip47WalletConnect.rpc.GetInfoMethod @@ -86,10 +87,14 @@ private const val PAYMENT_FAILED = "Payment failed" class WalletViewModel : ViewModel() { private var account: Account? = null + private var accountViewModel: AccountViewModel? = null private val _hasWalletSetup = MutableStateFlow(false) val hasWalletSetup = _hasWalletSetup.asStateFlow() + private val _lnAddress = MutableStateFlow("") + val lnAddress = _lnAddress.asStateFlow() + private val _balanceSats = MutableStateFlow(null) val balanceSats = _balanceSats.asStateFlow() @@ -137,15 +142,42 @@ class WalletViewModel : ViewModel() { onTimeout() } - fun init(account: Account) { - this.account = account - _hasWalletSetup.value = account.nip47SignerState.hasWalletConnectSetup() + fun init(accountViewModel: AccountViewModel) { + this.accountViewModel = accountViewModel + this.account = accountViewModel.account + _hasWalletSetup.value = accountViewModel.account.nip47SignerState.hasWalletConnectSetup() } fun refreshWalletSetup() { _hasWalletSetup.value = account?.nip47SignerState?.hasWalletConnectSetup() == true } + fun loadLnAddress() { + viewModelScope.launch(Dispatchers.IO) { + val info = + account + ?.userProfile() + ?.metadataOrNull() + ?.flow + ?.value + ?.info + _lnAddress.value = info?.lud16 ?: "" + } + } + + fun updateLnAddress(address: String) { + _lnAddress.value = address + } + + fun saveLnAddress() { + val accountVm = accountViewModel ?: return + val acc = account ?: return + accountVm.launchSigner { + val event = acc.userMetadata.sendNewUserMetadata(lnAddress = _lnAddress.value) + acc.sendLiterallyEverywhere(event) + } + } + fun fetchBalance() { val acc = account ?: return viewModelScope.launch(Dispatchers.IO) { From 05b352b61cafae598c9c3531cf23b1ad32aed966 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 8 Apr 2026 18:13:05 +0000 Subject: [PATCH 2/5] fix: update WalletViewModel.init call in sub-screens WalletReceiveScreen, WalletSendScreen, and WalletTransactionsScreen were still passing Account instead of AccountViewModel after the init signature change. https://claude.ai/code/session_017NPhwCnSzCuMn9sTX3ca37 --- .../amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt | 2 +- .../amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt | 2 +- .../ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt index c0451ede7..af1a106c2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt @@ -82,7 +82,7 @@ fun WalletReceiveScreen( val walletViewModel: WalletViewModel = viewModel() LaunchedEffect(accountViewModel) { - walletViewModel.init(accountViewModel.account) + walletViewModel.init(accountViewModel) } DisposableEffect(Unit) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt index ca5bd2609..35cc4a696 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt @@ -73,7 +73,7 @@ fun WalletSendScreen( val walletViewModel: WalletViewModel = viewModel() LaunchedEffect(accountViewModel) { - walletViewModel.init(accountViewModel.account) + walletViewModel.init(accountViewModel) } DisposableEffect(Unit) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt index 60235e15a..8d580d10d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt @@ -83,7 +83,7 @@ fun WalletTransactionsScreen( val walletViewModel: WalletViewModel = viewModel() LaunchedEffect(accountViewModel) { - walletViewModel.init(accountViewModel.account) + walletViewModel.init(accountViewModel) walletViewModel.fetchTransactions() } From bbc4155c40e10d7f3f738e3e31abbda110ad86bd Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 8 Apr 2026 18:23:25 +0000 Subject: [PATCH 3/5] feat: move lightning address and payment targets to wallet setup screen - Add trailingContent lambda to UpdateZapAmountContent so callers can inject sections inside its scrollable Column - Inject lightning address field and payment targets row into NIP47SetupScreen via trailingContent - Add WalletViewModel to NIP47SetupScreen to load/save the lightning address - Add settings icon button to WalletScreen TopAppBar when wallet is configured, navigating back to NIP47SetupScreen - Restore WalletScreen to its original layout (no ln/payment sections) https://claude.ai/code/session_017NPhwCnSzCuMn9sTX3ca37 --- .../amethyst/ui/note/UpdateZapAmountDialog.kt | 4 + .../loggedIn/settings/NIP47SetupScreen.kt | 117 ++++++++++++++- .../ui/screen/loggedIn/wallet/WalletScreen.kt | 134 +++++------------- 3 files changed, 148 insertions(+), 107 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt index ba4238425..a3827159d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt @@ -46,6 +46,7 @@ import androidx.compose.animation.togetherWith import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row @@ -148,6 +149,7 @@ fun UpdateZapAmountContent( onClose: () -> Unit, nip47uri: String? = null, accountViewModel: AccountViewModel, + trailingContent: @Composable ColumnScope.() -> Unit = {}, ) { val context = LocalContext.current val clipboardManager = LocalClipboard.current @@ -649,6 +651,8 @@ fun UpdateZapAmountContent( } } + trailingContent() + Spacer(modifier = Modifier.height(16.dp)) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt index 4b6036510..b33273aac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt @@ -20,20 +20,43 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.AccountBalanceWallet import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountContent import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.WalletViewModel +import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.ui.theme.placeholderText @Composable fun NIP47SetupScreen( @@ -44,17 +67,22 @@ fun NIP47SetupScreen( val postViewModel: UpdateZapAmountViewModel = viewModel() postViewModel.init(accountViewModel) + val walletViewModel: WalletViewModel = viewModel() + walletViewModel.init(accountViewModel) + LaunchedEffect(accountViewModel, postViewModel) { postViewModel.load() + walletViewModel.loadLnAddress() } - NIP47SetupScreen(postViewModel, accountViewModel, nav, nip47) + NIP47SetupScreen(postViewModel, walletViewModel, accountViewModel, nav, nip47) } @OptIn(ExperimentalMaterial3Api::class) @Composable fun NIP47SetupScreen( postViewModel: UpdateZapAmountViewModel, + walletViewModel: WalletViewModel, accountViewModel: AccountViewModel, nav: INav, nip47: String?, @@ -76,10 +104,89 @@ fun NIP47SetupScreen( }, ) { Column(Modifier.padding(it)) { - UpdateZapAmountContent(postViewModel, onClose = { - postViewModel.cancel() - nav.popBack() - }, nip47, accountViewModel) + UpdateZapAmountContent( + postViewModel, + onClose = { + postViewModel.cancel() + nav.popBack() + }, + nip47, + accountViewModel, + ) { + HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) + LightningAddressSetupSection(walletViewModel) + HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) + PaymentTargetsSetupRow(nav) + } + } + } +} + +@Composable +private fun LightningAddressSetupSection(walletViewModel: WalletViewModel) { + val lnAddress by walletViewModel.lnAddress.collectAsState() + + Column( + modifier = Modifier.padding(horizontal = 0.dp, vertical = 4.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + Text( + text = stringRes(R.string.lightning_address), + color = MaterialTheme.colorScheme.primary, + style = MaterialTheme.typography.titleSmall, + ) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + OutlinedTextField( + value = lnAddress, + onValueChange = { walletViewModel.updateLnAddress(it) }, + modifier = Modifier.weight(1f), + placeholder = { + Text( + text = "me@mylightningnode.com", + color = MaterialTheme.colorScheme.placeholderText, + ) + }, + singleLine = true, + ) + TextButton(onClick = { walletViewModel.saveLnAddress() }) { + Text(text = stringRes(R.string.save)) + } + } + } +} + +@Composable +private fun PaymentTargetsSetupRow(nav: INav) { + Row( + modifier = + Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + imageVector = Icons.Outlined.AccountBalanceWallet, + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = MaterialTheme.colorScheme.primary, + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = stringRes(R.string.payment_targets), + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + ) + } + TextButton(onClick = { nav.nav(Route.EditPaymentTargets) }) { + Text( + text = stringRes(R.string.manage), + fontWeight = FontWeight.SemiBold, + ) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt index 10aecc411..d4935ea94 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt @@ -30,28 +30,23 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.List import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowUpward -import androidx.compose.material.icons.outlined.AccountBalanceWallet +import androidx.compose.material.icons.outlined.Settings import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -70,7 +65,6 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes -import com.vitorpamplona.amethyst.ui.theme.placeholderText import java.text.NumberFormat @OptIn(ExperimentalMaterial3Api::class) @@ -84,10 +78,6 @@ fun WalletScreen( val hasWallet by walletViewModel.hasWalletSetup.collectAsState() - LaunchedEffect(accountViewModel) { - walletViewModel.loadLnAddress() - } - Scaffold( topBar = { TopAppBar( @@ -100,39 +90,43 @@ fun WalletScreen( ) } }, + actions = { + if (hasWallet) { + IconButton(onClick = { nav.nav(Route.Nip47NWCSetup()) }) { + Icon( + imageVector = Icons.Outlined.Settings, + contentDescription = stringRes(R.string.settings), + ) + } + } + }, ) }, ) { padding -> - Column( - modifier = - Modifier - .padding(padding) - .fillMaxSize() - .verticalScroll(rememberScrollState()), - ) { - if (!hasWallet) { - NoWalletSetup(nav = nav) - } else { - WalletHomeContent( - walletViewModel = walletViewModel, - nav = nav, - ) - } - - HorizontalDivider() - LightningAddressSection(walletViewModel = walletViewModel) - HorizontalDivider() - PaymentTargetsRow(nav = nav) + if (!hasWallet) { + NoWalletSetup( + modifier = Modifier.padding(padding), + nav = nav, + ) + } else { + WalletHomeContent( + walletViewModel = walletViewModel, + modifier = Modifier.padding(padding), + nav = nav, + ) } } } @Composable -private fun NoWalletSetup(nav: INav) { +private fun NoWalletSetup( + modifier: Modifier, + nav: INav, +) { Column( modifier = - Modifier - .fillMaxWidth() + modifier + .fillMaxSize() .padding(32.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, @@ -159,6 +153,7 @@ private fun NoWalletSetup(nav: INav) { @Composable private fun WalletHomeContent( walletViewModel: WalletViewModel, + modifier: Modifier, nav: INav, ) { val balance by walletViewModel.balanceSats.collectAsState() @@ -173,8 +168,8 @@ private fun WalletHomeContent( Column( modifier = - Modifier - .fillMaxWidth() + modifier + .fillMaxSize() .padding(24.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { @@ -222,7 +217,7 @@ private fun WalletHomeContent( ) } - Spacer(modifier = Modifier.height(32.dp)) + Spacer(modifier = Modifier.weight(1f)) // Action buttons Row( @@ -292,68 +287,3 @@ private fun WalletHomeContent( Spacer(modifier = Modifier.height(24.dp)) } } - -@Composable -private fun LightningAddressSection(walletViewModel: WalletViewModel) { - val lnAddress by walletViewModel.lnAddress.collectAsState() - - Column( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - Text( - text = stringRes(R.string.lightning_address), - style = MaterialTheme.typography.titleSmall, - fontWeight = FontWeight.SemiBold, - ) - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp), - ) { - OutlinedTextField( - value = lnAddress, - onValueChange = { walletViewModel.updateLnAddress(it) }, - modifier = Modifier.weight(1f), - placeholder = { - Text( - text = "me@mylightningnode.com", - color = MaterialTheme.colorScheme.placeholderText, - ) - }, - singleLine = true, - ) - TextButton(onClick = { walletViewModel.saveLnAddress() }) { - Text(text = stringRes(R.string.save)) - } - } - } -} - -@Composable -private fun PaymentTargetsRow(nav: INav) { - Row( - modifier = - Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 16.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - imageVector = Icons.Outlined.AccountBalanceWallet, - contentDescription = null, - modifier = Modifier.size(24.dp), - tint = MaterialTheme.colorScheme.onBackground, - ) - Spacer(modifier = Modifier.width(16.dp)) - Text( - text = stringRes(R.string.payment_targets), - style = MaterialTheme.typography.bodyLarge, - ) - } - TextButton(onClick = { nav.nav(Route.EditPaymentTargets) }) { - Text(text = stringRes(R.string.manage)) - } - } -} From 144b82dbe3aea95f68d474deda53ad0e211cf001 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 8 Apr 2026 18:32:08 +0000 Subject: [PATCH 4/5] refactor: inline lightning address and payment targets in wallet setup screen - Remove separate Save/Manage buttons; both are now saved via the screen's existing SavingTopBar save action - Lightning address: plain OutlinedTextField, saved on confirm - Payment targets: inline editable list (Column, not LazyColumn) with add/delete directly in the scrollable content area - Wire walletViewModel.saveLnAddress() and paymentTargetsViewModel.savePaymentTargets() into onPost - Wire paymentTargetsViewModel.refresh() into onCancel https://claude.ai/code/session_017NPhwCnSzCuMn9sTX3ca37 --- .../loggedIn/settings/NIP47SetupScreen.kt | 131 +++++++++++------- 1 file changed, 81 insertions(+), 50 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt index b33273aac..cfb2b6870 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt @@ -23,40 +23,42 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.AccountBalanceWallet +import androidx.compose.material.icons.rounded.Delete import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.actions.paymentTargets.PaymentTargetAddField +import com.vitorpamplona.amethyst.ui.actions.paymentTargets.PaymentTargetsViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountContent import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.WalletViewModel import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.ui.theme.SettingsCategorySpacingModifier +import com.vitorpamplona.amethyst.ui.theme.grayText import com.vitorpamplona.amethyst.ui.theme.placeholderText +import com.vitorpamplona.quartz.experimental.nipA3.PaymentTarget @Composable fun NIP47SetupScreen( @@ -70,12 +72,16 @@ fun NIP47SetupScreen( val walletViewModel: WalletViewModel = viewModel() walletViewModel.init(accountViewModel) + val paymentTargetsViewModel: PaymentTargetsViewModel = viewModel() + paymentTargetsViewModel.init(accountViewModel) + LaunchedEffect(accountViewModel, postViewModel) { postViewModel.load() walletViewModel.loadLnAddress() + paymentTargetsViewModel.load() } - NIP47SetupScreen(postViewModel, walletViewModel, accountViewModel, nav, nip47) + NIP47SetupScreen(postViewModel, walletViewModel, paymentTargetsViewModel, accountViewModel, nav, nip47) } @OptIn(ExperimentalMaterial3Api::class) @@ -83,6 +89,7 @@ fun NIP47SetupScreen( fun NIP47SetupScreen( postViewModel: UpdateZapAmountViewModel, walletViewModel: WalletViewModel, + paymentTargetsViewModel: PaymentTargetsViewModel, accountViewModel: AccountViewModel, nav: INav, nip47: String?, @@ -94,10 +101,13 @@ fun NIP47SetupScreen( isActive = postViewModel::hasChanged, onCancel = { postViewModel.cancel() + paymentTargetsViewModel.refresh() nav.popBack() }, onPost = { postViewModel.sendPost() + walletViewModel.saveLnAddress() + paymentTargetsViewModel.savePaymentTargets() nav.popBack() }, ) @@ -108,6 +118,7 @@ fun NIP47SetupScreen( postViewModel, onClose = { postViewModel.cancel() + paymentTargetsViewModel.refresh() nav.popBack() }, nip47, @@ -116,7 +127,7 @@ fun NIP47SetupScreen( HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) LightningAddressSetupSection(walletViewModel) HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) - PaymentTargetsSetupRow(nav) + PaymentTargetsInlineSection(paymentTargetsViewModel) } } } @@ -126,66 +137,86 @@ fun NIP47SetupScreen( private fun LightningAddressSetupSection(walletViewModel: WalletViewModel) { val lnAddress by walletViewModel.lnAddress.collectAsState() - Column( - modifier = Modifier.padding(horizontal = 0.dp, vertical = 4.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Text( text = stringRes(R.string.lightning_address), color = MaterialTheme.colorScheme.primary, style = MaterialTheme.typography.titleSmall, + modifier = SettingsCategorySpacingModifier, + ) + OutlinedTextField( + value = lnAddress, + onValueChange = { walletViewModel.updateLnAddress(it) }, + modifier = Modifier.fillMaxWidth(), + placeholder = { + Text( + text = "me@mylightningnode.com", + color = MaterialTheme.colorScheme.placeholderText, + ) + }, + singleLine = true, ) - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp), - ) { - OutlinedTextField( - value = lnAddress, - onValueChange = { walletViewModel.updateLnAddress(it) }, - modifier = Modifier.weight(1f), - placeholder = { - Text( - text = "me@mylightningnode.com", - color = MaterialTheme.colorScheme.placeholderText, - ) - }, - singleLine = true, - ) - TextButton(onClick = { walletViewModel.saveLnAddress() }) { - Text(text = stringRes(R.string.save)) - } - } } } @Composable -private fun PaymentTargetsSetupRow(nav: INav) { +private fun PaymentTargetsInlineSection(viewModel: PaymentTargetsViewModel) { + val targets by viewModel.paymentTargets.collectAsStateWithLifecycle() + + SettingsCategory( + R.string.payment_targets, + R.string.payment_targets_section_explainer, + SettingsCategorySpacingModifier, + ) + + if (targets.isEmpty()) { + Text( + text = stringRes(id = R.string.no_payment_targets_message), + modifier = Modifier.padding(vertical = 8.dp), + color = MaterialTheme.colorScheme.grayText, + style = MaterialTheme.typography.bodyMedium, + ) + } else { + Column { + targets.forEach { target -> + PaymentTargetInlineEntry(target = target, onDelete = { viewModel.removeTarget(target) }) + } + } + } + + PaymentTargetAddField { type, authority -> + viewModel.addTarget(type, authority) + } +} + +@Composable +private fun PaymentTargetInlineEntry( + target: PaymentTarget, + onDelete: () -> Unit, +) { Row( modifier = Modifier .fillMaxWidth() - .padding(vertical = 8.dp), + .padding(vertical = 6.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - imageVector = Icons.Outlined.AccountBalanceWallet, - contentDescription = null, - modifier = Modifier.size(20.dp), - tint = MaterialTheme.colorScheme.primary, - ) - Spacer(modifier = Modifier.width(8.dp)) + Column(modifier = Modifier.weight(1f)) { Text( - text = stringRes(R.string.payment_targets), - style = MaterialTheme.typography.titleSmall, - color = MaterialTheme.colorScheme.primary, + text = target.type.replaceFirstChar(Char::titlecase), + style = MaterialTheme.typography.bodyLarge, + ) + Text( + text = target.authority, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.grayText, ) } - TextButton(onClick = { nav.nav(Route.EditPaymentTargets) }) { - Text( - text = stringRes(R.string.manage), - fontWeight = FontWeight.SemiBold, + IconButton(onClick = onDelete) { + Icon( + imageVector = Icons.Rounded.Delete, + contentDescription = stringRes(id = R.string.delete_payment_target), ) } } From f550a5f426a41d488d6f74affba97f2963eaf9c4 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 8 Apr 2026 18:43:31 +0000 Subject: [PATCH 5/5] fix: consolidate wallet setup saves into a single signer call All three saves (zap settings, lightning address, payment targets) now run sequentially inside one accountViewModel.launchSigner block, so the signer is only invoked once per save instead of three times. - Extract sendPostSuspend() from UpdateZapAmountViewModel.sendPost() - Extract saveLnAddressSuspend() from WalletViewModel.saveLnAddress() - Extract savePaymentTargetsSuspend() from PaymentTargetsViewModel.savePaymentTargets() - NIP47SetupScreen.onPost calls all three suspend fns in one launchSigner https://claude.ai/code/session_017NPhwCnSzCuMn9sTX3ca37 --- .../actions/paymentTargets/PaymentTargetsViewModel.kt | 10 ++++++++-- .../amethyst/ui/note/UpdateZapAmountViewModel.kt | 8 +++++++- .../ui/screen/loggedIn/settings/NIP47SetupScreen.kt | 8 +++++--- .../ui/screen/loggedIn/wallet/WalletViewModel.kt | 10 +++++++--- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsViewModel.kt index 37c63c9ec..362df0c9c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsViewModel.kt @@ -79,9 +79,15 @@ class PaymentTargetsViewModel : ViewModel() { fun savePaymentTargets() { if (isModified) { accountViewModel.launchSigner { - account.savePaymentTargets(_paymentTargets.value) - refresh() + savePaymentTargetsSuspend() } } } + + suspend fun savePaymentTargetsSuspend() { + if (isModified) { + account.savePaymentTargets(_paymentTargets.value) + refresh() + } + } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountViewModel.kt index 5125b31e9..33a090373 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountViewModel.kt @@ -84,6 +84,12 @@ class UpdateZapAmountViewModel : ViewModel() { } fun sendPost() { + accountViewModel.launchSigner { + sendPostSuspend() + } + } + + suspend fun sendPostSuspend() { val nip47Update = if (walletConnectRelay.text.isNotBlank() && walletConnectPubkey.text.isNotBlank()) { val pubkeyHex = @@ -110,7 +116,7 @@ class UpdateZapAmountViewModel : ViewModel() { null } - accountViewModel.updateZapAmounts(amountSet, selectedZapType, nip47Update) + accountViewModel.account.updateZapAmounts(amountSet, selectedZapType, nip47Update) nextAmount = TextFieldValue("") } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt index cfb2b6870..eab38a637 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt @@ -105,9 +105,11 @@ fun NIP47SetupScreen( nav.popBack() }, onPost = { - postViewModel.sendPost() - walletViewModel.saveLnAddress() - paymentTargetsViewModel.savePaymentTargets() + accountViewModel.launchSigner { + postViewModel.sendPostSuspend() + walletViewModel.saveLnAddressSuspend() + paymentTargetsViewModel.savePaymentTargetsSuspend() + } nav.popBack() }, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt index 2c22a44a6..ce8ceddff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt @@ -171,13 +171,17 @@ class WalletViewModel : ViewModel() { fun saveLnAddress() { val accountVm = accountViewModel ?: return - val acc = account ?: return accountVm.launchSigner { - val event = acc.userMetadata.sendNewUserMetadata(lnAddress = _lnAddress.value) - acc.sendLiterallyEverywhere(event) + saveLnAddressSuspend() } } + suspend fun saveLnAddressSuspend() { + val acc = account ?: return + val event = acc.userMetadata.sendNewUserMetadata(lnAddress = _lnAddress.value) + acc.sendLiterallyEverywhere(event) + } + fun fetchBalance() { val acc = account ?: return viewModelScope.launch(Dispatchers.IO) {