Prepare secure config and reliable workout sync

This commit is contained in:
Hamza-Ayed
2026-10-04 00:33:44 +03:00
parent 05f1c9ec6b
commit e7f3c777d1
17 changed files with 553 additions and 119 deletions
+27 -7
View File
@@ -31,13 +31,12 @@ class SyncService extends GetxService {
static const String _apiKeyKey = 'api_key';
static const String _apiSecretKey = 'api_secret';
@override
Future<void> onInit() async {
super.onInit();
Future<SyncService> init() async {
await _checkConnectivity();
_startConnectivityMonitor();
_startPeriodicSync();
await _updatePendingCount();
return this;
}
// ─── Connectivity Monitoring ──────────────────────────────────
@@ -107,7 +106,7 @@ class SyncService extends GetxService {
/// Queue a workout for sync
Future<void> queueWorkout(Workout workout) async {
final payload = jsonEncode(workout.toApiPayload());
await _db.enqueueSync(workout.id, payload);
await _db.saveCompletedWorkout(workout, payload);
await _updatePendingCount();
// Try immediate sync if online
@@ -116,6 +115,14 @@ class SyncService extends GetxService {
}
}
Future<void> retryWorkout(String workoutId) async {
await _db.retryFailedSync(workoutId);
await _updatePendingCount();
if (_isOnline.value && !_isSyncing.value) {
await syncPendingWorkouts();
}
}
/// Process all pending sync items
Future<void> syncPendingWorkouts() async {
if (_isSyncing.value) return;
@@ -135,6 +142,7 @@ class SyncService extends GetxService {
debugPrint('[SYNC] Processing ${pendingItems.length} pending items');
for (final item in pendingItems) {
if (!_isRetryDue(item)) continue;
await _syncSingleItem(
id: item['id'] as int,
workoutId: item['workout_id'] as String,
@@ -177,7 +185,7 @@ class SyncService extends GetxService {
)
.timeout(const Duration(seconds: 30));
if (response.statusCode == 201) {
if (response.statusCode == 200 || response.statusCode == 201) {
await _db.updateSyncQueueItem(id, 'sent');
await _db.updateSyncStatus(
workoutId,
@@ -200,8 +208,20 @@ class SyncService extends GetxService {
}
Future<void> _updatePendingCount() async {
final items = await _db.getPendingSyncs();
_pendingCount.value = items.length;
_pendingCount.value = await _db.getPendingSyncCount();
}
bool _isRetryDue(Map<String, dynamic> item) {
if (item['status'] != 'failed') return true;
final lastAttempt = item['last_attempt'] as String?;
if (lastAttempt == null) return true;
final retryCount = item['retry_count'] as int? ?? 0;
final delaySeconds = (30 * (1 << retryCount)).clamp(30, 3600);
final attemptedAt = DateTime.tryParse(lastAttempt);
if (attemptedAt == null) return true;
return DateTime.now().toUtc().difference(attemptedAt.toUtc()).inSeconds >=
delaySeconds;
}
@override