Bring spice's restore date selector and sync progress when loading icon is tapped
What changed, and why it matters
This commit adds a user-friendly date picker for wallet restoration and makes tooltips show when tapping a status icon. It is a routine feature improvement with no apparent security relevance.
No security action required; review as normal UI/UX feature code.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces a ‘Restore Date’ field in the wallet restore screen that opens a date picker, formats the selected date, and maps it to a Monero restore height via the existing getHeightByDate helper. It also adds a 2014-4 baseline entry to the height lookup table and changes two Tooltip widgets to use tap-triggered tooltips. No security-sensitive logic, input validation, cryptography, or network handling is modified.
Changed components
lib/screens/restore_wallet.dartlib/screens/wallet_home.dartlib/util/get_height_by_date.dartlocalization filesInspect captured patch +59 / −3
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index c33500b..1ac956e 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -80,6 +80,7 @@
"restoreWalletDescription": "Input your Monero seed below. We will check common formats.",
"restoreWalletSeedLabel": "Seed",
"restoreWalletRestoreHeightLabel": "Restore Height (Optional)",
+ "restoreWalletRestoreDateLabel": "Restore Date",
"restoreWalletRestoreButton": "Restore",
"restoreWalletInvalidMnemonic": "Invalid seed.",
"navigationBarWallet": "Wallet",
diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart
index 4d53a50..2eda308 100644
--- a/lib/l10n/app_localizations.dart
+++ b/lib/l10n/app_localizations.dart
@@ -489,6 +489,12 @@ abstract class AppLocalizations {
/// **'Restore Height (Optional)'**
String get restoreWalletRestoreHeightLabel;
+ /// No description provided for @restoreWalletRestoreDateLabel.
+ ///
+ /// In en, this message translates to:
+ /// **'Restore Date'**
+ String get restoreWalletRestoreDateLabel;
+
/// No description provided for @restoreWalletRestoreButton.
///
/// In en, this message translates to:
diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart
index 503f317..ebb0200 100644
--- a/lib/l10n/app_localizations_en.dart
+++ b/lib/l10n/app_localizations_en.dart
@@ -220,6 +220,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get restoreWalletRestoreHeightLabel => 'Restore Height (Optional)';
+ @override
+ String get restoreWalletRestoreDateLabel => 'Restore Date';
+
@override
String get restoreWalletRestoreButton => 'Restore';
diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart
index 31971ed..bca1091 100644
--- a/lib/l10n/app_localizations_pt.dart
+++ b/lib/l10n/app_localizations_pt.dart
@@ -220,6 +220,9 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get restoreWalletRestoreHeightLabel => 'Bloco de Restauração (opcional)';
+ @override
+ String get restoreWalletRestoreDateLabel => 'Data de Restauração';
+
@override
String get restoreWalletRestoreButton => 'Restaurar';
diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb
index 0164cd2..4edf47f 100644
--- a/lib/l10n/app_pt.arb
+++ b/lib/l10n/app_pt.arb
@@ -80,6 +80,7 @@
"restoreWalletDescription": "Insira sua semente Monero abaixo. Verificaremos os formatos comuns.",
"restoreWalletSeedLabel": "Semente",
"restoreWalletRestoreHeightLabel": "Bloco de Restauração (opcional)",
+ "restoreWalletRestoreDateLabel": "Data de Restauração",
"restoreWalletRestoreButton": "Restaurar",
"restoreWalletInvalidMnemonic": "Semente inválida.",
"navigationBarWallet": "Carteira",
diff --git a/lib/screens/restore_wallet.dart b/lib/screens/restore_wallet.dart
index 2e3ead5..0b1da24 100644
--- a/lib/screens/restore_wallet.dart
+++ b/lib/screens/restore_wallet.dart
@@ -24,6 +24,8 @@ class RestoreWalletScreen extends StatefulWidget {
class _RestoreWalletScreenState extends State<RestoreWalletScreen> with SecureScreenMixin {
final _mnemonicController = TextEditingController();
final _restoreHeightController = TextEditingController();
+ final _restoreDateController = TextEditingController();
+ DateTime _restoreDate = DateTime.now();
bool _isPolyseed = false;
bool _isLoading = false;
String? _mnemonicError;
@@ -33,6 +35,7 @@ class _RestoreWalletScreenState extends State<RestoreWalletScreen> with SecureSc
void dispose() {
_mnemonicController.dispose();
_restoreHeightController.dispose();
+ _restoreDateController.dispose();
super.dispose();
}
@@ -143,6 +146,7 @@ class _RestoreWalletScreenState extends State<RestoreWalletScreen> with SecureSc
setState(() {
_isPolyseed = false;
_restoreHeightController.text = '';
+ _restoreDateController.text = '';
});
}
return;
@@ -155,16 +159,38 @@ class _RestoreWalletScreenState extends State<RestoreWalletScreen> with SecureSc
);
final birthday = polyseed.birthday;
- final restoreHeight = getHeightByDate(
- date: DateTime.fromMillisecondsSinceEpoch(birthday * 1000),
- );
+ final birthdayDate = DateTime.fromMillisecondsSinceEpoch(birthday * 1000);
+ final restoreHeight = getHeightByDate(date: birthdayDate);
setState(() {
_isPolyseed = true;
+ _restoreDate = birthdayDate;
+ _restoreDateController.text = _formatDate(birthdayDate);
_restoreHeightController.text = restoreHeight.toString();
});
}
+ String _formatDate(DateTime date) {
+ return '${date.year.toString().padLeft(4, '0')}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
+ }
+
+ Future<void> _pickDate() async {
+ final picked = await showDatePicker(
+ context: context,
+ initialDate: _restoreDate,
+ firstDate: DateTime(2014, 4),
+ lastDate: DateTime.now(),
+ );
+ if (picked == null) return;
+
+ setState(() {
+ _restoreDate = picked;
+ _restoreDateController.text = _formatDate(picked);
+ _restoreHeightController.text = getHeightByDate(date: picked).toString();
+ _restoreHeightError = null;
+ });
+ }
+
void _onMnemonicChanged(String value) {
_calculatePolyseedHeight();
@@ -226,6 +252,19 @@ class _RestoreWalletScreenState extends State<RestoreWalletScreen> with SecureSc
),
),
),
+ Padding(
+ padding: EdgeInsets.symmetric(horizontal: 20),
+ child: TextFormField(
+ controller: _restoreDateController,
+ readOnly: true,
+ onTap: _pickDate,
+ decoration: InputDecoration(
+ labelText: i18n.restoreWalletRestoreDateLabel,
+ border: OutlineInputBorder(),
+ suffixIcon: Icon(Icons.calendar_today),
+ ),
+ ),
+ ),
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: TextFormField(
diff --git a/lib/screens/wallet_home.dart b/lib/screens/wallet_home.dart
index 4ecfd48..d5640db 100644
--- a/lib/screens/wallet_home.dart
+++ b/lib/screens/wallet_home.dart
@@ -209,6 +209,7 @@ class _WalletHomeScreenState extends State<WalletHomeScreen> {
message:
'Not connecting: this connection requires Tor, but no Tor proxy is available. '
'Re-enable Tor, or edit the connection.',
+ triggerMode: TooltipTriggerMode.tap,
child: StatusIcon(status: StatusIconStatus.fail, torIsEnabled: wallet.usingTor),
);
}
@@ -235,6 +236,7 @@ class _WalletHomeScreenState extends State<WalletHomeScreen> {
return Tooltip(
message: message,
+ triggerMode: TooltipTriggerMode.tap,
child: StatusIcon(status: lwsConnectionIconStatus, torIsEnabled: wallet.usingTor),
);
}
diff --git a/lib/util/get_height_by_date.dart b/lib/util/get_height_by_date.dart
index 281ea81..6569676 100644
--- a/lib/util/get_height_by_date.dart
+++ b/lib/util/get_height_by_date.dart
@@ -6,6 +6,7 @@ import 'package:skylight_wallet/util/logging.dart';
final dateFormat = DateFormat('yyyy-MM');
final dates = {
+ "2014-4": 0,
"2014-5": 18844,
"2014-6": 65406,
"2014-7": 108882,
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.