feat: Introduce offline synchronization for time registrations via a new sync service.
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import 'dart:async';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import '../models/sync_operation.dart';
|
||||
|
||||
class SyncService {
|
||||
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
||||
final Connectivity _connectivity = Connectivity();
|
||||
late Box<Map> _queueBox;
|
||||
bool _isOnline = true;
|
||||
bool _isSyncing = false;
|
||||
final _uuid = const Uuid();
|
||||
|
||||
// Stream controller for sync status
|
||||
final _isSyncingController = StreamController<bool>.broadcast();
|
||||
Stream<bool> get isSyncingStream => _isSyncingController.stream;
|
||||
|
||||
bool get isOnline => _isOnline;
|
||||
|
||||
Future<void> init() async {
|
||||
_queueBox = await Hive.openBox<Map>('sync_queue');
|
||||
|
||||
// Sjekk initiell tilkobling
|
||||
try {
|
||||
final result = await _connectivity.checkConnectivity();
|
||||
_updateConnectionStatus(result);
|
||||
} catch (e) {
|
||||
print('Kunne ikke sjekke tilkobling: $e');
|
||||
}
|
||||
|
||||
// Lytt etter endringer
|
||||
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
|
||||
}
|
||||
|
||||
void _updateConnectionStatus(ConnectivityResult result) {
|
||||
_isOnline = result != ConnectivityResult.none;
|
||||
print('Tilkoblingsstatus endret: $_isOnline ($result)');
|
||||
|
||||
if (_isOnline) {
|
||||
_processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
// Legg til operasjon i køen
|
||||
Future<void> addToQueue(SyncOperation operation) async {
|
||||
await _queueBox.put(operation.id, operation.toMap());
|
||||
|
||||
// Prøv å synkronisere umiddelbart hvis vi er online
|
||||
if (_isOnline) {
|
||||
_processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
// Behandle køen
|
||||
Future<void> _processQueue() async {
|
||||
if (_isSyncing || _queueBox.isEmpty) return;
|
||||
|
||||
_isSyncing = true;
|
||||
_isSyncingController.add(true);
|
||||
|
||||
try {
|
||||
// Hent alle operasjoner og sorter etter tidsstempel
|
||||
final operations = _queueBox.values
|
||||
.map((map) => SyncOperation.fromMap(Map<String, dynamic>.from(map)))
|
||||
.toList()
|
||||
..sort((a, b) => a.timestamp.compareTo(b.timestamp));
|
||||
|
||||
for (final op in operations) {
|
||||
try {
|
||||
await _performOperation(op);
|
||||
await _queueBox.delete(op.id);
|
||||
} catch (e) {
|
||||
print('Feil ved synkronisering av operasjon ${op.id}: $e');
|
||||
// Vi lar den ligge i køen for å prøve igjen senere
|
||||
// Men hvis det er en permanent feil, burde vi kanskje flytte den til en "feil-kø"
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
_isSyncing = false;
|
||||
_isSyncingController.add(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _performOperation(SyncOperation op) async {
|
||||
final collection = _firestore.collection(op.collection);
|
||||
final docRef = collection.doc(op.docId);
|
||||
|
||||
switch (op.action) {
|
||||
case SyncAction.create:
|
||||
await docRef.set(op.data);
|
||||
break;
|
||||
case SyncAction.update:
|
||||
await docRef.update(op.data);
|
||||
break;
|
||||
case SyncAction.delete:
|
||||
await docRef.delete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Hjelpemetode for å opprette operasjon
|
||||
Future<void> queueOperation({
|
||||
required String collection,
|
||||
required String docId,
|
||||
required SyncAction action,
|
||||
required Map<String, dynamic> data,
|
||||
}) async {
|
||||
final op = SyncOperation(
|
||||
id: _uuid.v4(),
|
||||
collection: collection,
|
||||
docId: docId,
|
||||
action: action,
|
||||
data: data,
|
||||
timestamp: DateTime.now(),
|
||||
);
|
||||
await addToQueue(op);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user