feat(data): édition ponctuelle des séries en séance (ticket #21)

Étend le modèle Drift (tables.dart, app_database.dart/.g.dart) et la
couche application (entités, use cases, repositories) pour supporter
l'édition ponctuelle des séries pendant l'exécution d'une séance, sans
modifier le modèle/séance-modèle. build_runner OK, flutter analyze
propre, 30/30 tests verts, build APK debug validé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 00:19:02 +02:00
parent 7eb8f260e0
commit abfbb64de2
7 changed files with 621 additions and 15 deletions

View File

@ -717,11 +717,117 @@ final class ActiveWorkoutSessionUseCases {
actualScore: actualScore, actualScore: actualScore,
scoreLabelSnapshot: scoreLabelSnapshot, scoreLabelSnapshot: scoreLabelSnapshot,
scoreUnitSnapshot: scoreUnitSnapshot, scoreUnitSnapshot: scoreUnitSnapshot,
status: SetResultStatus.completed,
); );
await sessionRepository.saveSetResult(result); await sessionRepository.saveSetResult(result);
return result; return result;
} }
Future<ActiveSetResult> upsertSetResultAtPosition({
required String sessionId,
required int programIndex,
required int exerciseIndex,
required int setIndex,
required SetResultStatus status,
int? actualTimeMs,
int? actualReps,
double? actualScore,
String? scoreLabelSnapshot,
String? scoreUnitSnapshot,
String? note,
}) async {
final session = await _requiredSession(sessionId);
_ensureEditablePastPosition(
session: session,
programIndex: programIndex,
exerciseIndex: exerciseIndex,
setIndex: setIndex,
);
final snapshot = _findSetSnapshot(
resolvedTemplateSnapshotJson: session.resolvedTemplateSnapshotJson,
programIndex: programIndex,
exerciseIndex: exerciseIndex,
setIndex: setIndex,
);
if (snapshot == null) {
throw const DomainException(
'Set position not found in session snapshot.',
);
}
final existingResults = await sessionRepository.listSetResults(sessionId);
ActiveSetResult? existing;
for (final result in existingResults) {
if (result.programIndex == programIndex &&
result.exerciseIndex == exerciseIndex &&
result.setIndex == setIndex) {
existing = result;
break;
}
}
final now = clock.now();
final isSkipped = status == SetResultStatus.skipped;
final upserted = ActiveSetResult(
metadata: existing == null
? _newMetadata(ids, originDeviceId, now)
: existing.metadata.touch(now),
activeWorkoutSessionId: sessionId,
programSnapshotId: snapshot.programSnapshotId,
exerciseSnapshotId: snapshot.exerciseSnapshotId,
programIndex: programIndex,
exerciseIndex: exerciseIndex,
setIndex: setIndex,
startedAt: existing?.startedAt,
completedAt: isSkipped ? null : now,
actualTimeMs: isSkipped ? null : actualTimeMs,
actualReps: isSkipped ? null : actualReps,
actualScore: isSkipped ? null : actualScore,
scoreLabelSnapshot: isSkipped
? null
: scoreLabelSnapshot ?? snapshot.scoreLabelSnapshot,
scoreUnitSnapshot: isSkipped
? null
: scoreUnitSnapshot ?? snapshot.scoreUnitSnapshot,
note: note,
status: status,
);
await sessionRepository.saveSetResult(upserted);
return upserted;
}
Future<List<SetResultPositionState>> listSetResults(String sessionId) async {
final session = await _requiredSession(sessionId);
final snapshots = _listSetSnapshots(session.resolvedTemplateSnapshotJson);
final results = await sessionRepository.listSetResults(sessionId);
final resultsByPosition = {
for (final result in results)
_positionKey(
result.programIndex,
result.exerciseIndex,
result.setIndex,
): result,
};
return snapshots.map((snapshot) {
final result =
resultsByPosition[_positionKey(
snapshot.programIndex,
snapshot.exerciseIndex,
snapshot.setIndex,
)];
return SetResultPositionState(
programIndex: snapshot.programIndex,
exerciseIndex: snapshot.exerciseIndex,
setIndex: snapshot.setIndex,
status: result == null
? SetPositionStatus.pending
: switch (result.status) {
SetResultStatus.completed => SetPositionStatus.completed,
SetResultStatus.skipped => SetPositionStatus.skipped,
},
result: result,
);
}).toList();
}
Future<ActiveWorkoutSession> updateProgress({ Future<ActiveWorkoutSession> updateProgress({
required String sessionId, required String sessionId,
required int programIndex, required int programIndex,
@ -921,6 +1027,7 @@ final class CloseWorkoutSessionUseCase {
'actualScore': result.actualScore, 'actualScore': result.actualScore,
'scoreLabelSnapshot': result.scoreLabelSnapshot, 'scoreLabelSnapshot': result.scoreLabelSnapshot,
'scoreUnitSnapshot': result.scoreUnitSnapshot, 'scoreUnitSnapshot': result.scoreUnitSnapshot,
'status': result.status.name,
}, },
) )
.toList(), .toList(),
@ -945,6 +1052,24 @@ final class WorkoutHistoryUseCases {
Future<void> delete(String id) => repository.delete(id, clock.now()); Future<void> delete(String id) => repository.delete(id, clock.now());
} }
enum SetPositionStatus { pending, completed, skipped }
final class SetResultPositionState {
const SetResultPositionState({
required this.programIndex,
required this.exerciseIndex,
required this.setIndex,
required this.status,
this.result,
});
final int programIndex;
final int exerciseIndex;
final int setIndex;
final SetPositionStatus status;
final ActiveSetResult? result;
}
void _validateOverrideTargets( void _validateOverrideTargets(
String programSnapshotJson, String programSnapshotJson,
WorkoutTemplateExerciseOverrideConfig input, WorkoutTemplateExerciseOverrideConfig input,
@ -973,6 +1098,132 @@ void _validateOverrideTargets(
} }
} }
void _ensureEditablePastPosition({
required ActiveWorkoutSession session,
required int programIndex,
required int exerciseIndex,
required int setIndex,
}) {
final comparison = _comparePositions(
programIndex,
exerciseIndex,
setIndex,
session.currentProgramIndex,
session.currentExerciseIndex,
session.currentSetIndex,
);
if (comparison >= 0) {
throw const DomainException(
'Only past set results can be edited outside the normal execution flow.',
);
}
}
int _comparePositions(
int leftProgram,
int leftExercise,
int leftSet,
int rightProgram,
int rightExercise,
int rightSet,
) {
final programComparison = leftProgram.compareTo(rightProgram);
if (programComparison != 0) {
return programComparison;
}
final exerciseComparison = leftExercise.compareTo(rightExercise);
if (exerciseComparison != 0) {
return exerciseComparison;
}
return leftSet.compareTo(rightSet);
}
String _positionKey(int programIndex, int exerciseIndex, int setIndex) {
return '$programIndex:$exerciseIndex:$setIndex';
}
_SetPositionSnapshot? _findSetSnapshot({
required String resolvedTemplateSnapshotJson,
required int programIndex,
required int exerciseIndex,
required int setIndex,
}) {
for (final snapshot in _listSetSnapshots(resolvedTemplateSnapshotJson)) {
if (snapshot.programIndex == programIndex &&
snapshot.exerciseIndex == exerciseIndex &&
snapshot.setIndex == setIndex) {
return snapshot;
}
}
return null;
}
List<_SetPositionSnapshot> _listSetSnapshots(
String resolvedTemplateSnapshotJson,
) {
final decoded =
jsonDecode(resolvedTemplateSnapshotJson) as Map<String, dynamic>;
final programs = (decoded['programs'] as List<dynamic>? ?? const []);
final snapshots = <_SetPositionSnapshot>[];
for (var programIndex = 0; programIndex < programs.length; programIndex++) {
final program = programs[programIndex] as Map<String, dynamic>;
final programSnapshotId =
program['id'] as String? ?? 'program-$programIndex';
final programSnapshotJson = program['programSnapshotJson'] as String?;
if (programSnapshotJson == null) {
continue;
}
final programSnapshot =
jsonDecode(programSnapshotJson) as Map<String, dynamic>;
final exercises =
(programSnapshot['exercises'] as List<dynamic>? ?? const []);
for (
var exerciseIndex = 0;
exerciseIndex < exercises.length;
exerciseIndex++
) {
final exercise = exercises[exerciseIndex] as Map<String, dynamic>;
final exerciseSnapshotId =
exercise['id'] as String? ?? 'exercise-$exerciseIndex';
final setsCount = exercise['setsCount'] as int? ?? 0;
for (var setIndex = 0; setIndex < setsCount; setIndex++) {
snapshots.add(
_SetPositionSnapshot(
programSnapshotId: programSnapshotId,
exerciseSnapshotId: exerciseSnapshotId,
programIndex: programIndex,
exerciseIndex: exerciseIndex,
setIndex: setIndex,
scoreLabelSnapshot: exercise['scoreLabelSnapshot'] as String?,
scoreUnitSnapshot: exercise['scoreUnitSnapshot'] as String?,
),
);
}
}
}
return snapshots;
}
final class _SetPositionSnapshot {
const _SetPositionSnapshot({
required this.programSnapshotId,
required this.exerciseSnapshotId,
required this.programIndex,
required this.exerciseIndex,
required this.setIndex,
this.scoreLabelSnapshot,
this.scoreUnitSnapshot,
});
final String programSnapshotId;
final String exerciseSnapshotId;
final int programIndex;
final int exerciseIndex;
final int setIndex;
final String? scoreLabelSnapshot;
final String? scoreUnitSnapshot;
}
List<WorkoutHistorySetResult> _historyResultsFromActiveResults({ List<WorkoutHistorySetResult> _historyResultsFromActiveResults({
required String historyId, required String historyId,
required List<ActiveSetResult> results, required List<ActiveSetResult> results,
@ -1012,6 +1263,7 @@ List<WorkoutHistorySetResult> _historyResultsFromActiveResults({
result.scoreUnitSnapshot ?? snapshot?.scoreUnitSnapshot, result.scoreUnitSnapshot ?? snapshot?.scoreUnitSnapshot,
startedAt: result.startedAt, startedAt: result.startedAt,
completedAt: result.completedAt, completedAt: result.completedAt,
status: result.status,
); );
}).toList(); }).toList();
} }

