- Implémente la couche de synchronisation avec le serveur - Ajoute les fixtures versionnées pour les tests - Met à jour Drift database et repositories pour le support sync - Améliore les tests de synchronisation - Corrige et améliore le watch companion pour la collecte de métriques Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
217 lines
6.1 KiB
Dart
217 lines
6.1 KiB
Dart
import '../../domain/domain.dart';
|
|
import '../ports.dart';
|
|
|
|
const int starterSeedVersion = 2;
|
|
|
|
final class StarterExerciseSeed {
|
|
const StarterExerciseSeed({
|
|
required this.id,
|
|
required this.name,
|
|
required this.description,
|
|
this.category = ExerciseCategory.uncategorized,
|
|
this.businessTypes = const [],
|
|
this.hasTimeMeasure = false,
|
|
this.hasRepsMeasure = false,
|
|
this.hasScoreMeasure = false,
|
|
this.scoreInputMode = ScoreInputMode.manual,
|
|
this.scoreLabel,
|
|
this.scoreUnit,
|
|
this.defaultTargetTimeSeconds,
|
|
this.defaultTargetReps,
|
|
this.defaultTargetScore,
|
|
this.defaultTargetScoreTimeMs,
|
|
this.tags = const [],
|
|
this.steps = const [],
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final String description;
|
|
final ExerciseCategory category;
|
|
final List<BusinessExerciseType> businessTypes;
|
|
final bool hasTimeMeasure;
|
|
final bool hasRepsMeasure;
|
|
final bool hasScoreMeasure;
|
|
final ScoreInputMode scoreInputMode;
|
|
final String? scoreLabel;
|
|
final String? scoreUnit;
|
|
final int? defaultTargetTimeSeconds;
|
|
final int? defaultTargetReps;
|
|
final double? defaultTargetScore;
|
|
final int? defaultTargetScoreTimeMs;
|
|
final List<String> tags;
|
|
final List<StarterExerciseStepSeed> steps;
|
|
}
|
|
|
|
final class StarterExerciseStepSeed {
|
|
const StarterExerciseStepSeed({
|
|
required this.id,
|
|
required this.name,
|
|
required this.type,
|
|
required this.defaultTargetValue,
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final ExerciseStepType type;
|
|
final int defaultTargetValue;
|
|
}
|
|
|
|
final class StarterProgramSeed {
|
|
const StarterProgramSeed({
|
|
required this.id,
|
|
required this.name,
|
|
required this.defaultRestSeconds,
|
|
required this.exercises,
|
|
this.tags = const [],
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final int defaultRestSeconds;
|
|
final List<StarterProgramExerciseSeed> exercises;
|
|
final List<String> tags;
|
|
}
|
|
|
|
final class StarterProgramExerciseSeed {
|
|
const StarterProgramExerciseSeed({
|
|
required this.id,
|
|
required this.exerciseId,
|
|
required this.setsCount,
|
|
required this.enabledMeasures,
|
|
this.targetTimeSeconds,
|
|
this.targetReps,
|
|
this.targetScore,
|
|
this.targetScoreTimeMs,
|
|
this.restSecondsOverride,
|
|
});
|
|
|
|
final String id;
|
|
final String exerciseId;
|
|
final int setsCount;
|
|
final Set<WorkoutMeasure> enabledMeasures;
|
|
final int? targetTimeSeconds;
|
|
final int? targetReps;
|
|
final double? targetScore;
|
|
final int? targetScoreTimeMs;
|
|
final int? restSecondsOverride;
|
|
}
|
|
|
|
final class StarterWorkoutTemplateSeed {
|
|
const StarterWorkoutTemplateSeed({
|
|
required this.id,
|
|
required this.name,
|
|
required this.programSnapshotId,
|
|
this.tags = const [],
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final String programSnapshotId;
|
|
final List<String> tags;
|
|
}
|
|
|
|
StarterContent buildStarterContent({
|
|
required List<StarterExerciseSeed> exerciseSeeds,
|
|
required StarterProgramSeed programSeed,
|
|
required StarterWorkoutTemplateSeed templateSeed,
|
|
required DateTime now,
|
|
required String originDeviceId,
|
|
}) {
|
|
final exercisesById = <String, Exercise>{};
|
|
for (final seed in exerciseSeeds) {
|
|
exercisesById[seed.id] = Exercise(
|
|
metadata: _metadata(seed.id, now, originDeviceId),
|
|
name: seed.name,
|
|
description: seed.description,
|
|
hasTimeMeasure: seed.hasTimeMeasure,
|
|
hasRepsMeasure: seed.hasRepsMeasure,
|
|
hasScoreMeasure: seed.hasScoreMeasure,
|
|
scoreInputMode: seed.scoreInputMode,
|
|
scoreLabel: seed.scoreLabel,
|
|
scoreUnit: seed.scoreUnit,
|
|
defaultTargetTimeSeconds: seed.defaultTargetTimeSeconds,
|
|
defaultTargetReps: seed.defaultTargetReps,
|
|
defaultTargetScore: seed.defaultTargetScore,
|
|
defaultTargetScoreTimeMs: seed.defaultTargetScoreTimeMs,
|
|
category: seed.category,
|
|
businessTypes: seed.businessTypes,
|
|
isExample: true,
|
|
tags: seed.tags,
|
|
steps: [
|
|
for (var index = 0; index < seed.steps.length; index += 1)
|
|
ExerciseStep(
|
|
id: seed.steps[index].id,
|
|
position: index,
|
|
name: seed.steps[index].name,
|
|
type: seed.steps[index].type,
|
|
defaultTargetValue: seed.steps[index].defaultTargetValue,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
final programExercises = <ProgramExercise>[];
|
|
for (var index = 0; index < programSeed.exercises.length; index += 1) {
|
|
final seed = programSeed.exercises[index];
|
|
final exercise = exercisesById[seed.exerciseId];
|
|
if (exercise == null) {
|
|
throw DomainException('Unknown starter exercise id: ${seed.exerciseId}');
|
|
}
|
|
programExercises.add(
|
|
ProgramExercise.snapshotFromExercise(
|
|
metadata: _metadata(seed.id, now, originDeviceId),
|
|
programId: programSeed.id,
|
|
exercise: exercise,
|
|
position: index,
|
|
setsCount: seed.setsCount,
|
|
enabledMeasures: seed.enabledMeasures,
|
|
targetTimeSeconds: seed.targetTimeSeconds,
|
|
targetReps: seed.targetReps,
|
|
targetScore: seed.targetScore,
|
|
targetScoreTimeMs: seed.targetScoreTimeMs,
|
|
restSecondsOverride: seed.restSecondsOverride,
|
|
),
|
|
);
|
|
}
|
|
|
|
final program = Program(
|
|
metadata: _metadata(programSeed.id, now, originDeviceId),
|
|
name: programSeed.name,
|
|
defaultRestSeconds: programSeed.defaultRestSeconds,
|
|
isExample: true,
|
|
tags: programSeed.tags,
|
|
exercises: programExercises,
|
|
);
|
|
final templateProgram = WorkoutTemplateProgram.snapshotFromProgram(
|
|
metadata: _metadata(templateSeed.programSnapshotId, now, originDeviceId),
|
|
workoutTemplateId: templateSeed.id,
|
|
program: program,
|
|
position: 0,
|
|
);
|
|
final template = WorkoutTemplate(
|
|
metadata: _metadata(templateSeed.id, now, originDeviceId),
|
|
name: templateSeed.name,
|
|
isExample: true,
|
|
tags: templateSeed.tags,
|
|
programs: [templateProgram],
|
|
);
|
|
|
|
return StarterContent(
|
|
exercises: exercisesById.values.toList(growable: false),
|
|
program: program,
|
|
workoutTemplate: template,
|
|
);
|
|
}
|
|
|
|
EntityMetadata _metadata(String id, DateTime now, String originDeviceId) {
|
|
return EntityMetadata(
|
|
id: id,
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
originDeviceId: originDeviceId,
|
|
syncState: SyncState.localOnly,
|
|
localRevision: 0,
|
|
);
|
|
}
|