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? description,
|
||||||
String? imageMediaId,
|
String? imageMediaId,
|
||||||
List<String> imageMediaIds = const [],
|
List<String> imageMediaIds = const [],
|
||||||
|
String? iconMediaId,
|
||||||
String? videoMediaId,
|
String? videoMediaId,
|
||||||
required bool hasTimeMeasure,
|
required bool hasTimeMeasure,
|
||||||
required bool hasRepsMeasure,
|
required bool hasRepsMeasure,
|
||||||
@ -53,6 +54,7 @@ final class ExerciseUseCases {
|
|||||||
name: name,
|
name: name,
|
||||||
description: description,
|
description: description,
|
||||||
imageMediaIds: _resolveExerciseImageIds(imageMediaId, imageMediaIds),
|
imageMediaIds: _resolveExerciseImageIds(imageMediaId, imageMediaIds),
|
||||||
|
iconMediaId: iconMediaId,
|
||||||
videoMediaId: videoMediaId,
|
videoMediaId: videoMediaId,
|
||||||
hasTimeMeasure: hasTimeMeasure,
|
hasTimeMeasure: hasTimeMeasure,
|
||||||
hasRepsMeasure: hasRepsMeasure,
|
hasRepsMeasure: hasRepsMeasure,
|
||||||
@ -83,6 +85,7 @@ final class ExerciseUseCases {
|
|||||||
String? description,
|
String? description,
|
||||||
String? imageMediaId,
|
String? imageMediaId,
|
||||||
Object? imageMediaIds = _useCaseUnchanged,
|
Object? imageMediaIds = _useCaseUnchanged,
|
||||||
|
Object? iconMediaId = _useCaseUnchanged,
|
||||||
String? videoMediaId,
|
String? videoMediaId,
|
||||||
required bool hasTimeMeasure,
|
required bool hasTimeMeasure,
|
||||||
required bool hasRepsMeasure,
|
required bool hasRepsMeasure,
|
||||||
@ -123,13 +126,21 @@ final class ExerciseUseCases {
|
|||||||
defaultTargetScore: resolvedDefaultTargetScore,
|
defaultTargetScore: resolvedDefaultTargetScore,
|
||||||
defaultTargetScoreTimeMs: resolvedDefaultTargetScoreTimeMs,
|
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(
|
final updated = exercise.copyWith(
|
||||||
metadata: exercise.metadata.touch(clock.now()),
|
metadata: exercise.metadata.touch(clock.now()),
|
||||||
name: name,
|
name: name,
|
||||||
description: description,
|
description: description,
|
||||||
imageMediaIds: imageMediaIds == _useCaseUnchanged
|
imageMediaIds: resolvedImageMediaIds,
|
||||||
? _resolveExerciseImageIds(imageMediaId, exercise.imageMediaIds)
|
iconMediaId: resolvedIconMediaId,
|
||||||
: imageMediaIds as List<String>,
|
|
||||||
videoMediaId: videoMediaId,
|
videoMediaId: videoMediaId,
|
||||||
hasTimeMeasure: hasTimeMeasure,
|
hasTimeMeasure: hasTimeMeasure,
|
||||||
hasRepsMeasure: hasRepsMeasure,
|
hasRepsMeasure: hasRepsMeasure,
|
||||||
@ -190,6 +201,9 @@ final class ExerciseUseCases {
|
|||||||
imageMediaIds: exercise.imageMediaIds
|
imageMediaIds: exercise.imageMediaIds
|
||||||
.where((imageId) => imageId != mediaAssetId)
|
.where((imageId) => imageId != mediaAssetId)
|
||||||
.toList(),
|
.toList(),
|
||||||
|
iconMediaId: exercise.iconMediaId == mediaAssetId
|
||||||
|
? null
|
||||||
|
: exercise.iconMediaId,
|
||||||
metadata: exercise.metadata.touch(clock.now()),
|
metadata: exercise.metadata.touch(clock.now()),
|
||||||
);
|
);
|
||||||
await repository.save(updated);
|
await repository.save(updated);
|
||||||
@ -217,6 +231,22 @@ final class ExerciseUseCases {
|
|||||||
return updated;
|
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({
|
Future<Exercise> attachVideo({
|
||||||
required String exerciseId,
|
required String exerciseId,
|
||||||
required String mediaAssetId,
|
required String mediaAssetId,
|
||||||
|
|||||||
@ -126,6 +126,7 @@ final class Exercise {
|
|||||||
this.description,
|
this.description,
|
||||||
String? imageMediaId,
|
String? imageMediaId,
|
||||||
List<String> imageMediaIds = const [],
|
List<String> imageMediaIds = const [],
|
||||||
|
String? iconMediaId,
|
||||||
this.videoMediaId,
|
this.videoMediaId,
|
||||||
required this.hasTimeMeasure,
|
required this.hasTimeMeasure,
|
||||||
required this.hasRepsMeasure,
|
required this.hasRepsMeasure,
|
||||||
@ -139,10 +140,13 @@ final class Exercise {
|
|||||||
this.defaultTargetScoreTimeMs,
|
this.defaultTargetScoreTimeMs,
|
||||||
this.archivedAt,
|
this.archivedAt,
|
||||||
}) : name = _nonBlank(name, 'Exercise name'),
|
}) : name = _nonBlank(name, 'Exercise name'),
|
||||||
imageMediaIds = _validatedImageMediaIds(
|
imageMediaIds = _resolvedExerciseImageMediaIds(
|
||||||
imageMediaIds.isEmpty && imageMediaId != null
|
imageMediaId,
|
||||||
? [imageMediaId]
|
imageMediaIds,
|
||||||
: imageMediaIds,
|
),
|
||||||
|
iconMediaId = _validatedIconMediaId(
|
||||||
|
iconMediaId,
|
||||||
|
_resolvedExerciseImageMediaIds(imageMediaId, imageMediaIds),
|
||||||
) {
|
) {
|
||||||
_requireAtLeastOneMeasure(
|
_requireAtLeastOneMeasure(
|
||||||
hasTime: hasTimeMeasure,
|
hasTime: hasTimeMeasure,
|
||||||
@ -174,6 +178,7 @@ final class Exercise {
|
|||||||
final String name;
|
final String name;
|
||||||
final String? description;
|
final String? description;
|
||||||
final List<String> imageMediaIds;
|
final List<String> imageMediaIds;
|
||||||
|
final String? iconMediaId;
|
||||||
final String? videoMediaId;
|
final String? videoMediaId;
|
||||||
final bool hasTimeMeasure;
|
final bool hasTimeMeasure;
|
||||||
final bool hasRepsMeasure;
|
final bool hasRepsMeasure;
|
||||||
@ -206,6 +211,7 @@ final class Exercise {
|
|||||||
Object? description = _unchanged,
|
Object? description = _unchanged,
|
||||||
Object? imageMediaId = _unchanged,
|
Object? imageMediaId = _unchanged,
|
||||||
Object? imageMediaIds = _unchanged,
|
Object? imageMediaIds = _unchanged,
|
||||||
|
Object? iconMediaId = _unchanged,
|
||||||
Object? videoMediaId = _unchanged,
|
Object? videoMediaId = _unchanged,
|
||||||
bool? hasTimeMeasure,
|
bool? hasTimeMeasure,
|
||||||
bool? hasRepsMeasure,
|
bool? hasRepsMeasure,
|
||||||
@ -219,17 +225,25 @@ final class Exercise {
|
|||||||
Object? defaultTargetScoreTimeMs = _unchanged,
|
Object? defaultTargetScoreTimeMs = _unchanged,
|
||||||
Object? archivedAt = _unchanged,
|
Object? archivedAt = _unchanged,
|
||||||
}) {
|
}) {
|
||||||
|
final resolvedImageMediaIds = imageMediaIds == _unchanged
|
||||||
|
? imageMediaId == _unchanged
|
||||||
|
? this.imageMediaIds
|
||||||
|
: [if (imageMediaId != null) imageMediaId as String]
|
||||||
|
: imageMediaIds as List<String>;
|
||||||
|
final resolvedIconMediaId = iconMediaId == _unchanged
|
||||||
|
? this.iconMediaId != null &&
|
||||||
|
resolvedImageMediaIds.contains(this.iconMediaId)
|
||||||
|
? this.iconMediaId
|
||||||
|
: null
|
||||||
|
: iconMediaId as String?;
|
||||||
return Exercise(
|
return Exercise(
|
||||||
metadata: metadata ?? this.metadata,
|
metadata: metadata ?? this.metadata,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
description: description == _unchanged
|
description: description == _unchanged
|
||||||
? this.description
|
? this.description
|
||||||
: description as String?,
|
: description as String?,
|
||||||
imageMediaIds: imageMediaIds == _unchanged
|
imageMediaIds: resolvedImageMediaIds,
|
||||||
? imageMediaId == _unchanged
|
iconMediaId: resolvedIconMediaId,
|
||||||
? this.imageMediaIds
|
|
||||||
: [if (imageMediaId != null) imageMediaId as String]
|
|
||||||
: imageMediaIds as List<String>,
|
|
||||||
videoMediaId: videoMediaId == _unchanged
|
videoMediaId: videoMediaId == _unchanged
|
||||||
? this.videoMediaId
|
? this.videoMediaId
|
||||||
: videoMediaId as String?,
|
: videoMediaId as String?,
|
||||||
@ -957,6 +971,30 @@ List<String> _validatedImageMediaIds(List<String> ids) {
|
|||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> _resolvedExerciseImageMediaIds(
|
||||||
|
String? imageMediaId,
|
||||||
|
List<String> imageMediaIds,
|
||||||
|
) {
|
||||||
|
return _validatedImageMediaIds(
|
||||||
|
imageMediaIds.isEmpty && imageMediaId != null
|
||||||
|
? [imageMediaId]
|
||||||
|
: imageMediaIds,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _validatedIconMediaId(String? iconMediaId, List<String> imageMediaIds) {
|
||||||
|
if (iconMediaId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final normalized = _nonBlank(iconMediaId, 'Icon media id');
|
||||||
|
if (!imageMediaIds.contains(normalized)) {
|
||||||
|
throw const DomainException(
|
||||||
|
'Exercise icon must be one of the exercise images.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
void _requireAtLeastOneMeasure({
|
void _requireAtLeastOneMeasure({
|
||||||
required bool hasTime,
|
required bool hasTime,
|
||||||
required bool hasReps,
|
required bool hasReps,
|
||||||
|
|||||||
@ -37,7 +37,7 @@ final class AppDatabase extends _$AppDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 6;
|
int get schemaVersion => 7;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration {
|
MigrationStrategy get migration {
|
||||||
@ -70,6 +70,9 @@ final class AppDatabase extends _$AppDatabase {
|
|||||||
if (from < 6) {
|
if (from < 6) {
|
||||||
await _migrateToSchema6();
|
await _migrateToSchema6();
|
||||||
}
|
}
|
||||||
|
if (from < 7) {
|
||||||
|
await _migrateToSchema7();
|
||||||
|
}
|
||||||
await _createIndexes();
|
await _createIndexes();
|
||||||
},
|
},
|
||||||
beforeOpen: (details) async {
|
beforeOpen: (details) async {
|
||||||
@ -260,4 +263,11 @@ extension on AppDatabase {
|
|||||||
'exercise_image_media_ids_snapshot_json TEXT',
|
'exercise_image_media_ids_snapshot_json TEXT',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _migrateToSchema7() async {
|
||||||
|
await customStatement(
|
||||||
|
'ALTER TABLE exercises ADD COLUMN icon_media_id TEXT '
|
||||||
|
'REFERENCES media_assets(id)',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7959,6 +7959,20 @@ class $ExercisesTable extends Exercises
|
|||||||
type: DriftSqlType.string,
|
type: DriftSqlType.string,
|
||||||
requiredDuringInsert: false,
|
requiredDuringInsert: false,
|
||||||
);
|
);
|
||||||
|
static const VerificationMeta _iconMediaIdMeta = const VerificationMeta(
|
||||||
|
'iconMediaId',
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String> iconMediaId = GeneratedColumn<String>(
|
||||||
|
'icon_media_id',
|
||||||
|
aliasedName,
|
||||||
|
true,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||||
|
'REFERENCES media_assets (id)',
|
||||||
|
),
|
||||||
|
);
|
||||||
static const VerificationMeta _videoMediaIdMeta = const VerificationMeta(
|
static const VerificationMeta _videoMediaIdMeta = const VerificationMeta(
|
||||||
'videoMediaId',
|
'videoMediaId',
|
||||||
);
|
);
|
||||||
@ -8119,6 +8133,7 @@ class $ExercisesTable extends Exercises
|
|||||||
remoteRevision,
|
remoteRevision,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
|
iconMediaId,
|
||||||
videoMediaId,
|
videoMediaId,
|
||||||
hasTimeMeasure,
|
hasTimeMeasure,
|
||||||
hasRepsMeasure,
|
hasRepsMeasure,
|
||||||
@ -8254,6 +8269,15 @@ class $ExercisesTable extends Exercises
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('icon_media_id')) {
|
||||||
|
context.handle(
|
||||||
|
_iconMediaIdMeta,
|
||||||
|
iconMediaId.isAcceptableOrUnknown(
|
||||||
|
data['icon_media_id']!,
|
||||||
|
_iconMediaIdMeta,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
if (data.containsKey('video_media_id')) {
|
if (data.containsKey('video_media_id')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
_videoMediaIdMeta,
|
_videoMediaIdMeta,
|
||||||
@ -8420,6 +8444,10 @@ class $ExercisesTable extends Exercises
|
|||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
data['${effectivePrefix}description'],
|
data['${effectivePrefix}description'],
|
||||||
),
|
),
|
||||||
|
iconMediaId: attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}icon_media_id'],
|
||||||
|
),
|
||||||
videoMediaId: attachedDatabase.typeMapping.read(
|
videoMediaId: attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
data['${effectivePrefix}video_media_id'],
|
data['${effectivePrefix}video_media_id'],
|
||||||
@ -8491,6 +8519,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
final String? remoteRevision;
|
final String? remoteRevision;
|
||||||
final String name;
|
final String name;
|
||||||
final String? description;
|
final String? description;
|
||||||
|
final String? iconMediaId;
|
||||||
final String? videoMediaId;
|
final String? videoMediaId;
|
||||||
final bool hasTimeMeasure;
|
final bool hasTimeMeasure;
|
||||||
final bool hasRepsMeasure;
|
final bool hasRepsMeasure;
|
||||||
@ -8517,6 +8546,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
this.remoteRevision,
|
this.remoteRevision,
|
||||||
required this.name,
|
required this.name,
|
||||||
this.description,
|
this.description,
|
||||||
|
this.iconMediaId,
|
||||||
this.videoMediaId,
|
this.videoMediaId,
|
||||||
required this.hasTimeMeasure,
|
required this.hasTimeMeasure,
|
||||||
required this.hasRepsMeasure,
|
required this.hasRepsMeasure,
|
||||||
@ -8556,6 +8586,9 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
if (!nullToAbsent || description != null) {
|
if (!nullToAbsent || description != null) {
|
||||||
map['description'] = Variable<String>(description);
|
map['description'] = Variable<String>(description);
|
||||||
}
|
}
|
||||||
|
if (!nullToAbsent || iconMediaId != null) {
|
||||||
|
map['icon_media_id'] = Variable<String>(iconMediaId);
|
||||||
|
}
|
||||||
if (!nullToAbsent || videoMediaId != null) {
|
if (!nullToAbsent || videoMediaId != null) {
|
||||||
map['video_media_id'] = Variable<String>(videoMediaId);
|
map['video_media_id'] = Variable<String>(videoMediaId);
|
||||||
}
|
}
|
||||||
@ -8616,6 +8649,9 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
description: description == null && nullToAbsent
|
description: description == null && nullToAbsent
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(description),
|
: Value(description),
|
||||||
|
iconMediaId: iconMediaId == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(iconMediaId),
|
||||||
videoMediaId: videoMediaId == null && nullToAbsent
|
videoMediaId: videoMediaId == null && nullToAbsent
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(videoMediaId),
|
: Value(videoMediaId),
|
||||||
@ -8668,6 +8704,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
remoteRevision: serializer.fromJson<String?>(json['remoteRevision']),
|
remoteRevision: serializer.fromJson<String?>(json['remoteRevision']),
|
||||||
name: serializer.fromJson<String>(json['name']),
|
name: serializer.fromJson<String>(json['name']),
|
||||||
description: serializer.fromJson<String?>(json['description']),
|
description: serializer.fromJson<String?>(json['description']),
|
||||||
|
iconMediaId: serializer.fromJson<String?>(json['iconMediaId']),
|
||||||
videoMediaId: serializer.fromJson<String?>(json['videoMediaId']),
|
videoMediaId: serializer.fromJson<String?>(json['videoMediaId']),
|
||||||
hasTimeMeasure: serializer.fromJson<bool>(json['hasTimeMeasure']),
|
hasTimeMeasure: serializer.fromJson<bool>(json['hasTimeMeasure']),
|
||||||
hasRepsMeasure: serializer.fromJson<bool>(json['hasRepsMeasure']),
|
hasRepsMeasure: serializer.fromJson<bool>(json['hasRepsMeasure']),
|
||||||
@ -8705,6 +8742,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
'remoteRevision': serializer.toJson<String?>(remoteRevision),
|
'remoteRevision': serializer.toJson<String?>(remoteRevision),
|
||||||
'name': serializer.toJson<String>(name),
|
'name': serializer.toJson<String>(name),
|
||||||
'description': serializer.toJson<String?>(description),
|
'description': serializer.toJson<String?>(description),
|
||||||
|
'iconMediaId': serializer.toJson<String?>(iconMediaId),
|
||||||
'videoMediaId': serializer.toJson<String?>(videoMediaId),
|
'videoMediaId': serializer.toJson<String?>(videoMediaId),
|
||||||
'hasTimeMeasure': serializer.toJson<bool>(hasTimeMeasure),
|
'hasTimeMeasure': serializer.toJson<bool>(hasTimeMeasure),
|
||||||
'hasRepsMeasure': serializer.toJson<bool>(hasRepsMeasure),
|
'hasRepsMeasure': serializer.toJson<bool>(hasRepsMeasure),
|
||||||
@ -8738,6 +8776,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
Value<String?> remoteRevision = const Value.absent(),
|
Value<String?> remoteRevision = const Value.absent(),
|
||||||
String? name,
|
String? name,
|
||||||
Value<String?> description = const Value.absent(),
|
Value<String?> description = const Value.absent(),
|
||||||
|
Value<String?> iconMediaId = const Value.absent(),
|
||||||
Value<String?> videoMediaId = const Value.absent(),
|
Value<String?> videoMediaId = const Value.absent(),
|
||||||
bool? hasTimeMeasure,
|
bool? hasTimeMeasure,
|
||||||
bool? hasRepsMeasure,
|
bool? hasRepsMeasure,
|
||||||
@ -8768,6 +8807,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
: this.remoteRevision,
|
: this.remoteRevision,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
description: description.present ? description.value : this.description,
|
description: description.present ? description.value : this.description,
|
||||||
|
iconMediaId: iconMediaId.present ? iconMediaId.value : this.iconMediaId,
|
||||||
videoMediaId: videoMediaId.present ? videoMediaId.value : this.videoMediaId,
|
videoMediaId: videoMediaId.present ? videoMediaId.value : this.videoMediaId,
|
||||||
hasTimeMeasure: hasTimeMeasure ?? this.hasTimeMeasure,
|
hasTimeMeasure: hasTimeMeasure ?? this.hasTimeMeasure,
|
||||||
hasRepsMeasure: hasRepsMeasure ?? this.hasRepsMeasure,
|
hasRepsMeasure: hasRepsMeasure ?? this.hasRepsMeasure,
|
||||||
@ -8818,6 +8858,9 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
description: data.description.present
|
description: data.description.present
|
||||||
? data.description.value
|
? data.description.value
|
||||||
: this.description,
|
: this.description,
|
||||||
|
iconMediaId: data.iconMediaId.present
|
||||||
|
? data.iconMediaId.value
|
||||||
|
: this.iconMediaId,
|
||||||
videoMediaId: data.videoMediaId.present
|
videoMediaId: data.videoMediaId.present
|
||||||
? data.videoMediaId.value
|
? data.videoMediaId.value
|
||||||
: this.videoMediaId,
|
: this.videoMediaId,
|
||||||
@ -8871,6 +8914,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
..write('remoteRevision: $remoteRevision, ')
|
..write('remoteRevision: $remoteRevision, ')
|
||||||
..write('name: $name, ')
|
..write('name: $name, ')
|
||||||
..write('description: $description, ')
|
..write('description: $description, ')
|
||||||
|
..write('iconMediaId: $iconMediaId, ')
|
||||||
..write('videoMediaId: $videoMediaId, ')
|
..write('videoMediaId: $videoMediaId, ')
|
||||||
..write('hasTimeMeasure: $hasTimeMeasure, ')
|
..write('hasTimeMeasure: $hasTimeMeasure, ')
|
||||||
..write('hasRepsMeasure: $hasRepsMeasure, ')
|
..write('hasRepsMeasure: $hasRepsMeasure, ')
|
||||||
@ -8902,6 +8946,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
remoteRevision,
|
remoteRevision,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
|
iconMediaId,
|
||||||
videoMediaId,
|
videoMediaId,
|
||||||
hasTimeMeasure,
|
hasTimeMeasure,
|
||||||
hasRepsMeasure,
|
hasRepsMeasure,
|
||||||
@ -8932,6 +8977,7 @@ class Exercise extends DataClass implements Insertable<Exercise> {
|
|||||||
other.remoteRevision == this.remoteRevision &&
|
other.remoteRevision == this.remoteRevision &&
|
||||||
other.name == this.name &&
|
other.name == this.name &&
|
||||||
other.description == this.description &&
|
other.description == this.description &&
|
||||||
|
other.iconMediaId == this.iconMediaId &&
|
||||||
other.videoMediaId == this.videoMediaId &&
|
other.videoMediaId == this.videoMediaId &&
|
||||||
other.hasTimeMeasure == this.hasTimeMeasure &&
|
other.hasTimeMeasure == this.hasTimeMeasure &&
|
||||||
other.hasRepsMeasure == this.hasRepsMeasure &&
|
other.hasRepsMeasure == this.hasRepsMeasure &&
|
||||||
@ -8960,6 +9006,7 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
final Value<String?> remoteRevision;
|
final Value<String?> remoteRevision;
|
||||||
final Value<String> name;
|
final Value<String> name;
|
||||||
final Value<String?> description;
|
final Value<String?> description;
|
||||||
|
final Value<String?> iconMediaId;
|
||||||
final Value<String?> videoMediaId;
|
final Value<String?> videoMediaId;
|
||||||
final Value<bool> hasTimeMeasure;
|
final Value<bool> hasTimeMeasure;
|
||||||
final Value<bool> hasRepsMeasure;
|
final Value<bool> hasRepsMeasure;
|
||||||
@ -8987,6 +9034,7 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
this.remoteRevision = const Value.absent(),
|
this.remoteRevision = const Value.absent(),
|
||||||
this.name = const Value.absent(),
|
this.name = const Value.absent(),
|
||||||
this.description = const Value.absent(),
|
this.description = const Value.absent(),
|
||||||
|
this.iconMediaId = const Value.absent(),
|
||||||
this.videoMediaId = const Value.absent(),
|
this.videoMediaId = const Value.absent(),
|
||||||
this.hasTimeMeasure = const Value.absent(),
|
this.hasTimeMeasure = const Value.absent(),
|
||||||
this.hasRepsMeasure = const Value.absent(),
|
this.hasRepsMeasure = const Value.absent(),
|
||||||
@ -9015,6 +9063,7 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
this.remoteRevision = const Value.absent(),
|
this.remoteRevision = const Value.absent(),
|
||||||
required String name,
|
required String name,
|
||||||
this.description = const Value.absent(),
|
this.description = const Value.absent(),
|
||||||
|
this.iconMediaId = const Value.absent(),
|
||||||
this.videoMediaId = const Value.absent(),
|
this.videoMediaId = const Value.absent(),
|
||||||
required bool hasTimeMeasure,
|
required bool hasTimeMeasure,
|
||||||
required bool hasRepsMeasure,
|
required bool hasRepsMeasure,
|
||||||
@ -9052,6 +9101,7 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
Expression<String>? remoteRevision,
|
Expression<String>? remoteRevision,
|
||||||
Expression<String>? name,
|
Expression<String>? name,
|
||||||
Expression<String>? description,
|
Expression<String>? description,
|
||||||
|
Expression<String>? iconMediaId,
|
||||||
Expression<String>? videoMediaId,
|
Expression<String>? videoMediaId,
|
||||||
Expression<bool>? hasTimeMeasure,
|
Expression<bool>? hasTimeMeasure,
|
||||||
Expression<bool>? hasRepsMeasure,
|
Expression<bool>? hasRepsMeasure,
|
||||||
@ -9081,6 +9131,7 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
if (remoteRevision != null) 'remote_revision': remoteRevision,
|
if (remoteRevision != null) 'remote_revision': remoteRevision,
|
||||||
if (name != null) 'name': name,
|
if (name != null) 'name': name,
|
||||||
if (description != null) 'description': description,
|
if (description != null) 'description': description,
|
||||||
|
if (iconMediaId != null) 'icon_media_id': iconMediaId,
|
||||||
if (videoMediaId != null) 'video_media_id': videoMediaId,
|
if (videoMediaId != null) 'video_media_id': videoMediaId,
|
||||||
if (hasTimeMeasure != null) 'has_time_measure': hasTimeMeasure,
|
if (hasTimeMeasure != null) 'has_time_measure': hasTimeMeasure,
|
||||||
if (hasRepsMeasure != null) 'has_reps_measure': hasRepsMeasure,
|
if (hasRepsMeasure != null) 'has_reps_measure': hasRepsMeasure,
|
||||||
@ -9114,6 +9165,7 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
Value<String?>? remoteRevision,
|
Value<String?>? remoteRevision,
|
||||||
Value<String>? name,
|
Value<String>? name,
|
||||||
Value<String?>? description,
|
Value<String?>? description,
|
||||||
|
Value<String?>? iconMediaId,
|
||||||
Value<String?>? videoMediaId,
|
Value<String?>? videoMediaId,
|
||||||
Value<bool>? hasTimeMeasure,
|
Value<bool>? hasTimeMeasure,
|
||||||
Value<bool>? hasRepsMeasure,
|
Value<bool>? hasRepsMeasure,
|
||||||
@ -9142,6 +9194,7 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
remoteRevision: remoteRevision ?? this.remoteRevision,
|
remoteRevision: remoteRevision ?? this.remoteRevision,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
description: description ?? this.description,
|
description: description ?? this.description,
|
||||||
|
iconMediaId: iconMediaId ?? this.iconMediaId,
|
||||||
videoMediaId: videoMediaId ?? this.videoMediaId,
|
videoMediaId: videoMediaId ?? this.videoMediaId,
|
||||||
hasTimeMeasure: hasTimeMeasure ?? this.hasTimeMeasure,
|
hasTimeMeasure: hasTimeMeasure ?? this.hasTimeMeasure,
|
||||||
hasRepsMeasure: hasRepsMeasure ?? this.hasRepsMeasure,
|
hasRepsMeasure: hasRepsMeasure ?? this.hasRepsMeasure,
|
||||||
@ -9204,6 +9257,9 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
if (description.present) {
|
if (description.present) {
|
||||||
map['description'] = Variable<String>(description.value);
|
map['description'] = Variable<String>(description.value);
|
||||||
}
|
}
|
||||||
|
if (iconMediaId.present) {
|
||||||
|
map['icon_media_id'] = Variable<String>(iconMediaId.value);
|
||||||
|
}
|
||||||
if (videoMediaId.present) {
|
if (videoMediaId.present) {
|
||||||
map['video_media_id'] = Variable<String>(videoMediaId.value);
|
map['video_media_id'] = Variable<String>(videoMediaId.value);
|
||||||
}
|
}
|
||||||
@ -9266,6 +9322,7 @@ class ExercisesCompanion extends UpdateCompanion<Exercise> {
|
|||||||
..write('remoteRevision: $remoteRevision, ')
|
..write('remoteRevision: $remoteRevision, ')
|
||||||
..write('name: $name, ')
|
..write('name: $name, ')
|
||||||
..write('description: $description, ')
|
..write('description: $description, ')
|
||||||
|
..write('iconMediaId: $iconMediaId, ')
|
||||||
..write('videoMediaId: $videoMediaId, ')
|
..write('videoMediaId: $videoMediaId, ')
|
||||||
..write('hasTimeMeasure: $hasTimeMeasure, ')
|
..write('hasTimeMeasure: $hasTimeMeasure, ')
|
||||||
..write('hasRepsMeasure: $hasRepsMeasure, ')
|
..write('hasRepsMeasure: $hasRepsMeasure, ')
|
||||||
@ -22861,6 +22918,27 @@ final class $$MediaAssetsTableReferences
|
|||||||
extends BaseReferences<_$AppDatabase, $MediaAssetsTable, MediaAsset> {
|
extends BaseReferences<_$AppDatabase, $MediaAssetsTable, MediaAsset> {
|
||||||
$$MediaAssetsTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
$$MediaAssetsTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
||||||
|
|
||||||
|
static MultiTypedResultKey<$ExercisesTable, List<Exercise>>
|
||||||
|
_exerciseIconReferencesTable(_$AppDatabase db) =>
|
||||||
|
MultiTypedResultKey.fromTable(
|
||||||
|
db.exercises,
|
||||||
|
aliasName: 'media_assets__id__exercises__icon_media_id',
|
||||||
|
);
|
||||||
|
|
||||||
|
$$ExercisesTableProcessedTableManager get exerciseIconReferences {
|
||||||
|
final manager = $$ExercisesTableTableManager(
|
||||||
|
$_db,
|
||||||
|
$_db.exercises,
|
||||||
|
).filter((f) => f.iconMediaId.id.sqlEquals($_itemColumn<String>('id')!));
|
||||||
|
|
||||||
|
final cache = $_typedResult.readTableOrNull(
|
||||||
|
_exerciseIconReferencesTable($_db),
|
||||||
|
);
|
||||||
|
return ProcessedTableManager(
|
||||||
|
manager.$state.copyWith(prefetchedData: cache),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static MultiTypedResultKey<$ExercisesTable, List<Exercise>>
|
static MultiTypedResultKey<$ExercisesTable, List<Exercise>>
|
||||||
_exerciseVideoReferencesTable(_$AppDatabase db) =>
|
_exerciseVideoReferencesTable(_$AppDatabase db) =>
|
||||||
MultiTypedResultKey.fromTable(
|
MultiTypedResultKey.fromTable(
|
||||||
@ -23067,6 +23145,31 @@ class $$MediaAssetsTableFilterComposer
|
|||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Expression<bool> exerciseIconReferences(
|
||||||
|
Expression<bool> Function($$ExercisesTableFilterComposer f) f,
|
||||||
|
) {
|
||||||
|
final $$ExercisesTableFilterComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.id,
|
||||||
|
referencedTable: $db.exercises,
|
||||||
|
getReferencedColumn: (t) => t.iconMediaId,
|
||||||
|
builder:
|
||||||
|
(
|
||||||
|
joinBuilder, {
|
||||||
|
$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
}) => $$ExercisesTableFilterComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: $db.exercises,
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return f(composer);
|
||||||
|
}
|
||||||
|
|
||||||
Expression<bool> exerciseVideoReferences(
|
Expression<bool> exerciseVideoReferences(
|
||||||
Expression<bool> Function($$ExercisesTableFilterComposer f) f,
|
Expression<bool> Function($$ExercisesTableFilterComposer f) f,
|
||||||
) {
|
) {
|
||||||
@ -23371,6 +23474,31 @@ class $$MediaAssetsTableAnnotationComposer
|
|||||||
builder: (column) => column,
|
builder: (column) => column,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Expression<T> exerciseIconReferences<T extends Object>(
|
||||||
|
Expression<T> Function($$ExercisesTableAnnotationComposer a) f,
|
||||||
|
) {
|
||||||
|
final $$ExercisesTableAnnotationComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.id,
|
||||||
|
referencedTable: $db.exercises,
|
||||||
|
getReferencedColumn: (t) => t.iconMediaId,
|
||||||
|
builder:
|
||||||
|
(
|
||||||
|
joinBuilder, {
|
||||||
|
$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
}) => $$ExercisesTableAnnotationComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: $db.exercises,
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return f(composer);
|
||||||
|
}
|
||||||
|
|
||||||
Expression<T> exerciseVideoReferences<T extends Object>(
|
Expression<T> exerciseVideoReferences<T extends Object>(
|
||||||
Expression<T> Function($$ExercisesTableAnnotationComposer a) f,
|
Expression<T> Function($$ExercisesTableAnnotationComposer a) f,
|
||||||
) {
|
) {
|
||||||
@ -23486,6 +23614,7 @@ class $$MediaAssetsTableTableManager
|
|||||||
(MediaAsset, $$MediaAssetsTableReferences),
|
(MediaAsset, $$MediaAssetsTableReferences),
|
||||||
MediaAsset,
|
MediaAsset,
|
||||||
PrefetchHooks Function({
|
PrefetchHooks Function({
|
||||||
|
bool exerciseIconReferences,
|
||||||
bool exerciseVideoReferences,
|
bool exerciseVideoReferences,
|
||||||
bool exerciseImagesRefs,
|
bool exerciseImagesRefs,
|
||||||
bool programExerciseImageSnapshotReferences,
|
bool programExerciseImageSnapshotReferences,
|
||||||
@ -23609,6 +23738,7 @@ class $$MediaAssetsTableTableManager
|
|||||||
.toList(),
|
.toList(),
|
||||||
prefetchHooksCallback:
|
prefetchHooksCallback:
|
||||||
({
|
({
|
||||||
|
exerciseIconReferences = false,
|
||||||
exerciseVideoReferences = false,
|
exerciseVideoReferences = false,
|
||||||
exerciseImagesRefs = false,
|
exerciseImagesRefs = false,
|
||||||
programExerciseImageSnapshotReferences = false,
|
programExerciseImageSnapshotReferences = false,
|
||||||
@ -23617,6 +23747,7 @@ class $$MediaAssetsTableTableManager
|
|||||||
return PrefetchHooks(
|
return PrefetchHooks(
|
||||||
db: db,
|
db: db,
|
||||||
explicitlyWatchedTables: [
|
explicitlyWatchedTables: [
|
||||||
|
if (exerciseIconReferences) db.exercises,
|
||||||
if (exerciseVideoReferences) db.exercises,
|
if (exerciseVideoReferences) db.exercises,
|
||||||
if (exerciseImagesRefs) db.exerciseImages,
|
if (exerciseImagesRefs) db.exerciseImages,
|
||||||
if (programExerciseImageSnapshotReferences)
|
if (programExerciseImageSnapshotReferences)
|
||||||
@ -23627,6 +23758,27 @@ class $$MediaAssetsTableTableManager
|
|||||||
addJoins: null,
|
addJoins: null,
|
||||||
getPrefetchedDataCallback: (items) async {
|
getPrefetchedDataCallback: (items) async {
|
||||||
return [
|
return [
|
||||||
|
if (exerciseIconReferences)
|
||||||
|
await $_getPrefetchedData<
|
||||||
|
MediaAsset,
|
||||||
|
$MediaAssetsTable,
|
||||||
|
Exercise
|
||||||
|
>(
|
||||||
|
currentTable: table,
|
||||||
|
referencedTable: $$MediaAssetsTableReferences
|
||||||
|
._exerciseIconReferencesTable(db),
|
||||||
|
managerFromTypedResult: (p0) =>
|
||||||
|
$$MediaAssetsTableReferences(
|
||||||
|
db,
|
||||||
|
table,
|
||||||
|
p0,
|
||||||
|
).exerciseIconReferences,
|
||||||
|
referencedItemsForCurrentItem:
|
||||||
|
(item, referencedItems) => referencedItems.where(
|
||||||
|
(e) => e.iconMediaId == item.id,
|
||||||
|
),
|
||||||
|
typedResults: items,
|
||||||
|
),
|
||||||
if (exerciseVideoReferences)
|
if (exerciseVideoReferences)
|
||||||
await $_getPrefetchedData<
|
await $_getPrefetchedData<
|
||||||
MediaAsset,
|
MediaAsset,
|
||||||
@ -23734,6 +23886,7 @@ typedef $$MediaAssetsTableProcessedTableManager =
|
|||||||
(MediaAsset, $$MediaAssetsTableReferences),
|
(MediaAsset, $$MediaAssetsTableReferences),
|
||||||
MediaAsset,
|
MediaAsset,
|
||||||
PrefetchHooks Function({
|
PrefetchHooks Function({
|
||||||
|
bool exerciseIconReferences,
|
||||||
bool exerciseVideoReferences,
|
bool exerciseVideoReferences,
|
||||||
bool exerciseImagesRefs,
|
bool exerciseImagesRefs,
|
||||||
bool programExerciseImageSnapshotReferences,
|
bool programExerciseImageSnapshotReferences,
|
||||||
@ -23755,6 +23908,7 @@ typedef $$ExercisesTableCreateCompanionBuilder =
|
|||||||
Value<String?> remoteRevision,
|
Value<String?> remoteRevision,
|
||||||
required String name,
|
required String name,
|
||||||
Value<String?> description,
|
Value<String?> description,
|
||||||
|
Value<String?> iconMediaId,
|
||||||
Value<String?> videoMediaId,
|
Value<String?> videoMediaId,
|
||||||
required bool hasTimeMeasure,
|
required bool hasTimeMeasure,
|
||||||
required bool hasRepsMeasure,
|
required bool hasRepsMeasure,
|
||||||
@ -23784,6 +23938,7 @@ typedef $$ExercisesTableUpdateCompanionBuilder =
|
|||||||
Value<String?> remoteRevision,
|
Value<String?> remoteRevision,
|
||||||
Value<String> name,
|
Value<String> name,
|
||||||
Value<String?> description,
|
Value<String?> description,
|
||||||
|
Value<String?> iconMediaId,
|
||||||
Value<String?> videoMediaId,
|
Value<String?> videoMediaId,
|
||||||
Value<bool> hasTimeMeasure,
|
Value<bool> hasTimeMeasure,
|
||||||
Value<bool> hasRepsMeasure,
|
Value<bool> hasRepsMeasure,
|
||||||
@ -23803,6 +23958,23 @@ final class $$ExercisesTableReferences
|
|||||||
extends BaseReferences<_$AppDatabase, $ExercisesTable, Exercise> {
|
extends BaseReferences<_$AppDatabase, $ExercisesTable, Exercise> {
|
||||||
$$ExercisesTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
$$ExercisesTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
||||||
|
|
||||||
|
static $MediaAssetsTable _iconMediaIdTable(_$AppDatabase db) =>
|
||||||
|
db.mediaAssets.createAlias('exercises__icon_media_id__media_assets__id');
|
||||||
|
|
||||||
|
$$MediaAssetsTableProcessedTableManager? get iconMediaId {
|
||||||
|
final $_column = $_itemColumn<String>('icon_media_id');
|
||||||
|
if ($_column == null) return null;
|
||||||
|
final manager = $$MediaAssetsTableTableManager(
|
||||||
|
$_db,
|
||||||
|
$_db.mediaAssets,
|
||||||
|
).filter((f) => f.id.sqlEquals($_column));
|
||||||
|
final item = $_typedResult.readTableOrNull(_iconMediaIdTable($_db));
|
||||||
|
if (item == null) return manager;
|
||||||
|
return ProcessedTableManager(
|
||||||
|
manager.$state.copyWith(prefetchedData: [item]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static $MediaAssetsTable _videoMediaIdTable(_$AppDatabase db) =>
|
static $MediaAssetsTable _videoMediaIdTable(_$AppDatabase db) =>
|
||||||
db.mediaAssets.createAlias('exercises__video_media_id__media_assets__id');
|
db.mediaAssets.createAlias('exercises__video_media_id__media_assets__id');
|
||||||
|
|
||||||
@ -23988,6 +24160,29 @@ class $$ExercisesTableFilterComposer
|
|||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$$MediaAssetsTableFilterComposer get iconMediaId {
|
||||||
|
final $$MediaAssetsTableFilterComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.iconMediaId,
|
||||||
|
referencedTable: $db.mediaAssets,
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder:
|
||||||
|
(
|
||||||
|
joinBuilder, {
|
||||||
|
$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
}) => $$MediaAssetsTableFilterComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: $db.mediaAssets,
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
$$MediaAssetsTableFilterComposer get videoMediaId {
|
$$MediaAssetsTableFilterComposer get videoMediaId {
|
||||||
final $$MediaAssetsTableFilterComposer composer = $composerBuilder(
|
final $$MediaAssetsTableFilterComposer composer = $composerBuilder(
|
||||||
composer: this,
|
composer: this,
|
||||||
@ -24191,6 +24386,29 @@ class $$ExercisesTableOrderingComposer
|
|||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$$MediaAssetsTableOrderingComposer get iconMediaId {
|
||||||
|
final $$MediaAssetsTableOrderingComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.iconMediaId,
|
||||||
|
referencedTable: $db.mediaAssets,
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder:
|
||||||
|
(
|
||||||
|
joinBuilder, {
|
||||||
|
$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
}) => $$MediaAssetsTableOrderingComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: $db.mediaAssets,
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
$$MediaAssetsTableOrderingComposer get videoMediaId {
|
$$MediaAssetsTableOrderingComposer get videoMediaId {
|
||||||
final $$MediaAssetsTableOrderingComposer composer = $composerBuilder(
|
final $$MediaAssetsTableOrderingComposer composer = $composerBuilder(
|
||||||
composer: this,
|
composer: this,
|
||||||
@ -24330,6 +24548,29 @@ class $$ExercisesTableAnnotationComposer
|
|||||||
builder: (column) => column,
|
builder: (column) => column,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$$MediaAssetsTableAnnotationComposer get iconMediaId {
|
||||||
|
final $$MediaAssetsTableAnnotationComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.iconMediaId,
|
||||||
|
referencedTable: $db.mediaAssets,
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder:
|
||||||
|
(
|
||||||
|
joinBuilder, {
|
||||||
|
$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
}) => $$MediaAssetsTableAnnotationComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: $db.mediaAssets,
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
$$MediaAssetsTableAnnotationComposer get videoMediaId {
|
$$MediaAssetsTableAnnotationComposer get videoMediaId {
|
||||||
final $$MediaAssetsTableAnnotationComposer composer = $composerBuilder(
|
final $$MediaAssetsTableAnnotationComposer composer = $composerBuilder(
|
||||||
composer: this,
|
composer: this,
|
||||||
@ -24418,6 +24659,7 @@ class $$ExercisesTableTableManager
|
|||||||
(Exercise, $$ExercisesTableReferences),
|
(Exercise, $$ExercisesTableReferences),
|
||||||
Exercise,
|
Exercise,
|
||||||
PrefetchHooks Function({
|
PrefetchHooks Function({
|
||||||
|
bool iconMediaId,
|
||||||
bool videoMediaId,
|
bool videoMediaId,
|
||||||
bool exerciseImagesRefs,
|
bool exerciseImagesRefs,
|
||||||
bool programExercisesRefs,
|
bool programExercisesRefs,
|
||||||
@ -24449,6 +24691,7 @@ class $$ExercisesTableTableManager
|
|||||||
Value<String?> remoteRevision = const Value.absent(),
|
Value<String?> remoteRevision = const Value.absent(),
|
||||||
Value<String> name = const Value.absent(),
|
Value<String> name = const Value.absent(),
|
||||||
Value<String?> description = const Value.absent(),
|
Value<String?> description = const Value.absent(),
|
||||||
|
Value<String?> iconMediaId = const Value.absent(),
|
||||||
Value<String?> videoMediaId = const Value.absent(),
|
Value<String?> videoMediaId = const Value.absent(),
|
||||||
Value<bool> hasTimeMeasure = const Value.absent(),
|
Value<bool> hasTimeMeasure = const Value.absent(),
|
||||||
Value<bool> hasRepsMeasure = const Value.absent(),
|
Value<bool> hasRepsMeasure = const Value.absent(),
|
||||||
@ -24476,6 +24719,7 @@ class $$ExercisesTableTableManager
|
|||||||
remoteRevision: remoteRevision,
|
remoteRevision: remoteRevision,
|
||||||
name: name,
|
name: name,
|
||||||
description: description,
|
description: description,
|
||||||
|
iconMediaId: iconMediaId,
|
||||||
videoMediaId: videoMediaId,
|
videoMediaId: videoMediaId,
|
||||||
hasTimeMeasure: hasTimeMeasure,
|
hasTimeMeasure: hasTimeMeasure,
|
||||||
hasRepsMeasure: hasRepsMeasure,
|
hasRepsMeasure: hasRepsMeasure,
|
||||||
@ -24505,6 +24749,7 @@ class $$ExercisesTableTableManager
|
|||||||
Value<String?> remoteRevision = const Value.absent(),
|
Value<String?> remoteRevision = const Value.absent(),
|
||||||
required String name,
|
required String name,
|
||||||
Value<String?> description = const Value.absent(),
|
Value<String?> description = const Value.absent(),
|
||||||
|
Value<String?> iconMediaId = const Value.absent(),
|
||||||
Value<String?> videoMediaId = const Value.absent(),
|
Value<String?> videoMediaId = const Value.absent(),
|
||||||
required bool hasTimeMeasure,
|
required bool hasTimeMeasure,
|
||||||
required bool hasRepsMeasure,
|
required bool hasRepsMeasure,
|
||||||
@ -24532,6 +24777,7 @@ class $$ExercisesTableTableManager
|
|||||||
remoteRevision: remoteRevision,
|
remoteRevision: remoteRevision,
|
||||||
name: name,
|
name: name,
|
||||||
description: description,
|
description: description,
|
||||||
|
iconMediaId: iconMediaId,
|
||||||
videoMediaId: videoMediaId,
|
videoMediaId: videoMediaId,
|
||||||
hasTimeMeasure: hasTimeMeasure,
|
hasTimeMeasure: hasTimeMeasure,
|
||||||
hasRepsMeasure: hasRepsMeasure,
|
hasRepsMeasure: hasRepsMeasure,
|
||||||
@ -24556,6 +24802,7 @@ class $$ExercisesTableTableManager
|
|||||||
.toList(),
|
.toList(),
|
||||||
prefetchHooksCallback:
|
prefetchHooksCallback:
|
||||||
({
|
({
|
||||||
|
iconMediaId = false,
|
||||||
videoMediaId = false,
|
videoMediaId = false,
|
||||||
exerciseImagesRefs = false,
|
exerciseImagesRefs = false,
|
||||||
programExercisesRefs = false,
|
programExercisesRefs = false,
|
||||||
@ -24582,6 +24829,19 @@ class $$ExercisesTableTableManager
|
|||||||
dynamic
|
dynamic
|
||||||
>
|
>
|
||||||
>(state) {
|
>(state) {
|
||||||
|
if (iconMediaId) {
|
||||||
|
state =
|
||||||
|
state.withJoin(
|
||||||
|
currentTable: table,
|
||||||
|
currentColumn: table.iconMediaId,
|
||||||
|
referencedTable: $$ExercisesTableReferences
|
||||||
|
._iconMediaIdTable(db),
|
||||||
|
referencedColumn: $$ExercisesTableReferences
|
||||||
|
._iconMediaIdTable(db)
|
||||||
|
.id,
|
||||||
|
)
|
||||||
|
as T;
|
||||||
|
}
|
||||||
if (videoMediaId) {
|
if (videoMediaId) {
|
||||||
state =
|
state =
|
||||||
state.withJoin(
|
state.withJoin(
|
||||||
@ -24663,6 +24923,7 @@ typedef $$ExercisesTableProcessedTableManager =
|
|||||||
(Exercise, $$ExercisesTableReferences),
|
(Exercise, $$ExercisesTableReferences),
|
||||||
Exercise,
|
Exercise,
|
||||||
PrefetchHooks Function({
|
PrefetchHooks Function({
|
||||||
|
bool iconMediaId,
|
||||||
bool videoMediaId,
|
bool videoMediaId,
|
||||||
bool exerciseImagesRefs,
|
bool exerciseImagesRefs,
|
||||||
bool programExercisesRefs,
|
bool programExercisesRefs,
|
||||||
|
|||||||
@ -1078,6 +1078,7 @@ db.ExercisesCompanion _exerciseCompanion(domain.Exercise exercise) {
|
|||||||
remoteRevision: values[10] as Value<String?>,
|
remoteRevision: values[10] as Value<String?>,
|
||||||
name: Value(exercise.name),
|
name: Value(exercise.name),
|
||||||
description: Value(exercise.description),
|
description: Value(exercise.description),
|
||||||
|
iconMediaId: Value(exercise.iconMediaId),
|
||||||
videoMediaId: Value(exercise.videoMediaId),
|
videoMediaId: Value(exercise.videoMediaId),
|
||||||
hasTimeMeasure: Value(exercise.hasTimeMeasure),
|
hasTimeMeasure: Value(exercise.hasTimeMeasure),
|
||||||
hasRepsMeasure: Value(exercise.hasRepsMeasure),
|
hasRepsMeasure: Value(exercise.hasRepsMeasure),
|
||||||
@ -1099,6 +1100,7 @@ domain.Exercise _exerciseFromRow(db.Exercise row, List<String> imageMediaIds) {
|
|||||||
name: row.name,
|
name: row.name,
|
||||||
description: row.description,
|
description: row.description,
|
||||||
imageMediaIds: imageMediaIds,
|
imageMediaIds: imageMediaIds,
|
||||||
|
iconMediaId: row.iconMediaId,
|
||||||
videoMediaId: row.videoMediaId,
|
videoMediaId: row.videoMediaId,
|
||||||
hasTimeMeasure: row.hasTimeMeasure,
|
hasTimeMeasure: row.hasTimeMeasure,
|
||||||
hasRepsMeasure: row.hasRepsMeasure,
|
hasRepsMeasure: row.hasRepsMeasure,
|
||||||
|
|||||||
@ -55,6 +55,9 @@ class Exercises extends SyncableTable {
|
|||||||
|
|
||||||
TextColumn get name => text().withLength(min: 1)();
|
TextColumn get name => text().withLength(min: 1)();
|
||||||
TextColumn get description => text().nullable()();
|
TextColumn get description => text().nullable()();
|
||||||
|
@ReferenceName('exerciseIconReferences')
|
||||||
|
TextColumn get iconMediaId =>
|
||||||
|
text().nullable().references(MediaAssets, #id)();
|
||||||
@ReferenceName('exerciseVideoReferences')
|
@ReferenceName('exerciseVideoReferences')
|
||||||
TextColumn get videoMediaId =>
|
TextColumn get videoMediaId =>
|
||||||
text().nullable().references(MediaAssets, #id)();
|
text().nullable().references(MediaAssets, #id)();
|
||||||
|
|||||||
@ -267,15 +267,11 @@ final class ExerciseListTile extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final description = exercise.description?.trim();
|
final description = exercise.description?.trim();
|
||||||
final hasMedia =
|
final iconMediaId = exercise.iconMediaId ?? exercise.imageMediaId;
|
||||||
exercise.imageMediaId != null || exercise.videoMediaId != null;
|
final hasMedia = iconMediaId != null || exercise.videoMediaId != null;
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
leading: CircleAvatar(
|
leading: _ExerciseIconAvatar(iconMediaId: iconMediaId),
|
||||||
child: Icon(
|
|
||||||
hasMedia ? Icons.perm_media_outlined : Icons.fitness_center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
title: Text(exercise.name),
|
title: Text(exercise.name),
|
||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -328,6 +324,42 @@ final class ExerciseListTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class _ExerciseIconAvatar extends StatelessWidget {
|
||||||
|
const _ExerciseIconAvatar({required this.iconMediaId});
|
||||||
|
|
||||||
|
final String? iconMediaId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final icon = CircleAvatar(
|
||||||
|
child: Icon(
|
||||||
|
iconMediaId == null ? Icons.fitness_center : Icons.perm_media_outlined,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (iconMediaId == null) {
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
return Tooltip(
|
||||||
|
message: 'Icône d’exercice $iconMediaId',
|
||||||
|
child: Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
|
children: [
|
||||||
|
icon,
|
||||||
|
Positioned(
|
||||||
|
right: -2,
|
||||||
|
bottom: -2,
|
||||||
|
child: Icon(
|
||||||
|
Icons.star,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class ExerciseFormScreen extends StatefulWidget {
|
final class ExerciseFormScreen extends StatefulWidget {
|
||||||
const ExerciseFormScreen({
|
const ExerciseFormScreen({
|
||||||
required this.exerciseUseCases,
|
required this.exerciseUseCases,
|
||||||
@ -357,6 +389,7 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
|||||||
late final TextEditingController _defaultScoreController;
|
late final TextEditingController _defaultScoreController;
|
||||||
late final TextEditingController _defaultScoreTimeController;
|
late final TextEditingController _defaultScoreTimeController;
|
||||||
late List<String> _imageMediaIds;
|
late List<String> _imageMediaIds;
|
||||||
|
String? _iconMediaId;
|
||||||
String? _videoMediaId;
|
String? _videoMediaId;
|
||||||
final _selectedImageNamesById = <String, String>{};
|
final _selectedImageNamesById = <String, String>{};
|
||||||
String? _selectedVideoName;
|
String? _selectedVideoName;
|
||||||
@ -395,6 +428,7 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
_imageMediaIds = List<String>.of(exercise?.imageMediaIds ?? const []);
|
_imageMediaIds = List<String>.of(exercise?.imageMediaIds ?? const []);
|
||||||
|
_iconMediaId = exercise?.iconMediaId;
|
||||||
_videoMediaId = exercise?.videoMediaId;
|
_videoMediaId = exercise?.videoMediaId;
|
||||||
_hasTime = exercise?.hasTimeMeasure ?? true;
|
_hasTime = exercise?.hasTimeMeasure ?? true;
|
||||||
_hasReps = exercise?.hasRepsMeasure ?? false;
|
_hasReps = exercise?.hasRepsMeasure ?? false;
|
||||||
@ -450,9 +484,11 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
|||||||
_ImageGalleryField(
|
_ImageGalleryField(
|
||||||
imageMediaIds: _imageMediaIds,
|
imageMediaIds: _imageMediaIds,
|
||||||
imageNamesById: _selectedImageNamesById,
|
imageNamesById: _selectedImageNamesById,
|
||||||
|
iconMediaId: _iconMediaId,
|
||||||
importing: _importingImage,
|
importing: _importingImage,
|
||||||
onAdd: _importImage,
|
onAdd: _importImage,
|
||||||
onRemove: _removeImage,
|
onRemove: _removeImage,
|
||||||
|
onSetIcon: _setIcon,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_MediaImportField(
|
_MediaImportField(
|
||||||
@ -704,10 +740,17 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
|||||||
_imageMediaIds = _imageMediaIds
|
_imageMediaIds = _imageMediaIds
|
||||||
.where((imageId) => imageId != mediaAssetId)
|
.where((imageId) => imageId != mediaAssetId)
|
||||||
.toList();
|
.toList();
|
||||||
|
if (_iconMediaId == mediaAssetId) {
|
||||||
|
_iconMediaId = null;
|
||||||
|
}
|
||||||
_selectedImageNamesById.remove(mediaAssetId);
|
_selectedImageNamesById.remove(mediaAssetId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _setIcon(String mediaAssetId) {
|
||||||
|
setState(() => _iconMediaId = mediaAssetId);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _importVideo() async {
|
Future<void> _importVideo() async {
|
||||||
final sourcePath = await widget.mediaPicker.pickPath(MediaKind.video);
|
final sourcePath = await widget.mediaPicker.pickPath(MediaKind.video);
|
||||||
if (sourcePath == null) {
|
if (sourcePath == null) {
|
||||||
@ -795,6 +838,7 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
|||||||
name: _nameController.text.trim(),
|
name: _nameController.text.trim(),
|
||||||
description: _optionalText(_descriptionController),
|
description: _optionalText(_descriptionController),
|
||||||
imageMediaIds: _imageMediaIds,
|
imageMediaIds: _imageMediaIds,
|
||||||
|
iconMediaId: _iconMediaId,
|
||||||
videoMediaId: _videoMediaId,
|
videoMediaId: _videoMediaId,
|
||||||
hasTimeMeasure: _hasTime,
|
hasTimeMeasure: _hasTime,
|
||||||
hasRepsMeasure: _hasReps,
|
hasRepsMeasure: _hasReps,
|
||||||
@ -813,6 +857,7 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
|||||||
name: _nameController.text.trim(),
|
name: _nameController.text.trim(),
|
||||||
description: _optionalText(_descriptionController),
|
description: _optionalText(_descriptionController),
|
||||||
imageMediaIds: _imageMediaIds,
|
imageMediaIds: _imageMediaIds,
|
||||||
|
iconMediaId: _iconMediaId,
|
||||||
videoMediaId: _videoMediaId,
|
videoMediaId: _videoMediaId,
|
||||||
hasTimeMeasure: _hasTime,
|
hasTimeMeasure: _hasTime,
|
||||||
hasRepsMeasure: _hasReps,
|
hasRepsMeasure: _hasReps,
|
||||||
@ -969,16 +1014,20 @@ final class _ImageGalleryField extends StatelessWidget {
|
|||||||
const _ImageGalleryField({
|
const _ImageGalleryField({
|
||||||
required this.imageMediaIds,
|
required this.imageMediaIds,
|
||||||
required this.imageNamesById,
|
required this.imageNamesById,
|
||||||
|
required this.iconMediaId,
|
||||||
required this.importing,
|
required this.importing,
|
||||||
required this.onAdd,
|
required this.onAdd,
|
||||||
required this.onRemove,
|
required this.onRemove,
|
||||||
|
required this.onSetIcon,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<String> imageMediaIds;
|
final List<String> imageMediaIds;
|
||||||
final Map<String, String> imageNamesById;
|
final Map<String, String> imageNamesById;
|
||||||
|
final String? iconMediaId;
|
||||||
final bool importing;
|
final bool importing;
|
||||||
final VoidCallback onAdd;
|
final VoidCallback onAdd;
|
||||||
final ValueChanged<String> onRemove;
|
final ValueChanged<String> onRemove;
|
||||||
|
final ValueChanged<String> onSetIcon;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -998,10 +1047,12 @@ final class _ImageGalleryField extends StatelessWidget {
|
|||||||
for (var index = 0; index < imageMediaIds.length; index++)
|
for (var index = 0; index < imageMediaIds.length; index++)
|
||||||
_ImageThumbnail(
|
_ImageThumbnail(
|
||||||
mediaAssetId: imageMediaIds[index],
|
mediaAssetId: imageMediaIds[index],
|
||||||
|
selectedAsIcon: imageMediaIds[index] == iconMediaId,
|
||||||
label:
|
label:
|
||||||
imageNamesById[imageMediaIds[index]] ??
|
imageNamesById[imageMediaIds[index]] ??
|
||||||
'Image ${index + 1}',
|
'Image ${index + 1}',
|
||||||
onRemove: onRemove,
|
onRemove: onRemove,
|
||||||
|
onSetIcon: onSetIcon,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -1035,44 +1086,78 @@ final class _ImageGalleryField extends StatelessWidget {
|
|||||||
final class _ImageThumbnail extends StatelessWidget {
|
final class _ImageThumbnail extends StatelessWidget {
|
||||||
const _ImageThumbnail({
|
const _ImageThumbnail({
|
||||||
required this.mediaAssetId,
|
required this.mediaAssetId,
|
||||||
|
required this.selectedAsIcon,
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.onRemove,
|
required this.onRemove,
|
||||||
|
required this.onSetIcon,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String mediaAssetId;
|
final String mediaAssetId;
|
||||||
|
final bool selectedAsIcon;
|
||||||
final String label;
|
final String label;
|
||||||
final ValueChanged<String> onRemove;
|
final ValueChanged<String> onRemove;
|
||||||
|
final ValueChanged<String> onSetIcon;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
final tokens = courtBlazerTokensOf(context);
|
final tokens = courtBlazerTokensOf(context);
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 104,
|
width: 132,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
height: 104,
|
height: 154,
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
border: Border.all(color: tokens.border),
|
border: Border.all(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: selectedAsIcon
|
||||||
|
? theme.colorScheme.primary
|
||||||
|
: tokens.border,
|
||||||
|
width: selectedAsIcon ? 2 : 1,
|
||||||
|
),
|
||||||
|
color: theme.colorScheme.surface,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.image_outlined),
|
Icon(
|
||||||
|
Icons.image_outlined,
|
||||||
|
color: selectedAsIcon ? theme.colorScheme.primary : null,
|
||||||
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: Theme.of(context).textTheme.labelSmall,
|
style: theme.textTheme.labelSmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Définir comme icône',
|
||||||
|
onPressed: selectedAsIcon
|
||||||
|
? null
|
||||||
|
: () => onSetIcon(mediaAssetId),
|
||||||
|
icon: const Icon(Icons.star_outline, size: 18),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (selectedAsIcon)
|
||||||
|
Positioned(
|
||||||
|
top: 4,
|
||||||
|
left: 4,
|
||||||
|
child: Tooltip(
|
||||||
|
message: 'Icône choisie',
|
||||||
|
child: Icon(
|
||||||
|
Icons.star,
|
||||||
|
color: theme.colorScheme.primary,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 2,
|
top: 2,
|
||||||
right: 2,
|
right: 2,
|
||||||
|
|||||||
@ -897,7 +897,8 @@ final class _ProgramExerciseDraft {
|
|||||||
sourceExerciseId: exercise.metadata.id,
|
sourceExerciseId: exercise.metadata.id,
|
||||||
exerciseNameSnapshot: exercise.name,
|
exerciseNameSnapshot: exercise.name,
|
||||||
exerciseDescriptionSnapshot: exercise.description,
|
exerciseDescriptionSnapshot: exercise.description,
|
||||||
exerciseImageMediaIdSnapshot: exercise.imageMediaId,
|
exerciseImageMediaIdSnapshot:
|
||||||
|
exercise.iconMediaId ?? exercise.imageMediaId,
|
||||||
exerciseImageMediaIdsSnapshot: exercise.imageMediaIds,
|
exerciseImageMediaIdsSnapshot: exercise.imageMediaIds,
|
||||||
exerciseVideoMediaIdSnapshot: exercise.videoMediaId,
|
exerciseVideoMediaIdSnapshot: exercise.videoMediaId,
|
||||||
exerciseArchivedSnapshot: exercise.archivedAt != null,
|
exerciseArchivedSnapshot: exercise.archivedAt != null,
|
||||||
|
|||||||
@ -225,6 +225,72 @@ void main() {
|
|||||||
expect(updated.imageMediaId, 'media-1');
|
expect(updated.imageMediaId, 'media-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Exercise icon can be set to an image from the gallery', () async {
|
||||||
|
final repository = _FakeExerciseRepository()
|
||||||
|
..exercise = Exercise(
|
||||||
|
metadata: _metadata('exercise-1'),
|
||||||
|
name: 'Squat',
|
||||||
|
imageMediaIds: const ['media-1', 'media-2'],
|
||||||
|
hasTimeMeasure: false,
|
||||||
|
hasRepsMeasure: true,
|
||||||
|
hasScoreMeasure: false,
|
||||||
|
defaultTargetReps: 10,
|
||||||
|
);
|
||||||
|
final useCase = _exerciseUseCase(repository);
|
||||||
|
|
||||||
|
final updated = await useCase.setIcon(
|
||||||
|
exerciseId: 'exercise-1',
|
||||||
|
mediaAssetId: 'media-2',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(updated.iconMediaId, 'media-2');
|
||||||
|
expect(repository.saved.single.iconMediaId, 'media-2');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Exercise icon rejects images outside the gallery', () async {
|
||||||
|
final repository = _FakeExerciseRepository()
|
||||||
|
..exercise = Exercise(
|
||||||
|
metadata: _metadata('exercise-1'),
|
||||||
|
name: 'Squat',
|
||||||
|
imageMediaIds: const ['media-1'],
|
||||||
|
hasTimeMeasure: false,
|
||||||
|
hasRepsMeasure: true,
|
||||||
|
hasScoreMeasure: false,
|
||||||
|
defaultTargetReps: 10,
|
||||||
|
);
|
||||||
|
final useCase = _exerciseUseCase(repository);
|
||||||
|
|
||||||
|
await expectLater(
|
||||||
|
useCase.setIcon(exerciseId: 'exercise-1', mediaAssetId: 'media-2'),
|
||||||
|
throwsA(isA<DomainException>()),
|
||||||
|
);
|
||||||
|
expect(repository.saved, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Exercise icon is reset when its image is removed', () async {
|
||||||
|
final repository = _FakeExerciseRepository()
|
||||||
|
..exercise = Exercise(
|
||||||
|
metadata: _metadata('exercise-1'),
|
||||||
|
name: 'Squat',
|
||||||
|
imageMediaIds: const ['media-1', 'media-2'],
|
||||||
|
iconMediaId: 'media-2',
|
||||||
|
hasTimeMeasure: false,
|
||||||
|
hasRepsMeasure: true,
|
||||||
|
hasScoreMeasure: false,
|
||||||
|
defaultTargetReps: 10,
|
||||||
|
);
|
||||||
|
final useCase = _exerciseUseCase(repository);
|
||||||
|
|
||||||
|
final updated = await useCase.removeImage(
|
||||||
|
exerciseId: 'exercise-1',
|
||||||
|
mediaAssetId: 'media-2',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(updated.imageMediaIds, ['media-1']);
|
||||||
|
expect(updated.iconMediaId, isNull);
|
||||||
|
expect(repository.saved.single.iconMediaId, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
test('program exercise snapshot keeps the full image gallery', () async {
|
test('program exercise snapshot keeps the full image gallery', () async {
|
||||||
final exerciseRepository = _FakeExerciseRepository()
|
final exerciseRepository = _FakeExerciseRepository()
|
||||||
..exercise = Exercise(
|
..exercise = Exercise(
|
||||||
|
|||||||
@ -216,6 +216,72 @@ void main() {
|
|||||||
expect(find.text('Aucune image sélectionnée'), findsOneWidget);
|
expect(find.text('Aucune image sélectionnée'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('désigner une image comme icône l’indique visuellement', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
final exerciseRepository = _FakeExerciseRepository();
|
||||||
|
final storage = _FakeMediaStorage();
|
||||||
|
|
||||||
|
await tester.binding.setSurfaceSize(const Size(400, 1600));
|
||||||
|
addTearDown(() => tester.binding.setSurfaceSize(null));
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: ExerciseFormScreen(
|
||||||
|
exerciseUseCases: _exerciseUseCases(exerciseRepository),
|
||||||
|
mediaUseCases: _mediaUseCases(exerciseRepository, storage: storage),
|
||||||
|
mediaPicker: _FakeMediaPicker(
|
||||||
|
imagePaths: const [
|
||||||
|
'/tmp/imports/photo-1.png',
|
||||||
|
'/tmp/imports/photo-2.png',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.enterText(find.widgetWithText(TextFormField, 'Nom'), 'Squat');
|
||||||
|
await tester.enterText(
|
||||||
|
find.widgetWithText(TextFormField, 'Temps par défaut (s)'),
|
||||||
|
'45',
|
||||||
|
);
|
||||||
|
await tester.tap(find.text('Ajouter une image'));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.tap(find.text('Ajouter une image'));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
await tester.tap(find.byTooltip('Définir comme icône').last);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.byTooltip('Icône choisie'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Enregistrer'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(exerciseRepository.saved.single.iconMediaId, 'id-2');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ExerciseListTile utilise l’icône choisie', (tester) async {
|
||||||
|
final exercise = Exercise(
|
||||||
|
metadata: _metadata('exercise-1'),
|
||||||
|
name: 'Squat',
|
||||||
|
imageMediaIds: const ['image-1', 'image-2'],
|
||||||
|
iconMediaId: 'image-2',
|
||||||
|
hasTimeMeasure: true,
|
||||||
|
hasRepsMeasure: false,
|
||||||
|
hasScoreMeasure: false,
|
||||||
|
defaultTargetTimeSeconds: 45,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(body: ExerciseListTile(exercise: exercise)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.byTooltip('Icône d’exercice image-2'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'supprimer un exercice demande confirmation puis le retire de la liste',
|
'supprimer un exercice demande confirmation puis le retire de la liste',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
|
|||||||
Reference in New Issue
Block a user