Files
AudiOhm/frontend/lib/infrastructure/datasources/remote/auth_api_service.dart
T
root a89c7894cf Initial commit: AudiOhm - Alternative Spotify avec streaming YouTube
Backend:
- FastAPI avec PostgreSQL et Redis
- Authentification JWT complète
- API REST pour musique, playlists, recherche
- Streaming audio via yt-dlp
- SQLAlchemy 2.0 async

Frontend:
- Flutter avec thème néon cyberpunk
- State management Riverpod
- Layout adaptatif desktop/mobile
- Lecteur audio avec mini-player

Infrastructure:
- Docker Compose (PostgreSQL + Redis)
- Scripts d'installation automatisés
- Scripts de build pour exécutables

Fichiers ajoutés:
- BUILD_CLIENT_*.bat/sh: Scripts de compilation
- BUILD_CLIENT_README.md: Documentation compilation
- CHECK_FLUTTER.sh: Vérificateur d'environnement
- requirements.txt mis à jour pour Python 3.13
- Modèles SQLAlchemy corrigés (metadata -> extra_metadata)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-18 20:08:36 +00:00

186 lines
4.8 KiB
Dart

/// Auth API Service
library;
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/constants/api_constants.dart';
import '../../../domain/entities/user.dart';
import 'api_service.dart';
/// Auth API response models
class LoginResponse {
final String accessToken;
final String refreshToken;
final int expiresIn;
final User user;
LoginResponse({
required this.accessToken,
required this.refreshToken,
required this.expiresIn,
required this.user,
});
factory LoginResponse.fromJson(Map<String, dynamic> json) {
return LoginResponse(
accessToken: json['access_token'] as String,
refreshToken: json['refresh_token'] as String,
expiresIn: json['expires_in'] as int,
user: User.fromJson(json['user'] as Map<String, dynamic>),
);
}
}
/// Extension on User for JSON serialization
extension UserJson on User {
static User fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as String,
email: json['email'] as String,
username: json['username'] as String,
displayName: json['display_name'] as String?,
avatarUrl: json['avatar_url'] as String?,
isPremium: json['is_premium'] as bool? ?? false,
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'email': email,
'username': username,
if (displayName != null) 'display_name': displayName,
if (avatarUrl != null) 'avatar_url': avatarUrl,
'is_premium': isPremium,
'created_at': createdAt.toIso8601String(),
'updated_at': updatedAt.toIso8601String(),
};
}
}
/// Auth API Service
class AuthApiService {
AuthApiService(this._dio);
final Dio _dio;
/// Login with email and password
Future<LoginResponse> login(String email, String password) async {
try {
final response = await _dio.post(
ApiConstants.login,
data: {
'email': email,
'password': password,
},
);
return LoginResponse.fromJson(response.data);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Register a new user
Future<LoginResponse> register({
required String email,
required String username,
required String password,
String? displayName,
}) async {
try {
final response = await _dio.post(
ApiConstants.register,
data: {
'email': email,
'username': username,
'password': password,
if (displayName != null) 'display_name': displayName,
},
);
return LoginResponse.fromJson(response.data);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Refresh access token
Future<Map<String, dynamic>> refreshToken(String refreshToken) async {
try {
final response = await _dio.post(
ApiConstants.refresh,
data: {'refresh_token': refreshToken},
);
return response.data;
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Get current user profile
Future<User> getCurrentUser() async {
try {
final response = await _dio.get(ApiConstants.me);
return UserJson.fromJson(response.data);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Update user profile
Future<User> updateProfile({
String? displayName,
String? avatarUrl,
}) async {
try {
final response = await _dio.put(
ApiConstants.me,
data: {
if (displayName != null) 'display_name': displayName,
if (avatarUrl != null) 'avatar_url': avatarUrl,
},
);
return UserJson.fromJson(response.data);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// Logout
Future<void> logout() async {
try {
await _dio.post(ApiConstants.logout);
} on DioException catch (e) {
throw _handleDioError(e);
}
}
Exception _handleDioError(DioException error) {
if (error.response != null) {
final statusCode = error.response!.statusCode;
final message = error.response!.data['detail'] as String? ??
'An error occurred';
return Exception('$statusCode: $message');
} else if (error.type == DioExceptionType.connectionTimeout) {
return const Exception('Connection timeout');
} else if (error.type == DioExceptionType.receiveTimeout) {
return const Exception('Receive timeout');
} else {
return Exception('Network error: ${error.message}');
}
}
}
/// Provider for Auth API Service
final authApiServiceProvider = Provider<AuthApiService>((ref) {
final dio = ref.watch(apiServiceProvider);
return AuthApiService(dio);
});