Hide broken options in Bitcoin wallets without a private key (#3532)
* hide unavailable receive page options * hide broken options in wallets without a private key * hide exporting unavailable logs * hide sign/verify on airgapped wallets * hide mweb on hwws * hide mweb ad for hww
malik1004x committed
Aug 24, 2026 at 22:24 UTC
9b50011e75f7861ccb21f818a0ba4c5f5ab34590
9 files changed
+54
-7
cw_bitcoin/lib/bitcoin_wallet.dart
+21
@@ -7,6 +7,7 @@ import 'package:cw_bitcoin/.secrets.g.dart' as secrets;
7
import 'package:cw_bitcoin/address_from_output.dart';
8
import 'package:cw_bitcoin/bitcoin_address_record.dart';
9
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
10
+import "package:cw_bitcoin/bitcoin_receive_page_option.dart";
11
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
12
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
13
import 'package:cw_bitcoin/electrum_balance.dart';
@@ -33,6 +34,7 @@ import 'package:cw_core/output_info.dart';
34
import 'package:cw_core/payjoin_session.dart';
35
import 'package:cw_core/pending_transaction.dart';
36
import 'package:cw_core/sync_status.dart';
37
+import "package:cw_core/receive_page_option.dart";
38
import 'package:cw_core/unspent_coin_type.dart';
39
import 'package:cw_core/unspent_coins_info.dart';
40
import 'package:cw_core/utils/print_verbose.dart';
@@ -417,6 +419,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
419
420
late final PayjoinManager payjoinManager;
421
422
+ @override
423
+ bool get hasPayjoinSupport => keys.privateKey.isNotEmpty;
424
+
425
+ @override
426
+ bool get hasLightningSupport => lightningWallet?.sdk != null;
427
+
428
bool get isPayjoinAvailable => unspentCoinsInfo.values
429
.where((element) => element.walletId == id && element.isSending && !element.isFrozen)
430
.isNotEmpty;
@@ -673,4 +681,17 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
681
682
return super.signMessage(message, address: address);
683
}
684
+
685
+ @override
686
+ bool receiveOptionAvailable(ReceivePageOption option) {
687
+ if(option == BitcoinReceivePageOption.lightning) {
688
+ return hasLightningSupport;
689
+ }
690
+
691
+ if(option == BitcoinReceivePageOption.silent_payments) {
692
+ return hasSilentPaymentsScanning;
693
+ }
694
+
695
+ return true;
696
+ }
697
}
cw_bitcoin/lib/electrum_wallet.dart
+1
@@ -407,6 +407,7 @@ abstract class ElectrumWalletBase
407
@override
408
bool isTestnet;
409
410
+ @override
411
bool get hasSilentPaymentsScanning => type == WalletType.bitcoin && keys.privateKey.isNotEmpty;
412
413
@observable
cw_core/lib/wallet_base.dart
+11
@@ -1,3 +1,4 @@
1
+import "package:cw_core/receive_page_option.dart";
2
import 'package:mobx/mobx.dart';
3
import 'package:cw_core/balance.dart';
4
import 'package:cw_core/transaction_info.dart';
@@ -136,4 +137,14 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
137
/// Each wallet implementation should override this to make a single, efficient call
138
/// Returns true if the node is healthy, false otherwise
139
Future<bool> checkNodeHealth();
140
+
141
+ bool get hasPayjoinSupport => false;
142
+ bool get hasLightningSupport => false;
143
+ bool get hasSilentPaymentsScanning => false;
144
+
145
+ // hardware wallet - bitbox, ledger, trezor.
146
+ // we also have airgap wallets but those can't sign messages
147
+ bool get canSignMessages => walletInfo.hardwareWalletType == null || walletInfo.isHardwareWallet;
148
+
149
+ bool receiveOptionAvailable(ReceivePageOption option) => true;
150
}
lib/src/screens/settings/other_settings_page.dart
+3
@@ -143,6 +143,7 @@ class OtherSettingsPage extends BasePage {
143
},
144
}),
145
),
146
+ if(_otherSettingsViewModel.hasSignVerify)
147
ListItemRegularRow(
148
keyValue: "security_backup_page_sign_and_verify",
149
label: S.of(context).sign_verify_title,
@@ -152,10 +153,12 @@ class OtherSettingsPage extends BasePage {
153
],
154
if (_otherSettingsViewModel.walletType == WalletType.bitcoin)
155
"btc_logging": [
156
+ if(_otherSettingsViewModel.hasLightning)
157
ListItemRegularRow(
158
keyValue: "export_lightning_logs",
159
label: S.of(context).export_lightning_logs,
160
onTap: () => onExportLNLog(context)),
161
+ if(_otherSettingsViewModel.hasPayjoin)
162
ListItemRegularRow(
163
keyValue: "export_payjoin_logs",
164
label: S.of(context).export_payjoin_logs,
lib/src/screens/settings/privacy_page.dart
+1
-1
@@ -76,7 +76,7 @@ class PrivacyPage extends BasePage {
76
}),
77
],
78
"": [
79
- if (_privacySettingsViewModel.isBitcoin)
79
+ if (_privacySettingsViewModel.hasSilentPaymentsScanning)
80
ListItemRegularRow(
81
iconPath: "assets/new-ui/settings_row_icons/silent-payments.svg",
82
keyValue: "silent_payments",
lib/view_model/dashboard/dashboard_view_model.dart
+1
-1
@@ -635,7 +635,7 @@ abstract class DashboardViewModelBase with Store {
635
636
if (settingsStore.mwebAdDismissed) return false;
637
638
- return Platform.isAndroid || Platform.isIOS;
638
+ return (Platform.isAndroid || Platform.isIOS) && !wallet.isHardwareWallet;
639
}
640
641
@action
lib/view_model/dashboard/receive_option_view_model.dart
+2
-1
@@ -35,7 +35,8 @@ abstract class ReceiveOptionViewModelBase with Store {
35
ReceivePageOption selectedReceiveOption;
36
37
@computed
38
- List<ReceivePageOption> get options => _wallet.walletAddresses.receivePageOptions;
38
+ List<ReceivePageOption> get options =>
39
+ _wallet.walletAddresses.receivePageOptions.where(_wallet.receiveOptionAvailable).toList();
40
41
String get walletTypeString => walletTypeToString(_wallet.type);
42
lib/view_model/settings/other_settings_view_model.dart
+6
@@ -47,6 +47,8 @@ abstract class OtherSettingsViewModelBase with Store {
47
final SettingsStore _settingsStore;
48
final SendViewModel sendViewModel;
49
50
+ bool get hasSignVerify => _wallet.canSignMessages;
51
+
52
@computed
53
TransactionPriority get transactionPriority {
54
final priority = _settingsStore.getPriority(walletType, chainId: chainId);
@@ -173,6 +175,10 @@ abstract class OtherSettingsViewModelBase with Store {
175
return null;
176
}
177
178
+ bool get hasPayjoin => _wallet.hasPayjoinSupport;
179
+
180
+ bool get hasLightning => _wallet.hasLightningSupport;
181
+
182
Future<File?> getLightningLog() async {
183
final path = await pathForWalletDir(name: _wallet.name, type: walletType);
184
final logFile = File("$path/lightning.log");
lib/view_model/settings/privacy_settings_view_model.dart
+8
-4
@@ -25,7 +25,12 @@ abstract class PrivacySettingsViewModelBase with Store {
25
bool get isBitcoin => _wallet.type == WalletType.bitcoin;
26
27
@computed
28
- bool get hasMWEB => _wallet.type == WalletType.litecoin && (Platform.isIOS || Platform.isAndroid);
28
+ bool get hasSilentPaymentsScanning => _wallet.hasSilentPaymentsScanning;
29
+
30
+ @computed
31
+ bool get hasMWEB =>
32
+ _wallet.type == WalletType.litecoin && (Platform.isIOS || Platform.isAndroid) &&
33
+ !_wallet.isHardwareWallet;
34
35
@computed
36
bool get isAutoGenerateSubaddressesEnabled =>
@@ -108,11 +113,10 @@ abstract class PrivacySettingsViewModelBase with Store {
113
bool get usePayjoin => _settingsStore.usePayjoin;
114
115
@computed
111
- bool get canUsePayjoin => _wallet.type == WalletType.bitcoin && DeviceInfo.instance.isMobile;
116
+ bool get canUsePayjoin => _wallet.hasPayjoinSupport && DeviceInfo.instance.isMobile;
117
118
@computed
114
- bool get canUseLightning =>
115
- _wallet.type == WalletType.bitcoin && !Platform.isWindows && !Platform.isLinux;
119
+ bool get canUseLightning => _wallet.hasLightningSupport;
120
121
@computed
122
bool get useLightning => _wallet.type == WalletType.bitcoin && bitcoin!.useLightning(_wallet);