feat:login page done

This commit is contained in:
jahongireshonqulov
2025-10-29 12:00:33 +05:00
parent d3ad5b8ddd
commit 2ed2c430c0
27 changed files with 524 additions and 178 deletions

View File

@@ -0,0 +1,3 @@
<svg width="22" height="18" viewBox="0 0 22 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.4469 9L14.5457 18H10.8296L16.6691 10.5H0V7.5H16.6691L10.8296 0H14.5457L21.4469 9Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 214 B

View File

@@ -156,7 +156,16 @@
"baskets": "Baskets", "baskets": "Baskets",
"account": "Account", "account": "Account",
"changeLanguage": "Change language", "changeLanguage": "Change language",
"language": "Language" "language": "Language",
"login": "Login",
"phone_number": "Phone number",
"enter_phone_number": "Enter phone number",
"password": "Password",
"enter_password": "Enter password",
"forgot_password": "Forgot password",
"Continue": "Continue",
"dont_have_account": "Don't have an account?",
"sign_up": "SignUp"

View File

@@ -151,7 +151,16 @@
"baskets": "Корзина", "baskets": "Корзина",
"account": "Аккаунт", "account": "Аккаунт",
"language": "Язык", "language": "Язык",
"changeLanguage": "Сменить язык" "changeLanguage": "Сменить язык",
"login": "Вход",
"phone_number": "Номер телефона",
"enter_phone_number": "Введите номер телефона",
"password": "Пароль",
"enter_password": "Введите пароль",
"forgot_password": "Забыли пароль",
"Continue": "Продолжить",
"dont_have_account": "У вас нет аккаунта?",
"sign_up": "Зарегистрироваться"

View File

@@ -151,7 +151,16 @@
"baskets": "Savatcha", "baskets": "Savatcha",
"account": "Profil", "account": "Profil",
"language": "Til", "language": "Til",
"changeLanguage": "Tilni o'zgartirish" "changeLanguage": "Tilni o'zgartirish",
"login": "Kirish",
"phone_number": "Telefon raqami",
"enter_phone_number": "Telefon raqamingizni kiriting",
"password": "Parol",
"enter_password": "Parolni kiriting",
"forgot_password": "Parolni unutdingizmi",
"Continue": "Davom etish",
"dont_have_account": "Hisobingiz yoqmi?",
"sign_up": "Royxatdan otish"

View File

@@ -2,6 +2,7 @@ abstract class AppLocaleKeys {
///Storage keys ///Storage keys
static const String language = 'language'; static const String language = 'language';
static const String browseSearchHistory = 'browse-search-history'; static const String browseSearchHistory = 'browse-search-history';
static const String token = 'token';
static const String fontBold = "fontBold"; static const String fontBold = "fontBold";
static const String fontMedium = "fontMedium"; static const String fontMedium = "fontMedium";

View File

@@ -71,7 +71,10 @@ extension GetItInjectableX on _i174.GetIt {
() => _i241.LoginUseCase(gh<_i884.AuthRepository>()), () => _i241.LoginUseCase(gh<_i884.AuthRepository>()),
); );
gh.factory<_i1065.LoginBloc>( gh.factory<_i1065.LoginBloc>(
() => _i1065.LoginBloc(gh<_i241.LoginUseCase>()), () => _i1065.LoginBloc(
gh<_i241.LoginUseCase>(),
gh<_i321.StorageService>(),
),
); );
return this; return this;
} }

View File

