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:
@ -469,6 +469,77 @@ final class DriftActiveSessionRepository implements ActiveSessionRepository {
|
||||
return row == null ? null : _activeRestStateFromRow(row);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> saveScoreStopwatchState(
|
||||
domain.ActiveScoreStopwatchState state,
|
||||
) async {
|
||||
await _upsertWithChangeLog(
|
||||
database: database,
|
||||
tableName: 'active_score_stopwatch_states',
|
||||
entityType: 'ActiveScoreStopwatchState',
|
||||
metadata: state.metadata,
|
||||
write: () => database
|
||||
.into(database.activeScoreStopwatchStates)
|
||||
.insertOnConflictUpdate(_activeScoreStopwatchStateCompanion(state)),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteScoreStopwatchState({
|
||||
required String sessionId,
|
||||
required int programIndex,
|
||||
required int exerciseIndex,
|
||||
required int setIndex,
|
||||
required DateTime deletedAt,
|
||||
}) async {
|
||||
final row =
|
||||
await (database.select(database.activeScoreStopwatchStates)..where(
|
||||
(table) =>
|
||||
table.activeWorkoutSessionId.equals(sessionId) &
|
||||
table.programIndex.equals(programIndex) &
|
||||
table.exerciseIndex.equals(exerciseIndex) &
|
||||
table.setIndex.equals(setIndex) &
|
||||
table.deletedAt.isNull(),
|
||||
))
|
||||
.getSingleOrNull();
|
||||
if (row == null) {
|
||||
return;
|
||||
}
|
||||
final revision = row.localRevision + 1;
|
||||
await (database.delete(
|
||||
database.activeScoreStopwatchStates,
|
||||
)..where((table) => table.id.equals(row.id))).go();
|
||||
await _writeChangeLog(
|
||||
database: database,
|
||||
entityType: 'ActiveScoreStopwatchState',
|
||||
entityId: row.id,
|
||||
operation: 'delete',
|
||||
localRevision: revision,
|
||||
originDeviceId: row.originDeviceId,
|
||||
createdAt: deletedAt,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<domain.ActiveScoreStopwatchState?> findScoreStopwatchState({
|
||||
required String sessionId,
|
||||
required int programIndex,
|
||||
required int exerciseIndex,
|
||||
required int setIndex,
|
||||
}) async {
|
||||
final row =
|
||||
await (database.select(database.activeScoreStopwatchStates)..where(
|
||||
(table) =>
|
||||
table.activeWorkoutSessionId.equals(sessionId) &
|
||||
table.programIndex.equals(programIndex) &
|
||||
table.exerciseIndex.equals(exerciseIndex) &
|
||||
table.setIndex.equals(setIndex) &
|
||||
table.deletedAt.isNull(),
|
||||
))
|
||||
.getSingleOrNull();
|
||||
return row == null ? null : _activeScoreStopwatchStateFromRow(row);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<domain.ActiveSetResult>> listSetResults(String sessionId) async {
|
||||
final rows =
|
||||
@ -492,6 +563,26 @@ final class DriftActiveSessionRepository implements ActiveSessionRepository {
|
||||
.get();
|
||||
return rows.map(_activeRestStateFromRow).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<domain.ActiveScoreStopwatchState>> listScoreStopwatchStates(
|
||||
String sessionId,
|
||||
) async {
|
||||
final rows =
|
||||
await (database.select(database.activeScoreStopwatchStates)
|
||||
..where(
|
||||
(table) =>
|
||||
table.activeWorkoutSessionId.equals(sessionId) &
|
||||
table.deletedAt.isNull(),
|
||||
)
|
||||
..orderBy([
|
||||
(table) => OrderingTerm.asc(table.programIndex),
|
||||
(table) => OrderingTerm.asc(table.exerciseIndex),
|
||||
(table) => OrderingTerm.asc(table.setIndex),
|
||||
]))
|
||||
.get();
|
||||
return rows.map(_activeScoreStopwatchStateFromRow).toList();
|
||||
}
|
||||
}
|
||||
|
||||
final class DriftWorkoutHistoryRepository implements WorkoutHistoryRepository {
|
||||
@ -872,6 +963,7 @@ db.ExercisesCompanion _exerciseCompanion(domain.Exercise exercise) {
|
||||
hasTimeMeasure: Value(exercise.hasTimeMeasure),
|
||||
hasRepsMeasure: Value(exercise.hasRepsMeasure),
|
||||
hasScoreMeasure: Value(exercise.hasScoreMeasure),
|
||||
scoreInputMode: Value(_scoreInputModeToDb(exercise.scoreInputMode)),
|
||||
scoreLabel: Value(exercise.scoreLabel),
|
||||
scoreUnit: Value(exercise.scoreUnit),
|
||||
archivedAt: Value(_utcOrNull(exercise.archivedAt)),
|
||||
@ -888,6 +980,7 @@ domain.Exercise _exerciseFromRow(db.Exercise row) {
|
||||
hasTimeMeasure: row.hasTimeMeasure,
|
||||
hasRepsMeasure: row.hasRepsMeasure,
|
||||
hasScoreMeasure: row.hasScoreMeasure,
|
||||
scoreInputMode: _scoreInputModeFromDb(row.scoreInputMode),
|
||||
scoreLabel: row.scoreLabel,
|
||||
scoreUnit: row.scoreUnit,
|
||||
archivedAt: _utcOrNull(row.archivedAt),
|
||||
@ -995,6 +1088,9 @@ db.ProgramExercisesCompanion _programExerciseCompanion(
|
||||
availableTimeSnapshot: Value(exercise.availableTimeSnapshot),
|
||||
availableRepsSnapshot: Value(exercise.availableRepsSnapshot),
|
||||
availableScoreSnapshot: Value(exercise.availableScoreSnapshot),
|
||||
scoreInputModeSnapshot: Value(
|
||||
_scoreInputModeToDb(exercise.scoreInputModeSnapshot),
|
||||
),
|
||||
scoreLabelSnapshot: Value(exercise.scoreLabelSnapshot),
|
||||
scoreUnitSnapshot: Value(exercise.scoreUnitSnapshot),
|
||||
setsCount: Value(exercise.setsCount),
|
||||
@ -1004,6 +1100,7 @@ db.ProgramExercisesCompanion _programExerciseCompanion(
|
||||
targetTimeSeconds: Value(exercise.targetTimeSeconds),
|
||||
targetReps: Value(exercise.targetReps),
|
||||
targetScore: Value(exercise.targetScore),
|
||||
targetScoreTimeMs: Value(exercise.targetScoreTimeMs),
|
||||
restSecondsOverride: Value(exercise.restSecondsOverride),
|
||||
);
|
||||
}
|
||||
@ -1022,6 +1119,7 @@ domain.ProgramExercise _programExerciseFromRow(db.ProgramExercise row) {
|
||||
availableTimeSnapshot: row.availableTimeSnapshot,
|
||||
availableRepsSnapshot: row.availableRepsSnapshot,
|
||||
availableScoreSnapshot: row.availableScoreSnapshot,
|
||||
scoreInputModeSnapshot: _scoreInputModeFromDb(row.scoreInputModeSnapshot),
|
||||
scoreLabelSnapshot: row.scoreLabelSnapshot,
|
||||
scoreUnitSnapshot: row.scoreUnitSnapshot,
|
||||
setsCount: row.setsCount,
|
||||
@ -1031,6 +1129,7 @@ domain.ProgramExercise _programExerciseFromRow(db.ProgramExercise row) {
|
||||
targetTimeSeconds: row.targetTimeSeconds,
|
||||
targetReps: row.targetReps,
|
||||
targetScore: row.targetScore,
|
||||
targetScoreTimeMs: row.targetScoreTimeMs,
|
||||
restSecondsOverride: row.restSecondsOverride,
|
||||
);
|
||||
}
|
||||
@ -1132,6 +1231,7 @@ _workoutTemplateExerciseOverrideCompanion(
|
||||
targetTimeSecondsOverride: Value(override.targetTimeSecondsOverride),
|
||||
targetRepsOverride: Value(override.targetRepsOverride),
|
||||
targetScoreOverride: Value(override.targetScoreOverride),
|
||||
targetScoreTimeMsOverride: Value(override.targetScoreTimeMsOverride),
|
||||
);
|
||||
}
|
||||
|
||||
@ -1146,6 +1246,7 @@ domain.WorkoutTemplateExerciseOverride _workoutTemplateExerciseOverrideFromRow(
|
||||
targetTimeSecondsOverride: row.targetTimeSecondsOverride,
|
||||
targetRepsOverride: row.targetRepsOverride,
|
||||
targetScoreOverride: row.targetScoreOverride,
|
||||
targetScoreTimeMsOverride: row.targetScoreTimeMsOverride,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1225,6 +1326,10 @@ db.ActiveSetResultsCompanion _activeSetResultCompanion(
|
||||
actualTimeMs: Value(result.actualTimeMs),
|
||||
actualReps: Value(result.actualReps),
|
||||
actualScore: Value(result.actualScore),
|
||||
actualScoreTimeMs: Value(result.actualScoreTimeMs),
|
||||
scoreInputModeSnapshot: Value(
|
||||
_scoreInputModeToDb(result.scoreInputModeSnapshot),
|
||||
),
|
||||
scoreLabelSnapshot: Value(result.scoreLabelSnapshot),
|
||||
scoreUnitSnapshot: Value(result.scoreUnitSnapshot),
|
||||
note: Value(result.note),
|
||||
@ -1246,6 +1351,8 @@ domain.ActiveSetResult _activeSetResultFromRow(db.ActiveSetResult row) {
|
||||
actualTimeMs: row.actualTimeMs,
|
||||
actualReps: row.actualReps,
|
||||
actualScore: row.actualScore,
|
||||
actualScoreTimeMs: row.actualScoreTimeMs,
|
||||
scoreInputModeSnapshot: _scoreInputModeFromDb(row.scoreInputModeSnapshot),
|
||||
scoreLabelSnapshot: row.scoreLabelSnapshot,
|
||||
scoreUnitSnapshot: row.scoreUnitSnapshot,
|
||||
note: row.note,
|
||||
@ -1296,6 +1403,49 @@ domain.ActiveRestState _activeRestStateFromRow(db.ActiveRestState row) {
|
||||
);
|
||||
}
|
||||
|
||||
db.ActiveScoreStopwatchStatesCompanion _activeScoreStopwatchStateCompanion(
|
||||
domain.ActiveScoreStopwatchState state,
|
||||
) {
|
||||
final values = _metadataValues(state.metadata);
|
||||
return db.ActiveScoreStopwatchStatesCompanion(
|
||||
id: values[0] as Value<String>,
|
||||
createdAt: values[1] as Value<DateTime>,
|
||||
updatedAt: values[2] as Value<DateTime>,
|
||||
deletedAt: values[3] as Value<DateTime?>,
|
||||
schemaVersion: values[4] as Value<int>,
|
||||
syncState: values[5] as Value<String>,
|
||||
localRevision: values[6] as Value<int>,
|
||||
originDeviceId: values[7] as Value<String>,
|
||||
futureOwnerProfileId: values[8] as Value<String?>,
|
||||
lastSyncedAt: values[9] as Value<DateTime?>,
|
||||
remoteRevision: values[10] as Value<String?>,
|
||||
activeWorkoutSessionId: Value(state.activeWorkoutSessionId),
|
||||
programIndex: Value(state.programIndex),
|
||||
exerciseIndex: Value(state.exerciseIndex),
|
||||
setIndex: Value(state.setIndex),
|
||||
status: Value(_scoreStopwatchStatusToDb(state.status)),
|
||||
startedAt: Value(state.startedAt.toUtc()),
|
||||
accumulatedMs: Value(state.accumulatedMs),
|
||||
stoppedAt: Value(_utcOrNull(state.stoppedAt)),
|
||||
);
|
||||
}
|
||||
|
||||
domain.ActiveScoreStopwatchState _activeScoreStopwatchStateFromRow(
|
||||
db.ActiveScoreStopwatchState row,
|
||||
) {
|
||||
return domain.ActiveScoreStopwatchState(
|
||||
metadata: _metadataFromRow(row),
|
||||
activeWorkoutSessionId: row.activeWorkoutSessionId,
|
||||
programIndex: row.programIndex,
|
||||
exerciseIndex: row.exerciseIndex,
|
||||
setIndex: row.setIndex,
|
||||
status: _scoreStopwatchStatusFromDb(row.status),
|
||||
startedAt: _utc(row.startedAt),
|
||||
accumulatedMs: row.accumulatedMs,
|
||||
stoppedAt: _utcOrNull(row.stoppedAt),
|
||||
);
|
||||
}
|
||||
|
||||
db.WorkoutHistoriesCompanion _workoutHistoryCompanion(
|
||||
domain.WorkoutHistory history,
|
||||
) {
|
||||
@ -1350,12 +1500,17 @@ db.WorkoutHistorySetResultsCompanion _workoutHistorySetResultCompanion(
|
||||
timeEnabledSnapshot: Value(result.timeEnabledSnapshot),
|
||||
repsEnabledSnapshot: Value(result.repsEnabledSnapshot),
|
||||
scoreEnabledSnapshot: Value(result.scoreEnabledSnapshot),
|
||||
scoreInputModeSnapshot: Value(
|
||||
_scoreInputModeToDb(result.scoreInputModeSnapshot),
|
||||
),
|
||||
targetTimeSecondsSnapshot: Value(result.targetTimeSecondsSnapshot),
|
||||
targetRepsSnapshot: Value(result.targetRepsSnapshot),
|
||||
targetScoreSnapshot: Value(result.targetScoreSnapshot),
|
||||
targetScoreTimeMsSnapshot: Value(result.targetScoreTimeMsSnapshot),
|
||||
actualTimeMs: Value(result.actualTimeMs),
|
||||
actualReps: Value(result.actualReps),
|
||||
actualScore: Value(result.actualScore),
|
||||
actualScoreTimeMs: Value(result.actualScoreTimeMs),
|
||||
scoreLabelSnapshot: Value(result.scoreLabelSnapshot),
|
||||
scoreUnitSnapshot: Value(result.scoreUnitSnapshot),
|
||||
startedAt: Value(_utcOrNull(result.startedAt)),
|
||||
@ -1398,12 +1553,15 @@ domain.WorkoutHistorySetResult _workoutHistorySetResultFromRow(
|
||||
timeEnabledSnapshot: row.timeEnabledSnapshot,
|
||||
repsEnabledSnapshot: row.repsEnabledSnapshot,
|
||||
scoreEnabledSnapshot: row.scoreEnabledSnapshot,
|
||||
scoreInputModeSnapshot: _scoreInputModeFromDb(row.scoreInputModeSnapshot),
|
||||
targetTimeSecondsSnapshot: row.targetTimeSecondsSnapshot,
|
||||
targetRepsSnapshot: row.targetRepsSnapshot,
|
||||
targetScoreSnapshot: row.targetScoreSnapshot,
|
||||
targetScoreTimeMsSnapshot: row.targetScoreTimeMsSnapshot,
|
||||
actualTimeMs: row.actualTimeMs,
|
||||
actualReps: row.actualReps,
|
||||
actualScore: row.actualScore,
|
||||
actualScoreTimeMs: row.actualScoreTimeMs,
|
||||
scoreLabelSnapshot: row.scoreLabelSnapshot,
|
||||
scoreUnitSnapshot: row.scoreUnitSnapshot,
|
||||
startedAt: _utcOrNull(row.startedAt),
|
||||
@ -1446,6 +1604,17 @@ domain.MediaKind _mediaKindFromDb(String value) => switch (value) {
|
||||
_ => throw domain.DomainException('Unknown media kind: $value'),
|
||||
};
|
||||
|
||||
String _scoreInputModeToDb(domain.ScoreInputMode mode) => switch (mode) {
|
||||
domain.ScoreInputMode.manual => 'manual',
|
||||
domain.ScoreInputMode.stopwatch => 'stopwatch',
|
||||
};
|
||||
|
||||
domain.ScoreInputMode _scoreInputModeFromDb(String value) => switch (value) {
|
||||
'manual' => domain.ScoreInputMode.manual,
|
||||
'stopwatch' => domain.ScoreInputMode.stopwatch,
|
||||
_ => throw domain.DomainException('Unknown score input mode: $value'),
|
||||
};
|
||||
|
||||
String _setResultStatusToDb(domain.SetResultStatus status) => switch (status) {
|
||||
domain.SetResultStatus.completed => 'completed',
|
||||
domain.SetResultStatus.skipped => 'skipped',
|
||||
@ -1457,6 +1626,21 @@ domain.SetResultStatus _setResultStatusFromDb(String value) => switch (value) {
|
||||
_ => throw domain.DomainException('Unknown set result status: $value'),
|
||||
};
|
||||
|
||||
String _scoreStopwatchStatusToDb(domain.ActiveScoreStopwatchStatus status) =>
|
||||
switch (status) {
|
||||
domain.ActiveScoreStopwatchStatus.running => 'running',
|
||||
domain.ActiveScoreStopwatchStatus.stopped => 'stopped',
|
||||
};
|
||||
|
||||
domain.ActiveScoreStopwatchStatus _scoreStopwatchStatusFromDb(String value) =>
|
||||
switch (value) {
|
||||
'running' => domain.ActiveScoreStopwatchStatus.running,
|
||||
'stopped' => domain.ActiveScoreStopwatchStatus.stopped,
|
||||
_ => throw domain.DomainException(
|
||||
'Unknown active score stopwatch status: $value',
|
||||
),
|
||||
};
|
||||
|
||||
domain.ActiveWorkoutStatus _activeStatusFromDb(String value) => switch (value) {
|
||||
'running' => domain.ActiveWorkoutStatus.running,
|
||||
'paused' => domain.ActiveWorkoutStatus.paused,
|
||||
|
||||
Reference in New Issue
Block a user