1+ import 'dart:async' ;
12import 'package:dio/dio.dart' ;
23import 'package:flutter_secure_storage/flutter_secure_storage.dart' ;
4+ import 'package:connectivity_plus/connectivity_plus.dart' ;
5+ import 'package:progres/core/network/cache_manager.dart' ;
36
47class ApiClient {
58 static const String baseUrl = 'https://progres.mesrs.dz/api' ;
69 late final Dio _dio;
710 final FlutterSecureStorage _secureStorage;
11+ late final CacheManager _cacheManager;
12+ final Duration _shortTimeout = const Duration (seconds: 5 );
13+ final Connectivity _connectivity = Connectivity ();
814
915 ApiClient ({FlutterSecureStorage ? secureStorage})
1016 : _secureStorage = secureStorage ?? const FlutterSecureStorage () {
@@ -31,6 +37,12 @@ class ApiClient {
3137 },
3238 ),
3339 );
40+ CacheManager .getInstance ().then ((value) => _cacheManager = value);
41+ }
42+
43+ Future <bool > get isConnected async {
44+ final result = await _connectivity.checkConnectivity ();
45+ return result != ConnectivityResult .none;
3446 }
3547
3648 Future <void > saveToken (String token) async {
@@ -64,14 +76,61 @@ class ApiClient {
6476 await _secureStorage.delete (key: 'etablissement_id' );
6577 }
6678
79+ // Generate a cache key string based on path and query parameters
80+ String _cacheKey (String path, Map <String , dynamic >? queryParameters) {
81+ final queryStr =
82+ queryParameters != null
83+ ? Uri (queryParameters: queryParameters).query
84+ : '' ;
85+ return '$path ?$queryStr ' ;
86+ }
87+
6788 Future <Response > get (
6889 String path, {
6990 Map <String , dynamic >? queryParameters,
7091 }) async {
92+ final key = _cacheKey (path, queryParameters);
93+
94+ if (! await isConnected) {
95+ // offline - use cached data if available
96+ final cachedData = _cacheManager.getCache (key);
97+ if (cachedData != null ) {
98+ return Response (
99+ requestOptions: RequestOptions (path: path),
100+ data: cachedData,
101+ statusCode: 200 ,
102+ );
103+ } else {
104+ // No cache, throw offline error
105+ throw DioException (
106+ requestOptions: RequestOptions (path: path),
107+ error: 'No internet connection and no cached data' ,
108+ );
109+ }
110+ }
111+
71112 try {
72- final response = await _dio.get (path, queryParameters: queryParameters);
113+ // Try to get fresh data with a short timeout for fast fallback on slow responses
114+ final response = await _dio.get (
115+ path,
116+ queryParameters: queryParameters,
117+ options: Options (
118+ sendTimeout: _shortTimeout,
119+ receiveTimeout: _shortTimeout,
120+ ),
121+ );
122+ await _cacheManager.saveCache (key, response.data);
73123 return response;
74124 } catch (e) {
125+ // On failure, return cached data if available
126+ final cachedData = _cacheManager.getCache (key);
127+ if (cachedData != null ) {
128+ return Response (
129+ requestOptions: RequestOptions (path: path),
130+ data: cachedData,
131+ statusCode: 200 ,
132+ );
133+ }
75134 rethrow ;
76135 }
77136 }
@@ -95,6 +154,24 @@ class WebApiClient extends ApiClient {
95154 String path, {
96155 Map <String , dynamic >? queryParameters,
97156 }) async {
157+ final key = _cacheKey (path, queryParameters);
158+
159+ if (! await isConnected) {
160+ final cachedData = _cacheManager.getCache (key);
161+ if (cachedData != null ) {
162+ return Response (
163+ requestOptions: RequestOptions (path: path),
164+ data: cachedData,
165+ statusCode: 200 ,
166+ );
167+ } else {
168+ throw DioException (
169+ requestOptions: RequestOptions (path: path),
170+ error: 'No internet connection and no cached data' ,
171+ );
172+ }
173+ }
174+
98175 try {
99176 final Map <String , dynamic > proxyQueryParams = {
100177 'endpoint' : "api" + path,
@@ -104,9 +181,22 @@ class WebApiClient extends ApiClient {
104181 final response = await _dio.get (
105182 proxyBaseUrl,
106183 queryParameters: proxyQueryParams,
184+ options: Options (
185+ sendTimeout: _shortTimeout,
186+ receiveTimeout: _shortTimeout,
187+ ),
107188 );
189+ await _cacheManager.saveCache (key, response.data);
108190 return response;
109191 } catch (e) {
192+ final cachedData = _cacheManager.getCache (key);
193+ if (cachedData != null ) {
194+ return Response (
195+ requestOptions: RequestOptions (path: path),
196+ data: cachedData,
197+ statusCode: 200 ,
198+ );
199+ }
110200 rethrow ;
111201 }
112202 }
0 commit comments