@@ -63,8 +63,7 @@ import 'app_localizations_uz.dart';
/// be consistent with the languages listed in the AppLocalizations.supportedLocales /// be consistent with the languages listed in the AppLocalizations.supportedLocales
/// property. /// property.
abstract class AppLocalizations { abstract class AppLocalizations {
AppLocalizations(String locale) AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName; final String localeName;
@@ -72,8 +71,7 @@ abstract class AppLocalizations {
return Localizations.of<AppLocalizations>(context, AppLocalizations); return Localizations.of<AppLocalizations>(context, AppLocalizations);
} }
static const LocalizationsDelegate<AppLocalizations> delegate = static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
_AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations /// A list of this localizations delegate along with the default localizations
/// delegates. /// delegates.
@@ -85,19 +83,18 @@ abstract class AppLocalizations {
/// Additional delegates can be added by appending to this list in /// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list /// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required. /// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
<LocalizationsDelegate<dynamic>>[ delegate,
delegate, GlobalMaterialLocalizations.delegate,
GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, ];
];
/// A list of this localizations delegate's supported locales. /// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[ static const List<Locale> supportedLocales = <Locale>[
Locale('en'), Locale('en'),
Locale('ru'), Locale('ru'),
Locale('uz'), Locale('uz')
]; ];
/// No description provided for @useYourTAxiAccount. /// No description provided for @useYourTAxiAccount.
@@ -753,10 +750,63 @@ abstract class AppLocalizations {
/// In en, this message translates to: /// In en, this message translates to:
/// **'Language'** /// **'Language'**
String get language; String get language;
/// No description provided for @login.
///
/// In en, this message translates to:
/// **'Login'**
String get login;
/// No description provided for @phone_number.
///
/// In en, this message translates to:
/// **'Phone number'**
String get phone_number;
/// No description provided for @enter_phone_number.
///
/// In en, this message translates to:
/// **'Enter phone number'**
String get enter_phone_number;
/// No description provided for @password.
///
/// In en, this message translates to:
/// **'Password'**
String get password;
/// No description provided for @enter_password.
///
/// In en, this message translates to:
/// **'Enter password'**
String get enter_password;
/// No description provided for @forgot_password.
///
/// In en, this message translates to:
/// **'Forgot password'**
String get forgot_password;
/// No description provided for @continue.
///
/// In en, this message translates to:
/// **'Continue'**
String get Continue;
/// No description provided for @dont_have_account.
///
/// In en, this message translates to:
/// **'Don\'t have an account?'**
String get dont_have_account;
/// No description provided for @sign_up.
///
/// In en, this message translates to:
/// **'SignUp'**
String get sign_up;
} }
class _AppLocalizationsDelegate class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate(); const _AppLocalizationsDelegate();
@override @override
@@ -765,28 +815,26 @@ class _AppLocalizationsDelegate
} }
@override @override
bool isSupported(Locale locale) => bool isSupported(Locale locale) => <String>['en', 'ru', 'uz'].contains(locale.languageCode);
<String>['en', 'ru', 'uz'].contains(locale.languageCode);
@override @override
bool shouldReload(_AppLocalizationsDelegate old) => false; bool shouldReload(_AppLocalizationsDelegate old) => false;
} }
AppLocalizations lookupAppLocalizations(Locale locale) { AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified. // Lookup logic when only language code is specified.
switch (locale.languageCode) { switch (locale.languageCode) {
case 'en': case 'en': return AppLocalizationsEn();
return AppLocalizationsEn(); case 'ru': return AppLocalizationsRu();
case 'ru': case 'uz': return AppLocalizationsUz();
return AppLocalizationsRu();
case 'uz':
return AppLocalizationsUz();
} }
throw FlutterError( throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue ' 'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration ' 'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.', 'that was used.'
); );
} }

View File

@@ -21,8 +21,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get next => 'Next'; String get next => 'Next';
@override @override
String get contestToGetCallAndSms => String get contestToGetCallAndSms => 'By proceeding, you consent to get calls, Whatsapp or SMS messages, including by automated means, from uber and its affiliates to the number provided.';
'By proceeding, you consent to get calls, Whatsapp or SMS messages, including by automated means, from uber and its affiliates to the number provided.';
@override @override
String get continueWithGoogle => 'Continue with google'; String get continueWithGoogle => 'Continue with google';
@@ -239,8 +238,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get addItemsStartBasket => 'Add items to start a basket'; String get addItemsStartBasket => 'Add items to start a basket';
@override @override
String get basketHint => String get basketHint => 'Once you add items from a restaurant or store, your basket will appear here.';
'Once you add items from a restaurant or store, your basket will appear here.';
@override @override
String get startShopping => 'Start Shopping'; String get startShopping => 'Start Shopping';
@@ -346,4 +344,31 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get language => 'Language'; String get language => 'Language';
@override
String get login => 'Login';
@override
String get phone_number => 'Phone number';
@override
String get enter_phone_number => 'Enter phone number';
@override
String get password => 'Password';
@override
String get enter_password => 'Enter password';
@override
String get forgot_password => 'Forgot password';
@override
String get Continue => 'Continue';
@override
String get dont_have_account => 'Don\'t have an account?';
@override
String get sign_up => 'SignUp';
} }

View File

