2025-01-28 12:50:08 +01:00
|
|
|
import "dart:async";
|
2022-09-27 16:38:12 +02:00
|
|
|
|
2025-01-28 12:50:08 +01:00
|
|
|
import "package:flutter/material.dart";
|
|
|
|
import "package:flutter_login/src/config/forgot_password_spacer_options.dart";
|
|
|
|
import "package:flutter_login/src/config/spacer_options.dart";
|
|
|
|
import "package:flutter_login/src/service/login_validation.dart";
|
|
|
|
import "package:flutter_login/src/service/validation.dart";
|
2022-09-27 16:38:12 +02:00
|
|
|
|
2023-05-08 18:09:19 +02:00
|
|
|
@immutable
|
2022-09-27 16:38:12 +02:00
|
|
|
class LoginOptions {
|
|
|
|
const LoginOptions({
|
|
|
|
this.image,
|
2023-05-08 18:09:19 +02:00
|
|
|
this.maxFormWidth,
|
2023-02-13 14:33:37 +01:00
|
|
|
this.emailTextStyle,
|
|
|
|
this.passwordTextStyle,
|
2024-03-07 13:46:13 +01:00
|
|
|
this.emailTextAlign,
|
|
|
|
this.passwordTextAlign,
|
2024-04-19 10:10:09 +02:00
|
|
|
this.emailDecoration = const InputDecoration(
|
|
|
|
contentPadding: EdgeInsets.symmetric(horizontal: 8),
|
2025-01-28 12:50:08 +01:00
|
|
|
labelText: "Email address",
|
2024-04-19 10:10:09 +02:00
|
|
|
border: OutlineInputBorder(),
|
|
|
|
focusedBorder: OutlineInputBorder(
|
|
|
|
borderSide: BorderSide(
|
|
|
|
color: Color(0xff71C6D1),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
labelStyle: TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontWeight: FontWeight.w400,
|
|
|
|
fontSize: 16,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
this.passwordDecoration = const InputDecoration(
|
|
|
|
contentPadding: EdgeInsets.symmetric(horizontal: 8),
|
2025-01-28 12:50:08 +01:00
|
|
|
labelText: "Password",
|
2024-04-19 10:10:09 +02:00
|
|
|
border: OutlineInputBorder(),
|
|
|
|
focusedBorder: OutlineInputBorder(
|
|
|
|
borderSide: BorderSide(
|
|
|
|
color: Color(0xff71C6D1),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
labelStyle: TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontWeight: FontWeight.w400,
|
|
|
|
fontSize: 16,
|
|
|
|
),
|
|
|
|
),
|
2025-01-28 12:50:08 +01:00
|
|
|
this.initialEmail = "",
|
|
|
|
this.initialPassword = "",
|
2024-04-19 10:10:09 +02:00
|
|
|
this.spacers = const LoginSpacerOptions(
|
|
|
|
spacerBeforeTitle: 8,
|
|
|
|
spacerAfterTitle: 2,
|
|
|
|
formFlexValue: 2,
|
|
|
|
),
|
2022-09-27 16:38:12 +02:00
|
|
|
this.translations = const LoginTranslations(),
|
2025-01-28 16:35:59 +01:00
|
|
|
this.accessibilityIdentifiers = const LoginAccessibilityIdentifiers.empty(),
|
2022-09-29 17:22:26 +02:00
|
|
|
this.validationService,
|
2022-09-27 16:38:12 +02:00
|
|
|
this.loginButtonBuilder = _createLoginButton,
|
|
|
|
this.forgotPasswordButtonBuilder = _createForgotPasswordButton,
|
2022-09-29 17:22:26 +02:00
|
|
|
this.requestForgotPasswordButtonBuilder =
|
|
|
|
_createRequestForgotPasswordButton,
|
2022-09-27 16:38:12 +02:00
|
|
|
this.registrationButtonBuilder = _createRegisterButton,
|
2022-09-29 12:14:30 +02:00
|
|
|
this.emailInputContainerBuilder = _createEmailInputContainer,
|
|
|
|
this.passwordInputContainerBuilder = _createPasswordInputContainer,
|
2023-11-20 16:37:21 +01:00
|
|
|
this.showObscurePassword = true,
|
2024-04-19 10:10:09 +02:00
|
|
|
this.forgotPasswordSpacerOptions = const ForgotPasswordSpacerOptions(
|
2024-08-08 09:44:01 +02:00
|
|
|
spacerAfterButton: 4,
|
2024-04-19 10:10:09 +02:00
|
|
|
spacerBeforeTitle: 1,
|
|
|
|
),
|
|
|
|
this.loginBackgroundColor = const Color(0xffFAF9F6),
|
|
|
|
this.forgotPasswordBackgroundColor = const Color(0xffFAF9F6),
|
|
|
|
this.forgotPasswordScreenPadding = const Padding(
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 60),
|
|
|
|
),
|
|
|
|
this.forgotPasswordCustomAppBar,
|
2024-05-23 15:42:13 +02:00
|
|
|
this.suffixIconSize,
|
|
|
|
this.suffixIconPadding,
|
2022-09-27 16:38:12 +02:00
|
|
|
});
|
|
|
|
|
2024-02-19 16:03:18 +01:00
|
|
|
/// Builds the login button.
|
2022-09-27 16:38:12 +02:00
|
|
|
final ButtonBuilder loginButtonBuilder;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// Builds the registration button.
|
2022-09-27 16:38:12 +02:00
|
|
|
final ButtonBuilder registrationButtonBuilder;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// Builds the forgot password button.
|
2022-09-27 16:38:12 +02:00
|
|
|
final ButtonBuilder forgotPasswordButtonBuilder;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// Builds the request forgot password button.
|
2022-09-29 17:22:26 +02:00
|
|
|
final ButtonBuilder requestForgotPasswordButtonBuilder;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// Builds the email input container.
|
2022-09-29 12:14:30 +02:00
|
|
|
final InputContainerBuilder emailInputContainerBuilder;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// Builds the password input container.
|
2022-09-29 12:14:30 +02:00
|
|
|
final InputContainerBuilder passwordInputContainerBuilder;
|
2022-09-27 16:38:12 +02:00
|
|
|
|
2024-02-19 16:03:18 +01:00
|
|
|
/// The image to display on the login screen.
|
2022-09-27 16:38:12 +02:00
|
|
|
final Widget? image;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
2024-02-06 16:05:46 +01:00
|
|
|
/// Option to modify the spacing between the title, subtitle, image, form,
|
|
|
|
/// and button.
|
2023-05-08 18:09:19 +02:00
|
|
|
final LoginSpacerOptions spacers;
|
|
|
|
|
2024-03-04 13:25:26 +01:00
|
|
|
/// Option to modify the spacing between the items on the forgotPasswordForm.
|
|
|
|
final ForgotPasswordSpacerOptions forgotPasswordSpacerOptions;
|
|
|
|
|
2023-05-08 18:09:19 +02:00
|
|
|
/// Maximum width of the form. Defaults to 400.
|
|
|
|
final double? maxFormWidth;
|
|
|
|
|
2024-02-19 16:03:18 +01:00
|
|
|
/// Decoration for the email input field.
|
2023-03-14 11:16:13 +01:00
|
|
|
final InputDecoration emailDecoration;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// Decoration for the password input field.
|
2023-03-14 11:16:13 +01:00
|
|
|
final InputDecoration passwordDecoration;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// The initial email value for the email input field.
|
2022-09-27 16:38:12 +02:00
|
|
|
final String initialEmail;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// The initial password value for the password input field.
|
2022-09-27 16:38:12 +02:00
|
|
|
final String initialPassword;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// The text style for the email input field.
|
2023-02-13 14:33:37 +01:00
|
|
|
final TextStyle? emailTextStyle;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// The text style for the password input field.
|
2023-02-13 14:33:37 +01:00
|
|
|
final TextStyle? passwordTextStyle;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
2024-03-07 13:46:13 +01:00
|
|
|
/// The text alignment for the email input field.
|
|
|
|
final TextAlign? emailTextAlign;
|
|
|
|
|
|
|
|
/// The text alignment for the password input field.
|
|
|
|
final TextAlign? passwordTextAlign;
|
|
|
|
|
2024-02-19 16:03:18 +01:00
|
|
|
/// Translations for various texts on the login screen.
|
2022-09-27 16:38:12 +02:00
|
|
|
final LoginTranslations translations;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
2025-01-28 16:35:59 +01:00
|
|
|
/// Accessibility identifiers for the standard widgets in the component.
|
|
|
|
/// The inputfields and buttons have accessibility identifiers and their own
|
|
|
|
/// container so they are visible in the accessibility tree.
|
|
|
|
/// This is used for testing purposes.
|
|
|
|
final LoginAccessibilityIdentifiers accessibilityIdentifiers;
|
|
|
|
|
2024-02-19 16:03:18 +01:00
|
|
|
/// The validation service used for validating email and password inputs.
|
2022-09-29 17:22:26 +02:00
|
|
|
final ValidationService? validationService;
|
2024-02-19 16:03:18 +01:00
|
|
|
|
|
|
|
/// Determines whether the password field should be obscured.
|
2023-11-20 16:37:21 +01:00
|
|
|
final bool showObscurePassword;
|
2024-05-23 15:42:13 +02:00
|
|
|
final double? suffixIconSize;
|
|
|
|
final EdgeInsets? suffixIconPadding;
|
2022-09-29 17:22:26 +02:00
|
|
|
|
2024-02-19 16:03:18 +01:00
|
|
|
/// Get validations.
|
2022-09-29 17:22:26 +02:00
|
|
|
ValidationService get validations =>
|
|
|
|
validationService ?? LoginValidationService(this);
|
2024-04-19 10:10:09 +02:00
|
|
|
|
|
|
|
/// The background color for the login screen.
|
|
|
|
final Color loginBackgroundColor;
|
|
|
|
|
|
|
|
/// The background color for the forgot password screen.
|
|
|
|
final Color forgotPasswordBackgroundColor;
|
|
|
|
|
|
|
|
/// The padding for the forgot password screen.
|
|
|
|
final Padding forgotPasswordScreenPadding;
|
|
|
|
|
|
|
|
/// forgot password custom AppBar
|
|
|
|
final AppBar? forgotPasswordCustomAppBar;
|
2022-09-27 16:38:12 +02:00
|
|
|
}
|
|
|
|
|
2025-01-28 16:35:59 +01:00
|
|
|
/// Translations for all the texts in the component
|
2022-09-27 16:38:12 +02:00
|
|
|
class LoginTranslations {
|
2025-01-28 16:35:59 +01:00
|
|
|
/// Provide your own translations to override the default english translations
|
2022-09-27 16:38:12 +02:00
|
|
|
const LoginTranslations({
|
2025-01-28 12:50:08 +01:00
|
|
|
this.emailEmpty = "Please enter your email address",
|
|
|
|
this.passwordEmpty = "Please enter your password",
|
|
|
|
this.emailInvalid = "Please enter a valid email address",
|
|
|
|
this.loginButton = "Log in",
|
|
|
|
this.forgotPasswordButton = "Forgot password?",
|
|
|
|
this.requestForgotPasswordButton = "Send link",
|
|
|
|
this.registrationButton = "Create account",
|
2022-09-27 16:38:12 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
final String emailInvalid;
|
|
|
|
final String emailEmpty;
|
|
|
|
final String passwordEmpty;
|
2022-11-04 09:23:48 +01:00
|
|
|
final String loginButton;
|
|
|
|
final String forgotPasswordButton;
|
|
|
|
final String requestForgotPasswordButton;
|
|
|
|
final String registrationButton;
|
2022-09-27 16:38:12 +02:00
|
|
|
}
|
|
|
|
|
2025-01-28 16:35:59 +01:00
|
|
|
/// Accessibility identifiers for the standard widgets in the component.
|
|
|
|
class LoginAccessibilityIdentifiers {
|
|
|
|
/// Default [LoginAccessibilityIdentifiers] constructor where all the
|
|
|
|
/// identifiers are required. This is to ensure that apps automatically break
|
|
|
|
/// when new identifiers are added.
|
|
|
|
const LoginAccessibilityIdentifiers({
|
|
|
|
required this.emailTextFieldIdentifier,
|
|
|
|
required this.passwordTextFieldIdentifier,
|
|
|
|
required this.loginButtonIdentifier,
|
|
|
|
required this.forgotPasswordButtonIdentifier,
|
|
|
|
required this.requestForgotPasswordButtonIdentifier,
|
|
|
|
required this.registrationButtonIdentifier,
|
|
|
|
});
|
|
|
|
|
|
|
|
/// Empty [LoginAccessibilityIdentifiers] constructor where all the
|
|
|
|
/// identifiers are already set to their default values. You can override all
|
|
|
|
/// or some of the default values.
|
|
|
|
const LoginAccessibilityIdentifiers.empty({
|
|
|
|
this.emailTextFieldIdentifier = "email_text_field",
|
|
|
|
this.passwordTextFieldIdentifier = "password_text_field",
|
|
|
|
this.loginButtonIdentifier = "login_button",
|
|
|
|
this.forgotPasswordButtonIdentifier = "forgot_password_button",
|
|
|
|
this.requestForgotPasswordButtonIdentifier =
|
|
|
|
"request_forgot_password_button",
|
|
|
|
this.registrationButtonIdentifier = "registration_button",
|
|
|
|
});
|
|
|
|
|
|
|
|
/// Identifier for the email text field.
|
|
|
|
final String emailTextFieldIdentifier;
|
|
|
|
|
|
|
|
/// Identifier for the password text field.
|
|
|
|
final String passwordTextFieldIdentifier;
|
|
|
|
|
|
|
|
/// Identifier for the login button.
|
|
|
|
final String loginButtonIdentifier;
|
|
|
|
|
|
|
|
/// Identifier for the forgot password button.
|
|
|
|
final String forgotPasswordButtonIdentifier;
|
|
|
|
|
|
|
|
/// Identifier for the request forgot password button.
|
|
|
|
final String requestForgotPasswordButtonIdentifier;
|
|
|
|
|
|
|
|
/// Identifier for the registration button.
|
|
|
|
final String registrationButtonIdentifier;
|
|
|
|
}
|
|
|
|
|
2023-03-14 11:16:13 +01:00
|
|
|
Widget _createEmailInputContainer(Widget child) => Padding(
|
|
|
|
padding: const EdgeInsets.only(bottom: 15),
|
|
|
|
child: child,
|
|
|
|
);
|
2022-09-29 12:14:30 +02:00
|
|
|
|
2024-02-09 15:47:44 +01:00
|
|
|
Widget _createPasswordInputContainer(Widget child) => child;
|
2022-09-29 12:14:30 +02:00
|
|
|
|
2022-09-27 16:38:12 +02:00
|
|
|
Widget _createLoginButton(
|
|
|
|
BuildContext context,
|
|
|
|
OptionalAsyncCallback onPressed,
|
|
|
|
bool disabled,
|
2022-10-31 14:37:09 +01:00
|
|
|
OptionalAsyncCallback onDisabledPress,
|
2022-11-08 09:56:05 +01:00
|
|
|
LoginOptions options,
|
2024-02-06 16:05:46 +01:00
|
|
|
) =>
|
|
|
|
Opacity(
|
|
|
|
opacity: disabled ? 0.5 : 1.0,
|
2024-08-08 09:44:01 +02:00
|
|
|
child: Row(
|
|
|
|
children: [
|
|
|
|
Expanded(
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
|
|
child: FilledButton(
|
|
|
|
onPressed: () async =>
|
|
|
|
!disabled ? await onPressed() : await onDisabledPress(),
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.all(8),
|
|
|
|
child: Text(
|
|
|
|
options.translations.loginButton,
|
|
|
|
style: Theme.of(context).textTheme.displayLarge,
|
|
|
|
),
|
|
|
|
),
|
2024-04-19 10:10:09 +02:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
2024-08-08 09:44:01 +02:00
|
|
|
],
|
2024-02-06 16:05:46 +01:00
|
|
|
),
|
|
|
|
);
|
2022-09-27 16:38:12 +02:00
|
|
|
|
|
|
|
Widget _createForgotPasswordButton(
|
|
|
|
BuildContext context,
|
|
|
|
OptionalAsyncCallback onPressed,
|
|
|
|
bool disabled,
|
2022-10-31 14:37:09 +01:00
|
|
|
OptionalAsyncCallback onDisabledPress,
|
2022-11-08 09:56:05 +01:00
|
|
|
LoginOptions options,
|
2024-02-06 16:05:46 +01:00
|
|
|
) =>
|
|
|
|
Opacity(
|
|
|
|
opacity: disabled ? 0.5 : 1.0,
|
2024-04-19 10:10:09 +02:00
|
|
|
child: TextButton(
|
2024-02-06 16:05:46 +01:00
|
|
|
onPressed: !disabled ? onPressed : onDisabledPress,
|
2024-04-19 10:10:09 +02:00
|
|
|
child: Text(
|
|
|
|
options.translations.forgotPasswordButton,
|
|
|
|
style: const TextStyle(
|
|
|
|
decoration: TextDecoration.underline,
|
|
|
|
decorationColor: Color(0xff8D8D8D),
|
|
|
|
fontSize: 12,
|
|
|
|
fontWeight: FontWeight.w500,
|
|
|
|
color: Color(0xff8D8D8D),
|
|
|
|
),
|
|
|
|
),
|
2024-02-06 16:05:46 +01:00
|
|
|
),
|
|
|
|
);
|
2022-09-27 16:38:12 +02:00
|
|
|
|
2022-09-29 17:22:26 +02:00
|
|
|
Widget _createRequestForgotPasswordButton(
|
|
|
|
BuildContext context,
|
|
|
|
OptionalAsyncCallback onPressed,
|
|
|
|
bool disabled,
|
2022-10-31 14:37:09 +01:00
|
|
|
OptionalAsyncCallback onDisabledPress,
|
2022-11-08 09:56:05 +01:00
|
|
|
LoginOptions options,
|
2024-02-06 16:05:46 +01:00
|
|
|
) =>
|
|
|
|
Opacity(
|
|
|
|
opacity: disabled ? 0.5 : 1.0,
|
2024-08-14 14:30:47 +02:00
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.only(top: 8),
|
|
|
|
child: InkWell(
|
|
|
|
onTap: !disabled ? onPressed : onDisabledPress,
|
|
|
|
child: Container(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
borderRadius: BorderRadius.circular(20),
|
|
|
|
color: const Color(0xff71C6D1),
|
|
|
|
),
|
|
|
|
height: 44,
|
|
|
|
width: 254,
|
|
|
|
child: Center(
|
|
|
|
child: Text(
|
|
|
|
options.translations.requestForgotPasswordButton,
|
|
|
|
style: const TextStyle(
|
|
|
|
fontWeight: FontWeight.w800,
|
|
|
|
fontSize: 20,
|
|
|
|
color: Colors.white,
|
|
|
|
),
|
2024-04-19 10:10:09 +02:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
2024-02-06 16:05:46 +01:00
|
|
|
),
|
|
|
|
);
|
2022-09-29 17:22:26 +02:00
|
|
|
|
2022-09-27 16:38:12 +02:00
|
|
|
Widget _createRegisterButton(
|
|
|
|
BuildContext context,
|
|
|
|
OptionalAsyncCallback onPressed,
|
|
|
|
bool disabled,
|
2022-10-31 14:37:09 +01:00
|
|
|
OptionalAsyncCallback onDisabledPress,
|
2022-11-08 09:56:05 +01:00
|
|
|
LoginOptions options,
|
2024-02-06 16:05:46 +01:00
|
|
|
) =>
|
|
|
|
Opacity(
|
|
|
|
opacity: disabled ? 0.5 : 1.0,
|
2024-04-19 10:10:09 +02:00
|
|
|
child: TextButton(
|
2024-02-06 16:05:46 +01:00
|
|
|
onPressed: !disabled ? onPressed : onDisabledPress,
|
2024-04-19 10:10:09 +02:00
|
|
|
child: Text(
|
|
|
|
options.translations.registrationButton,
|
2024-08-08 09:44:01 +02:00
|
|
|
style: Theme.of(context).textTheme.displayMedium!.copyWith(
|
|
|
|
decoration: TextDecoration.underline,
|
|
|
|
),
|
2024-04-19 10:10:09 +02:00
|
|
|
),
|
2024-02-06 16:05:46 +01:00
|
|
|
),
|
|
|
|
);
|
2022-09-27 16:38:12 +02:00
|
|
|
|
|
|
|
typedef ButtonBuilder = Widget Function(
|
|
|
|
BuildContext context,
|
|
|
|
OptionalAsyncCallback onPressed,
|
2024-02-06 16:05:46 +01:00
|
|
|
// ignore: avoid_positional_boolean_parameters
|
2022-09-27 16:38:12 +02:00
|
|
|
bool isDisabled,
|
2022-10-31 14:37:09 +01:00
|
|
|
OptionalAsyncCallback onDisabledPress,
|
2022-11-08 09:56:05 +01:00
|
|
|
LoginOptions options,
|
2022-09-27 16:38:12 +02:00
|
|
|
);
|
|
|
|
|
2022-09-29 12:14:30 +02:00
|
|
|
typedef InputContainerBuilder = Widget Function(
|
|
|
|
Widget child,
|
|
|
|
);
|
|
|
|
|
2022-09-27 16:38:12 +02:00
|
|
|
typedef OptionalAsyncCallback = FutureOr<void> Function();
|