fix: alot

This commit is contained in:
2026-10-19 21:41:34 +02:00
parent 30dd74af90
commit b0074aeb3f
40 changed files with 1979 additions and 405 deletions
+32 -11
View File
@@ -1,8 +1,10 @@
import 'dart:async';
import 'dart:io';
import 'package:drift/drift.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart' as http;
import 'package:sentry_flutter/sentry_flutter.dart';
import '../database/app_database.dart';
@@ -65,20 +67,29 @@ class RemoteSyncService {
DateTime? _firstPendingChange;
bool _syncQueued = false;
_Credentials? _cachedCredentials;
Future<String?> get venueId => secureStorage.read(key: _venueIdKey);
Future<bool> get isConfigured async {
final token = await secureStorage.read(key: _authTokenKey);
final venueId = await this.venueId;
return (token?.isNotEmpty ?? false) && (venueId?.isNotEmpty ?? false);
}
Future<bool> get isConfigured async => await _credentials() != null;
Future<String?> get authToken async => (await _credentials())?.token;
Future<_Credentials?> _credentials() async {
if (_cachedCredentials != null) return _cachedCredentials;
final deviceId = await secureStorage.read(key: _deviceIdKey);
final token = await secureStorage.read(key: _authTokenKey);
if (deviceId == null || token == null) return null;
final venueId = await this.venueId;
if (deviceId == null ||
token == null ||
token.isEmpty ||
venueId == null ||
venueId.isEmpty) {
return null;
}
return (deviceId: deviceId, token: token);
return _cachedCredentials = (deviceId: deviceId, token: token);
}
void startPeriodicSync() {
@@ -109,8 +120,6 @@ class RemoteSyncService {
void resume() {
_paused = false;
// Catch up right away instead of waiting for the next poll
_onTabsChanged();
}
/// Pushes tab changes to the server soon after they happen instead of
@@ -164,7 +173,7 @@ class RemoteSyncService {
}
final credentials = await _credentials();
if (credentials == null || !await isConfigured) return;
if (credentials == null) return;
_isSyncing = true;
Duration nextDelay;
@@ -176,6 +185,7 @@ class RemoteSyncService {
_emit(RemoteSyncEventType.syncCompleted);
} on UnauthorizedException {
debugPrint('RemoteSyncService: token revoked');
_cachedCredentials = null;
await secureStorage.delete(key: _authTokenKey);
stopPeriodicSync();
_emit(RemoteSyncEventType.unauthorized);
@@ -183,7 +193,9 @@ class RemoteSyncService {
} on RateLimitedException catch (e) {
nextDelay = await _recordFailure(e, retryAfter: e.retryAfter);
} catch (e, stack) {
unawaited(Sentry.captureException(e, stackTrace: stack));
if (!_isConnectivityError(e)) {
unawaited(Sentry.captureException(e, stackTrace: stack));
}
nextDelay = await _recordFailure(e);
} finally {
_isSyncing = false;
@@ -197,6 +209,13 @@ class RemoteSyncService {
}
}
/// Offline tablets are expected, not worth an error report.
bool _isConnectivityError(Object error) {
return error is IOException ||
error is TimeoutException ||
error is http.ClientException;
}
Future<Duration> _recordFailure(Object error, {Duration? retryAfter}) async {
debugPrint('RemoteSyncService: sync failed: $error');
_consecutiveFailures++;
@@ -391,9 +410,11 @@ class RemoteSyncService {
await secureStorage.write(key: _deviceIdKey, value: deviceId);
await secureStorage.write(key: _authTokenKey, value: token);
await secureStorage.write(key: _venueIdKey, value: venueId);
_cachedCredentials = (deviceId: deviceId, token: token);
}
Future<void> clearCredentials() async {
_cachedCredentials = null;
await secureStorage.delete(key: _deviceIdKey);
await secureStorage.delete(key: _authTokenKey);
await secureStorage.delete(key: _venueIdKey);