137 lines
4.2 KiB
Dart
137 lines
4.2 KiB
Dart
// ignore_for_file: prefer_initializing_formals
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../auth/auth_service.dart';
|
|
import 'cloud_restore_service.dart';
|
|
|
|
enum CloudRestoreStatus {
|
|
idle,
|
|
restoring,
|
|
success,
|
|
partialFailure,
|
|
authRequired,
|
|
unavailable,
|
|
failure,
|
|
}
|
|
|
|
class CloudRestoreUiState {
|
|
final CloudRestoreStatus status;
|
|
final CloudRestoreResult? result;
|
|
final String? message;
|
|
|
|
const CloudRestoreUiState({
|
|
this.status = CloudRestoreStatus.idle,
|
|
this.result,
|
|
this.message,
|
|
});
|
|
|
|
bool get isRestoring => status == CloudRestoreStatus.restoring;
|
|
}
|
|
|
|
class CloudRestoreController extends StateNotifier<CloudRestoreUiState> {
|
|
final CloudRestoreService _restoreService;
|
|
final AuthService _authService;
|
|
|
|
CloudRestoreController({
|
|
required CloudRestoreService restoreService,
|
|
required AuthService authService,
|
|
}) : _restoreService = restoreService,
|
|
_authService = authService,
|
|
super(const CloudRestoreUiState());
|
|
|
|
Future<CloudRestoreResult?> restoreFromMotorCloud() async {
|
|
if (state.isRestoring) return state.result;
|
|
|
|
final user = _authService.currentUser;
|
|
if (user == null || user.isAnonymous) {
|
|
state = const CloudRestoreUiState(
|
|
status: CloudRestoreStatus.authRequired,
|
|
message: 'Sign in with a MotorCloud account to restore ride history.',
|
|
);
|
|
return null;
|
|
}
|
|
if (!_authService.isConfigured) {
|
|
state = const CloudRestoreUiState(
|
|
status: CloudRestoreStatus.unavailable,
|
|
message:
|
|
'MotorCloud is unavailable. Try again when Firebase services are available.',
|
|
);
|
|
return null;
|
|
}
|
|
|
|
state = const CloudRestoreUiState(status: CloudRestoreStatus.restoring);
|
|
try {
|
|
final result = await _restoreService.restore();
|
|
final hasFailures = result.failures > 0;
|
|
final hasRestoredOrMatched =
|
|
result.hasAnyRestoredData ||
|
|
result.existingRidesMatched > 0 ||
|
|
result.telemetryAlreadyPresent > 0 ||
|
|
result.telemetrySkipped > 0;
|
|
final status = result.requiresAuthentication && !hasRestoredOrMatched
|
|
? CloudRestoreStatus.authRequired
|
|
: (hasFailures && !hasRestoredOrMatched
|
|
? CloudRestoreStatus.failure
|
|
: (hasFailures
|
|
? CloudRestoreStatus.partialFailure
|
|
: CloudRestoreStatus.success));
|
|
state = CloudRestoreUiState(
|
|
status: status,
|
|
result: result,
|
|
message: _formatResult(result),
|
|
);
|
|
return result;
|
|
} on StateError catch (e) {
|
|
final message = e.message;
|
|
state = CloudRestoreUiState(
|
|
status: message.toLowerCase().contains('auth')
|
|
? CloudRestoreStatus.authRequired
|
|
: CloudRestoreStatus.unavailable,
|
|
message: message,
|
|
);
|
|
return null;
|
|
} catch (e) {
|
|
state = CloudRestoreUiState(
|
|
status: CloudRestoreStatus.failure,
|
|
message: 'MotorCloud restore failed: $e',
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
String _formatResult(CloudRestoreResult result) {
|
|
final parts = <String>[];
|
|
if (result.metadataRowsAdded > 0) {
|
|
parts.add('${result.metadataRowsAdded} ride(s) added');
|
|
}
|
|
if (result.telemetrySamplesRestored > 0) {
|
|
parts.add(
|
|
'${result.telemetrySamplesRestored} telemetry sample(s) restored',
|
|
);
|
|
}
|
|
if (result.performanceRunsRestored > 0) {
|
|
parts.add(
|
|
'${result.performanceRunsRestored} performance run(s) restored',
|
|
);
|
|
}
|
|
if (result.rideEventsRestored > 0) {
|
|
parts.add('${result.rideEventsRestored} ride event(s) restored');
|
|
}
|
|
if (result.existingRidesMatched > 0 || result.telemetryAlreadyPresent > 0) {
|
|
final alreadyPresent =
|
|
result.existingRidesMatched > result.telemetryAlreadyPresent
|
|
? result.existingRidesMatched
|
|
: result.telemetryAlreadyPresent;
|
|
parts.add('$alreadyPresent ride(s) already on this device');
|
|
}
|
|
if (result.failures > 0) {
|
|
parts.add('${result.failures} item(s) need attention');
|
|
}
|
|
if (parts.isEmpty) {
|
|
return 'No restorable MotorCloud rides were found for this account.';
|
|
}
|
|
return 'MotorCloud restore complete: ${parts.join(', ')}.';
|
|
}
|
|
}
|