147 lines
3.5 KiB
Dart
147 lines
3.5 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;
|
|
|
|
bool _isOffline = false;
|
|
|
|
/// The last sync failed for lack of a connection, not because of an error.
|
|
bool get isOffline => _isOffline;
|
|
|
|
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;
|
|
_isOffline = false;
|
|
case RemoteSyncEventType.syncFailed:
|
|
_lastError = event.message;
|
|
_isOffline = event.offline;
|
|
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();
|
|
}
|
|
}
|