import '../infrastructure/health_connect/health_connect.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; ExecutionDebugUseCase get executionDebugUseCase; SeedQaFunctionalContentUseCase get seedQaFunctionalContentUseCase; WorkoutTelemetryUseCases get workoutTelemetryUseCases; WatchCompanionProjectionUseCases get watchCompanionProjectionUseCases; CloseWorkoutSessionUseCase get closeWorkoutSessionUseCase; WorkoutHistoryUseCases get workoutHistoryUseCases; ProgressionStatsUseCase get progressionStatsUseCase; ExercisePerformanceReferenceUseCase get exercisePerformanceReferenceUseCase; WatchAlertPublisher get watchAlertPublisher; DataExportUseCase get dataExportUseCase; DataImportUseCase get dataImportUseCase; HealthConnectUseCases get healthConnectUseCases; EntitlementRevalidationUseCase get entitlementRevalidationUseCase; 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.executionDebugUseCase, required this.seedQaFunctionalContentUseCase, 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.healthConnectUseCases, required this.entitlementRevalidationUseCase, 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 ExecutionDebugUseCase executionDebugUseCase; @override final SeedQaFunctionalContentUseCase seedQaFunctionalContentUseCase; @override final WorkoutTelemetryUseCases workoutTelemetryUseCases; @override 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 HealthConnectUseCases healthConnectUseCases; @override final EntitlementRevalidationUseCase entitlementRevalidationUseCase; @override final SyncUseCases syncUseCases; @override final ShareUseCases shareUseCases; final SyncGateway syncGateway; static Future 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 entitlementSnapshotRepository = DriftEntitlementSnapshotRepository( 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 authTokenStore = SecureStorageAuthTokenStore(); 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 executionDebugUseCase = ExecutionDebugUseCase( sessionRepository: activeSessionRepository, clock: clock, ); final seedQaFunctionalContentUseCase = SeedQaFunctionalContentUseCase( seedStateRepository: starterSeedRepository, contentRepository: starterSeedRepository, clock: clock, originDeviceId: originDeviceId, ); final workoutTelemetryUseCases = WorkoutTelemetryUseCases( repository: telemetryRepository, sessionRepository: activeSessionRepository, clock: clock, ids: ids, ); final watchCompanionProjectionUseCases = WatchCompanionProjectionUseCases( sessionRepository: activeSessionRepository, clock: clock, ids: ids, originDeviceId: originDeviceId, activeWorkoutSensorUseCases: activeWorkoutSensorUseCases, ); final watchCompanionCommandHandler = WatchCompanionCommandHandler( sessionRepository: activeSessionRepository, activeSessionUseCases: activeWorkoutSessionUseCases, stepUseCases: activeExerciseStepUseCases, projectionSource: watchCompanionProjectionUseCases, ); final workoutHistoryUseCases = WorkoutHistoryUseCases( repository: historyRepository, clock: clock, ); final healthConnectUseCases = HealthConnectUseCases( gateway: const MethodChannelHealthConnectGateway(), historyRepository: historyRepository, telemetryUseCases: workoutTelemetryUseCases, ); 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)), ); final remoteEntitlementSnapshotSource = HttpRemoteEntitlementSnapshotSource( client: HttpApiClient(baseUrl: Uri.parse(HttpApiClient.defaultBaseUrl)), tokenStore: authTokenStore, ); return AppBootstrap._( database: database, authUseCases: AuthUseCases( tokenStore: authTokenStore, 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, executionDebugUseCase: executionDebugUseCase, seedQaFunctionalContentUseCase: seedQaFunctionalContentUseCase, workoutTelemetryUseCases: workoutTelemetryUseCases, watchCompanionProjectionUseCases: watchCompanionProjectionUseCases, watchCompanionCommandHandler: watchCompanionCommandHandler, watchWearDataLayerAdapter: watchWearDataLayerAdapter, sessionNotificationCoordinator: sessionNotificationCoordinator, closeWorkoutSessionUseCase: CloseWorkoutSessionUseCase( sessionRepository: activeSessionRepository, historyRepository: historyRepository, telemetryRepository: telemetryRepository, healthConnectUseCases: healthConnectUseCases, activeWorkoutSensorUseCases: activeWorkoutSensorUseCases, 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, ), healthConnectUseCases: healthConnectUseCases, entitlementRevalidationUseCase: EntitlementRevalidationUseCase( repository: entitlementSnapshotRepository, remote: remoteEntitlementSnapshotSource, ), syncUseCases: SyncUseCases( tokenStore: authTokenStore, remoteSyncApi: remoteSyncApi, metadataRepository: syncMetadataRepository, mappingRepository: mappingRepository, localChanges: localSyncChangeRepository, clock: clock, deviceId: originDeviceId, ), shareUseCases: ShareUseCases( tokenStore: authTokenStore, remoteShareApi: remoteShareApi, inboxRepository: shareInboxRepository, pendingActionRepository: pendingShareActionRepository, localChanges: localSyncChangeRepository, programRepository: programRepository, templateRepository: templateRepository, clock: clock, ids: ids, originDeviceId: originDeviceId, ), syncGateway: const NoOpSyncGateway(), ); } Future dispose() async { await sessionNotificationCoordinator.dispose(); await watchWearDataLayerAdapter.stop(); await watchCompanionProjectionUseCases.dispose(); await activeWorkoutSensorUseCases.dispose(); await database.close(); } }