sync status eta (#1701)

* sync status eta

* other necessary changes

* feat: Enhance Sync ETA display mode

- Enhance block rate calculation with weighted averages(accounts for network flunctuations and sync speed of more recent blocks while calculating eta, basically giving us more accuracy)
- Add option to switch between ETA and blocks remaining display in display settings
- Add placeholder ETA while gathering block data

* chore: Listen to smaller changes in eta

---------

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
Co-authored-by: Blazebrain <davidadegoke16@gmail.com>
This commit is contained in:
Matthew Fosse
2025-08-19 18:09:51 +03:00
committed by GitHub
co-authored by Omar Hatem Blazebrain
parent 013211e7a6
commit c8dca29f68
36 changed files with 361 additions and 8 deletions
+19 -4
View File
@@ -1,11 +1,26 @@
import 'package:cake_wallet/entities/sync_status_display_mode.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/sync_status.dart';
String syncStatusTitle(SyncStatus syncStatus) {
String syncStatusTitle(SyncStatus syncStatus, SyncStatusDisplayMode syncStatusDisplayMode) {
if (syncStatus is SyncingSyncStatus) {
return syncStatus.blocksLeft == 1
? S.current.block_remaining
: S.current.Blocks_remaining('${syncStatus.blocksLeft}');
if (syncStatus.blocksLeft == 1) {
return S.current.block_remaining;
}
// Check user preference for sync status display
if (syncStatusDisplayMode == SyncStatusDisplayMode.eta) {
// Get ETA with placeholder while gathering data
String eta = syncStatus.getFormattedEtaWithPlaceholder() ?? '';
if (eta.isEmpty) {
return S.current.Blocks_remaining('${syncStatus.blocksLeft}');
} else {
return "${syncStatus.formattedProgress()} - ${S.current.eta} $eta";
}
} else {
return S.current.Blocks_remaining('${syncStatus.blocksLeft}');
}
}
if (syncStatus is SyncedTipSyncStatus) {
+1
View File
@@ -114,5 +114,6 @@ class PreferencesKey {
static String backgroundSyncLastTrigger(String walletId) => 'background_sync_last_trigger_${walletId}';
static const backgroundSyncNotificationsEnabled = 'background_sync_notifications_enabled';
static const enableAutomaticNodeSwitching = 'enable_automatic_node_switching';
static const syncStatusDisplayMode = 'sync_status_display_mode';
static const backgroundImage = 'background_image';
}
@@ -0,0 +1,34 @@
enum SyncStatusDisplayMode { eta, blocksRemaining }
extension SyncStatusDisplayModeExtension on SyncStatusDisplayMode {
String get title {
switch (this) {
case SyncStatusDisplayMode.eta:
return 'ETA';
case SyncStatusDisplayMode.blocksRemaining:
return 'Blocks Remaining';
}
}
String get description {
switch (this) {
case SyncStatusDisplayMode.eta:
return 'Show estimated time remaining for sync completion';
case SyncStatusDisplayMode.blocksRemaining:
return 'Show number of blocks remaining to sync';
}
}
static SyncStatusDisplayMode fromString(String value) {
switch (value) {
case 'eta':
return SyncStatusDisplayMode.eta;
case 'blocksRemaining':
return SyncStatusDisplayMode.blocksRemaining;
default:
return SyncStatusDisplayMode.eta;
}
}
String toJson() => name;
}
@@ -20,7 +20,7 @@ class SyncIndicator extends StatelessWidget {
return Observer(builder: (_) {
final syncIndicatorWidth = 237.0;
final status = dashboardViewModel.status;
final statusText = syncStatusTitle(status);
final statusText = syncStatusTitle(status, dashboardViewModel.settingsStore.syncStatusDisplayMode);
final progress = status.progress();
final indicatorOffset = progress * syncIndicatorWidth;
final indicatorWidth = progress < 1
@@ -1,5 +1,6 @@
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/language_service.dart';
import 'package:cake_wallet/entities/sync_status_display_mode.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
@@ -46,6 +47,15 @@ class DisplaySettingsPage extends BasePage {
_displaySettingsViewModel.setShowAddressBookPopup(value);
},
),
SettingsPickerCell<SyncStatusDisplayMode>(
title: S.current.sync_status_display_mode,
items: SyncStatusDisplayMode.values.toList(),
selectedItem: _displaySettingsViewModel.syncStatusDisplayMode,
onItemSelected: (SyncStatusDisplayMode mode) =>
_displaySettingsViewModel.setSyncStatusDisplayMode(mode),
displayItem: (SyncStatusDisplayMode mode) => mode.title,
isGridView: false,
),
//if (!isHaven) it does not work correctly
if (!_displaySettingsViewModel.disabledFiatApiMode)
SettingsPickerCell<FiatCurrency>(
+16
View File
@@ -24,6 +24,7 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cake_wallet/entities/seed_phrase_length.dart';
import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/entities/sort_balance_types.dart';
import 'package:cake_wallet/entities/sync_status_display_mode.dart';
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/wownero/wownero.dart';
@@ -55,6 +56,7 @@ abstract class SettingsStoreBase with Store {
required SharedPreferences sharedPreferences,
required bool initialShouldShowMarketPlaceInDashboard,
required bool initialShowAddressBookPopupEnabled,
required SyncStatusDisplayMode initialSyncStatusDisplayMode,
required FiatCurrency initialFiatCurrency,
required BalanceDisplayMode initialBalanceDisplayMode,
required bool initialSaveRecipientAddress,
@@ -168,6 +170,7 @@ abstract class SettingsStoreBase with Store {
contactListAscending = initialContactListAscending,
shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard,
showAddressBookPopupEnabled = initialShowAddressBookPopupEnabled,
syncStatusDisplayMode = initialSyncStatusDisplayMode,
exchangeStatus = initialExchangeStatus,
pinCodeLength = initialPinLength,
languageCode = initialLanguageCode,
@@ -388,6 +391,11 @@ abstract class SettingsStoreBase with Store {
(bool value) =>
sharedPreferences.setBool(PreferencesKey.showAddressBookPopupEnabled, value));
reaction(
(_) => syncStatusDisplayMode,
(SyncStatusDisplayMode value) =>
sharedPreferences.setString(PreferencesKey.syncStatusDisplayMode, value.toJson()));
reaction((_) => pinCodeLength,
(int pinLength) => sharedPreferences.setInt(PreferencesKey.currentPinLength, pinLength));
@@ -674,6 +682,9 @@ abstract class SettingsStoreBase with Store {
@observable
bool showAddressBookPopupEnabled;
@observable
SyncStatusDisplayMode syncStatusDisplayMode;
@observable
ObservableList<ActionListDisplayMode> actionlistDisplayMode;
@@ -1012,6 +1023,8 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ?? true;
final showAddressBookPopupEnabled =
sharedPreferences.getBool(PreferencesKey.showAddressBookPopupEnabled) ?? true;
final syncStatusDisplayMode = SyncStatusDisplayModeExtension.fromString(
sharedPreferences.getString(PreferencesKey.syncStatusDisplayMode) ?? SyncStatusDisplayMode.eta.name);
final exchangeStatus = ExchangeApiMode.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ??
ExchangeApiMode.enabled.raw);
@@ -1307,6 +1320,7 @@ abstract class SettingsStoreBase with Store {
sharedPreferences: sharedPreferences,
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
initialShowAddressBookPopupEnabled: showAddressBookPopupEnabled,
initialSyncStatusDisplayMode: syncStatusDisplayMode,
nodes: nodes,
powNodes: powNodes,
appVersion: packageInfo.version,
@@ -1504,6 +1518,8 @@ abstract class SettingsStoreBase with Store {
showAddressBookPopupEnabled =
sharedPreferences.getBool(PreferencesKey.showAddressBookPopupEnabled) ??
showAddressBookPopupEnabled;
syncStatusDisplayMode = SyncStatusDisplayModeExtension.fromString(
sharedPreferences.getString(PreferencesKey.syncStatusDisplayMode) ?? SyncStatusDisplayMode.eta.name);
exchangeStatus = ExchangeApiMode.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ??
ExchangeApiMode.enabled.raw);
@@ -1,5 +1,6 @@
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/sync_status_display_mode.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/core/material_base_theme.dart';
import 'package:mobx/mobx.dart';
@@ -44,6 +45,9 @@ abstract class DisplaySettingsViewModelBase with Store {
@computed
bool get showAddressBookPopup => _settingsStore.showAddressBookPopupEnabled;
@computed
SyncStatusDisplayMode get syncStatusDisplayMode => _settingsStore.syncStatusDisplayMode;
@computed
String get backgroundImage => _settingsStore.backgroundImage;
@@ -91,6 +95,10 @@ abstract class DisplaySettingsViewModelBase with Store {
@action
void setShowAddressBookPopup(bool value) => _settingsStore.showAddressBookPopupEnabled = value;
@action
void setSyncStatusDisplayMode(SyncStatusDisplayMode value) =>
_settingsStore.syncStatusDisplayMode = value;
@action
void setBackgroundImage(String path) => _settingsStore.backgroundImage = path;
}