import "dart:convert"; import "package:flutter/foundation.dart"; import "package:shared_preferences/shared_preferences.dart"; import "api.dart"; import "models.dart"; const _tokenKey = "cc_token"; const _userKey = "cc_user"; /// Holds session state and persists the token across app restarts. class AuthService extends ChangeNotifier { final ApiClient api; AuthUser? user; bool ready = false; /// In-memory (never persisted) app-lock flag. When biometric login is enabled /// the app starts/returns locked: the token is still valid but the UI hides /// behind a biometric unlock instead of jumping straight to the dashboard. bool locked = false; AuthService(this.api) { api.onUnauthorized = () => logout(); } bool get isAuthenticated => api.token != null; void lock() { if (!locked && isAuthenticated) { locked = true; notifyListeners(); } } void unlock() { if (locked) { locked = false; notifyListeners(); } } Future loadFromStorage() async { final prefs = await SharedPreferences.getInstance(); final t = prefs.getString(_tokenKey); final u = prefs.getString(_userKey); if (t != null) { api.token = t; if (u != null) user = AuthUser.fromJson(jsonDecode(u)); } ready = true; notifyListeners(); } Future login(String email, String password) async { final (token, u) = await api.login(email, password); api.token = token; user = u; locked = false; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_tokenKey, token); await prefs.setString(_userKey, jsonEncode(u.toJson())); notifyListeners(); } Future logout() async { api.token = null; user = null; locked = false; final prefs = await SharedPreferences.getInstance(); await prefs.remove(_tokenKey); await prefs.remove(_userKey); notifyListeners(); } }