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; 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; 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 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, 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 dispose() async { await sessionNotificationCoordinator.dispose(); await watchWearDataLayerAdapter.stop(); await watchCompanionProjectionUseCases.dispose(); await activeWorkoutSensorUseCases.dispose(); await database.close(); } }