feat: Add initial Flutter Android project setup, core API client with authentication token management, and authentication service.

This commit is contained in:
Michael committed 2025-12-09 17:20:28 +01:00
1 parent ab6c7f585f
commit 664e89f2b8
3 files changed
+29 -21

No files matched your search

+1 -1
View File
@@ -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
+23 -15
View File
@@ -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<void> 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<void> 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<void> clearToken() async {
await setToken(null);
}
/// GET request
+5 -5
View File
@@ -19,7 +19,7 @@ class AuthApiService {
final token = data['token'] as String;
final userData = data['user'] as Map<String, dynamic>;
_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<AppUser?> 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;
}
}