View File

@ -8,6 +8,8 @@ enum WorkoutMeasure { time, reps, score }
enum ActiveWorkoutStatus { running, paused, savedExit, completed, abandoned } enum ActiveWorkoutStatus { running, paused, savedExit, completed, abandoned }
enum SetResultStatus { completed, skipped }
final class DomainException implements Exception { final class DomainException implements Exception {
const DomainException(this.message); const DomainException(this.message);
@ -572,7 +574,7 @@ final class ActiveWorkoutSession {
} }
final class ActiveSetResult { final class ActiveSetResult {
const ActiveSetResult({ ActiveSetResult({
required this.metadata, required this.metadata,
required this.activeWorkoutSessionId, required this.activeWorkoutSessionId,
required this.programSnapshotId, required this.programSnapshotId,
@ -588,7 +590,13 @@ final class ActiveSetResult {
this.scoreLabelSnapshot, this.scoreLabelSnapshot,
this.scoreUnitSnapshot, this.scoreUnitSnapshot,
this.note, this.note,
}); this.status = SetResultStatus.completed,
}) {
if (status == SetResultStatus.skipped &&
(actualTimeMs != null || actualReps != null || actualScore != null)) {
throw const DomainException('Skipped set results cannot have values.');
}
}
final EntityMetadata metadata; final EntityMetadata metadata;
final String activeWorkoutSessionId; final String activeWorkoutSessionId;
@ -605,6 +613,7 @@ final class ActiveSetResult {
final String? scoreLabelSnapshot; final String? scoreLabelSnapshot;
final String? scoreUnitSnapshot; final String? scoreUnitSnapshot;
final String? note; final String? note;
final SetResultStatus status;
} }
final class ActiveRestState { final class ActiveRestState {
@ -682,7 +691,7 @@ final class WorkoutHistory {
} }
final class WorkoutHistorySetResult { final class WorkoutHistorySetResult {
const WorkoutHistorySetResult({ WorkoutHistorySetResult({
required this.metadata, required this.metadata,
required this.workoutHistoryId, required this.workoutHistoryId,
required this.programSnapshotId, required this.programSnapshotId,
@ -705,7 +714,15 @@ final class WorkoutHistorySetResult {
this.scoreUnitSnapshot, this.scoreUnitSnapshot,
this.startedAt, this.startedAt,
this.completedAt, this.completedAt,
}); this.status = SetResultStatus.completed,
}) {
if (status == SetResultStatus.skipped &&
(actualTimeMs != null || actualReps != null || actualScore != null)) {
throw const DomainException(
'Skipped history results cannot have values.',
);
}
}
final EntityMetadata metadata; final EntityMetadata metadata;
final String workoutHistoryId; final String workoutHistoryId;
@ -729,6 +746,7 @@ final class WorkoutHistorySetResult {
final String? scoreUnitSnapshot; final String? scoreUnitSnapshot;
final DateTime? startedAt; final DateTime? startedAt;
final DateTime? completedAt; final DateTime? completedAt;
final SetResultStatus status;
} }
String _nonBlank(String? value, String label) { String _nonBlank(String? value, String label) {

View File

@ -35,7 +35,7 @@ final class AppDatabase extends _$AppDatabase {
} }
@override @override
int get schemaVersion => 1; int get schemaVersion => 2;
@override @override
MigrationStrategy get migration { MigrationStrategy get migration {
@ -44,6 +44,19 @@ final class AppDatabase extends _$AppDatabase {
await migrator.createAll(); await migrator.createAll();
await _createIndexes(); await _createIndexes();
}, },
onUpgrade: (migrator, from, to) async {
if (from < 2) {
await customStatement(
'ALTER TABLE active_set_results ADD COLUMN status TEXT NOT NULL '
"DEFAULT 'completed' CHECK (status IN ('completed', 'skipped'))",
);
await customStatement(
'ALTER TABLE workout_history_set_results ADD COLUMN status TEXT '
"NOT NULL DEFAULT 'completed' CHECK (status IN ('completed', "
"'skipped'))",
);
}
},
beforeOpen: (details) async { beforeOpen: (details) async {
await customStatement('PRAGMA foreign_keys = ON'); await customStatement('PRAGMA foreign_keys = ON');
}, },

View File

@ -3578,6 +3578,16 @@ class $ActiveSetResultsTable extends ActiveSetResults
type: DriftSqlType.string, type: DriftSqlType.string,
requiredDuringInsert: false, requiredDuringInsert: false,
); );
static const VerificationMeta _statusMeta = const VerificationMeta('status');
@override
late final GeneratedColumn<String> status = GeneratedColumn<String>(
'status',
aliasedName,
false,
type: DriftSqlType.string,
requiredDuringInsert: false,
defaultValue: const Constant('completed'),
);
@override @override
List<GeneratedColumn> get $columns => [ List<GeneratedColumn> get $columns => [
id, id,
@ -3605,6 +3615,7 @@ class $ActiveSetResultsTable extends ActiveSetResults
scoreLabelSnapshot, scoreLabelSnapshot,
scoreUnitSnapshot, scoreUnitSnapshot,
note, note,
status,
]; ];
@override @override
String get aliasedName => _alias ?? actualTableName; String get aliasedName => _alias ?? actualTableName;
@ -3837,6 +3848,12 @@ class $ActiveSetResultsTable extends ActiveSetResults
note.isAcceptableOrUnknown(data['note']!, _noteMeta), note.isAcceptableOrUnknown(data['note']!, _noteMeta),
); );
} }
if (data.containsKey('status')) {
context.handle(
_statusMeta,
status.isAcceptableOrUnknown(data['status']!, _statusMeta),
);
}
return context; return context;
} }
@ -3946,6 +3963,10 @@ class $ActiveSetResultsTable extends ActiveSetResults
DriftSqlType.string, DriftSqlType.string,
data['${effectivePrefix}note'], data['${effectivePrefix}note'],
), ),
status: attachedDatabase.typeMapping.read(
DriftSqlType.string,
data['${effectivePrefix}status'],
)!,
); );
} }
@ -3981,6 +4002,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
final String? scoreLabelSnapshot; final String? scoreLabelSnapshot;
final String? scoreUnitSnapshot; final String? scoreUnitSnapshot;
final String? note; final String? note;
final String status;
const ActiveSetResult({ const ActiveSetResult({
required this.id, required this.id,
required this.createdAt, required this.createdAt,
@ -4007,6 +4029,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
this.scoreLabelSnapshot, this.scoreLabelSnapshot,
this.scoreUnitSnapshot, this.scoreUnitSnapshot,
this.note, this.note,
required this.status,
}); });
@override @override
Map<String, Expression> toColumns(bool nullToAbsent) { Map<String, Expression> toColumns(bool nullToAbsent) {
@ -4060,6 +4083,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
if (!nullToAbsent || note != null) { if (!nullToAbsent || note != null) {
map['note'] = Variable<String>(note); map['note'] = Variable<String>(note);
} }
map['status'] = Variable<String>(status);
return map; return map;
} }
@ -4112,6 +4136,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
? const Value.absent() ? const Value.absent()
: Value(scoreUnitSnapshot), : Value(scoreUnitSnapshot),
note: note == null && nullToAbsent ? const Value.absent() : Value(note), note: note == null && nullToAbsent ? const Value.absent() : Value(note),
status: Value(status),
); );
} }
@ -4156,6 +4181,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
json['scoreUnitSnapshot'], json['scoreUnitSnapshot'],
), ),
note: serializer.fromJson<String?>(json['note']), note: serializer.fromJson<String?>(json['note']),
status: serializer.fromJson<String>(json['status']),
); );
} }
@override @override
@ -4189,6 +4215,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
'scoreLabelSnapshot': serializer.toJson<String?>(scoreLabelSnapshot), 'scoreLabelSnapshot': serializer.toJson<String?>(scoreLabelSnapshot),
'scoreUnitSnapshot': serializer.toJson<String?>(scoreUnitSnapshot), 'scoreUnitSnapshot': serializer.toJson<String?>(scoreUnitSnapshot),
'note': serializer.toJson<String?>(note), 'note': serializer.toJson<String?>(note),
'status': serializer.toJson<String>(status),
}; };
} }
@ -4218,6 +4245,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
Value<String?> scoreLabelSnapshot = const Value.absent(), Value<String?> scoreLabelSnapshot = const Value.absent(),
Value<String?> scoreUnitSnapshot = const Value.absent(), Value<String?> scoreUnitSnapshot = const Value.absent(),
Value<String?> note = const Value.absent(), Value<String?> note = const Value.absent(),
String? status,
}) => ActiveSetResult( }) => ActiveSetResult(
id: id ?? this.id, id: id ?? this.id,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
@ -4253,6 +4281,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
? scoreUnitSnapshot.value ? scoreUnitSnapshot.value
: this.scoreUnitSnapshot, : this.scoreUnitSnapshot,
note: note.present ? note.value : this.note, note: note.present ? note.value : this.note,
status: status ?? this.status,
); );
ActiveSetResult copyWithCompanion(ActiveSetResultsCompanion data) { ActiveSetResult copyWithCompanion(ActiveSetResultsCompanion data) {
return ActiveSetResult( return ActiveSetResult(
@ -4315,6 +4344,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
? data.scoreUnitSnapshot.value ? data.scoreUnitSnapshot.value
: this.scoreUnitSnapshot, : this.scoreUnitSnapshot,
note: data.note.present ? data.note.value : this.note, note: data.note.present ? data.note.value : this.note,
status: data.status.present ? data.status.value : this.status,
); );
} }
@ -4345,7 +4375,8 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
..write('actualScore: $actualScore, ') ..write('actualScore: $actualScore, ')
..write('scoreLabelSnapshot: $scoreLabelSnapshot, ') ..write('scoreLabelSnapshot: $scoreLabelSnapshot, ')
..write('scoreUnitSnapshot: $scoreUnitSnapshot, ') ..write('scoreUnitSnapshot: $scoreUnitSnapshot, ')
..write('note: $note') ..write('note: $note, ')
..write('status: $status')
..write(')')) ..write(')'))
.toString(); .toString();
} }
@ -4377,6 +4408,7 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
scoreLabelSnapshot, scoreLabelSnapshot,
scoreUnitSnapshot, scoreUnitSnapshot,
note, note,
status,
]); ]);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -4406,7 +4438,8 @@ class ActiveSetResult extends DataClass implements Insertable<ActiveSetResult> {
other.actualScore == this.actualScore && other.actualScore == this.actualScore &&
other.scoreLabelSnapshot == this.scoreLabelSnapshot && other.scoreLabelSnapshot == this.scoreLabelSnapshot &&
other.scoreUnitSnapshot == this.scoreUnitSnapshot && other.scoreUnitSnapshot == this.scoreUnitSnapshot &&
other.note == this.note); other.note == this.note &&
other.status == this.status);
} }
class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> { class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
@ -4435,6 +4468,7 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
final Value<String?> scoreLabelSnapshot; final Value<String?> scoreLabelSnapshot;
final Value<String?> scoreUnitSnapshot; final Value<String?> scoreUnitSnapshot;
final Value<String?> note; final Value<String?> note;
final Value<String> status;
final Value<int> rowid; final Value<int> rowid;
const ActiveSetResultsCompanion({ const ActiveSetResultsCompanion({
this.id = const Value.absent(), this.id = const Value.absent(),
@ -4462,6 +4496,7 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
this.scoreLabelSnapshot = const Value.absent(), this.scoreLabelSnapshot = const Value.absent(),
this.scoreUnitSnapshot = const Value.absent(), this.scoreUnitSnapshot = const Value.absent(),
this.note = const Value.absent(), this.note = const Value.absent(),
this.status = const Value.absent(),
this.rowid = const Value.absent(), this.rowid = const Value.absent(),
}); });
ActiveSetResultsCompanion.insert({ ActiveSetResultsCompanion.insert({
@ -4490,6 +4525,7 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
this.scoreLabelSnapshot = const Value.absent(), this.scoreLabelSnapshot = const Value.absent(),
this.scoreUnitSnapshot = const Value.absent(), this.scoreUnitSnapshot = const Value.absent(),
this.note = const Value.absent(), this.note = const Value.absent(),
this.status = const Value.absent(),
this.rowid = const Value.absent(), this.rowid = const Value.absent(),
}) : id = Value(id), }) : id = Value(id),
createdAt = Value(createdAt), createdAt = Value(createdAt),
@ -4529,6 +4565,7 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
Expression<String>? scoreLabelSnapshot, Expression<String>? scoreLabelSnapshot,
Expression<String>? scoreUnitSnapshot, Expression<String>? scoreUnitSnapshot,
Expression<String>? note, Expression<String>? note,
Expression<String>? status,
Expression<int>? rowid, Expression<int>? rowid,
}) { }) {
return RawValuesInsertable({ return RawValuesInsertable({
@ -4561,6 +4598,7 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
'score_label_snapshot': scoreLabelSnapshot, 'score_label_snapshot': scoreLabelSnapshot,
if (scoreUnitSnapshot != null) 'score_unit_snapshot': scoreUnitSnapshot, if (scoreUnitSnapshot != null) 'score_unit_snapshot': scoreUnitSnapshot,
if (note != null) 'note': note, if (note != null) 'note': note,
if (status != null) 'status': status,
if (rowid != null) 'rowid': rowid, if (rowid != null) 'rowid': rowid,
}); });
} }
@ -4591,6 +4629,7 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
Value<String?>? scoreLabelSnapshot, Value<String?>? scoreLabelSnapshot,
Value<String?>? scoreUnitSnapshot, Value<String?>? scoreUnitSnapshot,
Value<String?>? note, Value<String?>? note,
Value<String>? status,
Value<int>? rowid, Value<int>? rowid,
}) { }) {
return ActiveSetResultsCompanion( return ActiveSetResultsCompanion(
@ -4620,6 +4659,7 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
scoreLabelSnapshot: scoreLabelSnapshot ?? this.scoreLabelSnapshot, scoreLabelSnapshot: scoreLabelSnapshot ?? this.scoreLabelSnapshot,
scoreUnitSnapshot: scoreUnitSnapshot ?? this.scoreUnitSnapshot, scoreUnitSnapshot: scoreUnitSnapshot ?? this.scoreUnitSnapshot,
note: note ?? this.note, note: note ?? this.note,
status: status ?? this.status,
rowid: rowid ?? this.rowid, rowid: rowid ?? this.rowid,
); );
} }
@ -4706,6 +4746,9 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
if (note.present) { if (note.present) {
map['note'] = Variable<String>(note.value); map['note'] = Variable<String>(note.value);
} }
if (status.present) {
map['status'] = Variable<String>(status.value);
}
if (rowid.present) { if (rowid.present) {
map['rowid'] = Variable<int>(rowid.value); map['rowid'] = Variable<int>(rowid.value);
} }
@ -4740,6 +4783,7 @@ class ActiveSetResultsCompanion extends UpdateCompanion<ActiveSetResult> {
..write('scoreLabelSnapshot: $scoreLabelSnapshot, ') ..write('scoreLabelSnapshot: $scoreLabelSnapshot, ')
..write('scoreUnitSnapshot: $scoreUnitSnapshot, ') ..write('scoreUnitSnapshot: $scoreUnitSnapshot, ')
..write('note: $note, ') ..write('note: $note, ')
..write('status: $status, ')
..write('rowid: $rowid') ..write('rowid: $rowid')
..write(')')) ..write(')'))
.toString(); .toString();
@ -12033,6 +12077,16 @@ class $WorkoutHistorySetResultsTable extends WorkoutHistorySetResults
type: DriftSqlType.dateTime, type: DriftSqlType.dateTime,
requiredDuringInsert: false, requiredDuringInsert: false,
); );
static const VerificationMeta _statusMeta = const VerificationMeta('status');
@override
late final GeneratedColumn<String> status = GeneratedColumn<String>(
'status',
aliasedName,
false,
type: DriftSqlType.string,
requiredDuringInsert: false,
defaultValue: const Constant('completed'),
);
@override @override
List<GeneratedColumn> get $columns => [ List<GeneratedColumn> get $columns => [
id, id,
@ -12067,6 +12121,7 @@ class $WorkoutHistorySetResultsTable extends WorkoutHistorySetResults
scoreUnitSnapshot, scoreUnitSnapshot,
startedAt, startedAt,
completedAt, completedAt,
status,
]; ];
@override @override
String get aliasedName => _alias ?? actualTableName; String get aliasedName => _alias ?? actualTableName;
@ -12375,6 +12430,12 @@ class $WorkoutHistorySetResultsTable extends WorkoutHistorySetResults
), ),
); );
} }
if (data.containsKey('status')) {
context.handle(
_statusMeta,
status.isAcceptableOrUnknown(data['status']!, _statusMeta),
);
}
return context; return context;
} }
@ -12515,6 +12576,10 @@ class $WorkoutHistorySetResultsTable extends WorkoutHistorySetResults
DriftSqlType.dateTime, DriftSqlType.dateTime,
data['${effectivePrefix}completed_at'], data['${effectivePrefix}completed_at'],
), ),
status: attachedDatabase.typeMapping.read(
DriftSqlType.string,
data['${effectivePrefix}status'],
)!,
); );
} }
@ -12558,6 +12623,7 @@ class WorkoutHistorySetResult extends DataClass
final String? scoreUnitSnapshot; final String? scoreUnitSnapshot;
final DateTime? startedAt; final DateTime? startedAt;
final DateTime? completedAt; final DateTime? completedAt;
final String status;
const WorkoutHistorySetResult({ const WorkoutHistorySetResult({
required this.id, required this.id,
required this.createdAt, required this.createdAt,
@ -12591,6 +12657,7 @@ class WorkoutHistorySetResult extends DataClass
this.scoreUnitSnapshot, this.scoreUnitSnapshot,
this.startedAt, this.startedAt,
this.completedAt, this.completedAt,
required this.status,
}); });
@override @override
Map<String, Expression> toColumns(bool nullToAbsent) { Map<String, Expression> toColumns(bool nullToAbsent) {
@ -12657,6 +12724,7 @@ class WorkoutHistorySetResult extends DataClass
if (!nullToAbsent || completedAt != null) { if (!nullToAbsent || completedAt != null) {
map['completed_at'] = Variable<DateTime>(completedAt); map['completed_at'] = Variable<DateTime>(completedAt);
} }
map['status'] = Variable<String>(status);
return map; return map;
} }
@ -12723,6 +12791,7 @@ class WorkoutHistorySetResult extends DataClass
completedAt: completedAt == null && nullToAbsent completedAt: completedAt == null && nullToAbsent
? const Value.absent() ? const Value.absent()
: Value(completedAt), : Value(completedAt),
status: Value(status),
); );
} }
@ -12786,6 +12855,7 @@ class WorkoutHistorySetResult extends DataClass
), ),
startedAt: serializer.fromJson<DateTime?>(json['startedAt']), startedAt: serializer.fromJson<DateTime?>(json['startedAt']),
completedAt: serializer.fromJson<DateTime?>(json['completedAt']), completedAt: serializer.fromJson<DateTime?>(json['completedAt']),
status: serializer.fromJson<String>(json['status']),
); );
} }
@override @override
@ -12826,6 +12896,7 @@ class WorkoutHistorySetResult extends DataClass
'scoreUnitSnapshot': serializer.toJson<String?>(scoreUnitSnapshot), 'scoreUnitSnapshot': serializer.toJson<String?>(scoreUnitSnapshot),
'startedAt': serializer.toJson<DateTime?>(startedAt), 'startedAt': serializer.toJson<DateTime?>(startedAt),
'completedAt': serializer.toJson<DateTime?>(completedAt), 'completedAt': serializer.toJson<DateTime?>(completedAt),
'status': serializer.toJson<String>(status),
}; };
} }
@ -12862,6 +12933,7 @@ class WorkoutHistorySetResult extends DataClass
Value<String?> scoreUnitSnapshot = const Value.absent(), Value<String?> scoreUnitSnapshot = const Value.absent(),
Value<DateTime?> startedAt = const Value.absent(), Value<DateTime?> startedAt = const Value.absent(),
Value<DateTime?> completedAt = const Value.absent(), Value<DateTime?> completedAt = const Value.absent(),
String? status,
}) => WorkoutHistorySetResult( }) => WorkoutHistorySetResult(
id: id ?? this.id, id: id ?? this.id,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
@ -12909,6 +12981,7 @@ class WorkoutHistorySetResult extends DataClass
: this.scoreUnitSnapshot, : this.scoreUnitSnapshot,
startedAt: startedAt.present ? startedAt.value : this.startedAt, startedAt: startedAt.present ? startedAt.value : this.startedAt,
completedAt: completedAt.present ? completedAt.value : this.completedAt, completedAt: completedAt.present ? completedAt.value : this.completedAt,
status: status ?? this.status,
); );
WorkoutHistorySetResult copyWithCompanion( WorkoutHistorySetResult copyWithCompanion(
WorkoutHistorySetResultsCompanion data, WorkoutHistorySetResultsCompanion data,
@ -12996,6 +13069,7 @@ class WorkoutHistorySetResult extends DataClass
completedAt: data.completedAt.present completedAt: data.completedAt.present
? data.completedAt.value ? data.completedAt.value
: this.completedAt, : this.completedAt,
status: data.status.present ? data.status.value : this.status,
); );
} }
@ -13033,7 +13107,8 @@ class WorkoutHistorySetResult extends DataClass
..write('scoreLabelSnapshot: $scoreLabelSnapshot, ') ..write('scoreLabelSnapshot: $scoreLabelSnapshot, ')
..write('scoreUnitSnapshot: $scoreUnitSnapshot, ') ..write('scoreUnitSnapshot: $scoreUnitSnapshot, ')
..write('startedAt: $startedAt, ') ..write('startedAt: $startedAt, ')
..write('completedAt: $completedAt') ..write('completedAt: $completedAt, ')
..write('status: $status')
..write(')')) ..write(')'))
.toString(); .toString();
} }
@ -13072,6 +13147,7 @@ class WorkoutHistorySetResult extends DataClass
scoreUnitSnapshot, scoreUnitSnapshot,
startedAt, startedAt,
completedAt, completedAt,
status,
]); ]);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -13108,7 +13184,8 @@ class WorkoutHistorySetResult extends DataClass
other.scoreLabelSnapshot == this.scoreLabelSnapshot && other.scoreLabelSnapshot == this.scoreLabelSnapshot &&
other.scoreUnitSnapshot == this.scoreUnitSnapshot && other.scoreUnitSnapshot == this.scoreUnitSnapshot &&
other.startedAt == this.startedAt && other.startedAt == this.startedAt &&
other.completedAt == this.completedAt); other.completedAt == this.completedAt &&
other.status == this.status);
} }
class WorkoutHistorySetResultsCompanion class WorkoutHistorySetResultsCompanion
@ -13145,6 +13222,7 @@ class WorkoutHistorySetResultsCompanion
final Value<String?> scoreUnitSnapshot; final Value<String?> scoreUnitSnapshot;
final Value<DateTime?> startedAt; final Value<DateTime?> startedAt;
final Value<DateTime?> completedAt; final Value<DateTime?> completedAt;
final Value<String> status;
final Value<int> rowid; final Value<int> rowid;
const WorkoutHistorySetResultsCompanion({ const WorkoutHistorySetResultsCompanion({
this.id = const Value.absent(), this.id = const Value.absent(),
@ -13179,6 +13257,7 @@ class WorkoutHistorySetResultsCompanion
this.scoreUnitSnapshot = const Value.absent(), this.scoreUnitSnapshot = const Value.absent(),
this.startedAt = const Value.absent(), this.startedAt = const Value.absent(),
this.completedAt = const Value.absent(), this.completedAt = const Value.absent(),
this.status = const Value.absent(),
this.rowid = const Value.absent(), this.rowid = const Value.absent(),
}); });
WorkoutHistorySetResultsCompanion.insert({ WorkoutHistorySetResultsCompanion.insert({
@ -13214,6 +13293,7 @@ class WorkoutHistorySetResultsCompanion
this.scoreUnitSnapshot = const Value.absent(), this.scoreUnitSnapshot = const Value.absent(),
this.startedAt = const Value.absent(), this.startedAt = const Value.absent(),
this.completedAt = const Value.absent(), this.completedAt = const Value.absent(),
this.status = const Value.absent(),
this.rowid = const Value.absent(), this.rowid = const Value.absent(),
}) : id = Value(id), }) : id = Value(id),
createdAt = Value(createdAt), createdAt = Value(createdAt),
@ -13265,6 +13345,7 @@ class WorkoutHistorySetResultsCompanion
Expression<String>? scoreUnitSnapshot, Expression<String>? scoreUnitSnapshot,
Expression<DateTime>? startedAt, Expression<DateTime>? startedAt,
Expression<DateTime>? completedAt, Expression<DateTime>? completedAt,
Expression<String>? status,
Expression<int>? rowid, Expression<int>? rowid,
}) { }) {
return RawValuesInsertable({ return RawValuesInsertable({
@ -13311,6 +13392,7 @@ class WorkoutHistorySetResultsCompanion
if (scoreUnitSnapshot != null) 'score_unit_snapshot': scoreUnitSnapshot, if (scoreUnitSnapshot != null) 'score_unit_snapshot': scoreUnitSnapshot,
if (startedAt != null) 'started_at': startedAt, if (startedAt != null) 'started_at': startedAt,
if (completedAt != null) 'completed_at': completedAt, if (completedAt != null) 'completed_at': completedAt,
if (status != null) 'status': status,
if (rowid != null) 'rowid': rowid, if (rowid != null) 'rowid': rowid,
}); });
} }
@ -13348,6 +13430,7 @@ class WorkoutHistorySetResultsCompanion
Value<String?>? scoreUnitSnapshot, Value<String?>? scoreUnitSnapshot,
Value<DateTime?>? startedAt, Value<DateTime?>? startedAt,
Value<DateTime?>? completedAt, Value<DateTime?>? completedAt,
Value<String>? status,
Value<int>? rowid, Value<int>? rowid,
}) { }) {
return WorkoutHistorySetResultsCompanion( return WorkoutHistorySetResultsCompanion(
@ -13384,6 +13467,7 @@ class WorkoutHistorySetResultsCompanion
scoreUnitSnapshot: scoreUnitSnapshot ?? this.scoreUnitSnapshot, scoreUnitSnapshot: scoreUnitSnapshot ?? this.scoreUnitSnapshot,
startedAt: startedAt ?? this.startedAt, startedAt: startedAt ?? this.startedAt,
completedAt: completedAt ?? this.completedAt, completedAt: completedAt ?? this.completedAt,
status: status ?? this.status,
rowid: rowid ?? this.rowid, rowid: rowid ?? this.rowid,
); );
} }
@ -13499,6 +13583,9 @@ class WorkoutHistorySetResultsCompanion
if (completedAt.present) { if (completedAt.present) {
map['completed_at'] = Variable<DateTime>(completedAt.value); map['completed_at'] = Variable<DateTime>(completedAt.value);
} }
if (status.present) {
map['status'] = Variable<String>(status.value);
}
if (rowid.present) { if (rowid.present) {
map['rowid'] = Variable<int>(rowid.value); map['rowid'] = Variable<int>(rowid.value);
} }
@ -13540,6 +13627,7 @@ class WorkoutHistorySetResultsCompanion
..write('scoreUnitSnapshot: $scoreUnitSnapshot, ') ..write('scoreUnitSnapshot: $scoreUnitSnapshot, ')
..write('startedAt: $startedAt, ') ..write('startedAt: $startedAt, ')
..write('completedAt: $completedAt, ') ..write('completedAt: $completedAt, ')
..write('status: $status, ')
..write('rowid: $rowid') ..write('rowid: $rowid')
..write(')')) ..write(')'))
.toString(); .toString();
@ -18114,6 +18202,7 @@ typedef $$ActiveSetResultsTableCreateCompanionBuilder =
Value<String?> scoreLabelSnapshot, Value<String?> scoreLabelSnapshot,
Value<String?> scoreUnitSnapshot, Value<String?> scoreUnitSnapshot,
Value<String?> note, Value<String?> note,
Value<String> status,
Value<int> rowid, Value<int> rowid,
}); });
typedef $$ActiveSetResultsTableUpdateCompanionBuilder = typedef $$ActiveSetResultsTableUpdateCompanionBuilder =
@ -18143,6 +18232,7 @@ typedef $$ActiveSetResultsTableUpdateCompanionBuilder =
Value<String?> scoreLabelSnapshot, Value<String?> scoreLabelSnapshot,
Value<String?> scoreUnitSnapshot, Value<String?> scoreUnitSnapshot,
Value<String?> note, Value<String?> note,
Value<String> status,
Value<int> rowid, Value<int> rowid,
}); });
@ -18307,6 +18397,11 @@ class $$ActiveSetResultsTableFilterComposer
builder: (column) => ColumnFilters(column), builder: (column) => ColumnFilters(column),
); );
ColumnFilters<String> get status => $composableBuilder(
column: $table.status,
builder: (column) => ColumnFilters(column),
);
$$ActiveWorkoutSessionsTableFilterComposer get activeWorkoutSessionId { $$ActiveWorkoutSessionsTableFilterComposer get activeWorkoutSessionId {
final $$ActiveWorkoutSessionsTableFilterComposer composer = final $$ActiveWorkoutSessionsTableFilterComposer composer =
$composerBuilder( $composerBuilder(
@ -18461,6 +18556,11 @@ class $$ActiveSetResultsTableOrderingComposer
builder: (column) => ColumnOrderings(column), builder: (column) => ColumnOrderings(column),
); );
ColumnOrderings<String> get status => $composableBuilder(
column: $table.status,
builder: (column) => ColumnOrderings(column),
);
$$ActiveWorkoutSessionsTableOrderingComposer get activeWorkoutSessionId { $$ActiveWorkoutSessionsTableOrderingComposer get activeWorkoutSessionId {
final $$ActiveWorkoutSessionsTableOrderingComposer composer = final $$ActiveWorkoutSessionsTableOrderingComposer composer =
$composerBuilder( $composerBuilder(
@ -18599,6 +18699,9 @@ class $$ActiveSetResultsTableAnnotationComposer
GeneratedColumn<String> get note => GeneratedColumn<String> get note =>
$composableBuilder(column: $table.note, builder: (column) => column); $composableBuilder(column: $table.note, builder: (column) => column);
GeneratedColumn<String> get status =>
$composableBuilder(column: $table.status, builder: (column) => column);
$$ActiveWorkoutSessionsTableAnnotationComposer get activeWorkoutSessionId { $$ActiveWorkoutSessionsTableAnnotationComposer get activeWorkoutSessionId {
final $$ActiveWorkoutSessionsTableAnnotationComposer composer = final $$ActiveWorkoutSessionsTableAnnotationComposer composer =
$composerBuilder( $composerBuilder(
@ -18679,6 +18782,7 @@ class $$ActiveSetResultsTableTableManager
Value<String?> scoreLabelSnapshot = const Value.absent(), Value<String?> scoreLabelSnapshot = const Value.absent(),
Value<String?> scoreUnitSnapshot = const Value.absent(), Value<String?> scoreUnitSnapshot = const Value.absent(),
Value<String?> note = const Value.absent(), Value<String?> note = const Value.absent(),
Value<String> status = const Value.absent(),
Value<int> rowid = const Value.absent(), Value<int> rowid = const Value.absent(),
}) => ActiveSetResultsCompanion( }) => ActiveSetResultsCompanion(
id: id, id: id,
@ -18706,6 +18810,7 @@ class $$ActiveSetResultsTableTableManager
scoreLabelSnapshot: scoreLabelSnapshot, scoreLabelSnapshot: scoreLabelSnapshot,
scoreUnitSnapshot: scoreUnitSnapshot, scoreUnitSnapshot: scoreUnitSnapshot,
note: note, note: note,
status: status,
rowid: rowid, rowid: rowid,
), ),
createCompanionCallback: createCompanionCallback:
@ -18735,6 +18840,7 @@ class $$ActiveSetResultsTableTableManager
Value<String?> scoreLabelSnapshot = const Value.absent(), Value<String?> scoreLabelSnapshot = const Value.absent(),
Value<String?> scoreUnitSnapshot = const Value.absent(), Value<String?> scoreUnitSnapshot = const Value.absent(),
Value<String?> note = const Value.absent(), Value<String?> note = const Value.absent(),
Value<String> status = const Value.absent(),
Value<int> rowid = const Value.absent(), Value<int> rowid = const Value.absent(),
}) => ActiveSetResultsCompanion.insert( }) => ActiveSetResultsCompanion.insert(
id: id, id: id,
@ -18762,6 +18868,7 @@ class $$ActiveSetResultsTableTableManager
scoreLabelSnapshot: scoreLabelSnapshot, scoreLabelSnapshot: scoreLabelSnapshot,
scoreUnitSnapshot: scoreUnitSnapshot, scoreUnitSnapshot: scoreUnitSnapshot,
note: note, note: note,
status: status,
rowid: rowid, rowid: rowid,
), ),
withReferenceMapper: (p0) => p0 withReferenceMapper: (p0) => p0
@ -23550,6 +23657,7 @@ typedef $$WorkoutHistorySetResultsTableCreateCompanionBuilder =
Value<String?> scoreUnitSnapshot, Value<String?> scoreUnitSnapshot,
Value<DateTime?> startedAt, Value<DateTime?> startedAt,
Value<DateTime?> completedAt, Value<DateTime?> completedAt,
Value<String> status,
Value<int> rowid, Value<int> rowid,
}); });
typedef $$WorkoutHistorySetResultsTableUpdateCompanionBuilder = typedef $$WorkoutHistorySetResultsTableUpdateCompanionBuilder =
@ -23586,6 +23694,7 @@ typedef $$WorkoutHistorySetResultsTableUpdateCompanionBuilder =
Value<String?> scoreUnitSnapshot, Value<String?> scoreUnitSnapshot,
Value<DateTime?> startedAt, Value<DateTime?> startedAt,
Value<DateTime?> completedAt, Value<DateTime?> completedAt,
Value<String> status,
Value<int> rowid, Value<int> rowid,
}); });
@ -23786,6 +23895,11 @@ class $$WorkoutHistorySetResultsTableFilterComposer
builder: (column) => ColumnFilters(column), builder: (column) => ColumnFilters(column),
); );
ColumnFilters<String> get status => $composableBuilder(
column: $table.status,
builder: (column) => ColumnFilters(column),
);
$$WorkoutHistoriesTableFilterComposer get workoutHistoryId { $$WorkoutHistoriesTableFilterComposer get workoutHistoryId {
final $$WorkoutHistoriesTableFilterComposer composer = $composerBuilder( final $$WorkoutHistoriesTableFilterComposer composer = $composerBuilder(
composer: this, composer: this,
@ -23974,6 +24088,11 @@ class $$WorkoutHistorySetResultsTableOrderingComposer
builder: (column) => ColumnOrderings(column), builder: (column) => ColumnOrderings(column),
); );
ColumnOrderings<String> get status => $composableBuilder(
column: $table.status,
builder: (column) => ColumnOrderings(column),
);
$$WorkoutHistoriesTableOrderingComposer get workoutHistoryId { $$WorkoutHistoriesTableOrderingComposer get workoutHistoryId {
final $$WorkoutHistoriesTableOrderingComposer composer = $composerBuilder( final $$WorkoutHistoriesTableOrderingComposer composer = $composerBuilder(
composer: this, composer: this,
@ -24148,6 +24267,9 @@ class $$WorkoutHistorySetResultsTableAnnotationComposer
builder: (column) => column, builder: (column) => column,
); );
GeneratedColumn<String> get status =>
$composableBuilder(column: $table.status, builder: (column) => column);
$$WorkoutHistoriesTableAnnotationComposer get workoutHistoryId { $$WorkoutHistoriesTableAnnotationComposer get workoutHistoryId {
final $$WorkoutHistoriesTableAnnotationComposer composer = $composerBuilder( final $$WorkoutHistoriesTableAnnotationComposer composer = $composerBuilder(
composer: this, composer: this,
@ -24243,6 +24365,7 @@ class $$WorkoutHistorySetResultsTableTableManager
Value<String?> scoreUnitSnapshot = const Value.absent(), Value<String?> scoreUnitSnapshot = const Value.absent(),
Value<DateTime?> startedAt = const Value.absent(), Value<DateTime?> startedAt = const Value.absent(),
Value<DateTime?> completedAt = const Value.absent(), Value<DateTime?> completedAt = const Value.absent(),
Value<String> status = const Value.absent(),
Value<int> rowid = const Value.absent(), Value<int> rowid = const Value.absent(),
}) => WorkoutHistorySetResultsCompanion( }) => WorkoutHistorySetResultsCompanion(
id: id, id: id,
@ -24277,6 +24400,7 @@ class $$WorkoutHistorySetResultsTableTableManager
scoreUnitSnapshot: scoreUnitSnapshot, scoreUnitSnapshot: scoreUnitSnapshot,
startedAt: startedAt, startedAt: startedAt,
completedAt: completedAt, completedAt: completedAt,
status: status,
rowid: rowid, rowid: rowid,
), ),
createCompanionCallback: createCompanionCallback:
@ -24313,6 +24437,7 @@ class $$WorkoutHistorySetResultsTableTableManager
Value<String?> scoreUnitSnapshot = const Value.absent(), Value<String?> scoreUnitSnapshot = const Value.absent(),
Value<DateTime?> startedAt = const Value.absent(), Value<DateTime?> startedAt = const Value.absent(),
Value<DateTime?> completedAt = const Value.absent(), Value<DateTime?> completedAt = const Value.absent(),
Value<String> status = const Value.absent(),
Value<int> rowid = const Value.absent(), Value<int> rowid = const Value.absent(),
}) => WorkoutHistorySetResultsCompanion.insert( }) => WorkoutHistorySetResultsCompanion.insert(
id: id, id: id,
@ -24347,6 +24472,7 @@ class $$WorkoutHistorySetResultsTableTableManager
scoreUnitSnapshot: scoreUnitSnapshot, scoreUnitSnapshot: scoreUnitSnapshot,
startedAt: startedAt, startedAt: startedAt,
completedAt: completedAt, completedAt: completedAt,
status: status,
rowid: rowid, rowid: rowid,
), ),
withReferenceMapper: (p0) => p0 withReferenceMapper: (p0) => p0

