feat(exercice): galerie de 5 images par exercice (ticket #35)
Étend le modèle Drift (tables.dart, app_database.dart/.g.dart), les entités/use cases/repositories et exercise_library_screen.dart pour supporter jusqu'à 5 images par exercice au lieu d'une seule. flutter analyze propre, 63/63 tests verts, build APK debug validé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -124,7 +124,8 @@ final class Exercise {
|
||||
required this.metadata,
|
||||
required String name,
|
||||
this.description,
|
||||
this.imageMediaId,
|
||||
String? imageMediaId,
|
||||
List<String> imageMediaIds = const [],
|
||||
this.videoMediaId,
|
||||
required this.hasTimeMeasure,
|
||||
required this.hasRepsMeasure,
|
||||
@ -137,7 +138,12 @@ final class Exercise {
|
||||
this.defaultTargetScore,
|
||||
this.defaultTargetScoreTimeMs,
|
||||
this.archivedAt,
|
||||
}) : name = _nonBlank(name, 'Exercise name') {
|
||||
}) : name = _nonBlank(name, 'Exercise name'),
|
||||
imageMediaIds = _validatedImageMediaIds(
|
||||
imageMediaIds.isEmpty && imageMediaId != null
|
||||
? [imageMediaId]
|
||||
: imageMediaIds,
|
||||
) {
|
||||
_requireAtLeastOneMeasure(
|
||||
hasTime: hasTimeMeasure,
|
||||
hasReps: hasRepsMeasure,
|
||||
@ -167,7 +173,7 @@ final class Exercise {
|
||||
final EntityMetadata metadata;
|
||||
final String name;
|
||||
final String? description;
|
||||
final String? imageMediaId;
|
||||
final List<String> imageMediaIds;
|
||||
final String? videoMediaId;
|
||||
final bool hasTimeMeasure;
|
||||
final bool hasRepsMeasure;
|
||||
@ -187,6 +193,9 @@ final class Exercise {
|
||||
if (hasScoreMeasure) WorkoutMeasure.score,
|
||||
};
|
||||
|
||||
String? get imageMediaId =>
|
||||
imageMediaIds.isEmpty ? null : imageMediaIds.first;
|
||||
|
||||
Exercise archive(DateTime now) {
|
||||
return copyWith(archivedAt: now, metadata: metadata.touch(now));
|
||||
}
|
||||
@ -196,6 +205,7 @@ final class Exercise {
|
||||
String? name,
|
||||
Object? description = _unchanged,
|
||||
Object? imageMediaId = _unchanged,
|
||||
Object? imageMediaIds = _unchanged,
|
||||
Object? videoMediaId = _unchanged,
|
||||
bool? hasTimeMeasure,
|
||||
bool? hasRepsMeasure,
|
||||
@ -215,9 +225,11 @@ final class Exercise {
|
||||
description: description == _unchanged
|
||||
? this.description
|
||||
: description as String?,
|
||||
imageMediaId: imageMediaId == _unchanged
|
||||
? this.imageMediaId
|
||||
: imageMediaId as String?,
|
||||
imageMediaIds: imageMediaIds == _unchanged
|
||||
? imageMediaId == _unchanged
|
||||
? this.imageMediaIds
|
||||
: [if (imageMediaId != null) imageMediaId as String]
|
||||
: imageMediaIds as List<String>,
|
||||
videoMediaId: videoMediaId == _unchanged
|
||||
? this.videoMediaId
|
||||
: videoMediaId as String?,
|
||||
@ -921,6 +933,19 @@ String _nonBlank(String? value, String label) {
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
List<String> _validatedImageMediaIds(List<String> ids) {
|
||||
if (ids.length > 5) {
|
||||
throw const DomainException('An exercise cannot have more than 5 images.');
|
||||
}
|
||||
final normalized = ids
|
||||
.map((id) => _nonBlank(id, 'Image media id'))
|
||||
.toList(growable: false);
|
||||
if (normalized.toSet().length != normalized.length) {
|
||||
throw const DomainException('Exercise images must be unique.');
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
void _requireAtLeastOneMeasure({
|
||||
required bool hasTime,
|
||||
required bool hasReps,
|
||||
|
||||
Reference in New Issue
Block a user