2022-09-27 16:38:12 +02:00
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
2024-03-04 13:25:26 +01:00
|
|
|
import 'package:flutter_login/src/config/forgot_password_spacer_options.dart';
|
2023-05-08 18:09:19 +02:00
|
|
|
import 'package:flutter_login/src/config/spacer_options.dart';
|
2022-10-27 15:57:54 +02:00
|
|
|
import 'package:flutter_login/src/service/login_validation.dart';
|
2022-09-29 17:22:26 +02:00
|
|
|
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),
|
|
|
|
labelText: 'Email address',
|
|
|
|
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),
|
|
|
|
labelText: 'Password',
|
|
|
|
border: OutlineInputBorder(),
|
|
|
|
focusedBorder: OutlineInputBorder(
|
|
|
|
borderSide: BorderSide(
|
|
|
|
color: Color(0xff71C6D1),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
labelStyle: TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontWeight: FontWeight.w400,
|
|
|
|
fontSize: 16,
|
|
|
|
),
|
|
|
|
),
|
2022-09-27 16:38:12 +02: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(),
|
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
|
|
|
|
|
|
|
/// 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
|
|
|
}
|
|
|
|
|
|
|
|
class LoginTranslations {
|
|
|
|
const LoginTranslations({
|
2024-08-16 09:20:06 +02:00
|
|
|
this.emailEmpty = 'Please enter your email address',
|
|
|
|
this.passwordEmpty = 'Please enter your password',
|
|
|
|
this.emailInvalid = 'Please enter a valid email address',
|
2024-08-08 09:44:01 +02:00
|
|
|
this.loginButton = 'Log in',
|
2022-11-04 09:23:48 +01:00
|
|
|
this.forgotPasswordButton = 'Forgot password?',
|
2024-04-19 10:10:09 +02:00
|
|
|
this.requestForgotPasswordButton = 'Send link',
|
2024-08-08 09:44:01 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
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();
|