Files
kooltab/lib/viewmodels/remote_sync_view_model.dart
T
2026-10-19 21:41:34 +02:00

140 lines
3.3 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import '../database/app_database.dart';
import '../models/remote_command.dart';
import '../services/remote_sync_service.dart';
class RemoteSyncViewModel extends ChangeNotifier {
final RemoteSyncService syncService;
RemoteSyncViewModel({required this.syncService}) {
_eventSubscription = syncService.events.listen(_onEvent);
}
late final StreamSubscription<RemoteSyncEvent> _eventSubscription;
bool _hasLoaded = false;
bool get hasLoaded => _hasLoaded;
bool _isSyncing = false;
bool get isSyncing => _isSyncing;
bool _isConfigured = false;
bool get isConfigured => _isConfigured;
bool _wasRevoked = false;
/// The server rejected this device's token; it needs to be linked again.
bool get wasRevoked => _wasRevoked;
DateTime? _lastSyncAt;
DateTime? get lastSyncAt => _lastSyncAt;
String? _lastError;
String? get lastError => _lastError;
String? _venueId;
String? get venueId => _venueId;
List<ProcessedRemoteCommandRow> _activity = [];
List<ProcessedRemoteCommandRow> get activity => _activity;
Stream<RemoteSyncEvent> get tabsClosedRemotely => syncService.events.where(
(event) => event.type == RemoteSyncEventType.tabClosedRemotely,
);
Future<void> init() async {
await _refreshStatus();
_lastSyncAt = await syncService.lastSuccessfulSyncAt;
await _loadActivity();
if (_isConfigured) syncService.startPeriodicSync();
_hasLoaded = true;
notifyListeners();
}
/// Called once registration stored new credentials.
Future<void> activate() async {
await _refreshStatus();
if (_isConfigured) _wasRevoked = false;
notifyListeners();
if (!_isConfigured) return;
syncService.startPeriodicSync();
await syncNow();
}
Future<void> _refreshStatus() async {
_isConfigured = await syncService.isConfigured;
_venueId = await syncService.venueId;
}
Future<void> syncNow() async {
_isSyncing = true;
notifyListeners();
await syncService.sync();
_isSyncing = false;
await _loadActivity();
notifyListeners();
}
Future<void> _loadActivity() async {
try {
_activity = await syncService.getRecentActivity();
} on Exception catch (e) {
debugPrint('RemoteSyncViewModel: loadActivity error: $e');
}
}
Future<void> unlink() async {
syncService.stopPeriodicSync();
await syncService.clearCredentials();
_isConfigured = false;
_wasRevoked = false;
_venueId = null;
_lastSyncAt = null;
_lastError = null;
_activity = [];
notifyListeners();
}
void _onEvent(RemoteSyncEvent event) {
switch (event.type) {
case RemoteSyncEventType.syncCompleted:
_lastSyncAt = DateTime.now();
_lastError = null;
case RemoteSyncEventType.syncFailed:
_lastError = event.message;
case RemoteSyncEventType.unauthorized:
_isConfigured = false;
_wasRevoked = true;
case RemoteSyncEventType.tabClosedRemotely:
case RemoteSyncEventType.conflict:
break;
}
notifyListeners();
}
void pause() {
syncService.pause();
}
void resume() {
syncService.resume();
unawaited(syncNow());
}
@override
void dispose() {
_eventSubscription.cancel();
super.dispose();
}
}