merge(develop): clôture lot #91 Wear OS - fréquence cardiaque, notifications, finitions montre
Intègre le commit de clôture du lot #91 resté non fusionné. Conflits attendus sur entities.dart, workout_execution_screen.dart et watch_companion_projection_test.dart : arbitrage Architect - garder la base feature/ticket91-wear-os-watch-sync sur ces 3 fichiers puis réinjecter uniquement les invariants chronos utiles (Durée / Temps réalisé). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> # Conflicts: # lib/domain/entities.dart # lib/presentation/workout_execution_screen.dart # test/application/watch_companion_projection_test.dart
This commit is contained in:
@ -381,6 +381,11 @@ final class Exercise {
|
||||
targetScore: defaultTargetScore,
|
||||
targetScoreTimeMs: defaultTargetScoreTimeMs,
|
||||
);
|
||||
_requireLinkedStepSeriesScoreShape(
|
||||
steps: steps,
|
||||
scoreEnabled: hasScoreMeasure,
|
||||
scoreInputMode: scoreInputMode,
|
||||
);
|
||||
}
|
||||
|
||||
final EntityMetadata metadata;
|
||||
@ -514,6 +519,7 @@ final class ExerciseStep {
|
||||
this.scoreUnit,
|
||||
this.defaultTargetScore,
|
||||
this.defaultTargetScoreTimeMs,
|
||||
this.linkedToSeriesScore = false,
|
||||
}) : id = _nonBlank(id, 'Exercise step id'),
|
||||
name = _nonBlank(name, 'Exercise step name') {
|
||||
_requireNonNegative(position, 'Exercise step position');
|
||||
@ -525,6 +531,7 @@ final class ExerciseStep {
|
||||
scoreUnit: scoreUnit,
|
||||
defaultTargetScore: defaultTargetScore,
|
||||
defaultTargetScoreTimeMs: defaultTargetScoreTimeMs,
|
||||
linkedToSeriesScore: linkedToSeriesScore,
|
||||
);
|
||||
}
|
||||
|
||||
@ -539,6 +546,7 @@ final class ExerciseStep {
|
||||
final String? scoreUnit;
|
||||
final double? defaultTargetScore;
|
||||
final int? defaultTargetScoreTimeMs;
|
||||
final bool linkedToSeriesScore;
|
||||
|
||||
Map<String, Object?> toSnapshotJson() => {
|
||||
'id': id,
|
||||
@ -552,6 +560,7 @@ final class ExerciseStep {
|
||||
'scoreUnit': scoreUnit,
|
||||
'defaultTargetScore': defaultTargetScore,
|
||||
'defaultTargetScoreTimeMs': defaultTargetScoreTimeMs,
|
||||
'linkedToSeriesScore': linkedToSeriesScore,
|
||||
};
|
||||
}
|
||||
|
||||
@ -664,6 +673,11 @@ final class ProgramExercise {
|
||||
targetScore: targetScore,
|
||||
targetScoreTimeMs: targetScoreTimeMs,
|
||||
);
|
||||
_requireLinkedStepSeriesScoreShape(
|
||||
steps: exerciseStepsSnapshot,
|
||||
scoreEnabled: scoreEnabled,
|
||||
scoreInputMode: scoreInputModeSnapshot,
|
||||
);
|
||||
}
|
||||
|
||||
final EntityMetadata metadata;
|
||||
@ -1106,6 +1120,47 @@ final class ActiveScoreStopwatchState {
|
||||
}
|
||||
}
|
||||
|
||||
final class ActiveManualScoreState {
|
||||
ActiveManualScoreState({
|
||||
required this.metadata,
|
||||
required this.activeWorkoutSessionId,
|
||||
required this.programIndex,
|
||||
required this.exerciseIndex,
|
||||
required this.setIndex,
|
||||
required this.value,
|
||||
required this.updatedAt,
|
||||
}) {
|
||||
_requireNonNegative(programIndex, 'Program index');
|
||||
_requireNonNegative(exerciseIndex, 'Exercise index');
|
||||
_requireNonNegative(setIndex, 'Set index');
|
||||
_requireNullableNonNegativeDouble(value, 'Manual score value');
|
||||
}
|
||||
|
||||
final EntityMetadata metadata;
|
||||
final String activeWorkoutSessionId;
|
||||
final int programIndex;
|
||||
final int exerciseIndex;
|
||||
final int setIndex;
|
||||
final double value;
|
||||
final DateTime updatedAt;
|
||||
|
||||
ActiveManualScoreState copyWith({
|
||||
EntityMetadata? metadata,
|
||||
double? value,
|
||||
DateTime? updatedAt,
|
||||
}) {
|
||||
return ActiveManualScoreState(
|
||||
metadata: metadata ?? this.metadata,
|
||||
activeWorkoutSessionId: activeWorkoutSessionId,
|
||||
programIndex: programIndex,
|
||||
exerciseIndex: exerciseIndex,
|
||||
setIndex: setIndex,
|
||||
value: value ?? this.value,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final class ActiveSetTimerState {
|
||||
ActiveSetTimerState({
|
||||
required this.metadata,
|
||||
@ -1411,7 +1466,7 @@ final class ActiveExerciseStepResult {
|
||||
}
|
||||
|
||||
final class WorkoutHistory {
|
||||
const WorkoutHistory({
|
||||
WorkoutHistory({
|
||||
required this.metadata,
|
||||
this.sourceWorkoutTemplateId,
|
||||
this.sourceActiveWorkoutSessionId,
|
||||
@ -1421,9 +1476,17 @@ final class WorkoutHistory {
|
||||
required this.totalActiveMs,
|
||||
required this.completed,
|
||||
required this.historySnapshotJson,
|
||||
this.averageHeartRateBpm,
|
||||
this.maxHeartRateBpm,
|
||||
this.results = const [],
|
||||
this.stepResults = const [],
|
||||
});
|
||||
}) {
|
||||
_requireNullablePositiveDouble(
|
||||
averageHeartRateBpm,
|
||||
'Average heart rate bpm',
|
||||
);
|
||||
_requireNullablePositive(maxHeartRateBpm, 'Max heart rate bpm');
|
||||
}
|
||||
|
||||
final EntityMetadata metadata;
|
||||
final String? sourceWorkoutTemplateId;
|
||||
@ -1434,8 +1497,36 @@ final class WorkoutHistory {
|
||||
final int totalActiveMs;
|
||||
final bool completed;
|
||||
final String historySnapshotJson;
|
||||
final double? averageHeartRateBpm;
|
||||
final int? maxHeartRateBpm;
|
||||
final List<WorkoutHistorySetResult> results;
|
||||
final List<WorkoutHistoryStepResult> stepResults;
|
||||
|
||||
WorkoutHistory copyWith({
|
||||
EntityMetadata? metadata,
|
||||
Object? averageHeartRateBpm = _unchanged,
|
||||
Object? maxHeartRateBpm = _unchanged,
|
||||
}) {
|
||||
return WorkoutHistory(
|
||||
metadata: metadata ?? this.metadata,
|
||||
sourceWorkoutTemplateId: sourceWorkoutTemplateId,
|
||||
sourceActiveWorkoutSessionId: sourceActiveWorkoutSessionId,
|
||||
nameSnapshot: nameSnapshot,
|
||||
startedAt: startedAt,
|
||||
endedAt: endedAt,
|
||||
totalActiveMs: totalActiveMs,
|
||||
completed: completed,
|
||||
historySnapshotJson: historySnapshotJson,
|
||||
averageHeartRateBpm: averageHeartRateBpm == _unchanged
|
||||
? this.averageHeartRateBpm
|
||||
: averageHeartRateBpm as double?,
|
||||
maxHeartRateBpm: maxHeartRateBpm == _unchanged
|
||||
? this.maxHeartRateBpm
|
||||
: maxHeartRateBpm as int?,
|
||||
results: results,
|
||||
stepResults: stepResults,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final class WorkoutHistorySetResult {
|
||||
@ -1727,6 +1818,12 @@ void _requireNullableNonNegativeDouble(double? value, String label) {
|
||||
}
|
||||
}
|
||||
|
||||
void _requireNullablePositiveDouble(double? value, String label) {
|
||||
if (value != null && value <= 0) {
|
||||
throw DomainException('$label must be positive.');
|
||||
}
|
||||
}
|
||||
|
||||
void _requireScoreTargetShape({
|
||||
required bool scoreEnabled,
|
||||
required ScoreInputMode scoreInputMode,
|
||||
@ -1759,12 +1856,14 @@ void _validateExerciseStepScoreShape({
|
||||
required String? scoreUnit,
|
||||
required double? defaultTargetScore,
|
||||
required int? defaultTargetScoreTimeMs,
|
||||
required bool linkedToSeriesScore,
|
||||
}) {
|
||||
if (!hasScore) {
|
||||
if (scoreLabel != null ||
|
||||
scoreUnit != null ||
|
||||
defaultTargetScore != null ||
|
||||
defaultTargetScoreTimeMs != null) {
|
||||
defaultTargetScoreTimeMs != null ||
|
||||
linkedToSeriesScore) {
|
||||
throw const DomainException(
|
||||
'Disabled exercise step score must not define score values.',
|
||||
);
|
||||
@ -1790,6 +1889,11 @@ void _validateExerciseStepScoreShape({
|
||||
);
|
||||
}
|
||||
case ScoreInputMode.stopwatch:
|
||||
if (linkedToSeriesScore) {
|
||||
throw const DomainException(
|
||||
'Linked series score requires manual exercise step score.',
|
||||
);
|
||||
}
|
||||
if (scoreLabel != null ||
|
||||
scoreUnit != null ||
|
||||
defaultTargetScore != null) {
|
||||
@ -1826,6 +1930,19 @@ void _requireScoreResultShape({
|
||||
}
|
||||
}
|
||||
|
||||
void _requireLinkedStepSeriesScoreShape({
|
||||
required List<ExerciseStep> steps,
|
||||
required bool scoreEnabled,
|
||||
required ScoreInputMode scoreInputMode,
|
||||
}) {
|
||||
if (steps.any((step) => step.linkedToSeriesScore) &&
|
||||
(!scoreEnabled || scoreInputMode != ScoreInputMode.manual)) {
|
||||
throw const DomainException(
|
||||
'Linked step scores require manual series score.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _validateExerciseStepResult({
|
||||
required int programIndex,
|
||||
required int exerciseIndex,
|
||||
|
||||
Reference in New Issue
Block a user