Skip to content

Commit f8378ac

Browse files
committed
fix: address review findings - router guard, disclaimer ordering, bbswitch, dead code
1 parent 5603eba commit f8378ac

8 files changed

Lines changed: 32 additions & 23 deletions

File tree

lib/core/widgets/switch/bb_switch.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,27 @@ import 'package:bb_mobile/core/themes/app_theme.dart';
22
import 'package:flutter/material.dart';
33

44
class BBSwitch extends StatelessWidget {
5-
const BBSwitch({super.key, required this.value, required this.onChanged});
5+
const BBSwitch({
6+
super.key,
7+
required this.value,
8+
required this.onChanged,
9+
this.materialTapTargetSize,
10+
});
611

712
final bool value;
813

914
/// Null renders the switch disabled.
1015
final ValueChanged<bool>? onChanged;
1116

17+
/// Pass [MaterialTapTargetSize.shrinkWrap] for dense placements (e.g.
18+
/// single-line tiles).
19+
final MaterialTapTargetSize? materialTapTargetSize;
20+
1221
@override
1322
Widget build(BuildContext context) {
1423
return Switch(
1524
value: value,
25+
materialTapTargetSize: materialTapTargetSize,
1626
activeThumbColor: context.appColors.onSecondary,
1727
activeTrackColor: context.appColors.secondary,
1828
inactiveThumbColor: context.appColors.border,

lib/features/receive/presentation/bloc/receive_bloc.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,11 @@ class ReceiveBloc extends Bloc<ReceiveEvent, ReceiveState> {
142142
/// contribute as an input. Unconfirmed counts: the contribution path draws
143143
/// from BDK's listUnspent (which includes unconfirmed outputs), so waiting
144144
/// for a confirmation only delays payjoin activation on fresh wallets;
145-
/// worst case a strict sender rejects a proposal spending an unconfirmed
146-
/// input and the payment falls back to a normal broadcast.
145+
/// worst case is not just a strict sender rejecting the proposal (falling
146+
/// back to a normal broadcast): a payjoin tx spending our unconfirmed
147+
/// input can be invalidated by an RBF of that input's parent after both
148+
/// sides consider the payment done. _filterAvailableUtxos preferring
149+
/// confirmed UTXOs when available is the cheap mitigation.
147150
bool _isPayjoinEligible(Wallet wallet, bool payjoinEnabled) =>
148151
wallet.signsLocally && payjoinEnabled && wallet.balanceSat > BigInt.zero;
149152

@@ -236,7 +239,7 @@ class ReceiveBloc extends Bloc<ReceiveEvent, ReceiveState> {
236239

237240
// If the payjoin receiver is not set yet, we need to create it, but only
238241
// if the wallet is eligible (see _isPayjoinEligible: not watch-only,
239-
// payjoin enabled globally, and a confirmed balance to contribute) —
242+
// payjoin enabled globally, and a balance to contribute) —
240243
// when disabled the QR must never advertise a pj= endpoint, or the
241244
// sender's wallet would attempt a payjoin nobody here will process.
242245
//

lib/features/receive/presentation/bloc/receive_state.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ abstract class ReceiveState with _$ReceiveState {
285285
// would create the session.
286286
//
287287
// Also gated on [hasUtxos]: ReceiveBloc only creates a session for a
288-
// wallet with a confirmed balance to contribute (see
288+
// wallet with a balance to contribute (unconfirmed counts, see
289289
// ReceiveBloc._isPayjoinEligible — a payjoin proposal needs at least
290290
// one UTXO), so an empty wallet would otherwise hit the exact same
291291
// "stuck loading forever" bug as the disabled case.

lib/features/receive/ui/receive_router.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,12 @@ class ReceiveRouter {
146146
final wallet = state.extra is Wallet ? state.extra! as Wallet : null;
147147
// Same guard as the lightning and liquid routes: this pageBuilder
148148
// re-runs when popping back from the child amount route, and an
149-
// unconditional restart wipes the confirmed amount, message and
150-
// label the user just entered there.
151-
if (bloc.state.type != ReceiveType.bitcoin ||
152-
(wallet != null && bloc.state.wallet?.id != wallet.id)) {
149+
// unconditional restart wipes the confirmed amount and message the
150+
// user just entered there. Type mismatch only — comparing the
151+
// route-extra wallet would revert an in-flow dropdown switch on
152+
// pop-back (the extra still holds the wallet the flow was entered
153+
// with), and a fresh entry always has a null type anyway.
154+
if (bloc.state.type != ReceiveType.bitcoin) {
153155
bloc.add(ReceiveBitcoinStarted(wallet));
154156
}
155157
return NoTransitionPage(child: ReceiveQrPage(wallet: wallet));

lib/features/receive/ui/screens/receive_qr_screen.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class ReceiveQrPage extends StatelessWidget {
6161
// Half-gaps below the address block: matches the address→payjoin
6262
// spacing inside ReceiveQRDetails so the stack reads evenly.
6363
Gap(gap / 2),
64-
ReceiveInfoDetails(wallet: wallet),
64+
const ReceiveInfoDetails(),
6565
Gap(gap / 2),
6666
if (showAddressVerification) ...[
6767
if (isLedger)
@@ -235,9 +235,7 @@ class ReceiveQRDetails extends StatelessWidget {
235235
}
236236

237237
class ReceiveInfoDetails extends StatelessWidget {
238-
const ReceiveInfoDetails({super.key, this.wallet});
239-
240-
final Wallet? wallet;
238+
const ReceiveInfoDetails({super.key});
241239

242240
/// Suffix showing the unit the user entered in, when it wasn't BTC:
243241
/// sats → " (N sats)", fiat → " (~X CUR)". Entered-in-BTC shows nothing —

lib/features/receive/ui/widgets/receive_payjoin_toggle_button.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:bb_mobile/core/widgets/switch/bb_switch.dart';
12
import 'package:bb_mobile/core/themes/app_theme.dart';
23
import 'package:bb_mobile/core/utils/build_context_x.dart';
34
import 'package:bb_mobile/core/widgets/text/text.dart';
@@ -56,7 +57,7 @@ class ReceivePayjoinToggleTile extends StatelessWidget {
5657
color: context.appColors.secondary,
5758
),
5859
),
59-
Switch(
60+
BBSwitch(
6061
value: enabled,
6162
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
6263
onChanged: (value) {

lib/features/settings/ui/widgets/payjoin_disclaimer_dialog.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ abstract final class PayjoinDisclaimerDialog {
2222
static Future<void> showIfNeverShown(BuildContext context) async {
2323
final datasource = locator<PayjoinDisclaimerDatasource>();
2424
if (await datasource.readDisclaimerShown()) return;
25-
await datasource.writeDisclaimerShown();
25+
// Mark shown only once the dialog was actually displayed — writing
26+
// first would permanently skip the one-time disclosure if the context
27+
// is unmounted by the time the async read resolves.
2628
if (!context.mounted) return;
2729
await show(context);
30+
await datasource.writeDisclaimerShown();
2831
}
2932
}
3033

localization/app_en.arb

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,10 +1660,6 @@
16601660
"@receiveFeeExplanation": {
16611661
"description": "Explanation that fees are deducted from the sent amount"
16621662
},
1663-
"receiveNotePlaceholder": "Note",
1664-
"@receiveNotePlaceholder": {
1665-
"description": "Placeholder text for note input field"
1666-
},
16671663
"receiveReceiveAmount": "Receive Amount",
16681664
"@receiveReceiveAmount": {
16691665
"description": "Label for the amount that will be received after fees"
@@ -14929,10 +14925,6 @@
1492914925
"@sendPayjoinLabel": {
1493014926
"description": "Row title on the send confirmation details showing (with a tick) that this send will attempt a payjoin."
1493114927
},
14932-
"sendPayjoinWillBeAttempted": "A payjoin will be attempted for this payment.",
14933-
"@sendPayjoinWillBeAttempted": {
14934-
"description": "Confirm-screen indicator shown when a payjoin will be attempted for the send."
14935-
},
1493614928
"sendSentWithoutPayjoin": "Sent without Payjoin: the recipient did not complete the Payjoin, so a standard transaction was broadcast instead.",
1493714929
"@sendSentWithoutPayjoin": {
1493814930
"description": "Success-screen notice when a payjoin send fell back to a plain broadcast."

0 commit comments

Comments
 (0)