mirror of
https://github.com/hanskokx/arcane_framework.git
synced 2026-05-14 02:19:08 +02:00
v1.0.5
- Added the ability to use a generic type for the login method in ArcaneAuthenticationService - Added the ability to reset the ArcaneAuthenticationService, which will unregister the current interface and clear the authentication state - Removed unused testing tooling (e.g., `@visibleForTesting`) from the codebase Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
+17
-10
@@ -1,27 +1,34 @@
|
||||
## 1.0.5
|
||||
|
||||
- Added the ability to use a generic type for the login method in ArcaneAuthenticationService
|
||||
- Added the ability to reset the ArcaneAuthenticationService, which will unregister the current interface and clear the authentication state
|
||||
- Removed unused testing tooling (e.g., `@visibleForTesting`) from the codebase
|
||||
- Migration guide: Remove usages of `setMocked` in your tests
|
||||
|
||||
## 1.0.4
|
||||
|
||||
* Resolved an issue with authentication using the ArcaneAuthenticationService when logging in with an email and password
|
||||
- Resolved an issue with authentication using the ArcaneAuthenticationService when logging in with an email and password
|
||||
|
||||
## 1.0.3+1
|
||||
|
||||
* Added example project
|
||||
- Added example project
|
||||
|
||||
## 1.0.3
|
||||
|
||||
* Added the ability to switch back to the normal environment from the debug environment in ArcaneEnvironment
|
||||
* (breaking) Made the optional `onLoggedOut` callback a Future instead of a void function in ArcaneAuthenticationService
|
||||
* Added additional error handling to the login method in ArcaneAuthenticationService
|
||||
* Added support for following the system's theme in ArcaneTheme
|
||||
* Removed the BuildContext parameter from the `switchTheme` method in ArcaneTheme
|
||||
- Added the ability to switch back to the normal environment from the debug environment in ArcaneEnvironment
|
||||
- (breaking) Made the optional `onLoggedOut` callback a Future instead of a void function in ArcaneAuthenticationService
|
||||
- Added additional error handling to the login method in ArcaneAuthenticationService
|
||||
- Added support for following the system's theme in ArcaneTheme
|
||||
- Removed the BuildContext parameter from the `switchTheme` method in ArcaneTheme
|
||||
|
||||
## 1.0.2
|
||||
|
||||
* Migrated ArcaneAuthenticationService's isSignedIn to a ValueListenable
|
||||
- Migrated ArcaneAuthenticationService's isSignedIn to a ValueListenable
|
||||
|
||||
## 1.0.1+1
|
||||
|
||||
* Removed ID and secure storage services to improve platform compatibility
|
||||
- Removed ID and secure storage services to improve platform compatibility
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* Initial release
|
||||
- Initial release
|
||||
|
||||
@@ -45,6 +45,22 @@ class DebugAuthInterface implements ArcaneAuthInterface {
|
||||
return Result.ok(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void, String>> login<T>({
|
||||
T? input,
|
||||
Future<void> Function()? onLoggedIn,
|
||||
}) async {
|
||||
final bool alreadyLoggedIn = await isSignedIn;
|
||||
|
||||
if (alreadyLoggedIn) return Result.ok(null);
|
||||
|
||||
Arcane.log("Logging: $input");
|
||||
|
||||
_isSignedIn = true;
|
||||
|
||||
return Result.ok(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<String, String>> resendVerificationCode(String email) async {
|
||||
Arcane.log("Re-sending verification code to $email");
|
||||
|
||||
@@ -51,6 +51,27 @@ abstract class ArcaneAuthInterface {
|
||||
required String password,
|
||||
});
|
||||
|
||||
/// Logs the user in using an optional, generic `T` type of input.
|
||||
/// This login method is a generic method that can be used to login with any
|
||||
/// type of input. It is useful for login methods that do not require an email
|
||||
/// and password. Any type of input can be passed in, and it will be handled
|
||||
/// by the implementation of the method wihin the specific authentication
|
||||
/// service.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await authInterface.login<Map<String, String>>(
|
||||
/// input: {
|
||||
/// "username": "hello@world.com",
|
||||
/// "password": "password",
|
||||
/// },
|
||||
/// );
|
||||
/// ```
|
||||
Future<Result<void, String>> login<T>({
|
||||
T? input,
|
||||
Future<void> Function()? onLoggedIn,
|
||||
});
|
||||
|
||||
/// Re-sends a verification code to the user's email address.
|
||||
///
|
||||
/// This method is typically used when the user hasn't received or has lost their initial
|
||||
|
||||
@@ -15,7 +15,6 @@ part "authentication_interface.dart";
|
||||
class ArcaneAuthenticationService extends ArcaneService {
|
||||
ArcaneAuthenticationService._internal();
|
||||
|
||||
static bool _mocked = false;
|
||||
static final ArcaneAuthenticationService _instance =
|
||||
ArcaneAuthenticationService._internal();
|
||||
|
||||
@@ -32,11 +31,17 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
/// - `debug`: Debug mode has been enabled, enabling development features.
|
||||
AuthenticationStatus get status => _status;
|
||||
|
||||
static late ArcaneAuthInterface _authInterface;
|
||||
static ArcaneAuthInterface? _authInterface;
|
||||
|
||||
/// Provides direct access to the registered `ArcaneAuthInterface`, if one has
|
||||
/// been registered.
|
||||
ArcaneAuthInterface get authInterface => _authInterface;
|
||||
ArcaneAuthInterface get authInterface {
|
||||
assert(
|
||||
_authInterface != null,
|
||||
"No ArcaneAuthInterface has been registered",
|
||||
);
|
||||
return _authInterface!;
|
||||
}
|
||||
|
||||
/// A shortcut to `status != AuthenticationStatus.unauthenticated`.
|
||||
bool get isAuthenticated => status != AuthenticationStatus.unauthenticated;
|
||||
@@ -53,8 +58,20 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
/// provides one.
|
||||
Future<String?> get refreshToken => authInterface.refreshToken;
|
||||
|
||||
/// Removes any registered `ArcaneAuthInterface` and resets all values to
|
||||
/// default.
|
||||
Future<void> reset() async {
|
||||
_authInterface = null;
|
||||
_status = AuthenticationStatus.unauthenticated;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Registers an `ArcaneAuthInterface` within the `ArcaneAuthenticationService`.
|
||||
Future<void> registerInterface(ArcaneAuthInterface authInterface) async {
|
||||
if (_authInterface != null) {
|
||||
throw Exception("ArcaneAuthInterface has already been registered");
|
||||
}
|
||||
|
||||
_authInterface = authInterface;
|
||||
await authInterface.init();
|
||||
}
|
||||
@@ -66,8 +83,6 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
BuildContext context, {
|
||||
Future<void> Function()? onDebugModeSet,
|
||||
}) async {
|
||||
if (_mocked) return;
|
||||
|
||||
ArcaneEnvironment? environment;
|
||||
|
||||
try {
|
||||
@@ -98,8 +113,6 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
BuildContext context, {
|
||||
Future<void> Function()? onDebugModeUnset,
|
||||
}) async {
|
||||
if (_mocked) return;
|
||||
|
||||
ArcaneEnvironment? environment;
|
||||
|
||||
try {
|
||||
@@ -125,21 +138,15 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
|
||||
/// Sets `status` to `AuthenticationStatus.authenticated`.
|
||||
void setAuthenticated() {
|
||||
if (_mocked) return;
|
||||
|
||||
_setStatus(AuthenticationStatus.authenticated);
|
||||
}
|
||||
|
||||
/// Sets `status` to `AuthenticationStatus.unauthenticated`.
|
||||
void setUnauthenticated() {
|
||||
if (_mocked) return;
|
||||
|
||||
_setStatus(AuthenticationStatus.unauthenticated);
|
||||
}
|
||||
|
||||
void _setStatus(AuthenticationStatus newStatus) {
|
||||
if (_mocked) return;
|
||||
|
||||
_status = newStatus;
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -147,9 +154,13 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
/// Logs the current user out. Upon successful logout, `status` will be set to
|
||||
/// `AuthenticationStatus.unauthenticated`.
|
||||
Future<void> logOut({Future<void> Function()? onLoggedOut}) async {
|
||||
if (_mocked) return;
|
||||
if (!isAuthenticated) return;
|
||||
|
||||
assert(
|
||||
_authInterface != null,
|
||||
"No ArcaneAuthInterface has been registered",
|
||||
);
|
||||
|
||||
final Result<void, String> loggedOut = await authInterface.logout();
|
||||
|
||||
await loggedOut.fold(
|
||||
@@ -174,8 +185,6 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
required String password,
|
||||
Future<void> Function()? onLoggedIn,
|
||||
}) async {
|
||||
if (_mocked) return Result.ok(null);
|
||||
|
||||
if (status != AuthenticationStatus.unauthenticated) {
|
||||
return Result.error("Cannot sign in. Status is already ${status.name}.");
|
||||
}
|
||||
@@ -194,6 +203,27 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Logs the user in using an optional, generic `T` type of input.
|
||||
Future<Result<void, String>> login<T>({
|
||||
T? input,
|
||||
Future<void> Function()? onLoggedIn,
|
||||
}) async {
|
||||
if (_authInterface == null) {
|
||||
return Result.error("No ArcaneAuthInterface has been registered");
|
||||
}
|
||||
|
||||
final Result<void, String> result = await authInterface.login(
|
||||
input: input,
|
||||
);
|
||||
|
||||
if (result.isSuccess) {
|
||||
setAuthenticated();
|
||||
if (onLoggedIn != null) await onLoggedIn();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Attempts to register a new account using the provided `email` and
|
||||
/// `password`. Upon success, returns a `SignUpStep` indicating the next step
|
||||
/// in the signup process as a `SignUpStep`.
|
||||
@@ -201,7 +231,10 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
required String email,
|
||||
required String password,
|
||||
}) async {
|
||||
if (_mocked) return Result.ok(SignUpStep.done);
|
||||
if (_authInterface == null) {
|
||||
return Result.error("No ArcaneAuthInterface has been registered");
|
||||
}
|
||||
|
||||
final Result<SignUpStep, String> result = await authInterface.signup(
|
||||
email: email,
|
||||
password: password,
|
||||
@@ -216,7 +249,10 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
required String email,
|
||||
required String confirmationCode,
|
||||
}) async {
|
||||
if (_mocked) return Result.ok(false);
|
||||
if (_authInterface == null) {
|
||||
return Result.error("No ArcaneAuthInterface has been registered");
|
||||
}
|
||||
|
||||
final Result<bool, String> result = await authInterface.confirmSignup(
|
||||
username: email,
|
||||
confirmationCode: confirmationCode,
|
||||
@@ -228,7 +264,10 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
/// Re-sends a verification code to be used when confirming the user's
|
||||
/// registration.
|
||||
Future<Result<String, String>> resendVerificationCode(String email) async {
|
||||
if (_mocked) return Result.ok("");
|
||||
if (_authInterface == null) {
|
||||
return Result.error("No ArcaneAuthInterface has been registered");
|
||||
}
|
||||
|
||||
return authInterface.resendVerificationCode(email);
|
||||
}
|
||||
|
||||
@@ -243,7 +282,10 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
String? newPassword,
|
||||
String? confirmationCode,
|
||||
}) async {
|
||||
if (_mocked) return Result.ok(false);
|
||||
if (_authInterface == null) {
|
||||
return Result.error("No ArcaneAuthInterface has been registered");
|
||||
}
|
||||
|
||||
final Result<bool, String> result = await authInterface.resetPassword(
|
||||
email: email,
|
||||
newPassword: newPassword,
|
||||
@@ -252,12 +294,4 @@ class ArcaneAuthenticationService extends ArcaneService {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Marks the service as mocked for testing purposes.
|
||||
///
|
||||
/// If the service is mocked, no method will be executed.
|
||||
@visibleForTesting
|
||||
static void setMocked() {
|
||||
_mocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import "package:arcane_framework/arcane_framework.dart";
|
||||
import "package:flutter/foundation.dart";
|
||||
|
||||
part "feature_flags_extensions.dart";
|
||||
|
||||
@@ -41,15 +40,6 @@ class ArcaneFeatureFlags extends ArcaneService {
|
||||
/// to access the instance.
|
||||
static bool get initialized => I._initialized;
|
||||
|
||||
bool _mocked = false;
|
||||
|
||||
/// Marks the feature flags as mocked for testing purposes.
|
||||
///
|
||||
/// When the feature flags are mocked, they bypass certain initializations, making
|
||||
/// them easier to work with in unit tests.
|
||||
@visibleForTesting
|
||||
void setMocked() => _mocked = true;
|
||||
|
||||
/// Checks if a specific [feature] is enabled.
|
||||
///
|
||||
/// Returns `true` if the [feature] is in the list of enabled features, otherwise returns `false`.
|
||||
@@ -125,8 +115,6 @@ class ArcaneFeatureFlags extends ArcaneService {
|
||||
/// It is called automatically when enabling or disabling features if they haven't
|
||||
/// already been initialized.
|
||||
void _init() {
|
||||
if (_mocked) return;
|
||||
|
||||
_enabledFeatures.clear();
|
||||
|
||||
I._initialized = true;
|
||||
|
||||
@@ -35,22 +35,12 @@ class ArcaneLogger {
|
||||
/// Whether the logger has been initialized.
|
||||
bool get initialized => I._initialized;
|
||||
|
||||
/// Marks the logger as mocked for testing purposes.
|
||||
///
|
||||
/// If the logger is mocked, platform-specific features (such as tracking
|
||||
/// status) will not be initialized.
|
||||
@visibleForTesting
|
||||
void setMocked() => _mocked = true;
|
||||
bool _mocked = false;
|
||||
|
||||
/// Initializes the logger.
|
||||
///
|
||||
/// Sets up error handling for both Flutter and platform-specific errors.
|
||||
/// Also, retrieves the tracking authorization status if running on iOS or
|
||||
/// macOS.
|
||||
Future<void> _init() async {
|
||||
if (_mocked) return;
|
||||
|
||||
additionalMetadata.clear();
|
||||
|
||||
// Handles unhandled Flutter errors by logging them.
|
||||
@@ -146,8 +136,6 @@ class ArcaneLogger {
|
||||
StackTrace? stackTrace,
|
||||
Map<String, String>? metadata,
|
||||
}) {
|
||||
if (I._mocked) return;
|
||||
|
||||
if (!I._initialized) {
|
||||
throw Exception("ArcaneLogger has not yet been initialized.");
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
name: arcane_framework
|
||||
description: "Agnostic Reusable Component Architecture for New Ecosystems: a modern framework for bootstrapping new applications"
|
||||
version: 1.0.4
|
||||
version: 1.0.5
|
||||
repository: https://github.com/hanskokx/arcane_framework
|
||||
issue_tracker: https://github.com/hanskokx/arcane_framework/issues
|
||||
|
||||
|
||||
Reference in New Issue
Block a user