Add loading spinner in seed screen
What changed, and why it matters
This commit adds a visual loading spinner to the wallet restore screen and prevents the restore button from triggering multiple restore attempts at once. It is a user-experience improvement, not a security fix.
No security action required. Treat as a routine UI/UX improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces an _isLoading state flag in RestoreWalletScreen. The flag is set to true at the start of _restore() and reset to false in both success and error paths. The restore button now shows a CircularProgressIndicator while loading, and the _restore() method returns early if already loading. There are no cryptographic, authentication, or access-control changes.
Changed components
lib/screens/restore_wallet.dartInspect captured patch +30 / −2
diff --git a/lib/screens/restore_wallet.dart b/lib/screens/restore_wallet.dart
index 492cfa0..7b61365 100644
--- a/lib/screens/restore_wallet.dart
+++ b/lib/screens/restore_wallet.dart
@@ -15,13 +15,17 @@ class RestoreWalletScreen extends StatefulWidget {
class _RestoreWalletScreenState extends State<RestoreWalletScreen> {
final _mnemonicController = TextEditingController();
final _restoreHeightController = TextEditingController();
+ bool _isLoading = false;
String? _mnemonicError;
String? _restoreHeightError;
Future<void> _restore() async {
+ if (_isLoading) return;
+
final i18n = AppLocalizations.of(context)!;
setState(() {
+ _isLoading = true;
_mnemonicError = null;
_restoreHeightError = null;
});
@@ -50,9 +54,17 @@ class _RestoreWalletScreenState extends State<RestoreWalletScreen> {
await wallet.refresh();
await wallet.loadAllStats();
await wallet.connectToDaemon();
+
+ setState(() {
+ _isLoading = false;
+ });
} on Exception catch (error) {
final errorMsg = error.toString().replaceFirst('Exception: ', '');
+ setState(() {
+ _isLoading = false;
+ });
+
if (errorMsg == 'Invalid mnemonic.') {
setState(() {
_mnemonicError = i18n.restoreWalletInvalidMnemonic;
@@ -74,6 +86,9 @@ class _RestoreWalletScreenState extends State<RestoreWalletScreen> {
return;
} catch (error) {
log(LogLevel.error, error.toString());
+ setState(() {
+ _isLoading = false;
+ });
if (mounted) {
final i18n = AppLocalizations.of(context)!;
@@ -96,6 +111,7 @@ class _RestoreWalletScreenState extends State<RestoreWalletScreen> {
@override
Widget build(BuildContext context) {
final i18n = AppLocalizations.of(context)!;
+ final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
appBar: AppBar(title: Text('Skylight Monero Wallet')),
@@ -153,9 +169,21 @@ class _RestoreWalletScreenState extends State<RestoreWalletScreen> {
onPressed: () => Navigator.pop(context),
child: Text(i18n.cancel),
),
- FilledButton(
+ FilledButton.icon(
onPressed: _restore,
- child: Text(i18n.restoreWalletRestoreButton),
+ label: Text(i18n.restoreWalletRestoreButton),
+ icon: _isLoading
+ ? SizedBox(
+ width: 16,
+ height: 16,
+ child: CircularProgressIndicator(
+ strokeWidth: 2,
+ color: isDarkTheme
+ ? Theme.of(context).colorScheme.onPrimary
+ : Colors.white,
+ ),
+ )
+ : null,
),
],
),
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.