Files
GameTime/lib/application/app_bootstrap.dart
Blomios 65d43b9768 feat(watch): clôture lot #91 - fréquence cardiaque live, notifications de séance et finitions montre
Consolide le lot applicatif watch companion validé :
- télémétrie fréquence cardiaque live remontée montre -> téléphone
  (collecteur watch, adapter Wear Data Layer, persistance Drift,
  propagation aux écrans historique/programme/profil/exécution)
- notifications de séance en arrière-plan côté téléphone (service
  foreground de statut + passerelle applicative)
- finitions montre : chrono d'étape, score d'étape, retrait du bouton
  "lancer une séance", thème, icônes et polices watch_app

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 05:56:12 +02:00

286 lines
11 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;
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.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;
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<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 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 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,
);
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,
watchCompanionProjectionUseCases: watchCompanionProjectionUseCases,
watchCompanionCommandHandler: watchCompanionCommandHandler,
watchWearDataLayerAdapter: watchWearDataLayerAdapter,
sessionNotificationCoordinator: sessionNotificationCoordinator,
closeWorkoutSessionUseCase: CloseWorkoutSessionUseCase(
sessionRepository: activeSessionRepository,
historyRepository: historyRepository,
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();
}
}