View File

@ -929,6 +929,7 @@ db.ActiveSetResultsCompanion _activeSetResultCompanion(
scoreLabelSnapshot: Value(result.scoreLabelSnapshot), scoreLabelSnapshot: Value(result.scoreLabelSnapshot),
scoreUnitSnapshot: Value(result.scoreUnitSnapshot), scoreUnitSnapshot: Value(result.scoreUnitSnapshot),
note: Value(result.note), note: Value(result.note),
status: Value(_setResultStatusToDb(result.status)),
); );
} }
@ -949,6 +950,7 @@ domain.ActiveSetResult _activeSetResultFromRow(db.ActiveSetResult row) {
scoreLabelSnapshot: row.scoreLabelSnapshot, scoreLabelSnapshot: row.scoreLabelSnapshot,
scoreUnitSnapshot: row.scoreUnitSnapshot, scoreUnitSnapshot: row.scoreUnitSnapshot,
note: row.note, note: row.note,
status: _setResultStatusFromDb(row.status),
); );
} }
@ -1059,6 +1061,7 @@ db.WorkoutHistorySetResultsCompanion _workoutHistorySetResultCompanion(
scoreUnitSnapshot: Value(result.scoreUnitSnapshot), scoreUnitSnapshot: Value(result.scoreUnitSnapshot),
startedAt: Value(result.startedAt), startedAt: Value(result.startedAt),
completedAt: Value(result.completedAt), completedAt: Value(result.completedAt),
status: Value(_setResultStatusToDb(result.status)),
); );
} }
@ -1106,6 +1109,7 @@ domain.WorkoutHistorySetResult _workoutHistorySetResultFromRow(
scoreUnitSnapshot: row.scoreUnitSnapshot, scoreUnitSnapshot: row.scoreUnitSnapshot,
startedAt: row.startedAt, startedAt: row.startedAt,
completedAt: row.completedAt, completedAt: row.completedAt,
status: _setResultStatusFromDb(row.status),
); );
} }
@ -1143,6 +1147,17 @@ domain.MediaKind _mediaKindFromDb(String value) => switch (value) {
_ => throw domain.DomainException('Unknown media kind: $value'), _ => throw domain.DomainException('Unknown media kind: $value'),
}; };
String _setResultStatusToDb(domain.SetResultStatus status) => switch (status) {
domain.SetResultStatus.completed => 'completed',
domain.SetResultStatus.skipped => 'skipped',
};
domain.SetResultStatus _setResultStatusFromDb(String value) => switch (value) {
'completed' => domain.SetResultStatus.completed,
'skipped' => domain.SetResultStatus.skipped,
_ => throw domain.DomainException('Unknown set result status: $value'),
};
domain.ActiveWorkoutStatus _activeStatusFromDb(String value) => switch (value) { domain.ActiveWorkoutStatus _activeStatusFromDb(String value) => switch (value) {
'running' => domain.ActiveWorkoutStatus.running, 'running' => domain.ActiveWorkoutStatus.running,
'paused' => domain.ActiveWorkoutStatus.paused, 'paused' => domain.ActiveWorkoutStatus.paused,

View File

@ -244,6 +244,7 @@ class ActiveSetResults extends SyncableTable {
TextColumn get scoreLabelSnapshot => text().nullable()(); TextColumn get scoreLabelSnapshot => text().nullable()();
TextColumn get scoreUnitSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()();
TextColumn get note => text().nullable()(); TextColumn get note => text().nullable()();
TextColumn get status => text().withDefault(const Constant('completed'))();
@override @override
List<String> get customConstraints => [ List<String> get customConstraints => [
@ -255,6 +256,9 @@ class ActiveSetResults extends SyncableTable {
'CHECK (actual_time_ms IS NULL OR actual_time_ms >= 0)', 'CHECK (actual_time_ms IS NULL OR actual_time_ms >= 0)',
'CHECK (actual_reps IS NULL OR actual_reps >= 0)', 'CHECK (actual_reps IS NULL OR actual_reps >= 0)',
'CHECK (actual_score IS NULL OR actual_score >= 0)', 'CHECK (actual_score IS NULL OR actual_score >= 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))',
'CHECK (actual_score IS NULL OR (score_label_snapshot IS NOT NULL ' 'CHECK (actual_score IS NULL OR (score_label_snapshot IS NOT NULL '
'AND length(trim(score_label_snapshot)) > 0 ' 'AND length(trim(score_label_snapshot)) > 0 '
'AND score_unit_snapshot IS NOT NULL ' 'AND score_unit_snapshot IS NOT NULL '
@ -332,6 +336,7 @@ class WorkoutHistorySetResults extends SyncableTable {
TextColumn get scoreUnitSnapshot => text().nullable()(); TextColumn get scoreUnitSnapshot => text().nullable()();
DateTimeColumn get startedAt => dateTime().nullable()(); DateTimeColumn get startedAt => dateTime().nullable()();
DateTimeColumn get completedAt => dateTime().nullable()(); DateTimeColumn get completedAt => dateTime().nullable()();
TextColumn get status => text().withDefault(const Constant('completed'))();
@override @override
List<String> get customConstraints => [ List<String> get customConstraints => [
@ -349,6 +354,9 @@ class WorkoutHistorySetResults extends SyncableTable {
'CHECK (actual_time_ms IS NULL OR actual_time_ms >= 0)', 'CHECK (actual_time_ms IS NULL OR actual_time_ms >= 0)',
'CHECK (actual_reps IS NULL OR actual_reps >= 0)', 'CHECK (actual_reps IS NULL OR actual_reps >= 0)',
'CHECK (actual_score IS NULL OR actual_score >= 0)', 'CHECK (actual_score IS NULL OR actual_score >= 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))',
'CHECK (actual_score IS NULL OR (score_label_snapshot IS NOT NULL ' 'CHECK (actual_score IS NULL OR (score_label_snapshot IS NOT NULL '
'AND length(trim(score_label_snapshot)) > 0 ' 'AND length(trim(score_label_snapshot)) > 0 '
'AND score_unit_snapshot IS NOT NULL ' 'AND score_unit_snapshot IS NOT NULL '

View File

@ -209,6 +209,123 @@ void main() {
expect(active?.metadata.id, 'latest-active'); expect(active?.metadata.id, 'latest-active');
}); });
test('upsertSetResultAtPosition does not move session cursor', () async {
final clock = _FakeClock(DateTime.utc(2026, 7, 17, 12));
final session = _sessionWithSnapshot(
currentProgramIndex: 0,
currentExerciseIndex: 0,
currentSetIndex: 1,
);
final repository = _FakeActiveSessionRepository()..session = session;
final useCase = _activeUseCase(repository, clock);
await useCase.upsertSetResultAtPosition(
sessionId: session.metadata.id,
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
status: SetResultStatus.completed,
actualReps: 12,
);
expect(repository.session?.currentProgramIndex, 0);
expect(repository.session?.currentExerciseIndex, 0);
expect(repository.session?.currentSetIndex, 1);
expect(repository.results.single.actualReps, 12);
});
test(
'upsertSetResultAtPosition preserves existing id and createdAt',
() async {
final clock = _FakeClock(DateTime.utc(2026, 7, 17, 12));
final session = _sessionWithSnapshot(
currentProgramIndex: 0,
currentExerciseIndex: 0,
currentSetIndex: 1,
);
final existingCreatedAt = DateTime.utc(2026, 7, 17, 10);
final existing = ActiveSetResult(
metadata: EntityMetadata(
id: 'result-1',
createdAt: existingCreatedAt,
updatedAt: existingCreatedAt,
originDeviceId: 'device-1',
),
activeWorkoutSessionId: session.metadata.id,
programSnapshotId: 'program-snapshot-1',
exerciseSnapshotId: 'exercise-snapshot-1',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
actualReps: 8,
);
final repository = _FakeActiveSessionRepository()
..session = session
..results.add(existing);
final useCase = _activeUseCase(repository, clock);
final updated = await useCase.upsertSetResultAtPosition(
sessionId: session.metadata.id,
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
status: SetResultStatus.completed,
actualReps: 12,
);
expect(updated.metadata.id, 'result-1');
expect(updated.metadata.createdAt, existingCreatedAt);
expect(updated.actualReps, 12);
},
);
test(
'listSetResults returns pending, skipped and completed statuses',
() async {
final clock = _FakeClock(DateTime.utc(2026, 7, 17, 12));
final session = _sessionWithSnapshot(
currentProgramIndex: 0,
currentExerciseIndex: 0,
currentSetIndex: 2,
setsCount: 3,
);
final repository = _FakeActiveSessionRepository()
..session = session
..results.addAll([
ActiveSetResult(
metadata: _metadata('completed'),
activeWorkoutSessionId: session.metadata.id,
programSnapshotId: 'program-snapshot-1',
exerciseSnapshotId: 'exercise-snapshot-1',
programIndex: 0,
exerciseIndex: 0,
setIndex: 0,
actualReps: 10,
status: SetResultStatus.completed,
),
ActiveSetResult(
metadata: _metadata('skipped'),
activeWorkoutSessionId: session.metadata.id,
programSnapshotId: 'program-snapshot-1',
exerciseSnapshotId: 'exercise-snapshot-1',
programIndex: 0,
exerciseIndex: 0,
setIndex: 1,
status: SetResultStatus.skipped,
),
]);
final useCase = _activeUseCase(repository, clock);
final states = await useCase.listSetResults(session.metadata.id);
expect(states.map((state) => state.status), [
SetPositionStatus.completed,
SetPositionStatus.skipped,
SetPositionStatus.pending,
]);
},
);
} }
EntityMetadata _metadata(String id) { EntityMetadata _metadata(String id) {
@ -294,13 +411,17 @@ ActiveWorkoutSessionUseCases _activeUseCase(
} }
final class _FakeActiveSessionRepository implements ActiveSessionRepository { final class _FakeActiveSessionRepository implements ActiveSessionRepository {
ActiveWorkoutSession? session;
final results = <ActiveSetResult>[];
final restStates = <String, ActiveRestState>{}; final restStates = <String, ActiveRestState>{};
@override @override
Future<ActiveWorkoutSession?> findById(String id) async => null; Future<ActiveWorkoutSession?> findById(String id) async {
return session?.metadata.id == id ? session : null;
}
@override @override
Future<ActiveWorkoutSession?> findOpen() async => null; Future<ActiveWorkoutSession?> findOpen() async => session;
@override @override
Future<ActiveRestState?> findRestStateById(String id) async => restStates[id]; Future<ActiveRestState?> findRestStateById(String id) async => restStates[id];
@ -313,11 +434,16 @@ final class _FakeActiveSessionRepository implements ActiveSessionRepository {
} }
@override @override
Future<List<ActiveSetResult>> listSetResults(String sessionId) async => Future<List<ActiveSetResult>> listSetResults(String sessionId) async {
const []; return results
.where((result) => result.activeWorkoutSessionId == sessionId)
.toList();
}
@override @override
Future<void> save(ActiveWorkoutSession session) async {} Future<void> save(ActiveWorkoutSession session) async {
this.session = session;
}
@override @override
Future<void> saveRestState(ActiveRestState restState) async { Future<void> saveRestState(ActiveRestState restState) async {
@ -325,5 +451,53 @@ final class _FakeActiveSessionRepository implements ActiveSessionRepository {
} }
@override @override
Future<void> saveSetResult(ActiveSetResult result) async {} Future<void> saveSetResult(ActiveSetResult result) async {
results.removeWhere(
(existing) =>
existing.activeWorkoutSessionId == result.activeWorkoutSessionId &&
existing.programIndex == result.programIndex &&
existing.exerciseIndex == result.exerciseIndex &&
existing.setIndex == result.setIndex,
);
results.add(result);
}
}
ActiveWorkoutSession _sessionWithSnapshot({
required int currentProgramIndex,
required int currentExerciseIndex,
required int currentSetIndex,
int setsCount = 2,
}) {
return ActiveWorkoutSession(
metadata: _metadata('session-1'),
status: ActiveWorkoutStatus.running,
startedAt: DateTime.utc(2026, 7, 17, 12),
lastPersistedAt: DateTime.utc(2026, 7, 17, 12),
elapsedActiveMs: 0,
currentProgramIndex: currentProgramIndex,
currentExerciseIndex: currentExerciseIndex,
currentSetIndex: currentSetIndex,
resolvedTemplateSnapshotJson: jsonEncode({
'programs': [
{
'id': 'program-snapshot-1',
'programNameSnapshot': 'Programme',
'programSnapshotJson': jsonEncode({
'exercises': [
{
'id': 'exercise-snapshot-1',
'exerciseNameSnapshot': 'Squat',
'setsCount': setsCount,
'timeEnabled': false,
'repsEnabled': true,
'scoreEnabled': false,
'targetReps': 10,
},
],
}),
},
],
}),
);
} }