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>
This commit is contained in:
2026-07-28 05:56:12 +02:00
parent c65a5a76a9
commit 65d43b9768
80 changed files with 12292 additions and 892 deletions

View File

@ -1,6 +1,7 @@
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';
@ -12,6 +13,7 @@ abstract interface class AppDependencies {
WorkoutTemplateUseCases get workoutTemplateUseCases;
ActiveWorkoutSessionUseCases get activeWorkoutSessionUseCases;
ActiveExerciseStepUseCases get activeExerciseStepUseCases;
ActiveWorkoutSensorUseCases get activeWorkoutSensorUseCases;
CloseWorkoutSessionUseCase get closeWorkoutSessionUseCase;
WorkoutHistoryUseCases get workoutHistoryUseCases;
ProgressionStatsUseCase get progressionStatsUseCase;
@ -32,9 +34,11 @@ final class AppBootstrap implements AppDependencies {
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,
@ -61,9 +65,12 @@ final class AppBootstrap implements AppDependencies {
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
@ -122,6 +129,10 @@ final class AppBootstrap implements AppDependencies {
clock: clock,
ids: ids,
originDeviceId: originDeviceId,
activeSessionUseCases: activeWorkoutSessionUseCases,
);
final activeWorkoutSensorUseCases = ActiveWorkoutSensorUseCases(
clock: clock,
);
final watchCompanionProjectionUseCases = WatchCompanionProjectionUseCases(
sessionRepository: activeSessionRepository,
@ -135,12 +146,23 @@ final class AppBootstrap implements AppDependencies {
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,
@ -198,9 +220,11 @@ final class AppBootstrap implements AppDependencies {
),
activeWorkoutSessionUseCases: activeWorkoutSessionUseCases,
activeExerciseStepUseCases: activeExerciseStepUseCases,
activeWorkoutSensorUseCases: activeWorkoutSensorUseCases,
watchCompanionProjectionUseCases: watchCompanionProjectionUseCases,
watchCompanionCommandHandler: watchCompanionCommandHandler,
watchWearDataLayerAdapter: watchWearDataLayerAdapter,
sessionNotificationCoordinator: sessionNotificationCoordinator,
closeWorkoutSessionUseCase: CloseWorkoutSessionUseCase(
sessionRepository: activeSessionRepository,
historyRepository: historyRepository,
@ -208,10 +232,7 @@ final class AppBootstrap implements AppDependencies {
ids: ids,
originDeviceId: originDeviceId,
),
workoutHistoryUseCases: WorkoutHistoryUseCases(
repository: historyRepository,
clock: clock,
),
workoutHistoryUseCases: workoutHistoryUseCases,
progressionStatsUseCase: ProgressionStatsUseCase(
repository: progressionStatsRepository,
clock: clock,
@ -255,8 +276,10 @@ final class AppBootstrap implements AppDependencies {
}
Future<void> dispose() async {
await sessionNotificationCoordinator.dispose();
await watchWearDataLayerAdapter.stop();
await watchCompanionProjectionUseCases.dispose();
await activeWorkoutSensorUseCases.dispose();
await database.close();
}
}