mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
fix: Sync bar ETA (#2515)
* fix: Sync bar ETA * fix: Smooth ETA - WIP * fix: Show disconnected status when sync disconnects * feat: Display blocks remaining for the first five seconds and then switch to percentage * Update * fix: Extend duration for showing blocks remaining during sync from 5 to 15 seconds; update connectivity check to handle multiple connectivity results, and handle disconnected state while syncing * feat: Initially display block if the a reconnection is triggered while syncing * fix: More improvements to syncing
This commit is contained in:
@@ -2657,9 +2657,8 @@ abstract class ElectrumWalletBase
|
||||
|
||||
break;
|
||||
case electrum.ConnectionStatus.disconnected:
|
||||
if (syncStatus is! NotConnectedSyncStatus &&
|
||||
syncStatus is! ConnectingSyncStatus &&
|
||||
syncStatus is! SyncronizingSyncStatus) {
|
||||
// Always show disconnected status when connection is lost, regardless of current sync state
|
||||
if (syncStatus is! NotConnectedSyncStatus) {
|
||||
syncStatus = NotConnectedSyncStatus();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -21,6 +21,7 @@ class StartingScanSyncStatus extends SyncStatus {
|
||||
class SyncingSyncStatus extends SyncStatus {
|
||||
SyncingSyncStatus(this.blocksLeft, this.ptc) {
|
||||
updateEtaHistory(blocksLeft);
|
||||
_globalSyncStartTime ??= DateTime.now();
|
||||
}
|
||||
|
||||
double ptc;
|
||||
@@ -32,6 +33,19 @@ class SyncingSyncStatus extends SyncStatus {
|
||||
@override
|
||||
String toString() => '$blocksLeft';
|
||||
|
||||
/// Returns true if we should show blocks remaining instead of percentage
|
||||
/// Shows blocks remaining for the first 15 seconds of syncing
|
||||
bool shouldShowBlocksRemaining() {
|
||||
if (_globalSyncStartTime == null) return true;
|
||||
final elapsed = DateTime.now().difference(_globalSyncStartTime!);
|
||||
return elapsed.inSeconds < 15;
|
||||
}
|
||||
|
||||
/// Reset the global sync start time (call when sync completes or fails)
|
||||
static void resetSyncStartTime() {
|
||||
_globalSyncStartTime = null;
|
||||
}
|
||||
|
||||
factory SyncingSyncStatus.fromHeightValues(int chainTip, int initialSyncHeight, int syncHeight) {
|
||||
final track = chainTip - initialSyncHeight;
|
||||
final diff = track - (chainTip - syncHeight);
|
||||
@@ -45,21 +59,14 @@ class SyncingSyncStatus extends SyncStatus {
|
||||
|
||||
static void updateEtaHistory(int blocksLeft) {
|
||||
blockHistory[DateTime.now()] = blocksLeft;
|
||||
|
||||
// keep only the last 30 entries (gives us better statistical accuracy)
|
||||
while (blockHistory.length > 30) {
|
||||
blockHistory.remove(blockHistory.keys.first);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<DateTime, int> blockHistory = {};
|
||||
static Duration? lastEtaDuration;
|
||||
static const int _minDataPoints = 3;
|
||||
static const int _maxDataAgeMinutes = 2;
|
||||
static DateTime? _globalSyncStartTime;
|
||||
|
||||
String? getFormattedEtaWithPlaceholder() {
|
||||
_cleanOldEntries();
|
||||
|
||||
// If we have enough data, show actual ETA
|
||||
if (blockHistory.length >= _minDataPoints) {
|
||||
final eta = getFormattedEta();
|
||||
@@ -70,11 +77,6 @@ class SyncingSyncStatus extends SyncStatus {
|
||||
return '--:--';
|
||||
}
|
||||
|
||||
void _cleanOldEntries() {
|
||||
final cutoffTime = DateTime.now().subtract(Duration(minutes: _maxDataAgeMinutes));
|
||||
blockHistory.removeWhere((key, value) => key.isBefore(cutoffTime));
|
||||
}
|
||||
|
||||
String? getFormattedEta() {
|
||||
Duration? duration = getEtaDuration();
|
||||
|
||||
|
||||
@@ -4,6 +4,20 @@ import 'package:cw_core/sync_status.dart';
|
||||
|
||||
String syncStatusTitle(SyncStatus syncStatus, SyncStatusDisplayMode syncStatusDisplayMode) {
|
||||
if (syncStatus is SyncingSyncStatus) {
|
||||
// Show blocks remaining for the first 3 seconds, then switch to percentage
|
||||
if (syncStatus.shouldShowBlocksRemaining()) {
|
||||
if (syncStatus.blocksLeft == 1) {
|
||||
return S.current.block_remaining;
|
||||
}
|
||||
return S.current.Blocks_remaining('${syncStatus.blocksLeft}');
|
||||
}
|
||||
|
||||
// After 3 seconds, show percentage-based display
|
||||
// Don't show ETA for very few blocks (less than 100) to avoid inconsistency
|
||||
if (syncStatus.blocksLeft < 100) {
|
||||
return S.current.Blocks_remaining('${syncStatus.blocksLeft}');
|
||||
}
|
||||
|
||||
if (syncStatus.blocksLeft == 1) {
|
||||
return S.current.block_remaining;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/utils/tor.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
@@ -8,8 +7,6 @@ import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
Timer? _checkConnectionTimer;
|
||||
|
||||
@@ -29,7 +26,7 @@ void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore
|
||||
try {
|
||||
final connectivityResult = await (Connectivity().checkConnectivity());
|
||||
|
||||
if (connectivityResult == ConnectivityResult.none) {
|
||||
if (connectivityResult.contains(ConnectivityResult.none)) {
|
||||
wallet.syncStatus = FailedSyncStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/utils/tor.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
@@ -92,6 +93,7 @@ void startCurrentWalletChangeReaction(
|
||||
}
|
||||
|
||||
await wallet.connectToNode(node: node);
|
||||
SyncingSyncStatus.blockHistory.clear();
|
||||
if (wallet.type == WalletType.nano || wallet.type == WalletType.banano) {
|
||||
final powNode = settingsStore.getCurrentPowNode(wallet.type);
|
||||
await wallet.connectToPowNode(node: powNode);
|
||||
|
||||
@@ -19,13 +19,23 @@ void startWalletSyncStatusChangeReaction(
|
||||
_onWalletSyncStatusChangeReaction = reaction((_) => wallet.syncStatus, (SyncStatus status) async {
|
||||
try {
|
||||
if (status is ConnectedSyncStatus) {
|
||||
SyncingSyncStatus.resetSyncStartTime();
|
||||
await wallet.startSync();
|
||||
}
|
||||
|
||||
if (status is SyncingSyncStatus || status is ProcessingSyncStatus) {
|
||||
await WakelockPlus.enable();
|
||||
}
|
||||
if (status is SyncedSyncStatus || status is FailedSyncStatus) {
|
||||
|
||||
if (status is SyncedSyncStatus) {
|
||||
await WakelockPlus.disable();
|
||||
SyncingSyncStatus.resetSyncStartTime();
|
||||
SyncingSyncStatus.blockHistory.clear();
|
||||
}
|
||||
|
||||
if (status is FailedSyncStatus) {
|
||||
await WakelockPlus.disable();
|
||||
SyncingSyncStatus.resetSyncStartTime();
|
||||
}
|
||||
|
||||
if (status is SyncedSyncStatus &&
|
||||
|
||||
Reference in New Issue
Block a user