diff --git a/CHANGELOG.md b/CHANGELOG.md index e84c31f..42aa16c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## 2.1.0 + +### Authentication Service + +- [NEW] Added `AuthenticationStatus.unknown` as the new default authentication state (replaces `unauthenticated` as default). +- [NEW] Added `AuthenticationStatus.isUnknown` getter to explicitly check for unknown state. +- [CHANGE] `AuthenticationStatus.isUnauthenticated` now returns `true` for both `unauthenticated` and `unknown` states (use `isUnknown` to distinguish). +- [CHANGE] `ArcaneAuthenticationService` now initializes with `AuthenticationStatus.unknown` instead of `unauthenticated`. +- [CHANGE] `ArcaneAuthenticationService.reset()` now resets status to `unknown`. +- [CHANGE] Updated tests to reflect new default status behavior. + ## 2.0.6 ### Arcane Framework diff --git a/README.md b/README.md index 461c991..5e5d27d 100644 --- a/README.md +++ b/README.md @@ -966,6 +966,37 @@ void dispose() { } ``` +#### Authentication Status + +The `AuthenticationStatus` enum represents the current authentication state: + +| Status | Description | +| ----------------- | ----------------------------------------------------------- | +| `authenticated` | The user is authenticated and signed in. | +| `unauthenticated` | The user is not authenticated (explicitly signed out). | +| `unknown` | The authentication status is not yet known (initial state). | + +Use the provided getters to check the current status: + +```dart +// Check if user is authenticated +if (Arcane.auth.status.isAuthenticated) { + // User is signed in +} + +// Check if user is explicitly unauthenticated (signed out) +if (Arcane.auth.status.isUnauthenticated) { + // User is not signed in +} + +// Check if authentication status is still being determined +if (Arcane.auth.status.isUnknown) { + // Show loading indicator, etc. +} +``` + +The default status is `unknown` until an authentication interface is registered and initialized. After calling `reset()`, the status returns to `unknown`. + ### Application Environments Arcane environments are value-based and extensible. Two built-in values are diff --git a/lib/src/services/authentication/authentication_enums.dart b/lib/src/services/authentication/authentication_enums.dart index a0dd540..24db094 100644 --- a/lib/src/services/authentication/authentication_enums.dart +++ b/lib/src/services/authentication/authentication_enums.dart @@ -27,6 +27,7 @@ enum SignUpStep { /// This enum has two possible states: /// - `authenticated`: The user is authenticated. /// - `unauthenticated`: The user is not authenticated. +/// - `unknown` (default): The authentication status is not yet known. /// /// Example: /// ```dart @@ -40,11 +41,17 @@ enum AuthenticationStatus { authenticated, /// The user is not authenticated. - unauthenticated; + unauthenticated, + + /// The authentication status is currently unknown. + unknown; /// Returns `true` if the current status is `authenticated`. bool get isAuthenticated => this == authenticated; - /// Returns `true` if the current status is `unauthenticated`. - bool get isUnauthenticated => this == unauthenticated; + /// Returns `true` if the current status is not `authenticated`. + bool get isUnauthenticated => !isAuthenticated; + + /// Returns `true` if the current status is `unknown`. + bool get isUnknown => this == unknown; } diff --git a/lib/src/services/authentication/authentication_service.dart b/lib/src/services/authentication/authentication_service.dart index 5ad05ab..cf17a34 100644 --- a/lib/src/services/authentication/authentication_service.dart +++ b/lib/src/services/authentication/authentication_service.dart @@ -20,7 +20,7 @@ class ArcaneAuthenticationService extends ArcaneService { static ArcaneAuthenticationService get I => _instance; final ValueNotifier _notifier = - ValueNotifier(AuthenticationStatus.unauthenticated); + ValueNotifier(AuthenticationStatus.unknown); /// A `ValueNotifier` that emits the current `AuthenticationStatus`. ValueNotifier get notifier => _notifier; @@ -54,7 +54,7 @@ class ArcaneAuthenticationService extends ArcaneService { ArcaneAuthInterface? get authInterface => _authInterface; /// Returns `true` when the current status is authenticated. - bool get isAuthenticated => status == AuthenticationStatus.authenticated; + bool get isAuthenticated => status.isAuthenticated; final ValueNotifier _isSignedIn = ValueNotifier(false); @@ -86,7 +86,7 @@ class ArcaneAuthenticationService extends ArcaneService { /// default. Future reset() async { _authInterface = null; - _notifier.value = AuthenticationStatus.unauthenticated; + _notifier.value = AuthenticationStatus.unknown; _isSignedIn.value = isAuthenticated; _statusController.add(_notifier.value); _signedInController.add(_isSignedIn.value); diff --git a/pubspec.yaml b/pubspec.yaml index 5c745a8..665e920 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: arcane_framework description: "Agnostic Reusable Component Architecture for New Ecosystems: a modern framework for bootstrapping new applications" -version: 2.0.6 +version: 2.1.0 repository: https://github.com/hanskokx/arcane_framework issue_tracker: https://github.com/hanskokx/arcane_framework/issues diff --git a/test/services/authentication/authentication_enums_test.dart b/test/services/authentication/authentication_enums_test.dart index 6eff24c..15b7f6d 100644 --- a/test/services/authentication/authentication_enums_test.dart +++ b/test/services/authentication/authentication_enums_test.dart @@ -13,10 +13,17 @@ void main() { test("isAuthenticated returns true only for authenticated", () { expect(AuthenticationStatus.authenticated.isAuthenticated, isTrue); expect(AuthenticationStatus.unauthenticated.isAuthenticated, isFalse); + expect(AuthenticationStatus.unknown.isAuthenticated, isFalse); }); - test("isUnauthenticated returns true only for unauthenticated", () { + test("isUnauthenticated returns true for unauthenticated and unknown", () { expect(AuthenticationStatus.authenticated.isUnauthenticated, isFalse); expect(AuthenticationStatus.unauthenticated.isUnauthenticated, isTrue); + expect(AuthenticationStatus.unknown.isUnauthenticated, isTrue); + }); + test("isUnknown returns true only for unknown", () { + expect(AuthenticationStatus.authenticated.isUnknown, isFalse); + expect(AuthenticationStatus.unauthenticated.isUnknown, isFalse); + expect(AuthenticationStatus.unknown.isUnknown, isTrue); }); }); } diff --git a/test/services/authentication/authentication_service_test.dart b/test/services/authentication/authentication_service_test.dart index 903faa1..3642a33 100644 --- a/test/services/authentication/authentication_service_test.dart +++ b/test/services/authentication/authentication_service_test.dart @@ -28,7 +28,7 @@ void main() { expect(ArcaneAuthenticationService.I.authInterface, isNull); expect( ArcaneAuthenticationService.I.status, - AuthenticationStatus.unauthenticated, + AuthenticationStatus.unknown, ); expect(ArcaneAuthenticationService.I.isSignedIn.value, false); }); @@ -225,7 +225,67 @@ void main() { test("notifier getter reflects unauthenticated default", () { expect( ArcaneAuthenticationService.I.notifier.value, - AuthenticationStatus.unauthenticated, + AuthenticationStatus.unknown, + ); + }); + + test("isUnknown getter reflects unknown status", () { + expect( + ArcaneAuthenticationService.I.status.isUnknown, + isTrue, + ); + }); + + test("isUnknown getter reflects unknown status after a reset", () async { + expect( + ArcaneAuthenticationService.I.status.isUnknown, + isTrue, + ); + + ArcaneAuthenticationService.I.setAuthenticated(); + + expect( + ArcaneAuthenticationService.I.status.isUnknown, + isFalse, + ); + + expect( + ArcaneAuthenticationService.I.status.isAuthenticated, + isTrue, + ); + + ArcaneAuthenticationService.I.setUnauthenticated(); + + expect( + ArcaneAuthenticationService.I.status.isUnknown, + isFalse, + ); + + expect( + ArcaneAuthenticationService.I.status.isAuthenticated, + isFalse, + ); + + expect( + ArcaneAuthenticationService.I.status.isUnauthenticated, + isTrue, + ); + + await ArcaneAuthenticationService.I.reset(); + + expect( + ArcaneAuthenticationService.I.status.isUnknown, + isTrue, + ); + + expect( + ArcaneAuthenticationService.I.status.isAuthenticated, + isFalse, + ); + + expect( + ArcaneAuthenticationService.I.status.isUnauthenticated, + isTrue, ); }); @@ -334,7 +394,7 @@ void main() { expect(result.isFailure, true); expect( ArcaneAuthenticationService.I.status, - equals(AuthenticationStatus.unauthenticated), + equals(AuthenticationStatus.unknown), ); });