- Implémente la couche de synchronisation avec le serveur - Ajoute les fixtures versionnées pour les tests - Met à jour Drift database et repositories pour le support sync - Améliore les tests de synchronisation - Corrige et améliore le watch companion pour la collecte de métriques Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
303 lines
12 KiB
Dart
303 lines
12 KiB
Dart
import '../infrastructure/local/local.dart';
|
|
import '../infrastructure/remote/remote.dart';
|
|
import '../infrastructure/security/security.dart';
|
|
import '../infrastructure/session_notification/session_notification.dart';
|
|
import '../infrastructure/watch_bridge/watch_bridge.dart';
|
|
import 'application.dart';
|
|
|
|
abstract interface class AppDependencies {
|
|
AuthUseCases get authUseCases;
|
|
ExerciseUseCases get exerciseUseCases;
|
|
MediaUseCases get mediaUseCases;
|
|
ProgramUseCases get programUseCases;
|
|
WorkoutTemplateUseCases get workoutTemplateUseCases;
|
|
ActiveWorkoutSessionUseCases get activeWorkoutSessionUseCases;
|
|
ActiveExerciseStepUseCases get activeExerciseStepUseCases;
|
|
ActiveWorkoutSensorUseCases get activeWorkoutSensorUseCases;
|
|
WorkoutTelemetryUseCases get workoutTelemetryUseCases;
|
|
CloseWorkoutSessionUseCase get closeWorkoutSessionUseCase;
|
|
WorkoutHistoryUseCases get workoutHistoryUseCases;
|
|
ProgressionStatsUseCase get progressionStatsUseCase;
|
|
ExercisePerformanceReferenceUseCase get exercisePerformanceReferenceUseCase;
|
|
WatchAlertPublisher get watchAlertPublisher;
|
|
DataExportUseCase get dataExportUseCase;
|
|
DataImportUseCase get dataImportUseCase;
|
|
SyncUseCases get syncUseCases;
|
|
ShareUseCases get shareUseCases;
|
|
}
|
|
|
|
final class AppBootstrap implements AppDependencies {
|
|
AppBootstrap._({
|
|
required this.database,
|
|
required this.authUseCases,
|
|
required this.exerciseUseCases,
|
|
required this.mediaUseCases,
|
|
required this.programUseCases,
|
|
required this.workoutTemplateUseCases,
|
|
required this.activeWorkoutSessionUseCases,
|
|
required this.activeExerciseStepUseCases,
|
|
required this.activeWorkoutSensorUseCases,
|
|
required this.workoutTelemetryUseCases,
|
|
required this.watchCompanionProjectionUseCases,
|
|
required this.watchCompanionCommandHandler,
|
|
required this.watchWearDataLayerAdapter,
|
|
required this.sessionNotificationCoordinator,
|
|
required this.closeWorkoutSessionUseCase,
|
|
required this.workoutHistoryUseCases,
|
|
required this.progressionStatsUseCase,
|
|
required this.exercisePerformanceReferenceUseCase,
|
|
required this.dataExportUseCase,
|
|
required this.dataImportUseCase,
|
|
required this.syncUseCases,
|
|
required this.shareUseCases,
|
|
required this.syncGateway,
|
|
});
|
|
|
|
final AppDatabase database;
|
|
@override
|
|
final AuthUseCases authUseCases;
|
|
@override
|
|
final ExerciseUseCases exerciseUseCases;
|
|
@override
|
|
final MediaUseCases mediaUseCases;
|
|
@override
|
|
final ProgramUseCases programUseCases;
|
|
@override
|
|
final WorkoutTemplateUseCases workoutTemplateUseCases;
|
|
@override
|
|
final ActiveWorkoutSessionUseCases activeWorkoutSessionUseCases;
|
|
@override
|
|
final ActiveExerciseStepUseCases activeExerciseStepUseCases;
|
|
@override
|
|
final ActiveWorkoutSensorUseCases activeWorkoutSensorUseCases;
|
|
@override
|
|
final WorkoutTelemetryUseCases workoutTelemetryUseCases;
|
|
final WatchCompanionProjectionUseCases watchCompanionProjectionUseCases;
|
|
final WatchCompanionCommandHandler watchCompanionCommandHandler;
|
|
final WatchWearDataLayerAdapter watchWearDataLayerAdapter;
|
|
@override
|
|
WatchAlertPublisher get watchAlertPublisher => watchWearDataLayerAdapter;
|
|
final SessionNotificationCoordinator sessionNotificationCoordinator;
|
|
@override
|
|
final CloseWorkoutSessionUseCase closeWorkoutSessionUseCase;
|
|
@override
|
|
final WorkoutHistoryUseCases workoutHistoryUseCases;
|
|
@override
|
|
final ProgressionStatsUseCase progressionStatsUseCase;
|
|
@override
|
|
final ExercisePerformanceReferenceUseCase exercisePerformanceReferenceUseCase;
|
|
@override
|
|
final DataExportUseCase dataExportUseCase;
|
|
@override
|
|
final DataImportUseCase dataImportUseCase;
|
|
@override
|
|
final SyncUseCases syncUseCases;
|
|
@override
|
|
final ShareUseCases shareUseCases;
|
|
final SyncGateway syncGateway;
|
|
|
|
static Future<AppBootstrap> create() async {
|
|
final database = AppDatabase.open();
|
|
await database.customSelect('SELECT 1').get();
|
|
final exerciseRepository = DriftExerciseRepository(database);
|
|
final mediaRepository = DriftMediaAssetRepository(database);
|
|
final onlineAccountRepository = DriftOnlineAccountRepository(database);
|
|
final syncMetadataRepository = DriftSyncMetadataRepository(database);
|
|
final mappingRepository = DriftRemoteResourceMappingRepository(database);
|
|
final localSyncChangeRepository = DriftLocalSyncChangeRepository(database);
|
|
final starterSeedRepository = DriftStarterSeedRepository(database);
|
|
final shareInboxRepository = DriftShareInboxRepository(database);
|
|
final pendingShareActionRepository = DriftPendingShareActionRepository(
|
|
database,
|
|
);
|
|
final programRepository = DriftProgramRepository(database);
|
|
final templateRepository = DriftWorkoutTemplateRepository(database);
|
|
final activeSessionRepository = DriftActiveSessionRepository(database);
|
|
final historyRepository = DriftWorkoutHistoryRepository(database);
|
|
final telemetryRepository = DriftWorkoutTelemetryRepository(database);
|
|
final progressionStatsRepository = DriftProgressionStatsRepository(
|
|
database,
|
|
);
|
|
final performanceReferenceRepository =
|
|
DriftExercisePerformanceReferenceRepository(database);
|
|
final localDataBackupRepository = DriftLocalDataBackupRepository(database);
|
|
const localBackupMediaStore = PathProviderLocalMediaStorage();
|
|
final ids = LocalIdGenerator();
|
|
const clock = SystemClock();
|
|
const originDeviceId = 'local-device';
|
|
final activeWorkoutSessionUseCases = ActiveWorkoutSessionUseCases(
|
|
sessionRepository: activeSessionRepository,
|
|
templateRepository: templateRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
);
|
|
final activeExerciseStepUseCases = ActiveExerciseStepUseCases(
|
|
sessionRepository: activeSessionRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
activeSessionUseCases: activeWorkoutSessionUseCases,
|
|
);
|
|
final activeWorkoutSensorUseCases = ActiveWorkoutSensorUseCases(
|
|
clock: clock,
|
|
);
|
|
final workoutTelemetryUseCases = WorkoutTelemetryUseCases(
|
|
repository: telemetryRepository,
|
|
sessionRepository: activeSessionRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
);
|
|
final watchCompanionProjectionUseCases = WatchCompanionProjectionUseCases(
|
|
sessionRepository: activeSessionRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
);
|
|
final watchCompanionCommandHandler = WatchCompanionCommandHandler(
|
|
sessionRepository: activeSessionRepository,
|
|
activeSessionUseCases: activeWorkoutSessionUseCases,
|
|
stepUseCases: activeExerciseStepUseCases,
|
|
projectionSource: watchCompanionProjectionUseCases,
|
|
);
|
|
final workoutHistoryUseCases = WorkoutHistoryUseCases(
|
|
repository: historyRepository,
|
|
clock: clock,
|
|
);
|
|
final watchWearDataLayerAdapter = WatchWearDataLayerAdapter(
|
|
nativeChannel: const MethodChannelWatchBridgeNativeChannel(),
|
|
commandIngress: watchCompanionCommandHandler,
|
|
projectionSource: watchCompanionProjectionUseCases,
|
|
workoutHistoryUseCases: workoutHistoryUseCases,
|
|
activeWorkoutSensorUseCases: activeWorkoutSensorUseCases,
|
|
workoutTelemetryUseCases: workoutTelemetryUseCases,
|
|
);
|
|
final sessionNotificationCoordinator = SessionNotificationCoordinator(
|
|
projections: watchCompanionProjectionUseCases.projections,
|
|
gateway: const MethodChannelSessionNotificationGateway(),
|
|
);
|
|
await watchWearDataLayerAdapter.start();
|
|
sessionNotificationCoordinator.start();
|
|
await SeedStarterContentUseCase(
|
|
seedStateRepository: starterSeedRepository,
|
|
contentRepository: starterSeedRepository,
|
|
clock: clock,
|
|
originDeviceId: originDeviceId,
|
|
).run();
|
|
final remoteAuthApi = HttpRemoteAuthApi(
|
|
HttpApiClient(baseUrl: Uri.parse(HttpApiClient.defaultBaseUrl)),
|
|
);
|
|
final remoteSyncApi = HttpRemoteSyncApi(
|
|
HttpApiClient(baseUrl: Uri.parse(HttpApiClient.defaultBaseUrl)),
|
|
);
|
|
final remoteShareApi = HttpRemoteShareApi(
|
|
HttpApiClient(baseUrl: Uri.parse(HttpApiClient.defaultBaseUrl)),
|
|
);
|
|
|
|
return AppBootstrap._(
|
|
database: database,
|
|
authUseCases: AuthUseCases(
|
|
tokenStore: const SecureStorageAuthTokenStore(),
|
|
accountRepository: onlineAccountRepository,
|
|
remoteAuthApi: remoteAuthApi,
|
|
clock: clock,
|
|
ids: ids,
|
|
),
|
|
exerciseUseCases: ExerciseUseCases(
|
|
repository: exerciseRepository,
|
|
programRepository: programRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
),
|
|
mediaUseCases: MediaUseCases(
|
|
mediaRepository: mediaRepository,
|
|
exerciseRepository: exerciseRepository,
|
|
storage: const PathProviderLocalMediaStorage(),
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
),
|
|
programUseCases: ProgramUseCases(
|
|
programRepository: programRepository,
|
|
exerciseRepository: exerciseRepository,
|
|
templateRepository: templateRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
),
|
|
workoutTemplateUseCases: WorkoutTemplateUseCases(
|
|
templateRepository: templateRepository,
|
|
programRepository: programRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
),
|
|
activeWorkoutSessionUseCases: activeWorkoutSessionUseCases,
|
|
activeExerciseStepUseCases: activeExerciseStepUseCases,
|
|
activeWorkoutSensorUseCases: activeWorkoutSensorUseCases,
|
|
workoutTelemetryUseCases: workoutTelemetryUseCases,
|
|
watchCompanionProjectionUseCases: watchCompanionProjectionUseCases,
|
|
watchCompanionCommandHandler: watchCompanionCommandHandler,
|
|
watchWearDataLayerAdapter: watchWearDataLayerAdapter,
|
|
sessionNotificationCoordinator: sessionNotificationCoordinator,
|
|
closeWorkoutSessionUseCase: CloseWorkoutSessionUseCase(
|
|
sessionRepository: activeSessionRepository,
|
|
historyRepository: historyRepository,
|
|
telemetryRepository: telemetryRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
),
|
|
workoutHistoryUseCases: workoutHistoryUseCases,
|
|
progressionStatsUseCase: ProgressionStatsUseCase(
|
|
repository: progressionStatsRepository,
|
|
clock: clock,
|
|
),
|
|
exercisePerformanceReferenceUseCase: ExercisePerformanceReferenceUseCase(
|
|
repository: performanceReferenceRepository,
|
|
),
|
|
dataExportUseCase: DataExportUseCase(
|
|
repository: localDataBackupRepository,
|
|
mediaStore: localBackupMediaStore,
|
|
clock: clock,
|
|
),
|
|
dataImportUseCase: DataImportUseCase(
|
|
repository: localDataBackupRepository,
|
|
mediaStore: localBackupMediaStore,
|
|
clock: clock,
|
|
),
|
|
syncUseCases: SyncUseCases(
|
|
tokenStore: const SecureStorageAuthTokenStore(),
|
|
remoteSyncApi: remoteSyncApi,
|
|
metadataRepository: syncMetadataRepository,
|
|
mappingRepository: mappingRepository,
|
|
localChanges: localSyncChangeRepository,
|
|
clock: clock,
|
|
deviceId: originDeviceId,
|
|
),
|
|
shareUseCases: ShareUseCases(
|
|
tokenStore: const SecureStorageAuthTokenStore(),
|
|
remoteShareApi: remoteShareApi,
|
|
inboxRepository: shareInboxRepository,
|
|
pendingActionRepository: pendingShareActionRepository,
|
|
localChanges: localSyncChangeRepository,
|
|
programRepository: programRepository,
|
|
templateRepository: templateRepository,
|
|
clock: clock,
|
|
ids: ids,
|
|
originDeviceId: originDeviceId,
|
|
),
|
|
syncGateway: const NoOpSyncGateway(),
|
|
);
|
|
}
|
|
|
|
Future<void> dispose() async {
|
|
await sessionNotificationCoordinator.dispose();
|
|
await watchWearDataLayerAdapter.stop();
|
|
await watchCompanionProjectionUseCases.dispose();
|
|
await activeWorkoutSensorUseCases.dispose();
|
|
await database.close();
|
|
}
|
|
}
|