@@ -9,8 +9,7 @@ class AppLocalizationsRu extends AppLocalizations {
AppLocalizationsRu([String locale = 'ru']) : super(locale); AppLocalizationsRu([String locale = 'ru']) : super(locale);
@override @override
String get useYourTAxiAccount => String get useYourTAxiAccount => 'Используйте свой аккаунт Uber, чтобы начать';
'Используйте свой аккаунт Uber, чтобы начать';
@override @override
String get enterYourMobileNumber => 'Введите свой номер телефона'; String get enterYourMobileNumber => 'Введите свой номер телефона';
@@ -22,8 +21,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get next => 'Далее'; String get next => 'Далее';
@override @override
String get contestToGetCallAndSms => String get contestToGetCallAndSms => 'Продолжая, вы соглашаетесь получать звонки, сообщения WhatsApp или SMS, включая автоматические, от Uber и его партнеров на указанный номер.';
'Продолжая, вы соглашаетесь получать звонки, сообщения WhatsApp или SMS, включая автоматические, от Uber и его партнеров на указанный номер.';
@override @override
String get continueWithGoogle => 'Продолжить через Google'; String get continueWithGoogle => 'Продолжить через Google';
@@ -240,8 +238,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get addItemsStartBasket => 'Добавьте товары, чтобы создать корзину'; String get addItemsStartBasket => 'Добавьте товары, чтобы создать корзину';
@override @override
String get basketHint => String get basketHint => 'Когда вы добавите товары из ресторана или магазина, ваша корзина появится здесь.';
'Когда вы добавите товары из ресторана или магазина, ваша корзина появится здесь.';
@override @override
String get startShopping => 'Начать покупки'; String get startShopping => 'Начать покупки';
@@ -347,4 +344,31 @@ class AppLocalizationsRu extends AppLocalizations {
@override @override
String get language => 'Язык'; String get language => 'Язык';
@override
String get login => 'Login';
@override
String get phone_number => 'Phone number';
@override
String get enter_phone_number => 'Enter phone number';
@override
String get password => 'Password';
@override
String get enter_password => 'Enter password';
@override
String get forgot_password => 'Forgot password';
@override
String get Continue => 'Continue';
@override
String get dont_have_account => 'Don\'t have an account?';
@override
String get sign_up => 'SignUp';
} }

View File

