feat:verify your account page ui done

This commit is contained in:
jahongireshonqulov
2025-11-01 18:33:03 +05:00
parent 0b562d1dcc
commit c5a6c2dbed
21 changed files with 765 additions and 23 deletions

View File

@@ -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": "Weve sent a verification code to",
"verifyAccount": "Verify Account",
"didNotReceiveCode": "Didnt 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"
}

View File

@@ -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": "Войти"
}

View File

@@ -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 bolishi kerak.",
"resetPassword": "Parolni tiklash",
"changePasswordSuccess": "Parol muvaffaqiyatli ozgartirildi",
"changePasswordMessage": "Parolingiz yangilandi. Iltimos, uni eslab qoling. Rahmat!",
"login": "Kirish"
}

View File

@@ -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();
}
}

View File

@@ -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:
/// **'Weve 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:
/// **'Didnt 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

View File

@@ -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 => 'Weve sent a verification code to';
@override
String get verifyAccount => 'Verify Account';
@override
String get didNotReceiveCode => 'Didnt 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!';
}

View File

@@ -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 =>
'Ваш пароль был обновлён. Пожалуйста, запомните его. Спасибо!';
}

View File

@@ -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 bolishi kerak.';
@override
String get resetPassword => 'Parolni tiklash';
@override
String get changePasswordSuccess => 'Parol muvaffaqiyatli ozgartirildi';
@override
String get changePasswordMessage =>
'Parolingiz yangilandi. Iltimos, uni eslab qoling. Rahmat!';
}

View File

@@ -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),
),
),
],
);
}

View File

@@ -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';
}

View File

@@ -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);
}

View File

@@ -11,8 +11,6 @@ class AppThemeColors extends ThemeExtension<AppThemeColors> {
final Color inActiveColor1;
final Color inActiveColor2;
AppThemeColors({
required this.onBoardingColor,
required this.boxShadow,
@@ -22,7 +20,6 @@ class AppThemeColors extends ThemeExtension<AppThemeColors> {
required this.inActiveColor,
required this.inActiveColor1,
required this.inActiveColor2,
});
static AppThemeColors light = AppThemeColors(
@@ -33,7 +30,7 @@ class AppThemeColors extends ThemeExtension<AppThemeColors> {
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<AppThemeColors> {
borderColor: AppColors.c292F3D,
inActiveColor: AppColors.c292F3D,
inActiveColor1: AppColors.c626262,
inActiveColor2: AppColors.c292F3D
inActiveColor2: AppColors.c292F3D,
);
@override
@@ -57,7 +54,6 @@ class AppThemeColors extends ThemeExtension<AppThemeColors> {
Color? inActiveColor,
Color? inActiveColor1,
Color? inActiveColor2,
}) {
return AppThemeColors(
onBoardingColor: onBoardingColor ?? this.onBoardingColor,
@@ -67,7 +63,7 @@ class AppThemeColors extends ThemeExtension<AppThemeColors> {
borderColor: borderColor ?? this.borderColor,
inActiveColor: inActiveColor ?? this.inActiveColor,
inActiveColor1: inActiveColor1 ?? this.inActiveColor1,
inActiveColor2: inActiveColor2??this.inActiveColor2
inActiveColor2: inActiveColor2 ?? this.inActiveColor2,
);
}

View File

@@ -5,6 +5,8 @@ import 'package:food_delivery_client/core/core.dart';
class AppThemeTextStyles extends ThemeExtension<AppThemeTextStyles> {
//Regular fonts
final TextStyle size14Regular;
final TextStyle size14Regular1;
//Medium
@@ -14,6 +16,8 @@ class AppThemeTextStyles extends ThemeExtension<AppThemeTextStyles> {
final TextStyle size16SemiBold;
final TextStyle size24SemiBold;
final TextStyle size24SemiBold1;
//Bold
@@ -25,9 +29,11 @@ class AppThemeTextStyles extends ThemeExtension<AppThemeTextStyles> {
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<AppThemeTextStyles> {
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<AppThemeTextStyles> {
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<AppThemeTextStyles> {
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<AppThemeTextStyles> {
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<AppThemeTextStyles> {
@override
ThemeExtension<AppThemeTextStyles> 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<AppThemeTextStyles> {
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)!,

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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();
}
}

View File

@@ -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<ForgotPasswordBody> createState() => _ForgotPasswordBodyState();
}
class _ForgotPasswordBodyState extends State<ForgotPasswordBody> {
late final TextEditingController _phoneNumberController;
final _formKey = GlobalKey<FormState>();
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),
),
),
),
);
}
}

View File

@@ -108,7 +108,12 @@ class _WLoginBodyState extends State<WLoginBody> {
),
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<WLoginBody> {
Align(
alignment: AlignmentGeometry.centerRight,
child: TextButton(
onPressed: () {},
onPressed: () {
context.push(Routes.forgotPassword);
},
child: Text(
context.loc.forgot_password,
style: AppTextStyles.size14Regular

View File

@@ -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);
}
}

View File

@@ -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<VerifyAccountBody> createState() => _VerifyAccountBodyState();
}
class _VerifyAccountBodyState extends State<VerifyAccountBody> {
late TextEditingController _otpController;
final _formKey = GlobalKey<FormState>();
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),
),
),
),
);
}
}

View File

@@ -62,7 +62,8 @@ class _MyAppState extends State<MyApp> {
debugShowCheckedModeBanner: false,
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: themeState.themeMode,
themeMode: ThemeMode.dark,
// themeMode: themeState.themeMode,
routerConfig: sl<AppRoutes>().router,
locale: state.currentLocale,
supportedLocales: L10n.locales,