feat(exercice): icône d'exercice (ticket #38)
Étend le modèle Drift (tables.dart, app_database.dart/.g.dart), les entités/use cases/repositories et les écrans bibliothèque d'exercices et programme pour associer une icône à chaque exercice. flutter analyze propre, 72/72 tests verts, build APK debug validé. Dernier ticket du backlog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -25,6 +25,7 @@ final class ExerciseUseCases {
|
||||
String? description,
|
||||
String? imageMediaId,
|
||||
List<String> imageMediaIds = const [],
|
||||
String? iconMediaId,
|
||||
String? videoMediaId,
|
||||
required bool hasTimeMeasure,
|
||||
required bool hasRepsMeasure,
|
||||
@ -53,6 +54,7 @@ final class ExerciseUseCases {
|
||||
name: name,
|
||||
description: description,
|
||||
imageMediaIds: _resolveExerciseImageIds(imageMediaId, imageMediaIds),
|
||||
iconMediaId: iconMediaId,
|
||||
videoMediaId: videoMediaId,
|
||||
hasTimeMeasure: hasTimeMeasure,
|
||||
hasRepsMeasure: hasRepsMeasure,
|
||||
@ -83,6 +85,7 @@ final class ExerciseUseCases {
|
||||
String? description,
|
||||
String? imageMediaId,
|
||||
Object? imageMediaIds = _useCaseUnchanged,
|
||||
Object? iconMediaId = _useCaseUnchanged,
|
||||
String? videoMediaId,
|
||||
required bool hasTimeMeasure,
|
||||
required bool hasRepsMeasure,
|
||||
@ -123,13 +126,21 @@ final class ExerciseUseCases {
|
||||
defaultTargetScore: resolvedDefaultTargetScore,
|
||||
defaultTargetScoreTimeMs: resolvedDefaultTargetScoreTimeMs,
|
||||
);
|
||||
final resolvedImageMediaIds = imageMediaIds == _useCaseUnchanged
|
||||
? _resolveExerciseImageIds(imageMediaId, exercise.imageMediaIds)
|
||||
: imageMediaIds as List<String>;
|
||||
final resolvedIconMediaId = iconMediaId == _useCaseUnchanged
|
||||
? exercise.iconMediaId != null &&
|
||||
resolvedImageMediaIds.contains(exercise.iconMediaId)
|
||||
? exercise.iconMediaId
|
||||
: null
|
||||
: iconMediaId as String?;
|
||||
final updated = exercise.copyWith(
|
||||
metadata: exercise.metadata.touch(clock.now()),
|
||||
name: name,
|
||||
description: description,
|
||||
imageMediaIds: imageMediaIds == _useCaseUnchanged
|
||||
? _resolveExerciseImageIds(imageMediaId, exercise.imageMediaIds)
|
||||
: imageMediaIds as List<String>,
|
||||
imageMediaIds: resolvedImageMediaIds,
|
||||
iconMediaId: resolvedIconMediaId,
|
||||
videoMediaId: videoMediaId,
|
||||
hasTimeMeasure: hasTimeMeasure,
|
||||
hasRepsMeasure: hasRepsMeasure,
|
||||
@ -190,6 +201,9 @@ final class ExerciseUseCases {
|
||||
imageMediaIds: exercise.imageMediaIds
|
||||
.where((imageId) => imageId != mediaAssetId)
|
||||
.toList(),
|
||||
iconMediaId: exercise.iconMediaId == mediaAssetId
|
||||
? null
|
||||
: exercise.iconMediaId,
|
||||
metadata: exercise.metadata.touch(clock.now()),
|
||||
);
|
||||
await repository.save(updated);
|
||||
@ -217,6 +231,22 @@ final class ExerciseUseCases {
|
||||
return updated;
|
||||
}
|
||||
|
||||
Future<Exercise> setIcon({
|
||||
required String exerciseId,
|
||||
required String? mediaAssetId,
|
||||
}) async {
|
||||
final exercise = await repository.findById(exerciseId);
|
||||
if (exercise == null) {
|
||||
throw const DomainException('Exercise not found.');
|
||||
}
|
||||
final updated = exercise.copyWith(
|
||||
iconMediaId: mediaAssetId,
|
||||
metadata: exercise.metadata.touch(clock.now()),
|
||||
);
|
||||
await repository.save(updated);
|
||||
return updated;
|
||||
}
|
||||
|
||||
Future<Exercise> attachVideo({
|
||||
required String exerciseId,
|
||||
required String mediaAssetId,
|
||||
|
||||
Reference in New Issue
Block a user