feat(bibliothèque): migration Drift v16, seed basket et seeding au démarrage (ticket #80)

Ajoute la migration Drift v16 (enum ExerciseCategory, champ isExample sur
exercises/programs/workout_templates, table local_seed_metadata), le
contenu seed basket déterministe (21 exercices, 1 programme, 1 séance-
modèle) dans lib/application/starter_content/, les ports
StarterSeedStateRepository/StarterContentRepository et le use case
SeedStarterContentUseCase branché dans AppBootstrap.create().

Validé GO par QA/Main : dart analyze propre, suite complète 167 tests
(4 échecs préexistants sans rapport avec ce lot), 4 nouveaux tests seed
tous verts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 07:29:49 +02:00
parent 75f52200a2
commit 24e266c0e9
12 changed files with 2052 additions and 16 deletions

View File

@ -10,6 +10,17 @@ enum ScoreInputMode { manual, stopwatch }
enum ExerciseStepType { time, reps }
enum ExerciseCategory {
shoot,
freeThrows,
dribble,
finishing,
conditioning,
defense,
mobility,
uncategorized,
}
enum ActiveWorkoutStatus { running, paused, savedExit, completed, abandoned }
enum SetResultStatus { completed, skipped }
@ -321,6 +332,8 @@ final class Exercise {
this.defaultTargetScore,
this.defaultTargetScoreTimeMs,
this.autoStartNextTimedStep = true,
this.category = ExerciseCategory.uncategorized,
this.isExample = false,
List<ExerciseStep> steps = const [],
this.archivedAt,
}) : name = _nonBlank(name, 'Exercise name'),
@ -379,6 +392,8 @@ final class Exercise {
final double? defaultTargetScore;
final int? defaultTargetScoreTimeMs;
final bool autoStartNextTimedStep;
final ExerciseCategory category;
final bool isExample;
final List<ExerciseStep> steps;
final DateTime? archivedAt;
@ -414,6 +429,8 @@ final class Exercise {
Object? defaultTargetScore = _unchanged,
Object? defaultTargetScoreTimeMs = _unchanged,
bool? autoStartNextTimedStep,
ExerciseCategory? category,
bool? isExample,
Object? steps = _unchanged,
Object? archivedAt = _unchanged,
}) {
@ -463,6 +480,8 @@ final class Exercise {
: defaultTargetScoreTimeMs as int?,
autoStartNextTimedStep:
autoStartNextTimedStep ?? this.autoStartNextTimedStep,
category: category ?? this.category,
isExample: isExample ?? this.isExample,
steps: steps == _unchanged ? this.steps : steps as List<ExerciseStep>,
archivedAt: archivedAt == _unchanged
? this.archivedAt
@ -532,6 +551,7 @@ final class Program {
required this.metadata,
required String name,
required this.defaultRestSeconds,
this.isExample = false,
this.exercises = const [],
}) : name = _nonBlank(name, 'Program name') {
_requireNonNegative(defaultRestSeconds, 'Default rest seconds');
@ -540,6 +560,7 @@ final class Program {
final EntityMetadata metadata;
final String name;
final int defaultRestSeconds;
final bool isExample;
final List<ProgramExercise> exercises;
Program copyWith({
@ -547,11 +568,13 @@ final class Program {
EntityMetadata? metadata,
String? name,
int? defaultRestSeconds,
bool? isExample,
}) {
return Program(
metadata: metadata ?? this.metadata,
name: name ?? this.name,
defaultRestSeconds: defaultRestSeconds ?? this.defaultRestSeconds,
isExample: isExample ?? this.isExample,
exercises: exercises ?? this.exercises,
);
}
@ -745,6 +768,7 @@ final class WorkoutTemplate {
required this.metadata,
required String name,
this.lastStartedAt,
this.isExample = false,
this.programs = const [],
this.overrides = const [],
}) : name = _nonBlank(name, 'Workout template name');
@ -752,6 +776,7 @@ final class WorkoutTemplate {
final EntityMetadata metadata;
final String name;
final DateTime? lastStartedAt;
final bool isExample;
final List<WorkoutTemplateProgram> programs;
final List<WorkoutTemplateExerciseOverride> overrides;
}