@@ -9,8 +9,7 @@ class AppLocalizationsUz extends AppLocalizations {
AppLocalizationsUz([String locale = 'uz']) : super(locale); AppLocalizationsUz([String locale = 'uz']) : super(locale);
@override @override
String get useYourTAxiAccount => String get useYourTAxiAccount => 'Boshlash uchun Uber hisobingizdan foydalaning';
'Boshlash uchun Uber hisobingizdan foydalaning';
@override @override
String get enterYourMobileNumber => 'Telefon raqamingizni kiriting'; String get enterYourMobileNumber => 'Telefon raqamingizni kiriting';
@@ -22,8 +21,7 @@ class AppLocalizationsUz extends AppLocalizations {
String get next => 'Keyingi'; String get next => 'Keyingi';
@override @override
String get contestToGetCallAndSms => String get contestToGetCallAndSms => 'Davom etish orqali siz Uber va uning hamkorlaridan avtomatlashtirilgan qongiroqlar, WhatsApp yoki SMS xabarlarini olishga rozilik bildirasiz.';
'Davom etish orqali siz Uber va uning hamkorlaridan avtomatlashtirilgan qongiroqlar, WhatsApp yoki SMS xabarlarini olishga rozilik bildirasiz.';
@override @override
String get continueWithGoogle => 'Google orqali davom etish'; String get continueWithGoogle => 'Google orqali davom etish';
@@ -240,8 +238,7 @@ class AppLocalizationsUz extends AppLocalizations {
String get addItemsStartBasket => 'Savatni boshlash uchun mahsulot qoshing'; String get addItemsStartBasket => 'Savatni boshlash uchun mahsulot qoshing';
@override @override
String get basketHint => String get basketHint => 'Restorandan yoki do\'kondan mahsulot qoshsangiz, savatingiz shu yerda paydo boladi.';
'Restorandan yoki do\'kondan mahsulot qoshsangiz, savatingiz shu yerda paydo boladi.';
@override @override
String get startShopping => 'Xaridni boshlash'; String get startShopping => 'Xaridni boshlash';
@@ -347,4 +344,31 @@ class AppLocalizationsUz extends AppLocalizations {
@override @override
String get language => 'Til'; String get language => 'Til';
@override
String get login => 'Login';
@override
String get phone_number => 'Phone number';
@override
String get enter_phone_number => 'Enter phone number';
@override
String get password => 'Password';
@override
String get enter_password => 'Enter password';
@override
String get forgot_password => 'Forgot password';
@override
String get Continue => 'Continue';
@override
String get dont_have_account => 'Don\'t have an account?';
@override
String get sign_up => 'SignUp';
} }

View File

@@ -1,5 +1,4 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:food_delivery_client/core/network/header_interceptors.dart'; import 'package:food_delivery_client/core/network/header_interceptors.dart';
import 'package:food_delivery_client/food_delivery_client.dart'; import 'package:food_delivery_client/food_delivery_client.dart';
import 'error_handler_interceptor.dart'; import 'error_handler_interceptor.dart';

View File

@@ -1,5 +1,7 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.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/login_page/login_page.dart';
import 'package:food_delivery_client/feature/auth/presentation/pages/register_page/register_page.dart';
import 'package:food_delivery_client/feature/home/presentation/pages/restaurants_by_category_page/restaurants_by_category_page.dart'; import 'package:food_delivery_client/feature/home/presentation/pages/restaurants_by_category_page/restaurants_by_category_page.dart';
import '../../food_delivery_client.dart'; import '../../food_delivery_client.dart';
@@ -18,6 +20,16 @@ class AppRoutes {
pageBuilder: (context, state) => CupertinoPage(child: LoginPage()), pageBuilder: (context, state) => CupertinoPage(child: LoginPage()),
), ),
GoRoute(
path: Routes.register,
pageBuilder: (context, state) => CupertinoPage(child: RegisterPage()),
),
GoRoute(
path: Routes.forgotPassword,
pageBuilder: (context, state) =>
CupertinoPage(child: ForgotPasswordPage()),
),
GoRoute( GoRoute(
path: Routes.main, path: Routes.main,
pageBuilder: (context, state) => CupertinoPage(child: MainPage()), pageBuilder: (context, state) => CupertinoPage(child: MainPage()),

View File

@@ -6,5 +6,6 @@ abstract class Routes {
static const String categories = '/categories'; static const String categories = '/categories';
static const String filters = '/filters'; static const String filters = '/filters';
static const String browse = '/browse'; static const String browse = '/browse';
static const String forgotPassword = "/forgot-password";
static const String restaurantsByCategory = '/restaurants-by-category'; static const String restaurantsByCategory = '/restaurants-by-category';
} }

View File

@@ -48,6 +48,7 @@ abstract class AppIcons {
static const String icWallet = "$baseUrl/ic_wallet.svg"; static const String icWallet = "$baseUrl/ic_wallet.svg";
static const String icOrdersSvg = "$baseUrl/ic_orders_svg.svg"; static const String icOrdersSvg = "$baseUrl/ic_orders_svg.svg";
static const String icLanguage = "$baseUrl/ic_language.svg"; static const String icLanguage = "$baseUrl/ic_language.svg";
static const String icArrowRightLight = "$baseUrl/ic_arrow_right_light.svg";
///.png icons ///.png icons
static const String icBestOverall = "$baseUrl/ic_best.png"; static const String icBestOverall = "$baseUrl/ic_best.png";

View File

@@ -23,4 +23,5 @@ abstract class AppImages {
static const String imgDesert = "$baseUrl/img_desert.png"; static const String imgDesert = "$baseUrl/img_desert.png";
static const String imgPickUp = "$baseUrl/img_pick_up.png"; static const String imgPickUp = "$baseUrl/img_pick_up.png";
static const String imgAvatar = "$baseUrl/img_avatar.jpg"; static const String imgAvatar = "$baseUrl/img_avatar.jpg";
static const String imgBurger2 = "$baseUrl/img_burger2.png";
} }

View File

@@ -83,6 +83,19 @@ abstract class AppTextStyles {
fontFamily: _fontMedium, fontFamily: _fontMedium,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
); );
static const TextStyle size14Bold= TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_14,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
static const TextStyle size15Bold= TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_15,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
static const TextStyle size16Bold= TextStyle( static const TextStyle size16Bold= TextStyle(
color: _defaultColor, color: _defaultColor,

View File

@@ -1,4 +1,5 @@
import 'package:food_delivery_client/feature/auth/domain/usecases/login_usecase.dart'; import 'package:food_delivery_client/feature/auth/domain/usecases/login_usecase.dart';
import 'package:food_delivery_client/feature/common/presentation/widgets/w_toastification.dart';
import 'package:food_delivery_client/food_delivery_client.dart'; import 'package:food_delivery_client/food_delivery_client.dart';
part 'login_event.dart'; part 'login_event.dart';
@@ -10,8 +11,10 @@ part 'login_bloc.freezed.dart';
@injectable @injectable
class LoginBloc extends Bloc<LoginEvent, LoginState> { class LoginBloc extends Bloc<LoginEvent, LoginState> {
final LoginUseCase _loginUseCase; final LoginUseCase _loginUseCase;
final StorageService _storageService;
LoginBloc(this._loginUseCase) : super(const LoginState()) { LoginBloc(this._loginUseCase, this._storageService)
: super(const LoginState()) {
on<_Login>(_onLogin); on<_Login>(_onLogin);
} }
@@ -23,10 +26,12 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> {
response.fold( response.fold(
(l) { (l) {
log("${l.errorMessage}"); log("${l.errorMessage}");
showErrorToast(l.errorMessage);
emit(state.copyWith(status: RequestStatus.error)); emit(state.copyWith(status: RequestStatus.error));
}, },
(r) { (r) {
log(r.token); showSuccessToast("Login success");
_storageService.setString(key: AppLocaleKeys.token, value: r.token);
emit(state.copyWith(status: RequestStatus.loaded)); emit(state.copyWith(status: RequestStatus.loaded));
}, },
); );

View File

@@ -0,0 +1,12 @@
import '../../../../../food_delivery_client.dart';
class ForgotPasswordPage extends StatelessWidget {
const ForgotPasswordPage({super.key});
@override
Widget build(BuildContext context) {
return WLayout(
child: Scaffold(body: Column(children: [Text('Forgot password')])),
);
}
}

View File

@@ -1,7 +1,5 @@
import 'package:flutter/cupertino.dart';
import 'package:food_delivery_client/core/helpers/formatters.dart'; import 'package:food_delivery_client/core/helpers/formatters.dart';
import 'package:food_delivery_client/feature/auth/domain/usecases/login_usecase.dart'; import 'package:food_delivery_client/feature/auth/domain/usecases/login_usecase.dart';
import '../../../../../../food_delivery_client.dart'; import '../../../../../../food_delivery_client.dart';
import '../../../blocs/login_bloc/login_bloc.dart'; import '../../../blocs/login_bloc/login_bloc.dart';
@@ -38,86 +36,127 @@ class _WLoginBodyState extends State<WLoginBody> {
return Form( return Form(
key: _formKey, key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column( child: LayoutBuilder(
mainAxisSize: MainAxisSize.min, builder: (context, constraints) {
crossAxisAlignment: CrossAxisAlignment.start, return ConstrainedBox(
children: [ constraints: BoxConstraints(),
45.verticalSpace, child: Column(
Align( mainAxisSize: MainAxisSize.min,
alignment: AlignmentGeometry.center, crossAxisAlignment: CrossAxisAlignment.start,
child: Text("Let's go", style: AppTextStyles.size24Bold), children: [
), 45.verticalSpace,
20.verticalSpace, Align(
Text( alignment: AlignmentGeometry.center,
'Phone number', child: Text(context.loc.login, style: AppTextStyles.size24Bold),
style: AppTextStyles.size14Regular.copyWith( ),
color: AppColors.c6A6E7F, 20.verticalSpace,
), Text(
), context.loc.phone_number,
5.verticalSpace, style: AppTextStyles.size14Regular.copyWith(
AppTextFormField( color: AppColors.c6A6E7F,
height: 50, ),
hintText: "Enter phone number", ),
prefixIcon: Text( 5.verticalSpace,
"+ 998", AppTextFormField(
style: AppTextStyles.size16Regular.copyWith(fontSize: 16), height: 50,
), hintText: context.loc.enter_phone_number,
borderRadius: AppUtils.kBorderRadius8, prefixIcon: Text(
controller: _phoneController, "+ 998",
keyBoardType: TextInputType.number, style: AppTextStyles.size16Regular.copyWith(
fontSize: 16,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
Formatters.phoneFormatter,
LengthLimitingTextInputFormatter(12),
],
),
20.verticalSpace,
Text(
'Password',
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
height: 50,
hintText: "Enter password",
keyBoardType: TextInputType.text,
borderRadius: AppUtils.kBorderRadius8,
controller: _passwordController,
),
Align(
alignment: AlignmentGeometry.centerRight,
child: TextButton(
onPressed: () {},
child: Text('Forgot password'),
),
),
const Spacer(),
AppButton(
name: "Continue",
isLoading: state.status.isLoading(),
onPressed: () {
if (_formKey.currentState?.validate() ?? false) {
context.read<LoginBloc>().add(
LoginEvent.login(
LoginParams(
phoneNumber:
"+998${_phoneController.text.trim().replaceAll(" ", "")}",
password: _passwordController.text.trim(),
), ),
), ),
); borderRadius: AppUtils.kBorderRadius8,
} controller: _phoneController,
}, keyBoardType: TextInputType.number,
borderRadius: 15,
backgroundColor: AppColors.c34A853, inputFormatters: [
), FilteringTextInputFormatter.digitsOnly,
20.verticalSpace, Formatters.phoneFormatter,
], LengthLimitingTextInputFormatter(12),
).paddingSymmetric(horizontal: 16), ],
),
20.verticalSpace,
Text(
context.loc.password,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6A6E7F,
),
),
5.verticalSpace,
AppTextFormField(
height: 50,
obscureText: true,
hintText: context.loc.enter_password,
keyBoardType: TextInputType.text,
borderRadius: AppUtils.kBorderRadius8,
controller: _passwordController,
),
Align(
alignment: AlignmentGeometry.centerRight,
child: TextButton(
onPressed: () {
context.push(Routes.forgotPassword);
},
child: Text(
context.loc.forgot_password,
style: AppTextStyles.size14Medium.copyWith(
color: AppColors.c34A853,
),
),
),
),
const Spacer(),
AppButton(
name: context.loc.Continue,
isLoading: state.status.isLoading(),
trailing: SvgPicture.asset(
AppIcons.icArrowRightLight,
).paddingOnly(left: 10),
onPressed: () {
if (_formKey.currentState?.validate() ?? false) {
context.read<LoginBloc>().add(
LoginEvent.login(
LoginParams(
phoneNumber:
"+998${_phoneController.text.trim().replaceAll(" ", "")}",
password: _passwordController.text.trim(),
),
),
);
}
},
borderRadius: 15,
backgroundColor: AppColors.c34A853,
),
20.verticalSpace,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
context.loc.dont_have_account,
style: AppTextStyles.size14Medium,
),
TextButton(
onPressed: () {
context.pushReplacement(Routes.register);
},
child: Text(
context.loc.sign_up,
style: AppTextStyles.size15Bold.copyWith(
color: AppColors.c34A853,
),
),
),
],
),
20.verticalSpace,
],
).paddingSymmetric(horizontal: 16),
);
},
),
); );
}, },
); );

