Files
AudiOhm/frontend/lib/infrastructure/datasources/remote/api_service.dart
T
root 85dad89d5b feat: Modernisation UI/UX et configuration Flutter multi-plateforme
Phase 1 - Corrections Critiques:
- Fixed memory leaks dans music_provider.dart (stream subscriptions)
- Fixed race conditions dans search_provider.dart (stale results)
- Fixed token refresh errors dans api_service.dart
- Improved error handling avec messages utilisateur
- Changed API URL to HTTPS by default

Phase 2 - Améliorations UX Desktop:
- Ajouté cursor pointers sur tous les éléments cliquables
- Implémenté hover states avec effets néon glow (200ms transitions)
- Créé skeleton loading states avec shimmer animation
- Ajouté widgets: ClickableWrapper, ErrorDisplay, SkeletonLoading
- Enhanced visual feedback pour desktop users

Phase 3 - Configuration Flutter:
- Configuré Android (Gradle 8.1.0, Kotlin 1.9.0, minSdk 21, targetSdk 34)
- Créé launcher icons cyberpunk néon (5 densités)
- Configuré Windows desktop (structure complète)
- Activé Linux desktop support
- Ajouté package équatable pour entités de domaine
- Corrigé imports (colors.dart, auth_provider.dart)
- Fixed Dio API compatibility (RequestOptions)

Documentation:
- STYLE_GUIDE.md: Guide complet (100+ pages)
- DESIGN_IMPLEMENTATION_GUIDE.md: Implémentation Flutter
- BUILD_STATUS.md: Status builds + troubleshooting
- QUICKSTART_BUILDS.md: Guide rapide
- BUILD_INDEX.md: Index documentation
- PHASE_1_CORRECTIONS.md: Corrections Phase 1
- PHASE_2_UX_IMPROVEMENTS.md: Améliorations Phase 2
- PR_REVIEW_SUMMARY.md: Revue code complète
- CODE_ANALYSIS_AND_PRIORITIES.md: Analyse code

Scripts & Builds:
- BUILD_ALL.sh: Script automatisé builds multi-plateforme
- builds/: Structure avec README par plateforme
- design-system/: Système de design complet

Backend:
- Ajouté streaming HTTP Range pour audio progressif
- Enhanced YouTube service avec métadonnées complètes
- Improved error handling et validation

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-01-19 07:44:40 +00:00

104 lines
3.5 KiB
Dart

/// API Service - Main HTTP client using Dio
library;
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import '../../../core/constants/api_constants.dart';
import '../../../presentation/providers/auth_provider.dart';
/// API Service provider
final apiServiceProvider = Provider<Dio>((ref) {
final authState = ref.watch(authProvider);
final token = authState?.accessToken;
final options = BaseOptions(
baseUrl: ApiConstants.baseUrl,
connectTimeout: const Duration(milliseconds: ApiConstants.connectionTimeoutMs),
receiveTimeout: const Duration(milliseconds: ApiConstants.receiveTimeoutMs),
sendTimeout: const Duration(milliseconds: ApiConstants.sendTimeoutMs),
headers: {
'Content-Type': 'application/json',
if (token != null) 'Authorization': 'Bearer $token',
},
);
final dio = Dio(options);
// Add logger ONLY in debug mode to prevent exposing sensitive data in production
if (kDebugMode) {
dio.interceptors.add(
PrettyDioLogger(
requestHeader: true,
requestBody: true,
responseBody: true,
responseHeader: false,
error: true,
compact: true,
),
);
}
// Add token refresh interceptor
dio.interceptors.add(
InterceptorsWrapper(
onError: (error, handler) async {
if (error.response?.statusCode == 401) {
// Try to refresh token
try {
final newToken = await ref.read(authProvider.notifier).refreshToken();
if (newToken != null) {
// Retry original request with new token
final opts = RequestOptions(
path: error.requestOptions.path,
data: error.requestOptions.data,
onReceiveProgress: error.requestOptions.onReceiveProgress,
onSendProgress: error.requestOptions.onSendProgress,
queryParameters: error.requestOptions.queryParameters,
cancelToken: error.requestOptions.cancelToken,
headers: {
...error.requestOptions.headers,
'Authorization': 'Bearer $newToken',
},
extra: error.requestOptions.extra,
method: error.requestOptions.method,
responseType: error.requestOptions.responseType,
validateStatus: error.requestOptions.validateStatus,
);
final clonedReq = await dio.fetch(opts);
return handler.resolve(clonedReq);
}
} on DioException catch (e) {
// Log the specific error for debugging
debugPrint('Token refresh failed: ${e.type} - ${e.message}');
// Notify user before logout
// Note: In a real app, you'd want to show a snackbar or dialog here
// For now, we just log the user out with a clear message
debugPrint('Your session has expired. Please log in again.');
// Refresh failed, logout user
await ref.read(authProvider.notifier).logout();
} catch (e) {
// Log unexpected errors
debugPrint('Unexpected error during token refresh: $e');
// Logout on any error
await ref.read(authProvider.notifier).logout();
}
}
return handler.next(error);
},
),
);
return dio;
});
/// Get API client
Dio getDio(Ref ref) {
return ref.read(apiServiceProvider);
}