import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' as http; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'api_client.g.dart'; // --------------------------------------------------------------------------- // Configuration — set this to your Hostinger domain before building. // --------------------------------------------------------------------------- const String kApiBase = 'https://winded.prymsolutions.com/api'; const String _tokenKey = 'winded_auth_token'; // --------------------------------------------------------------------------- // ApiClient // --------------------------------------------------------------------------- class ApiClient { ApiClient(this._storage); final FlutterSecureStorage _storage; // --- Token management --- Future get token => _storage.read(key: _tokenKey); Future saveToken(String token) => _storage.write(key: _tokenKey, value: token); Future clearToken() => _storage.delete(key: _tokenKey); // --- HTTP helpers --- Future> _headers({bool auth = true}) async { final headers = {'Content-Type': 'application/json'}; if (auth) { final t = await token; if (t != null) headers['Authorization'] = 'Bearer $t'; } return headers; } Uri _uri(String path, [Map? params]) { final uri = Uri.parse('$kApiBase$path'); return params != null ? uri.replace(queryParameters: params) : uri; } Future> get( String path, { Map? params, bool auth = true, }) async { final res = await http.get(_uri(path, params), headers: await _headers(auth: auth)); return _parse(res); } Future> post( String path, Map body, { bool auth = true, }) async { final res = await http.post( _uri(path), headers: await _headers(auth: auth), body: jsonEncode(body), ); return _parse(res); } Future> put( String path, Map body, { Map? params, }) async { final res = await http.put( _uri(path, params), headers: await _headers(), body: jsonEncode(body), ); return _parse(res); } Future> delete( String path, { Map? params, }) async { final res = await http.delete(_uri(path, params), headers: await _headers()); return _parse(res); } Map _parse(http.Response res) { final body = jsonDecode(res.body) as Map; if (res.statusCode >= 400) { throw ApiException( message: (body['error'] as String?) ?? 'Unknown error', statusCode: res.statusCode, ); } return body; } } class ApiException implements Exception { const ApiException({required this.message, required this.statusCode}); final String message; final int statusCode; @override String toString() => 'ApiException($statusCode): $message'; } // --------------------------------------------------------------------------- // Providers // --------------------------------------------------------------------------- @Riverpod(keepAlive: true) ApiClient apiClient(ApiClientRef ref) { return ApiClient(const FlutterSecureStorage()); }