display "generating transaction" as a full-modal overlay (#3740)
What changed, and why it matters
This commit changes the user interface so that a 'Generating transaction...' loading spinner appears as a full-screen overlay while a transaction is being created. It does not change how transactions are built, signed, or broadcast, and it does not touch any security-sensitive logic. It is purely a visual/UX improvement.
No security action required. This is a routine UX change. Standard code review and QA for accessibility and layout are sufficient.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch adds a new Flutter StatelessWidget, GeneratingTransactionOverlay, which wraps the existing send confirmation content in a Stack. When sendViewModel.state is IsExecutingState, it shows a semantically labeled, pointer-blocking overlay with a CupertinoActivityIndicator and localized text. The only change in send_confirm_sheet.dart is wrapping _buildMainContent with the new overlay widget. No cryptographic, wallet, or network code is modified.
Changed components
lib/new-ui/widgets/send_page/generating_transaction_overlay.dartlib/new-ui/widgets/send_page/send_confirm_sheet.dartInspect captured patch +78 / −2
### lib/new-ui/widgets/send_page/generating_transaction_overlay.dart
@@ -0,0 +1,70 @@
+import "package:cake_wallet/core/execution_state.dart";
+import "package:cake_wallet/generated/i18n.dart";
+import "package:cake_wallet/view_model/send/send_view_model.dart";
+import "package:flutter/cupertino.dart";
+import "package:flutter/material.dart";
+import "package:flutter_mobx/flutter_mobx.dart";
+
+class GeneratingTransactionOverlay extends StatelessWidget {
+ const GeneratingTransactionOverlay({required this.sendViewModel, required this.child, super.key});
+
+ final SendViewModel sendViewModel;
+ final Widget child;
+
+ @override
+ Widget build(BuildContext context) => Observer(
+ builder: (_) => Stack(
+ alignment: Alignment.topCenter,
+ children: [
+ ExcludeSemantics(
+ excluding: sendViewModel.state.runtimeType == IsExecutingState,
+ child: child,
+ ),
+ Positioned.fill(
+ child: IgnorePointer(
+ ignoring: sendViewModel.state.runtimeType != IsExecutingState,
+ child: ExcludeSemantics(
+ excluding: sendViewModel.state.runtimeType != IsExecutingState,
+ child: AnimatedOpacity(
+ opacity: sendViewModel.state.runtimeType == IsExecutingState ? 1 : 0,
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeOutCubic,
+ child: ColoredBox(
+ color: Theme.of(context).colorScheme.surface,
+ child: Padding(
+ padding: const EdgeInsets.only(bottom: 32),
+ child: Semantics(
+ container: true,
+ liveRegion: true,
+ label: "${S.of(context).generating_transaction}...",
+ excludeSemantics: true,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ spacing: 12,
+ children: [
+ CupertinoActivityIndicator(
+ radius: 16,
+ color: Theme.of(context).colorScheme.onSurfaceVariant,
+ ),
+ Text(
+ "${S.of(context).generating_transaction}...",
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
+ color: Theme.of(context).colorScheme.onSurfaceVariant,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+}
### lib/new-ui/widgets/send_page/send_confirm_sheet.dart
@@ -10,6 +10,7 @@ import 'package:cake_wallet/new-ui/widgets/animated_dropdown.dart';
import 'package:cake_wallet/new-ui/widgets/coins_page/assets_history/transaction_details_modal.dart';
import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
+import "package:cake_wallet/new-ui/widgets/send_page/generating_transaction_overlay.dart";
import 'package:cake_wallet/new-ui/widgets/send_page/send_confirm_bottom_widget.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
@@ -175,8 +176,8 @@ class SendTransactionDetails extends StatelessWidget {
onTrailingPressed: Navigator.of(context).maybePop,
),
isPage
- ? Expanded(child: _buildMainContent(context))
- : Flexible(child: _buildMainContent(context))
+ ? Expanded(child: _buildOverlaidContent(context))
+ : Flexible(child: _buildOverlaidContent(context))
]),
);
}
@@ -194,6 +195,11 @@ class SendTransactionDetails extends StatelessWidget {
return "${decimals == null ? str : str.withDecimals(decimals)} $unit";
}
+ Widget _buildOverlaidContent(BuildContext context) => GeneratingTransactionOverlay(
+ sendViewModel: sendViewModel,
+ child: _buildMainContent(context),
+ );
+
Widget _buildMainContent(BuildContext context) => Observer(builder: (context) {
final transaction = sendViewModel.pendingTransaction;
final additionalCostNotice = sendViewModel.pendingTransactionAdditionalCostNotice;Why this scored 15/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.