summaryrefslogtreecommitdiff
path: root/player-android/lib/providers
diff options
context:
space:
mode:
Diffstat (limited to 'player-android/lib/providers')
-rw-r--r--player-android/lib/providers/current_user_provider.dart30
1 files changed, 17 insertions, 13 deletions
diff --git a/player-android/lib/providers/current_user_provider.dart b/player-android/lib/providers/current_user_provider.dart
index 560feb0..f1c7b12 100644
--- a/player-android/lib/providers/current_user_provider.dart
+++ b/player-android/lib/providers/current_user_provider.dart
@@ -6,17 +6,16 @@ import 'api_client_provider.dart';
/// Provides the currently authenticated [User] object.
///
-/// Calls [PlayerApiClient.login] is not used here — instead, the logged-in
-/// user is fetched lazily via [listUsers] or derived from the auth context.
-/// Since the server does not expose a "GET /api/v1/auth/me" endpoint, we
-/// obtain the current user by calling [listUsers] and matching against the
-/// stored username token.
+/// The [PlayerApiClient.login] call is not used here — instead, the logged-in
+/// user is fetched lazily via [listUsers] and matched against the stored
+/// username token. Since the server does not expose a "GET /api/v1/auth/me"
+/// endpoint, this round-trip is the only way to obtain the [User.isAdmin] flag.
///
/// The provider is autoDispose so it is released when no screen is watching it,
/// and keepAlive is not used — a fresh fetch is acceptable when navigating back.
///
-/// Returns null when the user list cannot be fetched or the username is not
-/// found among the registered users (e.g. during a race with logout).
+/// Returns null when the user list cannot be fetched, or when the username is
+/// not found among the registered users (e.g. during a race with logout).
final currentUserProvider = FutureProvider.autoDispose<User?>((ref) async {
// Obtain the stored username from token storage (same source as the settings
// screen's _currentUsernameProvider) to identify which user is logged in.
@@ -31,13 +30,18 @@ final currentUserProvider = FutureProvider.autoDispose<User?>((ref) async {
final client = ref.watch(apiClientProvider);
try {
final users = await client.listUsers();
- return users.firstWhere(
- (u) => u.username == username,
- orElse: () => User(id: 0, username: username, isAdmin: false),
+ // Cast to User? so orElse can return null when the username is not in the
+ // list (e.g. the account was deleted). null is the safest sentinel because
+ // it does not collide with the id=0 placeholder used in AdminUsersScreen.
+ return users.cast<User?>().firstWhere(
+ (u) => u?.username == username,
+ orElse: () => null,
);
} catch (_) {
- // If listUsers fails (e.g. non-admin user, network error) fall back to a
- // minimal user object with isAdmin=false so gating logic fails safely.
- return User(id: 0, username: username, isAdmin: false);
+ // If listUsers fails (e.g. non-admin user, network error) return null so
+ // callers that gate on isAdmin fail safely without a fake User(id:0) object
+ // that could collide with the optimistic placeholder sentinel in
+ // AdminUsersScreen.
+ return null;
}
});