merge(main): correctifs post-QA sur les repositories (ticket #13)
Fusionne feature/#13-repos-persistance directement dans main — petit lot de correctifs post-QA, pas de develop intermédiaire. analyze propre, 24/24 tests verts, build APK debug validé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
6
.ideai/tickets/13/carnet.md
Normal file
6
.ideai/tickets/13/carnet.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
issueRef: "#13"
|
||||||
|
version: 3
|
||||||
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
updatedAt: 1784319234004
|
||||||
|
---
|
||||||
16
.ideai/tickets/13/issue.md
Normal file
16
.ideai/tickets/13/issue.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
id: "da27e09c-79d2-43fa-90e5-3e8ef32e789f"
|
||||||
|
number: 13
|
||||||
|
title: "[DevBackend] Use cases de persistance et reprise du minuteur de repos"
|
||||||
|
status: "closed"
|
||||||
|
priority: "high"
|
||||||
|
sprint: null
|
||||||
|
links: [{"target":"#9","kind":"relatesTo"}]
|
||||||
|
agentRefs: [{"agentId":"10ee045b-1c41-479e-ba03-dceed9edd495","role":"assigned"}]
|
||||||
|
createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
createdAt: 1784318990378
|
||||||
|
updatedAt: 1784319234004
|
||||||
|
version: 3
|
||||||
|
---
|
||||||
|
Ajouter les use cases manquants pour que l'ajustement du minuteur de repos (±15s) soit persisté et que l'écran d'exécution puisse retrouver l'état de repos en cours après une fermeture d'app. lib/application/use_cases.dart expose déjà startRestAfterSet, mais aucun moyen de mettre à jour adjustedRestSeconds ou de marquer skippedAt après création. Le repository (lib/application/ports.dart / lib/infrastructure/local/drift_repositories.dart) expose déjà saveRestState et listRestStates — à réutiliser.
|
||||||
6
.ideai/tickets/14/carnet.md
Normal file
6
.ideai/tickets/14/carnet.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
issueRef: "#14"
|
||||||
|
version: 2
|
||||||
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
updatedAt: 1784319234693
|
||||||
|
---
|
||||||
18
.ideai/tickets/14/issue.md
Normal file
18
.ideai/tickets/14/issue.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
id: "bf12e886-4849-4095-afc9-aa37c61fa257"
|
||||||
|
number: 14
|
||||||
|
title: "[DevFrontend] Repos persistant/reprenable + temps réel par série"
|
||||||
|
status: "inProgress"
|
||||||
|
priority: "high"
|
||||||
|
sprint: null
|
||||||
|
links: [{"target":"#9","kind":"relatesTo"}]
|
||||||
|
agentRefs: [{"agentId":"9933c93a-b8a1-4164-a3bb-7063fdad747d","role":"assigned"}]
|
||||||
|
createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
createdAt: 1784318996196
|
||||||
|
updatedAt: 1784319234693
|
||||||
|
version: 2
|
||||||
|
---
|
||||||
|
Deux corrections sur lib/presentation/workout_execution_screen.dart, trouvées par QA (ticket #11) :
|
||||||
|
1. Les ajustements ±15s du minuteur de repos ne sont modifiés qu'en mémoire (_remainingRestSeconds) et jamais re-persistés — après un kill d'app pendant un repos, l'écran redémarre sur l'exercice actif au lieu de reprendre le décompte de repos exact. À l'ouverture de l'écran, il faut relire l'état de repos actif éventuel (listRestStates / le nouveau use case du ticket dédié) et calculer le temps restant depuis les horodatages persistés, pas repartir de zéro.
|
||||||
|
2. `actualTimeMs` est toujours enregistré à 0 (ligne ~315) même quand la mesure Temps est active pour la série — il faut chronométrer réellement le temps passé sur la série (depuis son démarrage jusqu'à "Terminer la série") et transmettre cette valeur réelle à recordCurrentSetResult.
|
||||||
6
.ideai/tickets/15/carnet.md
Normal file
6
.ideai/tickets/15/carnet.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
issueRef: "#15"
|
||||||
|
version: 1
|
||||||
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
updatedAt: 1784318999121
|
||||||
|
---
|
||||||
16
.ideai/tickets/15/issue.md
Normal file
16
.ideai/tickets/15/issue.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
id: "3463569f-e837-4af9-8156-4968e178d4e1"
|
||||||
|
number: 15
|
||||||
|
title: "[DevFrontend] Sélecteur de fichier pour l'import média (remplace la saisie manuelle de chemin)"
|
||||||
|
status: "open"
|
||||||
|
priority: "medium"
|
||||||
|
sprint: null
|
||||||
|
links: [{"target":"#6","kind":"relatesTo"}]
|
||||||
|
agentRefs: [{"agentId":"9933c93a-b8a1-4164-a3bb-7063fdad747d","role":"assigned"}]
|
||||||
|
createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
|
createdAt: 1784318999121
|
||||||
|
updatedAt: 1784318999121
|
||||||
|
version: 1
|
||||||
|
---
|
||||||
|
L'écran de création/édition d'exercice (lib/presentation/exercise_library_screen.dart) fait actuellement saisir manuellement un chemin de fichier pour importer une image/vidéo. Remplacer par un vrai sélecteur de fichiers via le package `image_picker` (à ajouter en dépendance dans pubspec.yaml — nouvelle dépendance, signalée et acceptée par l'utilisateur). Garder MediaUseCases.importMedia tel quel côté logique métier, seul le déclenchement du chemin source change (sélection graphique au lieu de TextField).
|
||||||
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"nextNumber": 13
|
"nextNumber": 16
|
||||||
}
|
}
|
||||||
@ -144,6 +144,42 @@
|
|||||||
"10ee045b-1c41-479e-ba03-dceed9edd495"
|
"10ee045b-1c41-479e-ba03-dceed9edd495"
|
||||||
],
|
],
|
||||||
"updatedAt": 1784301400489
|
"updatedAt": 1784301400489
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"issueRef": "#13",
|
||||||
|
"path": "13",
|
||||||
|
"title": "[DevBackend] Use cases de persistance et reprise du minuteur de repos",
|
||||||
|
"status": "closed",
|
||||||
|
"priority": "high",
|
||||||
|
"sprint": null,
|
||||||
|
"assignedAgentIds": [
|
||||||
|
"10ee045b-1c41-479e-ba03-dceed9edd495"
|
||||||
|
],
|
||||||
|
"updatedAt": 1784319234004
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"issueRef": "#14",
|
||||||
|
"path": "14",
|
||||||
|
"title": "[DevFrontend] Repos persistant/reprenable + temps réel par série",
|
||||||
|
"status": "inProgress",
|
||||||
|
"priority": "high",
|
||||||
|
"sprint": null,
|
||||||
|
"assignedAgentIds": [
|
||||||
|
"9933c93a-b8a1-4164-a3bb-7063fdad747d"
|
||||||
|
],
|
||||||
|
"updatedAt": 1784319234693
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"issueRef": "#15",
|
||||||
|
"path": "15",
|
||||||
|
"title": "[DevFrontend] Sélecteur de fichier pour l'import média (remplace la saisie manuelle de chemin)",
|
||||||
|
"status": "open",
|
||||||
|
"priority": "medium",
|
||||||
|
"sprint": null,
|
||||||
|
"assignedAgentIds": [
|
||||||
|
"9933c93a-b8a1-4164-a3bb-7063fdad747d"
|
||||||
|
],
|
||||||
|
"updatedAt": 1784318999121
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -80,6 +80,7 @@ abstract interface class ActiveSessionRepository {
|
|||||||
Future<void> save(ActiveWorkoutSession session);
|
Future<void> save(ActiveWorkoutSession session);
|
||||||
Future<void> saveSetResult(ActiveSetResult result);
|
Future<void> saveSetResult(ActiveSetResult result);
|
||||||
Future<void> saveRestState(ActiveRestState restState);
|
Future<void> saveRestState(ActiveRestState restState);
|
||||||
|
Future<ActiveRestState?> findRestStateById(String id);
|
||||||
Future<List<ActiveSetResult>> listSetResults(String sessionId);
|
Future<List<ActiveSetResult>> listSetResults(String sessionId);
|
||||||
Future<List<ActiveRestState>> listRestStates(String sessionId);
|
Future<List<ActiveRestState>> listRestStates(String sessionId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -803,6 +803,50 @@ final class ActiveWorkoutSessionUseCases {
|
|||||||
return rest;
|
return rest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ActiveRestState> adjustRestSeconds({
|
||||||
|
required String restStateId,
|
||||||
|
required int deltaSeconds,
|
||||||
|
}) async {
|
||||||
|
final rest = await sessionRepository.findRestStateById(restStateId);
|
||||||
|
if (rest == null) {
|
||||||
|
throw const DomainException('Active rest state not found.');
|
||||||
|
}
|
||||||
|
final now = clock.now();
|
||||||
|
final adjusted = rest.copyWith(
|
||||||
|
metadata: rest.metadata.touch(now),
|
||||||
|
adjustedRestSeconds: (rest.adjustedRestSeconds + deltaSeconds).clamp(
|
||||||
|
0,
|
||||||
|
1 << 31,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await sessionRepository.saveRestState(adjusted);
|
||||||
|
return adjusted;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ActiveRestState> skipRest({required String restStateId}) async {
|
||||||
|
final rest = await sessionRepository.findRestStateById(restStateId);
|
||||||
|
if (rest == null) {
|
||||||
|
throw const DomainException('Active rest state not found.');
|
||||||
|
}
|
||||||
|
final now = clock.now();
|
||||||
|
final skipped = rest.copyWith(
|
||||||
|
metadata: rest.metadata.touch(now),
|
||||||
|
skippedAt: now,
|
||||||
|
);
|
||||||
|
await sessionRepository.saveRestState(skipped);
|
||||||
|
return skipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ActiveRestState?> findActiveRest({required String sessionId}) async {
|
||||||
|
final restStates = await sessionRepository.listRestStates(sessionId);
|
||||||
|
final active =
|
||||||
|
restStates
|
||||||
|
.where((rest) => rest.endedAt == null && rest.skippedAt == null)
|
||||||
|
.toList()
|
||||||
|
..sort((left, right) => right.startedAt.compareTo(left.startedAt));
|
||||||
|
return active.isEmpty ? null : active.first;
|
||||||
|
}
|
||||||
|
|
||||||
Future<ActiveWorkoutSession> _requiredSession(String sessionId) async {
|
Future<ActiveWorkoutSession> _requiredSession(String sessionId) async {
|
||||||
final session = await sessionRepository.findById(sessionId);
|
final session = await sessionRepository.findById(sessionId);
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
|
|||||||
@ -631,6 +631,28 @@ final class ActiveRestState {
|
|||||||
final DateTime startedAt;
|
final DateTime startedAt;
|
||||||
final DateTime? endedAt;
|
final DateTime? endedAt;
|
||||||
final DateTime? skippedAt;
|
final DateTime? skippedAt;
|
||||||
|
|
||||||
|
ActiveRestState copyWith({
|
||||||
|
EntityMetadata? metadata,
|
||||||
|
int? adjustedRestSeconds,
|
||||||
|
Object? endedAt = _unchanged,
|
||||||
|
Object? skippedAt = _unchanged,
|
||||||
|
}) {
|
||||||
|
return ActiveRestState(
|
||||||
|
metadata: metadata ?? this.metadata,
|
||||||
|
activeWorkoutSessionId: activeWorkoutSessionId,
|
||||||
|
afterProgramIndex: afterProgramIndex,
|
||||||
|
afterExerciseIndex: afterExerciseIndex,
|
||||||
|
afterSetIndex: afterSetIndex,
|
||||||
|
plannedRestSeconds: plannedRestSeconds,
|
||||||
|
adjustedRestSeconds: adjustedRestSeconds ?? this.adjustedRestSeconds,
|
||||||
|
startedAt: startedAt,
|
||||||
|
endedAt: endedAt == _unchanged ? this.endedAt : endedAt as DateTime?,
|
||||||
|
skippedAt: skippedAt == _unchanged
|
||||||
|
? this.skippedAt
|
||||||
|
: skippedAt as DateTime?,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class WorkoutHistory {
|
final class WorkoutHistory {
|
||||||
|
|||||||
@ -398,6 +398,14 @@ final class DriftActiveSessionRepository implements ActiveSessionRepository {
|
|||||||
.insertOnConflictUpdate(_activeRestStateCompanion(restState));
|
.insertOnConflictUpdate(_activeRestStateCompanion(restState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<domain.ActiveRestState?> findRestStateById(String id) async {
|
||||||
|
final row = await (database.select(
|
||||||
|
database.activeRestStates,
|
||||||
|
)..where((table) => table.id.equals(id))).getSingleOrNull();
|
||||||
|
return row == null ? null : _activeRestStateFromRow(row);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<domain.ActiveSetResult>> listSetResults(String sessionId) async {
|
Future<List<domain.ActiveSetResult>> listSetResults(String sessionId) async {
|
||||||
final rows =
|
final rows =
|
||||||
|
|||||||
@ -111,6 +111,104 @@ void main() {
|
|||||||
clock.value = clock.value.add(const Duration(seconds: 15));
|
clock.value = clock.value.add(const Duration(seconds: 15));
|
||||||
expect(resumed.elapsedActiveMillisecondsAt(clock.now()), 45000);
|
expect(resumed.elapsedActiveMillisecondsAt(clock.now()), 45000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('adjustRestSeconds persists adjusted rest duration', () async {
|
||||||
|
final clock = _FakeClock(DateTime.utc(2026, 7, 17, 12));
|
||||||
|
final repository = _FakeActiveSessionRepository()
|
||||||
|
..restStates['rest-1'] = ActiveRestState(
|
||||||
|
metadata: _metadata('rest-1'),
|
||||||
|
activeWorkoutSessionId: 'session-1',
|
||||||
|
afterProgramIndex: 0,
|
||||||
|
afterExerciseIndex: 0,
|
||||||
|
afterSetIndex: 0,
|
||||||
|
plannedRestSeconds: 60,
|
||||||
|
adjustedRestSeconds: 60,
|
||||||
|
startedAt: clock.now(),
|
||||||
|
);
|
||||||
|
final useCase = _activeUseCase(repository, clock);
|
||||||
|
|
||||||
|
final adjusted = await useCase.adjustRestSeconds(
|
||||||
|
restStateId: 'rest-1',
|
||||||
|
deltaSeconds: -75,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(adjusted.adjustedRestSeconds, 0);
|
||||||
|
expect(repository.restStates['rest-1']!.adjustedRestSeconds, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('skipRest persists skippedAt timestamp', () async {
|
||||||
|
final clock = _FakeClock(DateTime.utc(2026, 7, 17, 12));
|
||||||
|
final repository = _FakeActiveSessionRepository()
|
||||||
|
..restStates['rest-1'] = ActiveRestState(
|
||||||
|
metadata: _metadata('rest-1'),
|
||||||
|
activeWorkoutSessionId: 'session-1',
|
||||||
|
afterProgramIndex: 0,
|
||||||
|
afterExerciseIndex: 0,
|
||||||
|
afterSetIndex: 0,
|
||||||
|
plannedRestSeconds: 60,
|
||||||
|
adjustedRestSeconds: 60,
|
||||||
|
startedAt: clock.now(),
|
||||||
|
);
|
||||||
|
clock.value = clock.value.add(const Duration(seconds: 10));
|
||||||
|
final useCase = _activeUseCase(repository, clock);
|
||||||
|
|
||||||
|
final skipped = await useCase.skipRest(restStateId: 'rest-1');
|
||||||
|
|
||||||
|
expect(skipped.skippedAt, clock.now());
|
||||||
|
expect(repository.restStates['rest-1']!.skippedAt, clock.now());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('findActiveRest returns latest non-ended non-skipped rest', () async {
|
||||||
|
final clock = _FakeClock(DateTime.utc(2026, 7, 17, 12));
|
||||||
|
final repository = _FakeActiveSessionRepository()
|
||||||
|
..restStates['ended'] = ActiveRestState(
|
||||||
|
metadata: _metadata('ended'),
|
||||||
|
activeWorkoutSessionId: 'session-1',
|
||||||
|
afterProgramIndex: 0,
|
||||||
|
afterExerciseIndex: 0,
|
||||||
|
afterSetIndex: 0,
|
||||||
|
plannedRestSeconds: 60,
|
||||||
|
adjustedRestSeconds: 60,
|
||||||
|
startedAt: clock.now(),
|
||||||
|
endedAt: clock.now().add(const Duration(seconds: 60)),
|
||||||
|
)
|
||||||
|
..restStates['older-active'] = ActiveRestState(
|
||||||
|
metadata: _metadata('older-active'),
|
||||||
|
activeWorkoutSessionId: 'session-1',
|
||||||
|
afterProgramIndex: 0,
|
||||||
|
afterExerciseIndex: 1,
|
||||||
|
afterSetIndex: 0,
|
||||||
|
plannedRestSeconds: 60,
|
||||||
|
adjustedRestSeconds: 60,
|
||||||
|
startedAt: clock.now().add(const Duration(seconds: 30)),
|
||||||
|
)
|
||||||
|
..restStates['latest-active'] = ActiveRestState(
|
||||||
|
metadata: _metadata('latest-active'),
|
||||||
|
activeWorkoutSessionId: 'session-1',
|
||||||
|
afterProgramIndex: 0,
|
||||||
|
afterExerciseIndex: 2,
|
||||||
|
afterSetIndex: 0,
|
||||||
|
plannedRestSeconds: 60,
|
||||||
|
adjustedRestSeconds: 60,
|
||||||
|
startedAt: clock.now().add(const Duration(seconds: 90)),
|
||||||
|
)
|
||||||
|
..restStates['skipped'] = ActiveRestState(
|
||||||
|
metadata: _metadata('skipped'),
|
||||||
|
activeWorkoutSessionId: 'session-1',
|
||||||
|
afterProgramIndex: 0,
|
||||||
|
afterExerciseIndex: 3,
|
||||||
|
afterSetIndex: 0,
|
||||||
|
plannedRestSeconds: 60,
|
||||||
|
adjustedRestSeconds: 60,
|
||||||
|
startedAt: clock.now().add(const Duration(seconds: 120)),
|
||||||
|
skippedAt: clock.now().add(const Duration(seconds: 125)),
|
||||||
|
);
|
||||||
|
final useCase = _activeUseCase(repository, clock);
|
||||||
|
|
||||||
|
final active = await useCase.findActiveRest(sessionId: 'session-1');
|
||||||
|
|
||||||
|
expect(active?.metadata.id, 'latest-active');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityMetadata _metadata(String id) {
|
EntityMetadata _metadata(String id) {
|
||||||
@ -181,3 +279,51 @@ final class _FakeProgramRepository implements ProgramRepository {
|
|||||||
@override
|
@override
|
||||||
Future<void> saveExercise(ProgramExercise exercise) async {}
|
Future<void> saveExercise(ProgramExercise exercise) async {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActiveWorkoutSessionUseCases _activeUseCase(
|
||||||
|
_FakeActiveSessionRepository repository,
|
||||||
|
_FakeClock clock,
|
||||||
|
) {
|
||||||
|
return ActiveWorkoutSessionUseCases(
|
||||||
|
sessionRepository: repository,
|
||||||
|
templateRepository: _FakeWorkoutTemplateRepository(),
|
||||||
|
clock: clock,
|
||||||
|
ids: _FakeIds(),
|
||||||
|
originDeviceId: 'device-1',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final class _FakeActiveSessionRepository implements ActiveSessionRepository {
|
||||||
|
final restStates = <String, ActiveRestState>{};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ActiveWorkoutSession?> findById(String id) async => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ActiveWorkoutSession?> findOpen() async => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ActiveRestState?> findRestStateById(String id) async => restStates[id];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<ActiveRestState>> listRestStates(String sessionId) async {
|
||||||
|
return restStates.values
|
||||||
|
.where((rest) => rest.activeWorkoutSessionId == sessionId)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<ActiveSetResult>> listSetResults(String sessionId) async =>
|
||||||
|
const [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> save(ActiveWorkoutSession session) async {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> saveRestState(ActiveRestState restState) async {
|
||||||
|
restStates[restState.metadata.id] = restState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> saveSetResult(ActiveSetResult result) async {}
|
||||||
|
}
|
||||||
|
|||||||
@ -284,6 +284,9 @@ final class _FakeActiveSessionRepository implements ActiveSessionRepository {
|
|||||||
@override
|
@override
|
||||||
Future<ActiveWorkoutSession?> findOpen() async => null;
|
Future<ActiveWorkoutSession?> findOpen() async => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ActiveRestState?> findRestStateById(String id) async => null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<ActiveRestState>> listRestStates(String sessionId) async {
|
Future<List<ActiveRestState>> listRestStates(String sessionId) async {
|
||||||
return const [];
|
return const [];
|
||||||
|
|||||||
@ -230,6 +230,9 @@ final class _FakeActiveSessionRepository implements ActiveSessionRepository {
|
|||||||
@override
|
@override
|
||||||
Future<ActiveWorkoutSession?> findOpen() async => session;
|
Future<ActiveWorkoutSession?> findOpen() async => session;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ActiveRestState?> findRestStateById(String id) async => null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<ActiveRestState>> listRestStates(String sessionId) async {
|
Future<List<ActiveRestState>> listRestStates(String sessionId) async {
|
||||||
return const [];
|
return const [];
|
||||||
|
|||||||
Reference in New Issue
Block a user