Ajoute l'adapter API distant (infrastructure/remote/auth_api.dart, http_api_client.dart) et le stockage sécurisé du token d'auth (infrastructure/security/secure_storage_auth_token_store.dart), câblés dans app_bootstrap.dart. Étend le modèle Drift (migration schemaVersion 9→10) et la couche application (ports, use cases, entités) pour la session de compte. flutter pub get OK (ajout http, flutter_secure_storage), build_runner OK, dart format appliqué, analyze propre (mêmes infos préexistantes), 109/109 tests verts, build APK debug validé. Premier ticket du chantier "Ajouter les features serveur au client" (#63). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
210 lines
5.6 KiB
Dart
210 lines
5.6 KiB
Dart
import '../domain/domain.dart';
|
|
|
|
abstract interface class Clock {
|
|
DateTime now();
|
|
}
|
|
|
|
final class SystemClock implements Clock {
|
|
const SystemClock();
|
|
|
|
@override
|
|
DateTime now() => DateTime.now().toUtc();
|
|
}
|
|
|
|
abstract interface class IdGenerator {
|
|
String newId();
|
|
}
|
|
|
|
enum RemoteAuthFailure {
|
|
invalidCredentials,
|
|
emailAlreadyUsed,
|
|
network,
|
|
unknown,
|
|
}
|
|
|
|
final class RemoteAuthException implements Exception {
|
|
const RemoteAuthException(this.failure, [this.message]);
|
|
|
|
final RemoteAuthFailure failure;
|
|
final String? message;
|
|
|
|
@override
|
|
String toString() => message ?? failure.name;
|
|
}
|
|
|
|
final class RemoteAuthResult {
|
|
const RemoteAuthResult({
|
|
required this.userId,
|
|
required this.email,
|
|
required this.token,
|
|
required this.expiresAt,
|
|
});
|
|
|
|
final String userId;
|
|
final String email;
|
|
final String token;
|
|
final DateTime expiresAt;
|
|
}
|
|
|
|
abstract interface class AuthTokenStore {
|
|
Future<void> saveToken(String token, DateTime expiresAt);
|
|
Future<String?> readToken();
|
|
Future<void> clearToken();
|
|
}
|
|
|
|
abstract interface class OnlineAccountRepository {
|
|
Future<UserAccountSession?> currentSession();
|
|
Future<void> saveSession(UserAccountSession session);
|
|
Future<void> clearSession();
|
|
}
|
|
|
|
abstract interface class RemoteAuthApi {
|
|
Future<RemoteAuthResult> register({
|
|
required String email,
|
|
required String password,
|
|
String? displayName,
|
|
});
|
|
|
|
Future<RemoteAuthResult> login({
|
|
required String email,
|
|
required String password,
|
|
});
|
|
|
|
Future<void> logout(String token);
|
|
}
|
|
|
|
abstract interface class ExerciseRepository {
|
|
Future<Exercise?> findById(String id);
|
|
Future<List<Exercise>> listActive();
|
|
Future<bool> isReferencedByProgram(String id);
|
|
Future<void> save(Exercise exercise);
|
|
}
|
|
|
|
final class StoredMediaFile {
|
|
const StoredMediaFile({
|
|
required this.localUri,
|
|
required this.mimeType,
|
|
required this.sizeBytes,
|
|
this.width,
|
|
this.height,
|
|
this.durationMs,
|
|
});
|
|
|
|
final String localUri;
|
|
final String? mimeType;
|
|
final int sizeBytes;
|
|
final int? width;
|
|
final int? height;
|
|
final int? durationMs;
|
|
}
|
|
|
|
abstract interface class LocalMediaStorage {
|
|
Future<StoredMediaFile> importFile({
|
|
required String sourcePath,
|
|
required MediaKind kind,
|
|
required String stableFileName,
|
|
});
|
|
|
|
Future<Set<String>> listManagedLocalUris();
|
|
Future<void> deleteByLocalUri(String localUri);
|
|
}
|
|
|
|
abstract interface class MediaAssetRepository {
|
|
Future<MediaAsset?> findById(String id);
|
|
Future<List<MediaAsset>> listActive();
|
|
Future<void> save(MediaAsset mediaAsset);
|
|
}
|
|
|
|
abstract interface class ProgramRepository {
|
|
Future<Program?> findById(String id);
|
|
Future<List<Program>> listActive();
|
|
Future<void> save(Program program);
|
|
Future<void> saveExercise(ProgramExercise exercise);
|
|
Future<void> replaceExercises(Program program, DateTime deletedAt);
|
|
}
|
|
|
|
abstract interface class WorkoutTemplateRepository {
|
|
Future<WorkoutTemplate?> findById(String id);
|
|
Future<List<WorkoutTemplate>> listActive();
|
|
Future<void> save(WorkoutTemplate template);
|
|
Future<void> saveProgram(WorkoutTemplateProgram program);
|
|
Future<void> saveOverride(WorkoutTemplateExerciseOverride override);
|
|
Future<void> replaceComposition(WorkoutTemplate template, DateTime deletedAt);
|
|
}
|
|
|
|
abstract interface class ActiveSessionRepository {
|
|
Future<ActiveWorkoutSession?> findById(String id);
|
|
Future<ActiveWorkoutSession?> findOpen();
|
|
Future<void> save(ActiveWorkoutSession session);
|
|
Future<void> saveSetResult(ActiveSetResult result);
|
|
Future<void> saveRestState(ActiveRestState restState);
|
|
Future<void> saveScoreStopwatchState(ActiveScoreStopwatchState state);
|
|
Future<void> saveExerciseStepProgressState(
|
|
ActiveExerciseStepProgressState state,
|
|
);
|
|
Future<void> saveExerciseStepResult(ActiveExerciseStepResult result);
|
|
Future<void> deleteScoreStopwatchState({
|
|
required String sessionId,
|
|
required int programIndex,
|
|
required int exerciseIndex,
|
|
required int setIndex,
|
|
required DateTime deletedAt,
|
|
});
|
|
Future<ActiveRestState?> findRestStateById(String id);
|
|
Future<ActiveScoreStopwatchState?> findScoreStopwatchState({
|
|
required String sessionId,
|
|
required int programIndex,
|
|
required int exerciseIndex,
|
|
required int setIndex,
|
|
});
|
|
Future<ActiveExerciseStepProgressState?> findExerciseStepProgressState({
|
|
required String sessionId,
|
|
required int programIndex,
|
|
required int exerciseIndex,
|
|
required int setIndex,
|
|
});
|
|
Future<List<ActiveSetResult>> listSetResults(String sessionId);
|
|
Future<List<ActiveExerciseStepProgressState>> listExerciseStepProgressStates(
|
|
String sessionId,
|
|
);
|
|
Future<List<ActiveExerciseStepResult>> listExerciseStepResults(
|
|
String sessionId,
|
|
);
|
|
Future<List<ActiveRestState>> listRestStates(String sessionId);
|
|
Future<List<ActiveScoreStopwatchState>> listScoreStopwatchStates(
|
|
String sessionId,
|
|
);
|
|
}
|
|
|
|
abstract interface class WorkoutHistoryRepository {
|
|
Future<WorkoutHistory?> findById(String id);
|
|
Future<List<WorkoutHistory>> listActive();
|
|
Future<void> save(WorkoutHistory history);
|
|
Future<void> saveSetResult(WorkoutHistorySetResult result);
|
|
Future<void> saveStepResult(WorkoutHistoryStepResult result);
|
|
Future<void> delete(String id, DateTime deletedAt);
|
|
}
|
|
|
|
final class SyncRunSummary {
|
|
const SyncRunSummary({
|
|
required this.pushedChanges,
|
|
required this.pulledChanges,
|
|
});
|
|
|
|
final int pushedChanges;
|
|
final int pulledChanges;
|
|
}
|
|
|
|
abstract interface class SyncGateway {
|
|
Future<SyncRunSummary> synchronize();
|
|
}
|
|
|
|
final class NoOpSyncGateway implements SyncGateway {
|
|
const NoOpSyncGateway();
|
|
|
|
@override
|
|
Future<SyncRunSummary> synchronize() async {
|
|
return const SyncRunSummary(pushedChanges: 0, pulledChanges: 0);
|
|
}
|
|
}
|