completed group batch feature
This commit is contained in:
87
lib/auth_state.dart
Normal file
87
lib/auth_state.dart
Normal file
@@ -0,0 +1,87 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// Tracks the user's authentication state so the [GoRouter] can decide
|
||||
/// whether to allow access to protected routes (such as the groups
|
||||
/// flow) or redirect to the sign-in screen.
|
||||
///
|
||||
/// The router is wired to refresh whenever [notifyListeners] is called,
|
||||
/// which means any place that mutates the auth state (login, logout,
|
||||
/// registration completion) just has to call [refresh] to keep the
|
||||
/// navigation layer in sync.
|
||||
class AuthState extends ChangeNotifier {
|
||||
/// SharedPreferences key used to persist the auth token returned by
|
||||
/// the backend after a successful sign-in.
|
||||
static const String _tokenKey = 'token';
|
||||
|
||||
bool _isLoggedIn = false;
|
||||
bool _initialized = false;
|
||||
|
||||
/// The route the user originally tried to visit before being sent to
|
||||
/// the sign-in screen. After a successful login, the redirect logic
|
||||
/// reads and clears this so the user lands where they were heading.
|
||||
String? _intendedRoute;
|
||||
|
||||
bool get isLoggedIn => _isLoggedIn;
|
||||
|
||||
String? get intendedRoute => _intendedRoute;
|
||||
|
||||
/// Loads the current auth state from disk. Safe to call multiple
|
||||
/// times; subsequent calls just re-read the token value.
|
||||
Future<void> initialize() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
_update(prefs.getString(_tokenKey) != null);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
/// Re-reads the auth state from disk and notifies listeners if it
|
||||
/// has changed. Call this from places that mutate the persisted
|
||||
/// token (e.g. after the login API call or after the user logs out).
|
||||
Future<void> refresh() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
_update(prefs.getString(_tokenKey) != null);
|
||||
}
|
||||
|
||||
void _update(bool loggedIn) {
|
||||
if (_isLoggedIn == loggedIn) return;
|
||||
_isLoggedIn = loggedIn;
|
||||
// NOTE: we intentionally do NOT clear _intendedRoute here. The
|
||||
// router's redirect callback reads it on the next build frame via
|
||||
// [consumeIntendedRoute], which is responsible for clearing it
|
||||
// after it has been consumed.
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Called by the router's redirect callback when a protected route
|
||||
/// is hit by an unauthenticated user. Stores the route the user was
|
||||
/// trying to visit and returns the sign-in path the router should
|
||||
/// navigate to.
|
||||
String? requireAuth(String attemptedRoute) {
|
||||
if (_isLoggedIn) return null;
|
||||
// Avoid stacking redirects when the user is already on the
|
||||
// sign-in / sign-up screens.
|
||||
if (attemptedRoute.startsWith('/onboarding/')) return null;
|
||||
_intendedRoute = attemptedRoute;
|
||||
return '/onboarding/landing';
|
||||
}
|
||||
|
||||
/// Returns the previously captured intended route so the router can
|
||||
/// navigate the user there after a successful sign-in. The value is
|
||||
/// consumed (cleared) once read to avoid loops.
|
||||
String? consumeIntendedRoute() {
|
||||
if (!_isLoggedIn) return null;
|
||||
final route = _intendedRoute;
|
||||
_intendedRoute = null;
|
||||
return route;
|
||||
}
|
||||
}
|
||||
|
||||
/// Global singleton so widgets and the router can share the same
|
||||
/// instance without needing to plumb a provider through the app.
|
||||
final AuthState authState = AuthState();
|
||||
|
||||
/// Whether the auth state has finished its first read from disk.
|
||||
/// The router waits for this before evaluating auth-gated redirects
|
||||
/// so we don't briefly bounce users to the sign-in screen on cold
|
||||
/// start before their persisted token has been loaded.
|
||||
bool get isAuthInitialized => authState._initialized;
|
||||
Reference in New Issue
Block a user