196 lines
4.9 KiB
Dart
196 lines
4.9 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import '../database/app_database.dart';
|
|
import '../models/remote_command.dart';
|
|
import '../services/remote_sync_service.dart';
|
|
import '../utils/app_config.dart';
|
|
|
|
class RemoteSyncViewModel extends ChangeNotifier {
|
|
final RemoteSyncService syncService;
|
|
|
|
RemoteSyncViewModel({required this.syncService}) {
|
|
_eventSubscription = syncService.events.listen(_onEvent);
|
|
}
|
|
|
|
StreamSubscription<RemoteSyncEvent>? _eventSubscription;
|
|
|
|
List<RemoteSyncEvent> _recentEvents = [];
|
|
|
|
List<RemoteSyncEvent> get recentEvents => _recentEvents;
|
|
|
|
bool _isSyncing = false;
|
|
bool get isSyncing => _isSyncing;
|
|
|
|
bool _isConfigured = false;
|
|
bool get isConfigured => _isConfigured;
|
|
|
|
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;
|
|
|
|
bool _isRegistering = false;
|
|
bool get isRegistering => _isRegistering;
|
|
|
|
String? _registrationError;
|
|
String? get registrationError => _registrationError;
|
|
|
|
Future<void> init() async {
|
|
_isConfigured = await syncService.isConfigured;
|
|
_venueId = await syncService.venueId;
|
|
_lastSyncAt = await syncService.lastSuccessfulSyncAt;
|
|
await loadActivity();
|
|
if (_isConfigured) {
|
|
syncService.startPeriodicSync();
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> refreshStatus() async {
|
|
_isConfigured = await syncService.isConfigured;
|
|
_venueId = await syncService.venueId;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> syncNow() async {
|
|
_isSyncing = true;
|
|
_lastError = null;
|
|
notifyListeners();
|
|
|
|
await syncService.sync();
|
|
|
|
_isSyncing = syncService.isSyncing;
|
|
_lastSyncAt = await syncService.lastSuccessfulSyncAt;
|
|
await loadActivity();
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> loadActivity() async {
|
|
try {
|
|
_activity = await syncService.getRecentActivity();
|
|
} catch (e) {
|
|
debugPrint('RemoteSyncViewModel: loadActivity error: $e');
|
|
}
|
|
}
|
|
|
|
Future<bool> registerDevice({
|
|
required String venueId,
|
|
required String deviceName,
|
|
required String registrationCode,
|
|
}) async {
|
|
_isRegistering = true;
|
|
_registrationError = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
final response = await http.post(
|
|
Uri.parse('$kRemoteServerUrl/devices/register'),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({
|
|
'venueId': venueId,
|
|
'name': deviceName,
|
|
'registrationCode': registrationCode,
|
|
}),
|
|
).timeout(const Duration(seconds: 15));
|
|
|
|
if (response.statusCode == 201) {
|
|
final data = jsonDecode(response.body) as Map<String, dynamic>;
|
|
final deviceId = data['deviceId'] as String;
|
|
final token = data['token'] as String;
|
|
|
|
await syncService.setCredentials(
|
|
deviceId: deviceId,
|
|
token: token,
|
|
venueId: venueId,
|
|
serverUrl: kRemoteServerUrl,
|
|
);
|
|
|
|
_isConfigured = true;
|
|
_venueId = venueId;
|
|
_isRegistering = false;
|
|
notifyListeners();
|
|
|
|
syncService.startPeriodicSync();
|
|
await syncNow();
|
|
|
|
return true;
|
|
} else {
|
|
final body = response.body;
|
|
String message;
|
|
try {
|
|
final errorData = jsonDecode(body) as Map<String, dynamic>;
|
|
message = errorData['message'] as String? ?? 'Registration failed';
|
|
} catch (_) {
|
|
message = 'Registration failed (HTTP ${response.statusCode})';
|
|
}
|
|
_registrationError = message;
|
|
_isRegistering = false;
|
|
notifyListeners();
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
debugPrint('RemoteSyncViewModel: registration error: $e');
|
|
_registrationError = e.toString();
|
|
_isRegistering = false;
|
|
notifyListeners();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<void> unlink() async {
|
|
syncService.stopPeriodicSync();
|
|
await syncService.clearCredentials();
|
|
_isConfigured = false;
|
|
_venueId = null;
|
|
_lastSyncAt = null;
|
|
_lastError = null;
|
|
_recentEvents = [];
|
|
_activity = [];
|
|
notifyListeners();
|
|
}
|
|
|
|
void startSync() {
|
|
syncService.startPeriodicSync();
|
|
syncNow();
|
|
}
|
|
|
|
void _onEvent(RemoteSyncEvent event) {
|
|
_recentEvents = [event, ..._recentEvents.take(49)];
|
|
_lastSyncAt = DateTime.now();
|
|
|
|
if (event.type == RemoteSyncEventType.syncFailed) {
|
|
_lastError = event.message;
|
|
} else if (event.type == RemoteSyncEventType.syncCompleted) {
|
|
_lastError = null;
|
|
}
|
|
|
|
notifyListeners();
|
|
}
|
|
|
|
void pause() {
|
|
syncService.pause();
|
|
}
|
|
|
|
void resume() {
|
|
syncService.resume();
|
|
syncNow();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_eventSubscription?.cancel();
|
|
syncService.dispose();
|
|
super.dispose();
|
|
}
|
|
} |