- Restore BuildingTransactionDialog in SendView on desktop (revert showLoading) - Replace AlertDialog with SDialog for collateral address picker - Revert custom CreateMasternodeView close button and cancel/pop behavior - Extract masternode collateral send notes to MasternodeCollateralNotes
What changed, and why it matters
This commit is a small UI cleanup in a cryptocurrency wallet app. It restores a 'building transaction' loading dialog on desktop, swaps one style of address picker dialog for another, and moves two hard-coded note strings into a shared constants file. There is no obvious security fix or vulnerability being introduced; it looks like ordinary bug-fix/refactoring work.
No security action required. Treat as normal code review/QA for UI consistency and regression testing around transaction building and cancellation on desktop and mobile.
Security signals we found
No security-relevant keywords in commit title or message
No changes to cryptography, key handling, network calls, or permissions
UI-only refactor with no obvious confidentiality/integrity/availability impact
No vendor or researcher attribution in commit
Evidence from the diff
The diff reverts a previous change that used showLoading on desktop for transaction generation, going back to a non-root Navigator BuildingTransactionDialog shown for both mobile and desktop. It replaces Material AlertDialog with the project’s SDialog for picking a collateral address. It removes a custom close-button override in CreateMasternodeView and extracts masternode collateral note strings into MasternodeCollateralNotes. The only behavior change of note is that the cancel button in BuildingTransactionDialog no longer pops the dialog itself; instead the caller’s onCancel callback is responsible for popping. This is a refactor/consistency change, not a security patch.
Changed components
lib/pages/send_view/send_view.dartlib/pages/send_view/sub_widgets/building_transaction_dialog.dartlib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dartlib/pages/masternodes/create_masternode_view.dartlib/pages/masternodes/masternodes_home_view.dartlib/pages/masternodes/masternode_constants.dartInspect captured patch +84 / −70
diff --git a/lib/pages/masternodes/create_masternode_view.dart b/lib/pages/masternodes/create_masternode_view.dart
index 9916c04..3692724 100644
--- a/lib/pages/masternodes/create_masternode_view.dart
+++ b/lib/pages/masternodes/create_masternode_view.dart
@@ -54,11 +54,7 @@ class _CreateMasternodeDialogState extends ConsumerState<CreateMasternodeView> {
style: STextStyles.desktopH3(context),
),
),
- DesktopDialogCloseButton(
- onPressedOverride: () {
- Navigator.of(context, rootNavigator: true).pop();
- },
- ),
+ const DesktopDialogCloseButton(),
],
),
Flexible(
diff --git a/lib/pages/masternodes/masternode_constants.dart b/lib/pages/masternodes/masternode_constants.dart
new file mode 100644
index 0000000..9ee8c69
--- /dev/null
+++ b/lib/pages/masternodes/masternode_constants.dart
@@ -0,0 +1,12 @@
+abstract final class MasternodeCollateralNotes {
+ MasternodeCollateralNotes._();
+
+ static const unshield =
+ "Masternode collateral unshield (1000 FIRO to transparent).";
+ static const prep = "Masternode collateral prep (1000 FIRO self-send).";
+
+ static bool isUnshield(String? note) =>
+ note != null && note.contains(unshield);
+
+ static bool isPrep(String? note) => note != null && note.contains(prep);
+}
diff --git a/lib/pages/masternodes/masternodes_home_view.dart b/lib/pages/masternodes/masternodes_home_view.dart
index 7510306..4e4d30d 100644
--- a/lib/pages/masternodes/masternodes_home_view.dart
+++ b/lib/pages/masternodes/masternodes_home_view.dart
@@ -27,6 +27,7 @@ import '../../widgets/loading_indicator.dart';
import '../../widgets/stack_dialog.dart';
import '../send_view/send_view.dart';
import 'create_masternode_view.dart';
+import 'masternode_constants.dart';
import 'sub_widgets/masternodes_list.dart';
import 'sub_widgets/masternodes_table_desktop.dart';
@@ -472,8 +473,8 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
? (unshieldAmount ?? kMasterNodeValue)
: kMasterNodeValue,
note: fromPrivate
- ? "Masternode collateral unshield (1000 FIRO to transparent)."
- : "Masternode collateral prep (1000 FIRO self-send).",
+ ? MasternodeCollateralNotes.unshield
+ : MasternodeCollateralNotes.prep,
),
),
);
diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart
index bf38577..a096614 100644
--- a/lib/pages/send_view/send_view.dart
+++ b/lib/pages/send_view/send_view.dart
@@ -68,6 +68,8 @@ import '../../widgets/background.dart';
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../widgets/custom_buttons/blue_text_button.dart';
import '../../widgets/dialogs/firo_exchange_address_dialog.dart';
+import '../../widgets/dialogs/s_dialog.dart';
+import '../../widgets/desktop/secondary_button.dart';
import '../../widgets/epic_txs_method_toggle.dart';
import '../../widgets/eth_fee_form.dart';
import '../../widgets/fee_slider.dart';
@@ -82,7 +84,7 @@ import '../../widgets/stack_text_field.dart';
import '../../widgets/textfield_icon_button.dart';
import '../address_book_views/address_book_view.dart';
import '../coin_control/coin_control_view.dart';
-import '../masternodes/masternodes_home_view.dart';
+import '../masternodes/masternode_constants.dart';
import 'confirm_transaction_view.dart';
import 'sub_widgets/building_transaction_dialog.dart';
import 'sub_widgets/dual_balance_selection_sheet.dart';
@@ -311,30 +313,52 @@ class _SendViewState extends ConsumerState<SendView> {
final selectedAddress = await showDialog<String>(
context: context,
- builder: (ctx) => AlertDialog(
- title: const Text("Choose your address"),
- content: SizedBox(
- width: 520,
- child: ListView.builder(
- shrinkWrap: true,
- itemCount: addresses.length,
- itemBuilder: (_, index) => ListTile(
- contentPadding: EdgeInsets.zero,
- title: Text(
- addresses[index],
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
+ builder: (ctx) => SDialog(
+ contentCanScroll: false,
+ padding: EdgeInsets.all(Util.isDesktop ? 32 : 16),
+ child: SizedBox(
+ width: Util.isDesktop ? 520 : null,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Text(
+ "Choose your address",
+ style: Util.isDesktop
+ ? STextStyles.desktopH3(ctx)
+ : STextStyles.pageTitleH2(ctx),
),
- onTap: () => Navigator.of(ctx).pop(addresses[index]),
- ),
+ const SizedBox(height: 16),
+ ConstrainedBox(
+ constraints: BoxConstraints(
+ maxHeight: MediaQuery.of(ctx).size.height * 0.5,
+ ),
+ child: ListView.builder(
+ shrinkWrap: true,
+ itemCount: addresses.length,
+ itemBuilder: (_, index) => ListTile(
+ contentPadding: EdgeInsets.zero,
+ title: Text(
+ addresses[index],
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ style: Util.isDesktop
+ ? STextStyles.w500_16(ctx)
+ : STextStyles.w500_14(ctx),
+ ),
+ onTap: () => Navigator.of(ctx).pop(addresses[index]),
+ ),
+ ),
+ ),
+ const SizedBox(height: 16),
+ SecondaryButton(
+ buttonHeight: ButtonHeight.l,
+ label: "Cancel",
+ onPressed: () => Navigator.of(ctx).pop(),
+ ),
+ ],
),
),
- actions: [
- TextButton(
- onPressed: () => Navigator.of(ctx).pop(),
- child: const Text("Cancel"),
- ),
- ],
),
);
@@ -947,14 +971,13 @@ class _SendViewState extends ConsumerState<SendView> {
}
}
- final shouldShowBuildingDialog = mounted && !Util.isDesktop;
- bool wasCancelled = false;
try {
- if (shouldShowBuildingDialog) {
+ bool wasCancelled = false;
+
+ if (mounted) {
unawaited(
showDialog<void>(
context: context,
- useRootNavigator: false,
useSafeArea: false,
barrierDismissible: false,
builder: (context) {
@@ -966,6 +989,8 @@ class _SendViewState extends ConsumerState<SendView> {
BalanceType.private,
onCancel: () {
wasCancelled = true;
+
+ Navigator.of(context).pop();
},
);
},
@@ -973,6 +998,8 @@ class _SendViewState extends ConsumerState<SendView> {
);
}
+ final time = Future<dynamic>.delayed(const Duration(milliseconds: 2500));
+
Future<TxData> txDataFuture;
if (isPaynymSend) {
@@ -1122,27 +1149,9 @@ class _SendViewState extends ConsumerState<SendView> {
);
}
- TxData txData;
- if (Util.isDesktop && mounted) {
- Exception? buildEx;
- final desktopResult = await showLoading<TxData>(
- whileFuture: txDataFuture,
- context: context,
- message: "Generating transaction...",
- delay: const Duration(milliseconds: 2500),
- rootNavigator: true,
- onException: (e) => buildEx = e,
- );
- if (buildEx != null) throw buildEx!;
- if (desktopResult == null || !mounted) return;
- txData = desktopResult;
- } else {
- final time = Future<dynamic>.delayed(
- const Duration(milliseconds: 2500),
- );
- final results = await Future.wait([txDataFuture, time]);
- txData = results.first as TxData;
- }
+ final results = await Future.wait([txDataFuture, time]);
+
+ TxData txData = results.first as TxData;
if (!wasCancelled && mounted) {
if (isPaynymSend) {
@@ -1157,10 +1166,8 @@ class _SendViewState extends ConsumerState<SendView> {
txData = txData.copyWith(noteOnChain: onChainNoteController.text);
}
- if (shouldShowBuildingDialog) {
- // pop building dialog
- Navigator.of(context, rootNavigator: false).pop();
- }
+ // pop building dialog
+ Navigator.of(context).pop();
unawaited(
Navigator.of(context).push(
@@ -1186,10 +1193,8 @@ class _SendViewState extends ConsumerState<SendView> {
} catch (e, s) {
Logging.instance.e("$e\n$s", error: e, stackTrace: s);
if (mounted) {
- if (shouldShowBuildingDialog && !wasCancelled) {
- // pop building dialog
- Navigator.of(context, rootNavigator: false).pop();
- }
+ // pop building dialog
+ Navigator.of(context).pop();
unawaited(
showDialog<dynamic>(
@@ -1370,10 +1375,9 @@ class _SendViewState extends ConsumerState<SendView> {
walletId = widget.walletId;
clipboard = widget.clipboard;
_isMasternodeCollateralUnshield =
- (_data?.note.contains("Masternode collateral unshield") ?? false) &&
- isFiro;
+ MasternodeCollateralNotes.isUnshield(_data?.note) && isFiro;
_isMasternodeCollateralSelfSend =
- ((_data?.note.contains("Masternode collateral prep") ?? false) ||
+ (MasternodeCollateralNotes.isPrep(_data?.note) ||
_isMasternodeCollateralUnshield) &&
isFiro;
diff --git a/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart b/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart
index 095bd9f..0d1e9ef 100644
--- a/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart
+++ b/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart
@@ -72,7 +72,6 @@ class _RestoringDialogState extends ConsumerState<BuildingTransactionDialog> {
buttonHeight: ButtonHeight.l,
label: "Cancel",
onPressed: () {
- Navigator.of(context).pop();
onCancel.call();
},
),
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart
index b15555d..b8dc85f 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart
@@ -537,8 +537,9 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
}
}
- bool wasCancelled = false;
try {
+ bool wasCancelled = false;
+
if (mounted) {
unawaited(
showDialog<dynamic>(
@@ -561,6 +562,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
BalanceType.private,
onCancel: () {
wasCancelled = true;
+
+ Navigator.of(context).pop();
},
),
),
@@ -772,9 +775,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
} catch (e, s) {
Logging.instance.e("Desktop send: ", error: e, stackTrace: s);
if (mounted) {
- if (!wasCancelled) {
- Navigator.of(context, rootNavigator: true).pop();
- }
+ // pop building dialog
+ Navigator.of(context, rootNavigator: true).pop();
unawaited(
showDialog<void>(
Why this scored 11/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.