diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettings.kt index b90861d506..35761beaea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettings.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettings.kt @@ -58,6 +58,11 @@ data class UiSettings( val fontFamily: FontFamilyType = FontFamilyType.SYSTEM, val fontSize: FontSizeType = FontSizeType.NORMAL, val composeSignature: String = "", + // Whether the on-chain (Bitcoin/Taproot) wallet is shown across the app: the + // "Bitcoin" card on the wallet screen, the on-chain chip on profiles, and the + // on-chain rail in the Send Payment screen. Defaults to true (shown) so the + // behavior is unchanged for everyone who doesn't turn it off. + val showOnchainWallet: Boolean = true, ) enum class ThemeType( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettingsFlow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettingsFlow.kt index f84459a560..947270eb6e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettingsFlow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettingsFlow.kt @@ -58,6 +58,7 @@ class UiSettingsFlow( val fontFamily: MutableStateFlow = MutableStateFlow(FontFamilyType.SYSTEM), val fontSize: MutableStateFlow = MutableStateFlow(FontSizeType.NORMAL), val composeSignature: MutableStateFlow = MutableStateFlow(""), + val showOnchainWallet: MutableStateFlow = MutableStateFlow(true), ) { val listOfFlows: List> = listOf>( @@ -90,6 +91,7 @@ class UiSettingsFlow( fontFamily, fontSize, composeSignature, + showOnchainWallet, ) // emits at every change in any of the propertyes. @@ -126,6 +128,7 @@ class UiSettingsFlow( flows[26] as FontFamilyType, flows[27] as FontSizeType, flows[28] as String, + flows[29] as Boolean, ) } @@ -160,6 +163,7 @@ class UiSettingsFlow( fontFamily.value, fontSize.value, composeSignature.value, + showOnchainWallet.value, ) fun update(torSettings: UiSettings): Boolean { @@ -281,6 +285,10 @@ class UiSettingsFlow( composeSignature.tryEmit(torSettings.composeSignature) any = true } + if (showOnchainWallet.value != torSettings.showOnchainWallet) { + showOnchainWallet.tryEmit(torSettings.showOnchainWallet) + any = true + } return any } @@ -335,6 +343,7 @@ class UiSettingsFlow( MutableStateFlow(uiSettings.fontFamily), MutableStateFlow(uiSettings.fontSize), MutableStateFlow(uiSettings.composeSignature), + MutableStateFlow(uiSettings.showOnchainWallet), ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/UISharedPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/UISharedPreferences.kt index c101e4bc58..f35b3124ce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/UISharedPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/UISharedPreferences.kt @@ -127,6 +127,7 @@ class UiSharedPreferences( val UI_FONT_FAMILY = stringPreferencesKey("ui.font_family") val UI_FONT_SIZE = stringPreferencesKey("ui.font_size") val UI_COMPOSE_SIGNATURE = stringPreferencesKey("ui.compose_signature") + val UI_SHOW_ONCHAIN_WALLET = booleanPreferencesKey("ui.show_onchain_wallet") suspend fun uiPreferences(context: Context): UiSettings? = try { @@ -168,6 +169,7 @@ class UiSharedPreferences( fontFamily = preferences[UI_FONT_FAMILY]?.let { FontFamilyType.valueOf(it) } ?: FontFamilyType.SYSTEM, fontSize = preferences[UI_FONT_SIZE]?.let { FontSizeType.valueOf(it) } ?: FontSizeType.NORMAL, composeSignature = preferences[UI_COMPOSE_SIGNATURE] ?: "", + showOnchainWallet = preferences[UI_SHOW_ONCHAIN_WALLET] ?: true, ) } catch (e: Exception) { if (e is CancellationException) throw e @@ -221,6 +223,7 @@ class UiSharedPreferences( preferences[UI_FONT_FAMILY] = sharedSettings.fontFamily.name preferences[UI_FONT_SIZE] = sharedSettings.fontSize.name preferences[UI_COMPOSE_SIGNATURE] = sharedSettings.composeSignature + preferences[UI_SHOW_ONCHAIN_WALLET] = sharedSettings.showOnchainWallet } } catch (e: Exception) { if (e is CancellationException) throw e diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfilePaymentRailChips.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfilePaymentRailChips.kt index 43bf6693b3..b64b7bc3f0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfilePaymentRailChips.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfilePaymentRailChips.kt @@ -47,6 +47,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons @@ -103,7 +104,9 @@ fun DisplayPaymentRailChips( ?.target ?.mintUrl } - val onchainAvailable = LocalCache.onchainBackend != null + val showOnchainWallet by accountViewModel.settings.uiSettingsFlow.showOnchainWallet + .collectAsStateWithLifecycle() + val onchainAvailable = showOnchainWallet && LocalCache.onchainBackend != null val address = remember(baseUser.pubkeyHex) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/SendPaymentScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/SendPaymentScreen.kt index 9363aa9567..d9a2fc3da0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/SendPaymentScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/SendPaymentScreen.kt @@ -160,7 +160,11 @@ private fun SendPaymentLoaded( // Cheap read, intentionally not remembered: the chain backend is wired up // asynchronously at boot and a frozen `remember {}` would hide the // on-chain rail for the whole composition if the screen won the race. - val onchainAvailable = LocalCache.onchainBackend != null + // Also honors the user's "show on-chain wallet" preference — off hides the + // rail everywhere, matching the wallet screen and profile chips. + val showOnchainWallet by accountViewModel.settings.uiSettingsFlow.showOnchainWallet + .collectAsStateWithLifecycle() + val onchainAvailable = showOnchainWallet && LocalCache.onchainBackend != null // When navigated from a `bitcoin` payment target, the on-chain rail pays // that announced address directly (plain send, no NIP-BC receipt) instead // of the recipient's pubkey-derived Taproot address. Re-validated here in diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ProfileUiSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ProfileUiSettingsScreen.kt index c39794a696..137ffacbe3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ProfileUiSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ProfileUiSettingsScreen.kt @@ -92,6 +92,7 @@ fun ProfileUiSettingsContent(accountViewModel: AccountViewModel) { val showAppRecommendations by ui.showProfileAppRecommendations.collectAsStateWithLifecycle() val showZapReceived by ui.showProfileZapReceivedFeed.collectAsStateWithLifecycle() val showFollowers by ui.showProfileFollowersFeed.collectAsStateWithLifecycle() + val showOnchainWallet by ui.showOnchainWallet.collectAsStateWithLifecycle() Column( modifier = @@ -136,6 +137,13 @@ fun ProfileUiSettingsContent(accountViewModel: AccountViewModel) { ) HorizontalDivider(modifier = Modifier.padding(horizontal = Size20dp)) + ProfileUiSwitchRow( + title = stringRes(R.string.profile_ui_setting_onchain_wallet), + checked = showOnchainWallet, + onCheckedChange = { ui.showOnchainWallet.tryEmit(it) }, + ) + HorizontalDivider(modifier = Modifier.padding(horizontal = Size20dp)) + Column(modifier = Modifier.padding(vertical = 12.dp, horizontal = Size20dp)) { GalleryChoice(ui) } 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 4d5db6d518..829c98f12a 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 @@ -103,6 +103,8 @@ fun WalletScreen( // the first composition pass. init() is idempotent — just sets refs. cashuWalletViewModel.init(accountViewModel) + val showOnchainWallet by accountViewModel.settings.uiSettingsFlow.showOnchainWallet + .collectAsState() val hasNwcWallet by walletViewModel.hasWalletSetup.collectAsState() val cashuWalletEvent by cashuWalletViewModel.walletEvent.collectAsState() val hasCashuWallet = cashuWalletEvent != null @@ -147,11 +149,13 @@ fun WalletScreen( }, ) { padding -> Column(modifier = Modifier.padding(padding)) { - OnchainSection( - accountViewModel = accountViewModel, - nav = nav, - modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), - ) + if (showOnchainWallet) { + OnchainSection( + accountViewModel = accountViewModel, + nav = nav, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + ) + } if (!hasWallet) { NoWalletSetup( modifier = Modifier, diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 96d1287e7d..40ab075e01 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -2608,6 +2608,7 @@ App Recommendations Zap Received Feed Followers Feed + Bitcoin (on-chain) Wallet Reaction Row Configure which reaction buttons are shown, their order, and whether to display counters. Enabled