feat(domain): fondation domain du score chronométré (ticket #25)
Étend le modèle Drift (tables.dart, app_database.dart/.g.dart), les entités du domaine, les ports et use cases pour poser les fondations du score chronométré. build_runner OK, flutter analyze propre, 39/39 tests verts, build APK debug validé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -65,6 +65,8 @@ class Exercises extends SyncableTable {
|
||||
BoolColumn get hasTimeMeasure => boolean()();
|
||||
BoolColumn get hasRepsMeasure => boolean()();
|
||||
BoolColumn get hasScoreMeasure => boolean()();
|
||||
TextColumn get scoreInputMode =>
|
||||
text().withDefault(const Constant('manual'))();
|
||||
TextColumn get scoreLabel => text().nullable()();
|
||||
TextColumn get scoreUnit => text().nullable()();
|
||||
DateTimeColumn get archivedAt => dateTime().nullable()();
|
||||
@ -72,9 +74,11 @@ class Exercises extends SyncableTable {
|
||||
@override
|
||||
List<String> get customConstraints => [
|
||||
'CHECK (has_time_measure OR has_reps_measure OR has_score_measure)',
|
||||
'CHECK (NOT has_score_measure OR (score_label IS NOT NULL '
|
||||
'AND length(trim(score_label)) > 0 AND score_unit IS NOT NULL '
|
||||
'AND length(trim(score_unit)) > 0))',
|
||||
"CHECK (score_input_mode IN ('manual', 'stopwatch'))",
|
||||
"CHECK (has_score_measure OR score_input_mode = 'manual')",
|
||||
"CHECK (score_input_mode != 'manual' OR NOT has_score_measure OR "
|
||||
'(score_label IS NOT NULL AND length(trim(score_label)) > 0 '
|
||||
'AND score_unit IS NOT NULL AND length(trim(score_unit)) > 0))',
|
||||
];
|
||||
}
|
||||
|
||||
@ -111,6 +115,8 @@ class ProgramExercises extends SyncableTable {
|
||||
BoolColumn get availableTimeSnapshot => boolean()();
|
||||
BoolColumn get availableRepsSnapshot => boolean()();
|
||||
BoolColumn get availableScoreSnapshot => boolean()();
|
||||
TextColumn get scoreInputModeSnapshot =>
|
||||
text().withDefault(const Constant('manual'))();
|
||||
TextColumn get scoreLabelSnapshot => text().nullable()();
|
||||
TextColumn get scoreUnitSnapshot => text().nullable()();
|
||||
IntColumn get setsCount => integer()();
|
||||
@ -120,6 +126,7 @@ class ProgramExercises extends SyncableTable {
|
||||
IntColumn get targetTimeSeconds => integer().nullable()();
|
||||
IntColumn get targetReps => integer().nullable()();
|
||||
RealColumn get targetScore => real().nullable()();
|
||||
IntColumn get targetScoreTimeMs => integer().nullable()();
|
||||
IntColumn get restSecondsOverride => integer().nullable()();
|
||||
|
||||
@override
|
||||
@ -134,11 +141,18 @@ class ProgramExercises extends SyncableTable {
|
||||
'CHECK (target_time_seconds IS NULL OR target_time_seconds > 0)',
|
||||
'CHECK (target_reps IS NULL OR target_reps > 0)',
|
||||
'CHECK (target_score IS NULL OR target_score >= 0)',
|
||||
'CHECK (target_score_time_ms IS NULL OR target_score_time_ms > 0)',
|
||||
'CHECK (rest_seconds_override IS NULL OR rest_seconds_override >= 0)',
|
||||
'CHECK (target_time_seconds IS NULL OR time_enabled)',
|
||||
'CHECK (target_reps IS NULL OR reps_enabled)',
|
||||
'CHECK (target_score IS NULL OR score_enabled)',
|
||||
'CHECK (NOT available_score_snapshot OR (score_label_snapshot '
|
||||
"CHECK (score_input_mode_snapshot IN ('manual', 'stopwatch'))",
|
||||
'CHECK (target_score IS NULL OR '
|
||||
"(score_enabled AND score_input_mode_snapshot = 'manual'))",
|
||||
'CHECK (target_score_time_ms IS NULL OR '
|
||||
"(score_enabled AND score_input_mode_snapshot = 'stopwatch'))",
|
||||
'CHECK (target_score IS NULL OR target_score_time_ms IS NULL)',
|
||||
"CHECK (score_input_mode_snapshot != 'manual' OR "
|
||||
'NOT available_score_snapshot OR (score_label_snapshot '
|
||||
'IS NOT NULL AND length(trim(score_label_snapshot)) > 0 '
|
||||
'AND score_unit_snapshot IS NOT NULL '
|
||||
'AND length(trim(score_unit_snapshot)) > 0))',
|
||||
@ -185,6 +199,7 @@ class WorkoutTemplateExerciseOverrides extends SyncableTable {
|
||||
IntColumn get targetTimeSecondsOverride => integer().nullable()();
|
||||
IntColumn get targetRepsOverride => integer().nullable()();
|
||||
RealColumn get targetScoreOverride => real().nullable()();
|
||||
IntColumn get targetScoreTimeMsOverride => integer().nullable()();
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => [
|
||||
@ -194,6 +209,10 @@ class WorkoutTemplateExerciseOverrides extends SyncableTable {
|
||||
'target_time_seconds_override > 0)',
|
||||
'CHECK (target_reps_override IS NULL OR target_reps_override > 0)',
|
||||
'CHECK (target_score_override IS NULL OR target_score_override >= 0)',
|
||||
'CHECK (target_score_time_ms_override IS NULL OR '
|
||||
'target_score_time_ms_override > 0)',
|
||||
'CHECK (target_score_override IS NULL OR '
|
||||
'target_score_time_ms_override IS NULL)',
|
||||
];
|
||||
}
|
||||
|
||||
@ -241,6 +260,9 @@ class ActiveSetResults extends SyncableTable {
|
||||
IntColumn get actualTimeMs => integer().nullable()();
|
||||
IntColumn get actualReps => integer().nullable()();
|
||||
RealColumn get actualScore => real().nullable()();
|
||||
IntColumn get actualScoreTimeMs => integer().nullable()();
|
||||
TextColumn get scoreInputModeSnapshot =>
|
||||
text().withDefault(const Constant('manual'))();
|
||||
TextColumn get scoreLabelSnapshot => text().nullable()();
|
||||
TextColumn get scoreUnitSnapshot => text().nullable()();
|
||||
TextColumn get note => text().nullable()();
|
||||
@ -256,9 +278,17 @@ class ActiveSetResults extends SyncableTable {
|
||||
'CHECK (actual_time_ms IS NULL OR actual_time_ms >= 0)',
|
||||
'CHECK (actual_reps IS NULL OR actual_reps >= 0)',
|
||||
'CHECK (actual_score IS NULL OR actual_score >= 0)',
|
||||
'CHECK (actual_score_time_ms IS NULL OR actual_score_time_ms >= 0)',
|
||||
"CHECK (status IN ('completed', 'skipped'))",
|
||||
'CHECK (status != \'skipped\' OR (actual_time_ms IS NULL '
|
||||
'AND actual_reps IS NULL AND actual_score IS NULL))',
|
||||
'AND actual_reps IS NULL AND actual_score IS NULL '
|
||||
'AND actual_score_time_ms IS NULL))',
|
||||
"CHECK (score_input_mode_snapshot IN ('manual', 'stopwatch'))",
|
||||
'CHECK (actual_score IS NULL OR '
|
||||
"score_input_mode_snapshot = 'manual')",
|
||||
'CHECK (actual_score_time_ms IS NULL OR '
|
||||
"score_input_mode_snapshot = 'stopwatch')",
|
||||
'CHECK (actual_score IS NULL OR actual_score_time_ms IS NULL)',
|
||||
'CHECK (actual_score IS NULL OR (score_label_snapshot IS NOT NULL '
|
||||
'AND length(trim(score_label_snapshot)) > 0 '
|
||||
'AND score_unit_snapshot IS NOT NULL '
|
||||
@ -266,6 +296,32 @@ class ActiveSetResults extends SyncableTable {
|
||||
];
|
||||
}
|
||||
|
||||
class ActiveScoreStopwatchStates extends SyncableTable {
|
||||
@override
|
||||
String get tableName => 'active_score_stopwatch_states';
|
||||
|
||||
TextColumn get activeWorkoutSessionId =>
|
||||
text().references(ActiveWorkoutSessions, #id)();
|
||||
IntColumn get programIndex => integer()();
|
||||
IntColumn get exerciseIndex => integer()();
|
||||
IntColumn get setIndex => integer()();
|
||||
TextColumn get status => text()();
|
||||
DateTimeColumn get startedAt => dateTime()();
|
||||
IntColumn get accumulatedMs => integer()();
|
||||
DateTimeColumn get stoppedAt => dateTime().nullable()();
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => [
|
||||
'UNIQUE (active_workout_session_id, program_index, exercise_index, '
|
||||
'set_index)',
|
||||
'CHECK (program_index >= 0)',
|
||||
'CHECK (exercise_index >= 0)',
|
||||
'CHECK (set_index >= 0)',
|
||||
"CHECK (status IN ('running', 'stopped'))",
|
||||
'CHECK (accumulated_ms >= 0)',
|
||||
];
|
||||
}
|
||||
|
||||
class ActiveRestStates extends SyncableTable {
|
||||
@override
|
||||
String get tableName => 'active_rest_states';
|
||||
@ -326,12 +382,16 @@ class WorkoutHistorySetResults extends SyncableTable {
|
||||
BoolColumn get timeEnabledSnapshot => boolean()();
|
||||
BoolColumn get repsEnabledSnapshot => boolean()();
|
||||
BoolColumn get scoreEnabledSnapshot => boolean()();
|
||||
TextColumn get scoreInputModeSnapshot =>
|
||||
text().withDefault(const Constant('manual'))();
|
||||
IntColumn get targetTimeSecondsSnapshot => integer().nullable()();
|
||||
IntColumn get targetRepsSnapshot => integer().nullable()();
|
||||
RealColumn get targetScoreSnapshot => real().nullable()();
|
||||
IntColumn get targetScoreTimeMsSnapshot => integer().nullable()();
|
||||
IntColumn get actualTimeMs => integer().nullable()();
|
||||
IntColumn get actualReps => integer().nullable()();
|
||||
RealColumn get actualScore => real().nullable()();
|
||||
IntColumn get actualScoreTimeMs => integer().nullable()();
|
||||
TextColumn get scoreLabelSnapshot => text().nullable()();
|
||||
TextColumn get scoreUnitSnapshot => text().nullable()();
|
||||
DateTimeColumn get startedAt => dateTime().nullable()();
|
||||
@ -351,12 +411,28 @@ class WorkoutHistorySetResults extends SyncableTable {
|
||||
'target_time_seconds_snapshot > 0)',
|
||||
'CHECK (target_reps_snapshot IS NULL OR target_reps_snapshot > 0)',
|
||||
'CHECK (target_score_snapshot IS NULL OR target_score_snapshot >= 0)',
|
||||
'CHECK (target_score_time_ms_snapshot IS NULL OR '
|
||||
'target_score_time_ms_snapshot > 0)',
|
||||
'CHECK (actual_time_ms IS NULL OR actual_time_ms >= 0)',
|
||||
'CHECK (actual_reps IS NULL OR actual_reps >= 0)',
|
||||
'CHECK (actual_score IS NULL OR actual_score >= 0)',
|
||||
'CHECK (actual_score_time_ms IS NULL OR actual_score_time_ms >= 0)',
|
||||
"CHECK (status IN ('completed', 'skipped'))",
|
||||
'CHECK (status != \'skipped\' OR (actual_time_ms IS NULL '
|
||||
'AND actual_reps IS NULL AND actual_score IS NULL))',
|
||||
'AND actual_reps IS NULL AND actual_score IS NULL '
|
||||
'AND actual_score_time_ms IS NULL))',
|
||||
"CHECK (score_input_mode_snapshot IN ('manual', 'stopwatch'))",
|
||||
'CHECK (target_score_snapshot IS NULL OR '
|
||||
"(score_enabled_snapshot AND score_input_mode_snapshot = 'manual'))",
|
||||
'CHECK (target_score_time_ms_snapshot IS NULL OR '
|
||||
"(score_enabled_snapshot AND score_input_mode_snapshot = 'stopwatch'))",
|
||||
'CHECK (target_score_snapshot IS NULL OR '
|
||||
'target_score_time_ms_snapshot IS NULL)',
|
||||
'CHECK (actual_score IS NULL OR '
|
||||
"score_input_mode_snapshot = 'manual')",
|
||||
'CHECK (actual_score_time_ms IS NULL OR '
|
||||
"score_input_mode_snapshot = 'stopwatch')",
|
||||
'CHECK (actual_score IS NULL OR actual_score_time_ms IS NULL)',
|
||||
'CHECK (actual_score IS NULL OR (score_label_snapshot IS NOT NULL '
|
||||
'AND length(trim(score_label_snapshot)) > 0 '
|
||||
'AND score_unit_snapshot IS NOT NULL '
|
||||
|
||||
Reference in New Issue
Block a user