diff --git a/assets/translations/app_en.arb b/assets/translations/app_en.arb index 71dddc9..9c3e567 100644 --- a/assets/translations/app_en.arb +++ b/assets/translations/app_en.arb @@ -35,6 +35,25 @@ "discover": "Discover", "cart": "Cart", "transactions": "Transactions", - "profile": "Profile" + "profile": "Profile", + "forgotPassword": "Forgot Password", + "forgotPasswordSubtitle": "Please enter your phone number to reset your password.", + "phoneNumber": "Phone Number", + "sendCode": "Send Code", + "verifyYourAccount": "Verify Your Account", + "verifyAccountSubtitle": "We’ve sent a verification code to", + "verifyAccount": "Verify Account", + "didNotReceiveCode": "Didn’t receive the code?", + "resend": "Resend", + "createNewPassword": "Create New Password", + "createNewPasswordSubtitle": "Please create your new password.", + "oldPassword": "Old Password", + "newPassword": "New Password", + "confirmNewPassword": "Confirm New Password", + "passwordHint": "*Password must have at least 8 characters, including number and symbol.", + "resetPassword": "Reset Password", + "changePasswordSuccess": "Change Password Success", + "changePasswordMessage": "We have updated your password. Please remember your password, thank you!", + "login": "Login" } \ No newline at end of file diff --git a/assets/translations/app_ru.arb b/assets/translations/app_ru.arb index 5ae464e..eb72bc0 100644 --- a/assets/translations/app_ru.arb +++ b/assets/translations/app_ru.arb @@ -35,6 +35,25 @@ "discover": "Обзор", "cart": "Корзина", "transactions": "Транзакции", - "profile": "Профиль" + "profile": "Профиль", + "forgotPassword": "Забыли пароль", + "forgotPasswordSubtitle": "Пожалуйста, введите свой номер телефона, чтобы сбросить пароль.", + "phoneNumber": "Номер телефона", + "sendCode": "Отправить код", + "verifyYourAccount": "Подтвердите аккаунт", + "verifyAccountSubtitle": "Мы отправили код подтверждения на", + "verifyAccount": "Подтвердить", + "didNotReceiveCode": "Не получили код?", + "resend": "Отправить повторно", + "createNewPassword": "Создайте новый пароль", + "createNewPasswordSubtitle": "Пожалуйста, создайте новый пароль.", + "oldPassword": "Старый пароль", + "newPassword": "Новый пароль", + "confirmNewPassword": "Подтвердите пароль", + "passwordHint": "*Пароль должен содержать не менее 8 символов, включая цифры и символы.", + "resetPassword": "Сбросить пароль", + "changePasswordSuccess": "Пароль успешно изменён", + "changePasswordMessage": "Ваш пароль был обновлён. Пожалуйста, запомните его. Спасибо!", + "login": "Войти" } \ No newline at end of file diff --git a/assets/translations/app_uz.arb b/assets/translations/app_uz.arb index 5fd8f8c..e63a256 100644 --- a/assets/translations/app_uz.arb +++ b/assets/translations/app_uz.arb @@ -35,6 +35,25 @@ "discover": "Kashf etish", "cart": "Savat", "transactions": "Tranzaksiyalar", - "profile": "Profil" + "profile": "Profil", + "forgotPassword": "Parolni unutdingizmi", + "forgotPasswordSubtitle": "Parolingizni tiklash uchun telefon raqamingizni kiriting.", + "phoneNumber": "Telefon raqami", + "sendCode": "Kod yuborish", + "verifyYourAccount": "Hisobni tasdiqlang", + "verifyAccountSubtitle": "Tasdiqlash kodi quyidagi raqamga yuborildi", + "verifyAccount": "Hisobni tasdiqlash", + "didNotReceiveCode": "Kod kelmadimi?", + "resend": "Qayta yuborish", + "createNewPassword": "Yangi parol yarating", + "createNewPasswordSubtitle": "Iltimos, yangi parolingizni yarating.", + "oldPassword": "Eski parol", + "newPassword": "Yangi parol", + "confirmNewPassword": "Parolni tasdiqlang", + "passwordHint": "*Parol kamida 8 ta belgi, raqam va belgidan iborat bo‘lishi kerak.", + "resetPassword": "Parolni tiklash", + "changePasswordSuccess": "Parol muvaffaqiyatli o‘zgartirildi", + "changePasswordMessage": "Parolingiz yangilandi. Iltimos, uni eslab qoling. Rahmat!", + "login": "Kirish" } \ No newline at end of file diff --git a/lib/core/helpers/string_helpers.dart b/lib/core/helpers/string_helpers.dart new file mode 100644 index 0000000..6094b35 --- /dev/null +++ b/lib/core/helpers/string_helpers.dart @@ -0,0 +1,22 @@ +class StringHelpers { + static String formatUzbekPhoneNumber(String input) { + final digits = input.replaceAll(RegExp(r'\D'), ''); + + String formatted = digits; + if (formatted.startsWith('998')) { + formatted = formatted.substring(3); + } else if (formatted.startsWith('8')) { + formatted = formatted.substring(1); + } + + final buffer = StringBuffer('+998 '); + for (int i = 0; i < formatted.length && i < 9; i++) { + buffer.write(formatted[i]); + if (i == 1 || i == 4 || i == 6) { + buffer.write(' '); + } + } + + return buffer.toString().trim(); + } +} diff --git a/lib/core/l10n/app_localizations.dart b/lib/core/l10n/app_localizations.dart index 3c2dc92..b5d288e 100644 --- a/lib/core/l10n/app_localizations.dart +++ b/lib/core/l10n/app_localizations.dart @@ -279,6 +279,114 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Profile'** String get profile; + + /// No description provided for @forgotPassword. + /// + /// In en, this message translates to: + /// **'Forgot Password'** + String get forgotPassword; + + /// No description provided for @forgotPasswordSubtitle. + /// + /// In en, this message translates to: + /// **'Please enter your phone number to reset your password.'** + String get forgotPasswordSubtitle; + + /// No description provided for @phoneNumber. + /// + /// In en, this message translates to: + /// **'Phone Number'** + String get phoneNumber; + + /// No description provided for @sendCode. + /// + /// In en, this message translates to: + /// **'Send Code'** + String get sendCode; + + /// No description provided for @verifyYourAccount. + /// + /// In en, this message translates to: + /// **'Verify Your Account'** + String get verifyYourAccount; + + /// No description provided for @verifyAccountSubtitle. + /// + /// In en, this message translates to: + /// **'We’ve sent a verification code to'** + String get verifyAccountSubtitle; + + /// No description provided for @verifyAccount. + /// + /// In en, this message translates to: + /// **'Verify Account'** + String get verifyAccount; + + /// No description provided for @didNotReceiveCode. + /// + /// In en, this message translates to: + /// **'Didn’t receive the code?'** + String get didNotReceiveCode; + + /// No description provided for @resend. + /// + /// In en, this message translates to: + /// **'Resend'** + String get resend; + + /// No description provided for @createNewPassword. + /// + /// In en, this message translates to: + /// **'Create New Password'** + String get createNewPassword; + + /// No description provided for @createNewPasswordSubtitle. + /// + /// In en, this message translates to: + /// **'Please create your new password.'** + String get createNewPasswordSubtitle; + + /// No description provided for @oldPassword. + /// + /// In en, this message translates to: + /// **'Old Password'** + String get oldPassword; + + /// No description provided for @newPassword. + /// + /// In en, this message translates to: + /// **'New Password'** + String get newPassword; + + /// No description provided for @confirmNewPassword. + /// + /// In en, this message translates to: + /// **'Confirm New Password'** + String get confirmNewPassword; + + /// No description provided for @passwordHint. + /// + /// In en, this message translates to: + /// **'*Password must have at least 8 characters, including number and symbol.'** + String get passwordHint; + + /// No description provided for @resetPassword. + /// + /// In en, this message translates to: + /// **'Reset Password'** + String get resetPassword; + + /// No description provided for @changePasswordSuccess. + /// + /// In en, this message translates to: + /// **'Change Password Success'** + String get changePasswordSuccess; + + /// No description provided for @changePasswordMessage. + /// + /// In en, this message translates to: + /// **'We have updated your password. Please remember your password, thank you!'** + String get changePasswordMessage; } class _AppLocalizationsDelegate diff --git a/lib/core/l10n/app_localizations_en.dart b/lib/core/l10n/app_localizations_en.dart index 6463562..a29949e 100644 --- a/lib/core/l10n/app_localizations_en.dart +++ b/lib/core/l10n/app_localizations_en.dart @@ -105,4 +105,61 @@ class AppLocalizationsEn extends AppLocalizations { @override String get profile => 'Profile'; + + @override + String get forgotPassword => 'Forgot Password'; + + @override + String get forgotPasswordSubtitle => + 'Please enter your phone number to reset your password.'; + + @override + String get phoneNumber => 'Phone Number'; + + @override + String get sendCode => 'Send Code'; + + @override + String get verifyYourAccount => 'Verify Your Account'; + + @override + String get verifyAccountSubtitle => 'We’ve sent a verification code to'; + + @override + String get verifyAccount => 'Verify Account'; + + @override + String get didNotReceiveCode => 'Didn’t receive the code?'; + + @override + String get resend => 'Resend'; + + @override + String get createNewPassword => 'Create New Password'; + + @override + String get createNewPasswordSubtitle => 'Please create your new password.'; + + @override + String get oldPassword => 'Old Password'; + + @override + String get newPassword => 'New Password'; + + @override + String get confirmNewPassword => 'Confirm New Password'; + + @override + String get passwordHint => + '*Password must have at least 8 characters, including number and symbol.'; + + @override + String get resetPassword => 'Reset Password'; + + @override + String get changePasswordSuccess => 'Change Password Success'; + + @override + String get changePasswordMessage => + 'We have updated your password. Please remember your password, thank you!'; } diff --git a/lib/core/l10n/app_localizations_ru.dart b/lib/core/l10n/app_localizations_ru.dart index a39cfd0..c9a2178 100644 --- a/lib/core/l10n/app_localizations_ru.dart +++ b/lib/core/l10n/app_localizations_ru.dart @@ -103,4 +103,61 @@ class AppLocalizationsRu extends AppLocalizations { @override String get profile => 'Профиль'; + + @override + String get forgotPassword => 'Забыли пароль'; + + @override + String get forgotPasswordSubtitle => + 'Пожалуйста, введите свой номер телефона, чтобы сбросить пароль.'; + + @override + String get phoneNumber => 'Номер телефона'; + + @override + String get sendCode => 'Отправить код'; + + @override + String get verifyYourAccount => 'Подтвердите аккаунт'; + + @override + String get verifyAccountSubtitle => 'Мы отправили код подтверждения на'; + + @override + String get verifyAccount => 'Подтвердить'; + + @override + String get didNotReceiveCode => 'Не получили код?'; + + @override + String get resend => 'Отправить повторно'; + + @override + String get createNewPassword => 'Создайте новый пароль'; + + @override + String get createNewPasswordSubtitle => 'Пожалуйста, создайте новый пароль.'; + + @override + String get oldPassword => 'Старый пароль'; + + @override + String get newPassword => 'Новый пароль'; + + @override + String get confirmNewPassword => 'Подтвердите пароль'; + + @override + String get passwordHint => + '*Пароль должен содержать не менее 8 символов, включая цифры и символы.'; + + @override + String get resetPassword => 'Сбросить пароль'; + + @override + String get changePasswordSuccess => 'Пароль успешно изменён'; + + @override + String get changePasswordMessage => + 'Ваш пароль был обновлён. Пожалуйста, запомните его. Спасибо!'; } diff --git a/lib/core/l10n/app_localizations_uz.dart b/lib/core/l10n/app_localizations_uz.dart index 0b88e4c..bee7956 100644 --- a/lib/core/l10n/app_localizations_uz.dart +++ b/lib/core/l10n/app_localizations_uz.dart @@ -103,4 +103,63 @@ class AppLocalizationsUz extends AppLocalizations { @override String get profile => 'Profil'; + + @override + String get forgotPassword => 'Parolni unutdingizmi'; + + @override + String get forgotPasswordSubtitle => + 'Parolingizni tiklash uchun telefon raqamingizni kiriting.'; + + @override + String get phoneNumber => 'Telefon raqami'; + + @override + String get sendCode => 'Kod yuborish'; + + @override + String get verifyYourAccount => 'Hisobni tasdiqlang'; + + @override + String get verifyAccountSubtitle => + 'Tasdiqlash kodi quyidagi raqamga yuborildi'; + + @override + String get verifyAccount => 'Hisobni tasdiqlash'; + + @override + String get didNotReceiveCode => 'Kod kelmadimi?'; + + @override + String get resend => 'Qayta yuborish'; + + @override + String get createNewPassword => 'Yangi parol yarating'; + + @override + String get createNewPasswordSubtitle => + 'Iltimos, yangi parolingizni yarating.'; + + @override + String get oldPassword => 'Eski parol'; + + @override + String get newPassword => 'Yangi parol'; + + @override + String get confirmNewPassword => 'Parolni tasdiqlang'; + + @override + String get passwordHint => + '*Parol kamida 8 ta belgi, raqam va belgidan iborat bo‘lishi kerak.'; + + @override + String get resetPassword => 'Parolni tiklash'; + + @override + String get changePasswordSuccess => 'Parol muvaffaqiyatli o‘zgartirildi'; + + @override + String get changePasswordMessage => + 'Parolingiz yangilandi. Iltimos, uni eslab qoling. Rahmat!'; } diff --git a/lib/core/router/app_routes.dart b/lib/core/router/app_routes.dart index cdc25d8..b0d1490 100644 --- a/lib/core/router/app_routes.dart +++ b/lib/core/router/app_routes.dart @@ -1,5 +1,8 @@ import 'package:flutter/cupertino.dart'; +import 'package:food_delivery_client/feature/auth/presentation/pages/create_new_password_page/create_new_password_page.dart'; +import 'package:food_delivery_client/feature/auth/presentation/pages/forgot_password_page/forgot_password_page.dart'; import 'package:food_delivery_client/feature/auth/presentation/pages/login_page/login_page.dart'; +import 'package:food_delivery_client/feature/auth/presentation/pages/verify_account_page/verify_account_page.dart'; import 'package:food_delivery_client/feature/onboarding/presentation/pages/onboarding_page/onboarding_page.dart'; import 'package:food_delivery_client/feature/onboarding/presentation/pages/splash_page/splash_page.dart'; @@ -30,6 +33,23 @@ class AppRoutes { path: Routes.main, pageBuilder: (context, state) => CupertinoPage(child: MainPage()), ), + GoRoute( + path: Routes.forgotPassword, + pageBuilder: (context, state) => + CupertinoPage(child: ForgotPasswordPage()), + ), + GoRoute( + path: Routes.verifyAccount, + pageBuilder: (context, state) => CupertinoPage( + child: VerifyAccountPage(phoneNumber: state.extra as String), + ), + ), + GoRoute( + path: Routes.createNewPassword, + pageBuilder: (context, state) => CupertinoPage( + child: CreateNewPasswordPage(phoneNumber: state.extra as String), + ), + ), ], ); } diff --git a/lib/core/router/routes_name.dart b/lib/core/router/routes_name.dart index d19c679..12d5d49 100644 --- a/lib/core/router/routes_name.dart +++ b/lib/core/router/routes_name.dart @@ -4,12 +4,7 @@ abstract class Routes { static const String login = '/login'; static const String register = '/register'; static const String main = '/main'; - static const String categories = '/categories'; - static const String filters = '/filters'; - static const String browse = '/browse'; - static const String forgotPassword = "/forgot-password"; - static const String restaurantsByCategory = '/restaurants-by-category'; - static const String verifyPhoneNumber = "/verify-phone-number"; - static const String verifyOtpCode = "/verify-otp-code"; - static const String resetPassword = "/reset-password"; + static const String createNewPassword = '/create-new-password'; + static const String forgotPassword = '/forgot-password'; + static const String verifyAccount = '/verify-account'; } diff --git a/lib/core/theme/app_colors.dart b/lib/core/theme/app_colors.dart index a0282e7..88d03c8 100644 --- a/lib/core/theme/app_colors.dart +++ b/lib/core/theme/app_colors.dart @@ -55,6 +55,5 @@ abstract class AppColors { static const Color cA7AEC1 = Color(0xFFA7AEC1); static const Color c151B33 = Color(0xFF151B33); static const Color cE5E7EB = Color(0xFFE5E7EB); - - + static const Color cE2E8F0 = Color(0xFFE2E8F0); } diff --git a/lib/core/theme/app_theme_colors.dart b/lib/core/theme/app_theme_colors.dart index ac86d80..b1b17e6 100644 --- a/lib/core/theme/app_theme_colors.dart +++ b/lib/core/theme/app_theme_colors.dart @@ -11,8 +11,6 @@ class AppThemeColors extends ThemeExtension { final Color inActiveColor1; final Color inActiveColor2; - - AppThemeColors({ required this.onBoardingColor, required this.boxShadow, @@ -22,7 +20,6 @@ class AppThemeColors extends ThemeExtension { required this.inActiveColor, required this.inActiveColor1, required this.inActiveColor2, - }); static AppThemeColors light = AppThemeColors( @@ -33,7 +30,7 @@ class AppThemeColors extends ThemeExtension { borderColor: AppColors.cE2E4EA, inActiveColor: AppColors.cE2E4EA, inActiveColor1: AppColors.cA9A9A9, - inActiveColor2: AppColors.cE5E7EB + inActiveColor2: AppColors.cE5E7EB, ); static AppThemeColors dark = AppThemeColors( @@ -44,7 +41,7 @@ class AppThemeColors extends ThemeExtension { borderColor: AppColors.c292F3D, inActiveColor: AppColors.c292F3D, inActiveColor1: AppColors.c626262, - inActiveColor2: AppColors.c292F3D + inActiveColor2: AppColors.c292F3D, ); @override @@ -57,7 +54,6 @@ class AppThemeColors extends ThemeExtension { Color? inActiveColor, Color? inActiveColor1, Color? inActiveColor2, - }) { return AppThemeColors( onBoardingColor: onBoardingColor ?? this.onBoardingColor, @@ -67,7 +63,7 @@ class AppThemeColors extends ThemeExtension { borderColor: borderColor ?? this.borderColor, inActiveColor: inActiveColor ?? this.inActiveColor, inActiveColor1: inActiveColor1 ?? this.inActiveColor1, - inActiveColor2: inActiveColor2??this.inActiveColor2 + inActiveColor2: inActiveColor2 ?? this.inActiveColor2, ); } diff --git a/lib/core/theme/app_theme_textstyles.dart b/lib/core/theme/app_theme_textstyles.dart index 453d790..e00b5cc 100644 --- a/lib/core/theme/app_theme_textstyles.dart +++ b/lib/core/theme/app_theme_textstyles.dart @@ -5,6 +5,8 @@ import 'package:food_delivery_client/core/core.dart'; class AppThemeTextStyles extends ThemeExtension { //Regular fonts final TextStyle size14Regular; + final TextStyle size14Regular1; + //Medium @@ -14,6 +16,8 @@ class AppThemeTextStyles extends ThemeExtension { final TextStyle size16SemiBold; final TextStyle size24SemiBold; + final TextStyle size24SemiBold1; + //Bold @@ -25,9 +29,11 @@ class AppThemeTextStyles extends ThemeExtension { AppThemeTextStyles({ required this.size14Regular, + required this.size14Regular1, required this.size16Medium, required this.size16SemiBold, required this.size24SemiBold, + required this.size24SemiBold1, required this.size14Bold, required this.size24Bold, required this.size64Black, @@ -47,6 +53,13 @@ class AppThemeTextStyles extends ThemeExtension { fontFamily: _fontRegular, color: AppColors.c151B33, ), + size14Regular1: TextStyle( + fontSize: 14, + height: 1.6, + fontWeight: FontWeight.w400, + fontFamily: _fontRegular, + color: AppColors.c151B33, + ), size16Medium: TextStyle( fontSize: 16, height: 1.3, @@ -67,6 +80,14 @@ class AppThemeTextStyles extends ThemeExtension { fontFamily: _fontSemiBold, color: AppColors.c1A202C, ), + size24SemiBold1: TextStyle( + fontSize: 24, + height: 1.25, + letterSpacing: -.48, + fontWeight: FontWeight.w600, + fontFamily: _fontSemiBold, + color: AppColors.c000000, + ), size14Bold: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, @@ -95,6 +116,13 @@ class AppThemeTextStyles extends ThemeExtension { fontFamily: _fontRegular, color: AppColors.cFFFFFF, ), + size14Regular1: TextStyle( + fontSize: 14, + height: 1.6, + fontWeight: FontWeight.w400, + fontFamily: _fontRegular, + color: AppColors.cA9A9A9, + ), size16Medium: TextStyle( fontSize: 16, height: 1.3, @@ -115,6 +143,14 @@ class AppThemeTextStyles extends ThemeExtension { fontFamily: _fontSemiBold, color: AppColors.cFFFFFF, ), + size24SemiBold1: TextStyle( + fontSize: 24, + height: 1.25, + letterSpacing: -.48, + fontWeight: FontWeight.w600, + fontFamily: _fontSemiBold, + color: AppColors.cFFFFFF, + ), size14Bold: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, @@ -138,18 +174,22 @@ class AppThemeTextStyles extends ThemeExtension { @override ThemeExtension copyWith({ TextStyle? size14Regular, + TextStyle? size14Regular1, TextStyle? size16Medium, TextStyle? size16SemiBold, TextStyle? size24SemiBold, + TextStyle? size24SemiBold1, TextStyle? size14Bold, TextStyle? size24Bold, TextStyle? size64Black, }) { return AppThemeTextStyles( size14Regular: size14Regular ?? this.size14Regular, + size14Regular1: size14Regular1 ?? this.size14Regular1, size16Medium: size16Medium ?? this.size16Medium, size16SemiBold: size16SemiBold ?? this.size16SemiBold, size24SemiBold: size24SemiBold ?? this.size24SemiBold, + size24SemiBold1: size24SemiBold1 ?? this.size24SemiBold1, size14Bold: size14Bold ?? this.size14Bold, size24Bold: size24Bold ?? this.size24Bold, size64Black: size64Black ?? this.size64Black, @@ -164,9 +204,11 @@ class AppThemeTextStyles extends ThemeExtension { if (other is! AppThemeTextStyles) return this; return AppThemeTextStyles( size14Regular: TextStyle.lerp(size14Regular, other.size14Regular, t)!, + size14Regular1: TextStyle.lerp(size14Regular1, other.size14Regular1, t)!, size16Medium: TextStyle.lerp(size16Medium, other.size16Medium, t)!, size16SemiBold: TextStyle.lerp(size16SemiBold, other.size16SemiBold, t)!, size24SemiBold: TextStyle.lerp(size24SemiBold, other.size24SemiBold, t)!, + size24SemiBold1: TextStyle.lerp(size24SemiBold1, other.size24SemiBold1, t)!, size14Bold: TextStyle.lerp(size14Bold, other.size14Bold, t)!, size24Bold: TextStyle.lerp(size24Bold, other.size24Bold, t)!, size64Black: TextStyle.lerp(size64Black, other.size64Black, t)!, diff --git a/lib/feature/auth/presentation/pages/create_new_password_page/create_new_password_page.dart b/lib/feature/auth/presentation/pages/create_new_password_page/create_new_password_page.dart new file mode 100644 index 0000000..6adcbb3 --- /dev/null +++ b/lib/feature/auth/presentation/pages/create_new_password_page/create_new_password_page.dart @@ -0,0 +1,12 @@ +import '../../../../../food_delivery_client.dart'; + +class CreateNewPasswordPage extends StatelessWidget { + const CreateNewPasswordPage({super.key, required this.phoneNumber}); + + final String phoneNumber; + + @override + Widget build(BuildContext context) { + return WLayout(child: Scaffold()); + } +} diff --git a/lib/feature/auth/presentation/pages/create_new_password_page/widgets/create_new_password_body.dart b/lib/feature/auth/presentation/pages/create_new_password_page/widgets/create_new_password_body.dart new file mode 100644 index 0000000..0a96a3b --- /dev/null +++ b/lib/feature/auth/presentation/pages/create_new_password_page/widgets/create_new_password_body.dart @@ -0,0 +1,10 @@ +import '../../../../../../food_delivery_client.dart'; + +class CreateNewPasswordBody extends StatelessWidget { + const CreateNewPasswordBody({super.key}); + + @override + Widget build(BuildContext context) { + return WLayout(child: Scaffold()); + } +} diff --git a/lib/feature/auth/presentation/pages/forgot_password_page/forgot_password_page.dart b/lib/feature/auth/presentation/pages/forgot_password_page/forgot_password_page.dart new file mode 100644 index 0000000..cd5e9bf --- /dev/null +++ b/lib/feature/auth/presentation/pages/forgot_password_page/forgot_password_page.dart @@ -0,0 +1,12 @@ +import 'package:food_delivery_client/feature/auth/presentation/pages/forgot_password_page/widgets/forgot_password_body.dart'; + +import '../../../../../food_delivery_client.dart'; + +class ForgotPasswordPage extends StatelessWidget { + const ForgotPasswordPage({super.key}); + + @override + Widget build(BuildContext context) { + return ForgotPasswordBody(); + } +} diff --git a/lib/feature/auth/presentation/pages/forgot_password_page/widgets/forgot_password_body.dart b/lib/feature/auth/presentation/pages/forgot_password_page/widgets/forgot_password_body.dart new file mode 100644 index 0000000..c5cc56a --- /dev/null +++ b/lib/feature/auth/presentation/pages/forgot_password_page/widgets/forgot_password_body.dart @@ -0,0 +1,115 @@ +import 'package:food_delivery_client/core/helpers/formatters.dart'; +import 'package:food_delivery_client/core/helpers/validator_helpers.dart'; +import 'package:food_delivery_client/feature/common/presentation/widgets/app_text_form_field.dart'; + +import '../../../../../../food_delivery_client.dart'; + +class ForgotPasswordBody extends StatefulWidget { + const ForgotPasswordBody({super.key}); + + @override + State createState() => _ForgotPasswordBodyState(); +} + +class _ForgotPasswordBodyState extends State { + late final TextEditingController _phoneNumberController; + final _formKey = GlobalKey(); + bool _isValid = false; + + void _validateForm() { + final isValid = _formKey.currentState?.validate() ?? false; + + if (isValid != _isValid) { + setState(() { + _isValid = isValid; + }); + } + } + + @override + void initState() { + _phoneNumberController = TextEditingController(); + _phoneNumberController.addListener(_validateForm); + super.initState(); + } + + @override + void dispose() { + _phoneNumberController.removeListener(_validateForm); + _phoneNumberController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Form( + key: _formKey, + autovalidateMode: AutovalidateMode.onUserInteraction, + child: WLayout( + child: Scaffold( + resizeToAvoidBottomInset: true, + body: SingleChildScrollView( + keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 30.verticalSpace, + WBackButton(), + 20.verticalSpace, + Text( + context.loc.forgotPassword, + style: context.appThemeTextStyles.size24Bold, + ), + 8.verticalSpace, + Text( + context.loc.forgotPasswordSubtitle, + style: AppTextStyles.size14Regular.copyWith( + color: AppColors.cA7AEC1, + height: 1.6, + ), + ).paddingOnly(right: 50), + 30.verticalSpace, + Text( + context.loc.phoneNumber, + style: context.appThemeTextStyles.size16Medium, + ), + 10.verticalSpace, + AppTextFormField( + controller: _phoneNumberController, + keyBoardType: TextInputType.number, + prefixIcon: Text( + "+ 998", + style: context.appThemeTextStyles.size14Regular, + ), + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + Formatters.phoneFormatter, + LengthLimitingTextInputFormatter(12), + ], + validator: (value) { + return Validators.validatePhoneNumber( + _phoneNumberController.text.trim(), + ); + }, + ), + 100.verticalSpace, + AppButton( + name: context.loc.sendCode, + isActive: _isValid, + onPressed: () { + context.push( + Routes.verifyAccount, + extra: + "+998${_phoneNumberController.text.trim().replaceAll(" ", "")}", + ); + if (_formKey.currentState?.validate() ?? false) {} + }, + ), + ], + ).paddingSymmetric(horizontal: 24), + ), + ), + ), + ); + } +} diff --git a/lib/feature/auth/presentation/pages/login_page/widgets/login_body.dart b/lib/feature/auth/presentation/pages/login_page/widgets/login_body.dart index e566a6b..11426cf 100644 --- a/lib/feature/auth/presentation/pages/login_page/widgets/login_body.dart +++ b/lib/feature/auth/presentation/pages/login_page/widgets/login_body.dart @@ -108,7 +108,12 @@ class _WLoginBodyState extends State { ), 10.verticalSpace, AppTextFormField( - prefixIcon: Text("+ 998"), + prefixIcon: Text( + "+ 998", + style: context + .appThemeTextStyles + .size14Regular, + ), controller: _phoneNumberController, hintText: context.loc.enter_email_or_phone, inputFormatters: [ @@ -143,7 +148,9 @@ class _WLoginBodyState extends State { Align( alignment: AlignmentGeometry.centerRight, child: TextButton( - onPressed: () {}, + onPressed: () { + context.push(Routes.forgotPassword); + }, child: Text( context.loc.forgot_password, style: AppTextStyles.size14Regular diff --git a/lib/feature/auth/presentation/pages/verify_account_page/verify_account_page.dart b/lib/feature/auth/presentation/pages/verify_account_page/verify_account_page.dart new file mode 100644 index 0000000..f76c9a8 --- /dev/null +++ b/lib/feature/auth/presentation/pages/verify_account_page/verify_account_page.dart @@ -0,0 +1,13 @@ +import 'package:food_delivery_client/feature/auth/presentation/pages/verify_account_page/widgets/verify_account_body.dart'; +import '../../../../../food_delivery_client.dart'; + +class VerifyAccountPage extends StatelessWidget { + const VerifyAccountPage({super.key, required this.phoneNumber}); + + final String phoneNumber; + + @override + Widget build(BuildContext context) { + return VerifyAccountBody(phoneNumber: phoneNumber); + } +} diff --git a/lib/feature/auth/presentation/pages/verify_account_page/widgets/verify_account_body.dart b/lib/feature/auth/presentation/pages/verify_account_page/widgets/verify_account_body.dart new file mode 100644 index 0000000..5eea5e0 --- /dev/null +++ b/lib/feature/auth/presentation/pages/verify_account_page/widgets/verify_account_body.dart @@ -0,0 +1,160 @@ +import 'package:food_delivery_client/core/helpers/string_helpers.dart'; +import 'package:food_delivery_client/core/helpers/validator_helpers.dart'; +import 'package:pinput/pinput.dart'; +import '../../../../../../food_delivery_client.dart'; + +class VerifyAccountBody extends StatefulWidget { + const VerifyAccountBody({super.key, required this.phoneNumber}); + + final String phoneNumber; + + @override + State createState() => _VerifyAccountBodyState(); +} + +class _VerifyAccountBodyState extends State { + late TextEditingController _otpController; + final _formKey = GlobalKey(); + bool _isValid = false; + + void _formValidator() { + final isValid = _formKey.currentState?.validate() ?? false; + if (_isValid != isValid) { + setState(() { + _isValid = isValid; + }); + } + } + + @override + void initState() { + _otpController = TextEditingController(); + _otpController.addListener(_formValidator); + super.initState(); + } + + @override + void dispose() { + _otpController.removeListener(_formValidator); + _otpController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final defaultPinTheme = PinTheme( + height: 56, + width: 56, + textStyle: context.appThemeTextStyles.size24SemiBold1, + decoration: BoxDecoration( + border: Border.all( + color: context.appThemeColors.borderColor, + style: BorderStyle.solid, + width: 1, + ), + color: context.theme.scaffoldBackgroundColor, + borderRadius: AppUtils.kBorderRadius12, + ), + ); + return Form( + key: _formKey, + autovalidateMode: AutovalidateMode.onUserInteraction, + child: WLayout( + child: Scaffold( + resizeToAvoidBottomInset: true, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 30.verticalSpace, + WBackButton(), + 20.verticalSpace, + Text( + context.loc.verifyYourAccount, + style: context.appThemeTextStyles.size24Bold, + ), + 8.verticalSpace, + RichText( + text: TextSpan( + text: context.loc.verifyAccountSubtitle, + style: AppTextStyles.size14Regular.copyWith( + color: AppColors.cA7AEC1, + height: 1.6, + ), + children: [ + TextSpan(text: " "), + TextSpan( + text: StringHelpers.formatUzbekPhoneNumber( + widget.phoneNumber, + ), + style: AppTextStyles.size14Regular.copyWith( + color: AppColors.cFF6F00, + ), + ), + ], + ), + ), + 50.verticalSpace, + Pinput( + autofocus: true, + enabled: true, + length: 5, + controller: _otpController, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + LengthLimitingTextInputFormatter(5), + ], + defaultPinTheme: defaultPinTheme, + focusedPinTheme: defaultPinTheme.copyWith( + decoration: defaultPinTheme.decoration?.copyWith( + border: Border.all(color: AppColors.cFF6F00), + ), + ), + validator: (value) { + return Validators.validateOtpFields( + _otpController.text.trim(), + ); + }, + ), + 90.verticalSpace, + AppButton( + isActive: _isValid, + name: context.loc.verifyAccount, + onPressed: () {}, + ), + 20.verticalSpace, + Align( + alignment: AlignmentGeometry.center, + child: RichText( + text: TextSpan( + text: context.loc.didNotReceiveCode, + style: context.appThemeTextStyles.size14Regular1, + children: [ + WidgetSpan( + baseline: TextBaseline.alphabetic, + alignment: PlaceholderAlignment.baseline, + child: TextButton( + onPressed: () {}, + child: Text( + context.loc.resend, + style: AppTextStyles.size14Regular.copyWith( + color: AppColors.cFF6F00, + ), + ), + ), + ), + ], + ), + ), + ), + ], + ).paddingSymmetric(horizontal: 24), + ), + ), + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index 1042477..d1319ad 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -62,7 +62,8 @@ class _MyAppState extends State { debugShowCheckedModeBanner: false, theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, - themeMode: themeState.themeMode, + themeMode: ThemeMode.dark, + // themeMode: themeState.themeMode, routerConfig: sl().router, locale: state.currentLocale, supportedLocales: L10n.locales,