look ahead
This commit is contained in:
@@ -51,6 +51,8 @@ class SyncController extends ChangeNotifier {
|
||||
bool _queuedFullSync = false;
|
||||
Timer? _pushDebounce;
|
||||
Timer? _progressHold;
|
||||
Timer? _uiNotifyThrottle;
|
||||
var _uiNotifyQueued = false;
|
||||
String? _lastError;
|
||||
DateTime? _lastSyncedAt;
|
||||
String _lastSyncSummary = '';
|
||||
@@ -64,6 +66,7 @@ class SyncController extends ChangeNotifier {
|
||||
double _syncProgress = 0;
|
||||
bool _showProgressRing = false;
|
||||
bool _progressSuccess = false;
|
||||
int _lastNotifiedProgressPct = -1;
|
||||
|
||||
bool get isSyncing => _syncing;
|
||||
String? get lastError => _lastError;
|
||||
@@ -86,6 +89,25 @@ class SyncController extends ChangeNotifier {
|
||||
/// Ring turns green when this is true (sync finished successfully).
|
||||
bool get progressSuccess => _progressSuccess;
|
||||
|
||||
void _notifyUiNow() {
|
||||
_uiNotifyThrottle?.cancel();
|
||||
_uiNotifyQueued = false;
|
||||
_lastNotifiedProgressPct = (_syncProgress * 100).round();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Coalesce high-frequency progress/status into ~10 Hz UI updates.
|
||||
void _notifyUiThrottled() {
|
||||
if (_uiNotifyQueued) return;
|
||||
_uiNotifyQueued = true;
|
||||
_uiNotifyThrottle?.cancel();
|
||||
_uiNotifyThrottle = Timer(const Duration(milliseconds: 100), () {
|
||||
_uiNotifyQueued = false;
|
||||
_lastNotifiedProgressPct = (_syncProgress * 100).round();
|
||||
notifyListeners();
|
||||
});
|
||||
}
|
||||
|
||||
void _announce(String message, {bool isProgress = false, bool isError = false}) {
|
||||
_feedbackEpoch++;
|
||||
_feedback = SyncFeedback(
|
||||
@@ -94,24 +116,38 @@ class SyncController extends ChangeNotifier {
|
||||
isProgress: isProgress,
|
||||
isError: isError,
|
||||
);
|
||||
notifyListeners();
|
||||
_notifyUiNow();
|
||||
}
|
||||
|
||||
void _setProgress(double value, {bool success = false}) {
|
||||
_syncProgress = value.clamp(0.0, 1.0);
|
||||
final next = value.clamp(0.0, 1.0);
|
||||
final pct = (next * 100).round();
|
||||
_syncProgress = next;
|
||||
_showProgressRing = true;
|
||||
_progressSuccess = success;
|
||||
notifyListeners();
|
||||
// Skip tiny progress moves — avatar only shows whole percents.
|
||||
if (!success &&
|
||||
pct == _lastNotifiedProgressPct &&
|
||||
_showProgressRing) {
|
||||
return;
|
||||
}
|
||||
if (success) {
|
||||
_notifyUiNow();
|
||||
} else {
|
||||
_notifyUiThrottled();
|
||||
}
|
||||
}
|
||||
|
||||
void _setStatus(String message) {
|
||||
if (_statusDetail == message) return;
|
||||
_statusDetail = message;
|
||||
notifyListeners();
|
||||
_notifyUiThrottled();
|
||||
}
|
||||
|
||||
void _finishProgress({required bool success}) {
|
||||
_progressHold?.cancel();
|
||||
_uiNotifyThrottle?.cancel();
|
||||
_uiNotifyQueued = false;
|
||||
_statusDetail = '';
|
||||
if (success) {
|
||||
_setProgress(1, success: true);
|
||||
@@ -119,13 +155,15 @@ class SyncController extends ChangeNotifier {
|
||||
_showProgressRing = false;
|
||||
_progressSuccess = false;
|
||||
_syncProgress = 0;
|
||||
notifyListeners();
|
||||
_lastNotifiedProgressPct = -1;
|
||||
_notifyUiNow();
|
||||
});
|
||||
} else {
|
||||
_showProgressRing = false;
|
||||
_progressSuccess = false;
|
||||
_syncProgress = 0;
|
||||
notifyListeners();
|
||||
_lastNotifiedProgressPct = -1;
|
||||
_notifyUiNow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,12 +176,15 @@ class SyncController extends ChangeNotifier {
|
||||
if (!loggedIn) {
|
||||
_pushDebounce?.cancel();
|
||||
_progressHold?.cancel();
|
||||
_uiNotifyThrottle?.cancel();
|
||||
_uiNotifyQueued = false;
|
||||
_lastError = null;
|
||||
_statusDetail = '';
|
||||
_showProgressRing = false;
|
||||
_progressSuccess = false;
|
||||
_syncProgress = 0;
|
||||
notifyListeners();
|
||||
_lastNotifiedProgressPct = -1;
|
||||
_notifyUiNow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +232,11 @@ class SyncController extends ChangeNotifier {
|
||||
_setProgress(0.5);
|
||||
_setStatus('Merging…');
|
||||
final mergedMeta = mergeTxMetaStores(_meta.exportStore(), remoteMeta);
|
||||
await _meta.replaceStore(mergedMeta);
|
||||
await _bank.applySyncedTransactions(remoteTxs);
|
||||
// Apply without notifying — one rebuild after both stores are ready.
|
||||
await _meta.replaceStore(mergedMeta, notify: false);
|
||||
await _bank.applySyncedTransactions(remoteTxs, notify: false);
|
||||
_meta.notifyListeners();
|
||||
_bank.notifyListeners();
|
||||
_setProgress(0.55);
|
||||
_setStatus('Pushing…');
|
||||
final metaSummary = await service.push(
|
||||
@@ -283,6 +327,7 @@ class SyncController extends ChangeNotifier {
|
||||
void dispose() {
|
||||
_pushDebounce?.cancel();
|
||||
_progressHold?.cancel();
|
||||
_uiNotifyThrottle?.cancel();
|
||||
_auth.removeListener(_onAuthChanged);
|
||||
_meta.onPersisted = null;
|
||||
super.dispose();
|
||||
|
||||
Reference in New Issue
Block a user