From 664e89f2b85e3f99ea822965cd238ac3e61019e6 Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Tue, 9 Dec 2025 17:20:28 +0100 Subject: [PATCH] feat: Add initial Flutter Android project setup, core API client with authentication token management, and authentication service. --- android/app/build.gradle.kts | 2 +- lib/core/api/api_client.dart | 38 +++++++++++++++---------- lib/core/services/auth_api_service.dart | 10 +++---- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 915242d..a8a12b0 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.xtremflow" + applicationId = "com.xtremflow.mobile" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index dcfa6c5..ccebe81 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -1,5 +1,5 @@ import 'package:dio/dio.dart'; -import 'dart:html' as html; +import 'package:shared_preferences/shared_preferences.dart'; /// API Client for communicating with the backend class ApiClient { @@ -26,39 +26,47 @@ class ApiClient { /// Get base URL (same origin for production) String _getBaseUrl() { - // Use current origin for API calls + // For mobile, this needs to be configured or passed in. + // For now, returning empty string implies relative path (works for web). + // TODO: Configure base URL for mobile return ''; } /// Set authentication token - void setToken(String? token) { + Future setToken(String? token) async { _token = token; if (token != null) { _dio.options.headers['Authorization'] = 'Bearer $token'; - // Store in localStorage for persistence - html.window.localStorage['auth_token'] = token; + // Store in SharedPreferences for persistence + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('auth_token', token); } else { _dio.options.headers.remove('Authorization'); - html.window.localStorage.remove('auth_token'); + final prefs = await SharedPreferences.getInstance(); + await prefs.remove('auth_token'); } } - /// Get stored token from localStorage - String? getStoredToken() { - return html.window.localStorage['auth_token']; + /// Get stored token from memory + String? getToken() { + return _token; } - /// Restore token from localStorage - void restoreToken() { - final storedToken = getStoredToken(); + /// Restore token from SharedPreferences + Future restoreToken() async { + final prefs = await SharedPreferences.getInstance(); + final storedToken = prefs.getString('auth_token'); if (storedToken != null) { - setToken(storedToken); + // We call setToken but avoid the async loop? + // Just set memory and header directly to avoid double SP call + _token = storedToken; + _dio.options.headers['Authorization'] = 'Bearer $storedToken'; } } /// Clear token - void clearToken() { - setToken(null); + Future clearToken() async { + await setToken(null); } /// GET request diff --git a/lib/core/services/auth_api_service.dart b/lib/core/services/auth_api_service.dart index 891d236..fc3ec2c 100644 --- a/lib/core/services/auth_api_service.dart +++ b/lib/core/services/auth_api_service.dart @@ -19,7 +19,7 @@ class AuthApiService { final token = data['token'] as String; final userData = data['user'] as Map; - _api.setToken(token); + await _api.setToken(token); return AuthResult( success: true, @@ -51,15 +51,15 @@ class AuthApiService { try { await _api.post('/api/auth/logout'); } finally { - _api.clearToken(); + await _api.clearToken(); } } /// Get current user from token Future getCurrentUser() async { - _api.restoreToken(); + await _api.restoreToken(); - if (_api.getStoredToken() == null) { + if (_api.getToken() == null) { return null; } @@ -76,7 +76,7 @@ class AuthApiService { createdAt: DateTime.now(), ); } catch (e) { - _api.clearToken(); + await _api.clearToken(); return null; } }