View File

@@ -0,0 +1,12 @@
import '../../../../../food_delivery_client.dart';
class RegisterPage extends StatelessWidget {
const RegisterPage({super.key});
@override
Widget build(BuildContext context) {
return WLayout(
child: Scaffold(body: Column(children: [Text("register")])),
);
}
}

View File

@@ -11,7 +11,7 @@ class AppButton extends StatelessWidget {
this.height, this.height,
this.textColor, this.textColor,
this.width, this.width,
this.action, this.leading,
this.trailing, this.trailing,
this.mainAxisAlignment, this.mainAxisAlignment,
this.isLoading = false, this.isLoading = false,
@@ -25,7 +25,7 @@ class AppButton extends StatelessWidget {
final double? borderRadius; final double? borderRadius;
final double? width; final double? width;
final double? height; final double? height;
final Widget? action; final Widget? leading;
final Widget? trailing; final Widget? trailing;
final bool isLoading; final bool isLoading;
final MainAxisAlignment? mainAxisAlignment; final MainAxisAlignment? mainAxisAlignment;
@@ -57,7 +57,7 @@ class AppButton extends StatelessWidget {
mainAxisAlignment: mainAxisAlignment:
mainAxisAlignment ?? MainAxisAlignment.center, mainAxisAlignment ?? MainAxisAlignment.center,
children: [ children: [
action ?? AppUtils.kSizedBox, leading?? AppUtils.kSizedBox,
Text( Text(
name, name,
style: AppTextStyles.size16Bold.copyWith( style: AppTextStyles.size16Bold.copyWith(

View File

@@ -1,7 +1,7 @@
import '../../../../food_delivery_client.dart'; import '../../../../food_delivery_client.dart';
class AppTextFormField extends StatelessWidget { class AppTextFormField extends StatefulWidget {
AppTextFormField({ const AppTextFormField({
super.key, super.key,
this.maxLines, this.maxLines,
this.minLines, this.minLines,
@@ -21,6 +21,7 @@ class AppTextFormField extends StatelessWidget {
this.focusNode, this.focusNode,
this.borderRadius, this.borderRadius,
this.height, this.height,
this.suffixIcon,
}); });
final int? maxLines; final int? maxLines;
@@ -32,63 +33,86 @@ class AppTextFormField extends StatelessWidget {
final Function(String? value)? onChanged; final Function(String? value)? onChanged;
final List<TextInputFormatter>? inputFormatters; final List<TextInputFormatter>? inputFormatters;
final TextInputType? keyBoardType; final TextInputType? keyBoardType;
FormFieldValidator<String>? validator;
final bool obscureText; final bool obscureText;
final Color? fillColor; final Color? fillColor;
final String? hintText; final String? hintText;
final TextStyle? hintTextStyle; final TextStyle? hintTextStyle;
late final Widget? prefixIcon; final Widget? prefixIcon;
final String? prefixSvgPath; final String? prefixSvgPath;
final FocusNode? focusNode; final FocusNode? focusNode;
final BorderRadius? borderRadius; final BorderRadius? borderRadius;
final double? height; final double? height;
final Widget? suffixIcon;
@override
State<AppTextFormField> createState() => _AppTextFormFieldState();
}
class _AppTextFormFieldState extends State<AppTextFormField> {
FormFieldValidator<String>? validator;
bool visibility = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
height: height ?? 44, height: widget.height ?? 44,
child: TextFormField( child: TextFormField(
enabled: true, enabled: true,
autofocus: true, autofocus: true,
maxLines: maxLines ?? 1, maxLines: widget.maxLines ?? 1,
minLines: minLines ?? 1, minLines: widget.minLines ?? 1,
onChanged: onChanged, onChanged: widget.onChanged,
focusNode: focusNode, focusNode: widget.focusNode,
inputFormatters: inputFormatters, inputFormatters: widget.inputFormatters,
keyboardType: keyBoardType, keyboardType: widget.keyBoardType,
style: textStyle ?? AppTextStyles.size16Regular, style: widget.textStyle ?? AppTextStyles.size16Regular,
onTap: onTap, onTap: widget.onTap,
textAlign: textAlign ?? TextAlign.start, textAlign: widget.textAlign ?? TextAlign.start,
controller: controller, controller: widget.controller,
validator: validator, validator: validator,
obscureText: widget.obscureText?visibility:false,
obscuringCharacter: "*",
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration( decoration: InputDecoration(
enabled: true, enabled: true,
filled: true, filled: true,
fillColor: fillColor ?? AppColors.cEEEEEE, fillColor: widget.fillColor ?? AppColors.cEEEEEE,
hintText: hintText, hintText: widget.hintText,
hintStyle: hintTextStyle, hintStyle: widget.hintTextStyle,
suffixIcon: widget.obscureText
? IconButton(
onPressed: () {
setState(() {
visibility = !visibility;
});
},
icon: Icon(
visibility ? Icons.visibility : Icons.visibility_off,
),
)
: widget.suffixIcon,
prefixIconConstraints: BoxConstraints(minHeight: 24, minWidth: 0), prefixIconConstraints: BoxConstraints(minHeight: 24, minWidth: 0),
prefixIcon: prefixIcon?.paddingOnly(left: 10).paddingAll(3), prefixIcon: widget.prefixIcon?.paddingOnly(left: 10).paddingAll(3),
contentPadding: EdgeInsets.symmetric(vertical: 12, horizontal: 12), contentPadding: EdgeInsets.symmetric(vertical: 12, horizontal: 12),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: borderRadius ?? AppUtils.kBorderRadius40, borderRadius: widget.borderRadius ?? AppUtils.kBorderRadius40,
borderSide: BorderSide.none, borderSide: BorderSide.none,
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: borderRadius ?? AppUtils.kBorderRadius40, borderRadius: widget.borderRadius ?? AppUtils.kBorderRadius40,
borderSide: BorderSide.none, borderSide: BorderSide.none,
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: borderRadius ?? AppUtils.kBorderRadius40, borderRadius: widget.borderRadius ?? AppUtils.kBorderRadius40,
borderSide: BorderSide.none, borderSide: BorderSide.none,
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: borderRadius ?? AppUtils.kBorderRadius40, borderRadius: widget.borderRadius ?? AppUtils.kBorderRadius40,
borderSide: BorderSide.none, borderSide: BorderSide.none,
), ),
disabledBorder: OutlineInputBorder( disabledBorder: OutlineInputBorder(
borderRadius: borderRadius ?? AppUtils.kBorderRadius40, borderRadius: widget.borderRadius ?? AppUtils.kBorderRadius40,
borderSide: BorderSide.none, borderSide: BorderSide.none,
), ),
), ),

View File

@@ -0,0 +1,43 @@
import 'package:toastification/toastification.dart';
import '../../../../food_delivery_client.dart';
showErrorToast(String? message) {
toastification.show(
context: navigatorKey.currentContext,
type: ToastificationType.error,
style: ToastificationStyle.fillColored,
title: Text(message ?? "", maxLines: 5),
autoCloseDuration: TimeDelayConst.duration3,
);
}
showSuccessToast(String message) {
toastification.show(
context: navigatorKey.currentContext,
type: ToastificationType.success,
style: ToastificationStyle.fillColored,
title: Text(message, maxLines: 5),
autoCloseDuration: TimeDelayConst.duration3,
);
}
showWarningToast(String message) {
toastification.show(
context: navigatorKey.currentContext,
type: ToastificationType.warning,
style: ToastificationStyle.fillColored,
title: Text(message, maxLines: 5),
autoCloseDuration: TimeDelayConst.duration3,
);
}
showInfoToast(String message) {
toastification.show(
alignment: Alignment.bottomCenter,
context: navigatorKey.currentContext,
type: ToastificationType.info,
style: ToastificationStyle.fillColored,
title: Text(message, maxLines: 5),
autoCloseDuration: TimeDelayConst.duration3,
);
}

View File

@@ -1,4 +1,5 @@
import 'package:food_delivery_client/feature/common/presentation/blocs/language_bloc/language_bloc.dart'; import 'package:food_delivery_client/feature/common/presentation/blocs/language_bloc/language_bloc.dart';
import 'package:toastification/toastification.dart';
import 'food_delivery_client.dart'; import 'food_delivery_client.dart';
@@ -44,28 +45,30 @@ class _MyAppState extends State<MyApp> {
return BlocBuilder<LanguageBloc, LanguageState>( return BlocBuilder<LanguageBloc, LanguageState>(
bloc: context.read<LanguageBloc>()..add(LanguageEvent.started()), bloc: context.read<LanguageBloc>()..add(LanguageEvent.started()),
builder: (context, state) { builder: (context, state) {
return MaterialApp.router( return ToastificationWrapper(
title: "Uber Eats", child: MaterialApp.router(
debugShowCheckedModeBanner: false, title: "Uber Eats",
theme: AppTheme.lightTheme, debugShowCheckedModeBanner: false,
routerConfig: sl<AppRoutes>().router, theme: AppTheme.lightTheme,
locale: state.currentLocale, routerConfig: sl<AppRoutes>().router,
supportedLocales: L10n.locales, locale: state.currentLocale,
localizationsDelegates: [ supportedLocales: L10n.locales,
AppLocalizations.delegate, localizationsDelegates: [
GlobalMaterialLocalizations.delegate, AppLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
], GlobalCupertinoLocalizations.delegate,
builder: (context, child) => GestureDetector( ],
onTap: () { builder: (context, child) => GestureDetector(
FocusManager.instance.primaryFocus?.unfocus(); onTap: () {
}, FocusManager.instance.primaryFocus?.unfocus();
child: MediaQuery( },
data: MediaQuery.of( child: MediaQuery(
context, data: MediaQuery.of(
).copyWith(textScaler: const TextScaler.linear(1)), context,
child: child!, ).copyWith(textScaler: const TextScaler.linear(1)),
child: child!,
),
), ),
), ),
); );

View File

@@ -397,6 +397,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.2" version: "4.1.2"
iconsax_flutter:
dependency: transitive
description:
name: iconsax_flutter
sha256: d14b4cec8586025ac15276bdd40f6eea308cb85748135965bb6255f14beb2564
url: "https://pub.dev"
source: hosted
version: "1.0.1"
injectable: injectable:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -605,6 +613,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
pausable_timer:
dependency: transitive
description:
name: pausable_timer
sha256: "6ef1a95441ec3439de6fb63f39a011b67e693198e7dae14e20675c3c00e86074"
url: "https://pub.dev"
source: hosted
version: "3.1.0+3"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
@@ -882,6 +898,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.6" version: "0.7.6"
toastification:
dependency: "direct main"
description:
name: toastification
sha256: "69db2bff425b484007409650d8bcd5ed1ce2e9666293ece74dcd917dacf23112"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

View File

@@ -24,6 +24,8 @@ dependencies:
dartz: ^0.10.1 dartz: ^0.10.1
mask_text_input_formatter: ^2.9.0 mask_text_input_formatter: ^2.9.0
#for notify user about error or success
toastification: ^3.0.3
#DI #DI
get_it: ^8.2.0 get_it: ^8.2.0