From 263daf859a9c6405dadfd18ebab78fb5193b6f0d Mon Sep 17 00:00:00 2001 From: jayesh Date: Thu, 30 May 2024 13:59:40 +0530 Subject: [PATCH] register step screen, otp screen, register screen --- assets/images/auth_screen/png/stage_one.png | Bin 0 -> 4136 bytes assets/images/auth_screen/png/stage_two.png | Bin 0 -> 1018 bytes assets/images/auth_screen/svg/first_step.svg | 10 ++ assets/images/auth_screen/svg/second_step.svg | 10 ++ assets/images/auth_screen/svg/third_step.svg | 10 ++ .../biometric_screen/png/biomertric_face.png | Bin 0 -> 18163 bytes .../png/biometric_fingerprint.png | Bin 0 -> 25423 bytes .../biometric_screen/svg/biometric_bg.svg | 23 ++++ .../images/country_flag/svg/bahrain_flag.svg | 9 -- .../images/country_flag/svg/kuwait_flag.svg | 9 -- assets/images/country_flag/svg/oman_flag.svg | 9 -- assets/images/country_flag/svg/qatar_flag.svg | 9 -- .../country_flag/svg/saudi_arabia_flag.svg | 9 -- .../svg/united_arab_emirates_flag.svg | 9 -- assets/images/dialog/svg/exit_icon.svg | 3 + lib/core/routes/route_name.dart | 10 ++ lib/core/routes/routes.dart | 46 +++++-- lib/core/styles/app_color.dart | 5 + lib/core/styles/app_images.dart | 21 ++++ lib/core/styles/app_text.dart | 33 ++++- .../utils/constant/register_step_data.dart | 20 +++ .../presentation/pages/biometric_layout.dart | 49 ++++++++ .../presentation/pages/biometric_screen.dart | 14 +++ .../bloc/choose_country_bloc.dart | 10 ++ .../bloc/choose_country_event.dart | 4 +- .../pages/choose_country_layout.dart | 1 - .../widgets/country_selection_list.dart | 2 +- .../login/presentation/bloc/login_bloc.dart | 11 +- .../presentation/pages/login_screen.dart | 43 ++++--- .../presentation/widgets/bottom_section.dart | 11 +- .../presentation/widgets/login_form.dart | 3 + .../presentation/bloc/otp_bloc.dart | 53 ++++++++ .../presentation/bloc/otp_event.dart | 29 +++++ .../presentation/bloc/otp_state.dart | 33 +++++ .../presentation/pages/otp_layout.dart | 19 +++ .../presentation/pages/otp_screen.dart | 26 ++++ .../widgets/otp_fill_section.dart | 68 ++++++++++ .../presentation/widgets/otp_top_section.dart | 40 ++++++ .../presentation/bloc/register_bloc.dart | 74 +++++++++++ .../presentation/bloc/register_event.dart | 33 +++++ .../presentation/bloc/register_state.dart | 32 +++++ .../presentation/pages/register_layout.dart | 21 ++++ .../presentation/pages/register_screen.dart | 33 +++++ .../pages/register_step_layout.dart | 23 ++++ .../pages/register_step_screen.dart | 30 +++++ .../widgets/register_bottom_section.dart | 106 ++++++++++++++++ .../presentation/widgets/register_form.dart | 76 +++++++++++ .../widgets/register_step_bottom_section.dart | 54 ++++++++ .../widgets/register_step_count.dart | 39 ++++++ .../widgets/register_step_top_section.dart | 39 ++++++ .../widgets/register_top_section.dart | 39 ++++++ .../widgets/login_signup_button.dart | 18 ++- lib/main.dart | 6 +- lib/shared/components/exit_app_dialog.dart | 119 ++++++++++++++++++ lib/shared/components/text_widget.dart | 23 ++-- pubspec.lock | 16 +++ pubspec.yaml | 9 +- 57 files changed, 1348 insertions(+), 103 deletions(-) create mode 100644 assets/images/auth_screen/png/stage_one.png create mode 100644 assets/images/auth_screen/png/stage_two.png create mode 100644 assets/images/auth_screen/svg/first_step.svg create mode 100644 assets/images/auth_screen/svg/second_step.svg create mode 100644 assets/images/auth_screen/svg/third_step.svg create mode 100644 assets/images/biometric_screen/png/biomertric_face.png create mode 100644 assets/images/biometric_screen/png/biometric_fingerprint.png create mode 100644 assets/images/biometric_screen/svg/biometric_bg.svg delete mode 100644 assets/images/country_flag/svg/bahrain_flag.svg delete mode 100644 assets/images/country_flag/svg/kuwait_flag.svg delete mode 100644 assets/images/country_flag/svg/oman_flag.svg delete mode 100644 assets/images/country_flag/svg/qatar_flag.svg delete mode 100644 assets/images/country_flag/svg/saudi_arabia_flag.svg delete mode 100644 assets/images/country_flag/svg/united_arab_emirates_flag.svg create mode 100644 assets/images/dialog/svg/exit_icon.svg create mode 100644 lib/core/utils/constant/register_step_data.dart create mode 100644 lib/features/biometric/presentation/pages/biometric_layout.dart create mode 100644 lib/features/biometric/presentation/pages/biometric_screen.dart create mode 100644 lib/features/otpVerification/presentation/bloc/otp_bloc.dart create mode 100644 lib/features/otpVerification/presentation/bloc/otp_event.dart create mode 100644 lib/features/otpVerification/presentation/bloc/otp_state.dart create mode 100644 lib/features/otpVerification/presentation/pages/otp_layout.dart create mode 100644 lib/features/otpVerification/presentation/pages/otp_screen.dart create mode 100644 lib/features/otpVerification/presentation/widgets/otp_fill_section.dart create mode 100644 lib/features/otpVerification/presentation/widgets/otp_top_section.dart create mode 100644 lib/features/register/presentation/bloc/register_bloc.dart create mode 100644 lib/features/register/presentation/bloc/register_event.dart create mode 100644 lib/features/register/presentation/bloc/register_state.dart create mode 100644 lib/features/register/presentation/pages/register_layout.dart create mode 100644 lib/features/register/presentation/pages/register_screen.dart create mode 100644 lib/features/register/presentation/pages/register_step_layout.dart create mode 100644 lib/features/register/presentation/pages/register_step_screen.dart create mode 100644 lib/features/register/presentation/widgets/register_bottom_section.dart create mode 100644 lib/features/register/presentation/widgets/register_form.dart create mode 100644 lib/features/register/presentation/widgets/register_step_bottom_section.dart create mode 100644 lib/features/register/presentation/widgets/register_step_count.dart create mode 100644 lib/features/register/presentation/widgets/register_step_top_section.dart create mode 100644 lib/features/register/presentation/widgets/register_top_section.dart create mode 100644 lib/shared/components/exit_app_dialog.dart diff --git a/assets/images/auth_screen/png/stage_one.png b/assets/images/auth_screen/png/stage_one.png new file mode 100644 index 0000000000000000000000000000000000000000..4f2d753f584de900eab138083c800e0e6c044a25 GIT binary patch literal 4136 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 literal 0 HcmV?d00001 diff --git a/assets/images/auth_screen/svg/first_step.svg b/assets/images/auth_screen/svg/first_step.svg new file mode 100644 index 0000000..5c3174b --- /dev/null +++ b/assets/images/auth_screen/svg/first_step.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/auth_screen/svg/second_step.svg b/assets/images/auth_screen/svg/second_step.svg new file mode 100644 index 0000000..ca94e68 --- /dev/null +++ b/assets/images/auth_screen/svg/second_step.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/auth_screen/svg/third_step.svg b/assets/images/auth_screen/svg/third_step.svg new file mode 100644 index 0000000..7b842e4 --- /dev/null +++ b/assets/images/auth_screen/svg/third_step.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/biometric_screen/png/biomertric_face.png b/assets/images/biometric_screen/png/biomertric_face.png new file mode 100644 index 0000000000000000000000000000000000000000..5044e8bfc43b78fda6dc6ec6761da3229886330d GIT binary patch literal 18163 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 literal 0 HcmV?d00001 diff --git a/assets/images/biometric_screen/png/biometric_fingerprint.png b/assets/images/biometric_screen/png/biometric_fingerprint.png new file mode 100644 index 0000000000000000000000000000000000000000..57fafeb5b1b182ea3e31face95aa8df5126453b5 GIT binary patch literal 25423 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 + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/country_flag/svg/bahrain_flag.svg b/assets/images/country_flag/svg/bahrain_flag.svg deleted file mode 100644 index 25d8620..0000000 --- a/assets/images/country_flag/svg/bahrain_flag.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/country_flag/svg/kuwait_flag.svg b/assets/images/country_flag/svg/kuwait_flag.svg deleted file mode 100644 index bbc8958..0000000 --- a/assets/images/country_flag/svg/kuwait_flag.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/country_flag/svg/oman_flag.svg b/assets/images/country_flag/svg/oman_flag.svg deleted file mode 100644 index 1636dff..0000000 --- a/assets/images/country_flag/svg/oman_flag.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/country_flag/svg/qatar_flag.svg b/assets/images/country_flag/svg/qatar_flag.svg deleted file mode 100644 index 68b2a67..0000000 --- a/assets/images/country_flag/svg/qatar_flag.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/country_flag/svg/saudi_arabia_flag.svg b/assets/images/country_flag/svg/saudi_arabia_flag.svg deleted file mode 100644 index de0b22e..0000000 --- a/assets/images/country_flag/svg/saudi_arabia_flag.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/country_flag/svg/united_arab_emirates_flag.svg b/assets/images/country_flag/svg/united_arab_emirates_flag.svg deleted file mode 100644 index 56291aa..0000000 --- a/assets/images/country_flag/svg/united_arab_emirates_flag.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/dialog/svg/exit_icon.svg b/assets/images/dialog/svg/exit_icon.svg new file mode 100644 index 0000000..a505a6b --- /dev/null +++ b/assets/images/dialog/svg/exit_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/core/routes/route_name.dart b/lib/core/routes/route_name.dart index b7f6820..7cfc698 100644 --- a/lib/core/routes/route_name.dart +++ b/lib/core/routes/route_name.dart @@ -9,6 +9,10 @@ class RouteName { //Login static const String loginScreen = 'loginScreen'; + //Register + static const String registerStepScreen = 'registerStepScreen'; + static const String registerScreen = 'registerScreen'; + //No Internet static const String noInternetScreen = 'noInternet'; @@ -17,4 +21,10 @@ class RouteName { //choose country static const String chooseCountryScreen = 'chooseCountryScreen'; + + //Biometric + static const String biometricScreen = 'biometricScreen'; + + //Biometric + static const String otpScreen = 'otpScreen'; } diff --git a/lib/core/routes/routes.dart b/lib/core/routes/routes.dart index f3e3ff6..5792d5c 100644 --- a/lib/core/routes/routes.dart +++ b/lib/core/routes/routes.dart @@ -2,7 +2,11 @@ import 'package:go_router/go_router.dart'; import 'package:tanami_app/core/routes/route_name.dart'; +import 'package:tanami_app/features/biometric/presentation/pages/biometric_screen.dart'; import 'package:tanami_app/features/countrySelection/presentation/pages/choose_country_screen.dart'; +import 'package:tanami_app/features/otpVerification/presentation/pages/otp_screen.dart'; +import 'package:tanami_app/features/register/presentation/pages/register_screen.dart'; +import 'package:tanami_app/features/register/presentation/pages/register_step_screen.dart'; import 'package:tanami_app/features/welcome/presentation/pages/weclome_screen.dart'; import '../../features/login/presentation/pages/login_screen.dart'; @@ -23,18 +27,23 @@ final goRouter = GoRouter( builder: (context, state) { return const SplashScreen(); }, - // redirect: (context, state) { - // if (true) { - // return "/login"; - // } - // return "/"; - // }, routes: [ GoRoute( name: RouteName.loginScreen, - path: RouteName.loginScreen, + path: "${RouteName.loginScreen}/:fromScreen", builder: (context, state) { - return const LoginScreen(); + return LoginScreen( + fromScreen: state.pathParameters["fromScreen"]!, + ); + }, + ), + GoRoute( + name: RouteName.registerStepScreen, + path: "${RouteName.registerStepScreen}/:fromScreentype", + builder: (context, state) { + return RegisterStepScreen( + fromScreen: state.pathParameters["fromScreentype"]!, + ); }, ), GoRoute( @@ -51,6 +60,27 @@ final goRouter = GoRouter( return const ChooseCountryScreen(); }, ), + GoRoute( + name: RouteName.biometricScreen, + path: RouteName.biometricScreen, + builder: (context, state) { + return const BiometricScreen(); + }, + ), + GoRoute( + name: RouteName.registerScreen, + path: RouteName.registerScreen, + builder: (context, state) { + return const RegisterScreen(); + }, + ), + GoRoute( + name: RouteName.otpScreen, + path: RouteName.otpScreen, + builder: (context, state) { + return const OtpScreen(); + }, + ), ]), // GoRoute( diff --git a/lib/core/styles/app_color.dart b/lib/core/styles/app_color.dart index 7fc536b..ac91fbe 100644 --- a/lib/core/styles/app_color.dart +++ b/lib/core/styles/app_color.dart @@ -36,4 +36,9 @@ class AppColor { //Radio Color static const Color radioActiveColor = Color(0xFF0B8933); + + //Otp Color + static const Color strokeColor = Color(0xFFB4B4B4); + static const Color otpTextColor = Color(0xFF191B1E); + static const Color fillColor = Color(0xFFF6F6F6); } diff --git a/lib/core/styles/app_images.dart b/lib/core/styles/app_images.dart index 893c708..feab15b 100644 --- a/lib/core/styles/app_images.dart +++ b/lib/core/styles/app_images.dart @@ -22,6 +22,16 @@ class AppImages { "assets/images/auth_screen/svg/hide_password.svg"; static const String showPassword = "assets/images/auth_screen/svg/show_password.svg"; + static const String step1Image = + "assets/images/auth_screen/svg/first_step.svg"; + static const String step2Image = + "assets/images/auth_screen/svg/second_step.svg"; + static const String step3Image = + "assets/images/auth_screen/svg/third_step.svg"; + static const String stage1Image = + "assets/images/auth_screen/png/stage_one.png"; + static const String stage2Image = + "assets/images/auth_screen/png/stage_two.png"; //Country Flag static const String bahrainFlag = @@ -35,4 +45,15 @@ class AppImages { "assets/images/country_flag/png/saudi_arabia_flag.png"; static const String unitedArabEmiratesFlag = "assets/images/country_flag/png/uae_flag.png"; + + //Biometric Screen + static const String biometricBg = + "assets/images/biometric_screen/svg/biometric_bg.svg"; + static const String biometricFingerprint = + "assets/images/biometric_screen/png/biometric_fingerprint.png"; + static const String biometricFace = + "assets/images/biometric_screen/png/biomertric_face.png"; + + //Dialog + static const String exitAppIcon = "assets/images/dialog/svg/exit_icon.svg"; } diff --git a/lib/core/styles/app_text.dart b/lib/core/styles/app_text.dart index d13575e..7b878ea 100644 --- a/lib/core/styles/app_text.dart +++ b/lib/core/styles/app_text.dart @@ -29,6 +29,26 @@ class AppText { static const String invalidPassword = "Invalid Password"; static const String forgorPassword = "Forgot Password"; + //Register + static const String getStartedToday = "Get started today"; + static const String setupYourTanamiAccountToBegin = + "Setup your Tanami account to begin investing in a few simple steps"; + static const String step1 = "Step 1"; + static const String step2 = "Step 2"; + static const String step3 = "Step 3"; + static const String enterYourCountryOfResidence = + "Enter your country of residence and mobile number"; + static const String enterNameEmailPassword = + "Enter your name, email and password"; + static const String enableBiometricAuthentication = + "Enable biometric authentication and select a unique pin code for easy access"; + static const String getStarted = "Get started"; + static const String welcome = "Welcome!"; + static const String selectYourCountryOfResidence = + "Select your country of residence and enter your mobile number"; + static const String nextText = "Next"; + static const String backText = "Back"; + //Country Name static const String bahrainCountryText = "Bahrain"; static const String kuwaitCountryText = "Kuwait"; @@ -36,6 +56,17 @@ class AppText { static const String qatarCountryText = "Qatar"; static const String saudiArabiaCountryText = "Saudi Arabia"; static const String uaeCountryText = "United Arab Emirates"; - static const String confirmSelectionText = "Confirm selection"; + + //Dialog + static const String exitText = "Exit"; + static const String cancelText = "Cancel"; + static const String areYouSureYouWantToExitText = + "Are you sure you want to Exit?"; + + //OTP + static const String checkYourMessages = "Check your messages"; + static const String referToSameOtpMessage = + "Please refer to the same OTP message shown below"; + static const String resendSms = "Resend SMS"; } diff --git a/lib/core/utils/constant/register_step_data.dart b/lib/core/utils/constant/register_step_data.dart new file mode 100644 index 0000000..3022a35 --- /dev/null +++ b/lib/core/utils/constant/register_step_data.dart @@ -0,0 +1,20 @@ +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; + +List title = [ + AppText.step1, + AppText.step2, + AppText.step3, +]; + +List description = [ + AppText.enterYourCountryOfResidence, + AppText.enterNameEmailPassword, + AppText.enableBiometricAuthentication, +]; + +List stepImage = [ + AppImages.step1Image, + AppImages.step2Image, + AppImages.step3Image, +]; diff --git a/lib/features/biometric/presentation/pages/biometric_layout.dart b/lib/features/biometric/presentation/pages/biometric_layout.dart new file mode 100644 index 0000000..c738d53 --- /dev/null +++ b/lib/features/biometric/presentation/pages/biometric_layout.dart @@ -0,0 +1,49 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../../../core/styles/app_images.dart'; + +class BiometricLayout extends StatelessWidget { + const BiometricLayout({super.key}); + + @override + Widget build(BuildContext context) { + String biometricImage = ""; + if (Platform.isIOS) { + biometricImage = AppImages.biometricFace; + } else { + biometricImage = AppImages.biometricFingerprint; + } + return Scaffold( + body: SizedBox( + width: 1.sw, + height: 1.sh, + child: Stack( + children: [ + Positioned.fill( + child: SvgPicture.asset( + height: 1.sh, + width: 1.sw, + AppImages.biometricBg, + fit: BoxFit.cover, + ), + ), + Positioned.fill( + child: Align( + alignment: Alignment.center, + child: Image.asset( + biometricImage, + width: 133, + height: 155, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/features/biometric/presentation/pages/biometric_screen.dart b/lib/features/biometric/presentation/pages/biometric_screen.dart new file mode 100644 index 0000000..f977b6f --- /dev/null +++ b/lib/features/biometric/presentation/pages/biometric_screen.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:tanami_app/features/biometric/presentation/pages/biometric_layout.dart'; + +class BiometricScreen extends StatelessWidget { + const BiometricScreen({super.key}); + + @override + Widget build(BuildContext context) { + return const Scaffold( + // resizeToAvoidBottomInset: true, + body: BiometricLayout(), + ); + } +} diff --git a/lib/features/countrySelection/presentation/bloc/choose_country_bloc.dart b/lib/features/countrySelection/presentation/bloc/choose_country_bloc.dart index 8712902..1df18ea 100644 --- a/lib/features/countrySelection/presentation/bloc/choose_country_bloc.dart +++ b/lib/features/countrySelection/presentation/bloc/choose_country_bloc.dart @@ -6,12 +6,22 @@ import 'choose_country_state.dart'; class RadioBloc extends Bloc { RadioBloc() : super(RadioInitial()) { on(_onRadioSelected); + on(_onResetRadioSelection); } void _onRadioSelected(RadioSelected event, Emitter emit) { emit(RadioSelectionChanged(event.selectedIndex)); } + void _onResetRadioSelection( + ResetRadioSelection event, Emitter emit) { + emit(RadioInitial()); + } + + void resetSelection() { + add(ResetRadioSelection()); + } + int get selectedCountry { if (state is RadioSelectionChanged) { return (state as RadioSelectionChanged).selectedIndex; diff --git a/lib/features/countrySelection/presentation/bloc/choose_country_event.dart b/lib/features/countrySelection/presentation/bloc/choose_country_event.dart index 5cf9a32..9c8d94e 100644 --- a/lib/features/countrySelection/presentation/bloc/choose_country_event.dart +++ b/lib/features/countrySelection/presentation/bloc/choose_country_event.dart @@ -10,8 +10,10 @@ abstract class RadioEvent extends Equatable { class RadioSelected extends RadioEvent { final int selectedIndex; - const RadioSelected(this.selectedIndex); + const RadioSelected([this.selectedIndex = 0]); @override List get props => [selectedIndex]; } + +class ResetRadioSelection extends RadioEvent {} diff --git a/lib/features/countrySelection/presentation/pages/choose_country_layout.dart b/lib/features/countrySelection/presentation/pages/choose_country_layout.dart index 7c4ab28..ebdc5e6 100644 --- a/lib/features/countrySelection/presentation/pages/choose_country_layout.dart +++ b/lib/features/countrySelection/presentation/pages/choose_country_layout.dart @@ -24,7 +24,6 @@ class ChooseCountryLayout extends StatelessWidget { child: ButtonWidget().elevatedBtn( txtClr: AppColor.plainWhite, function: () { - // radioBloc.add(const BackPressed(true)); goRouter.pop(); }, text: AppText.confirmSelectionText, diff --git a/lib/features/countrySelection/presentation/widgets/country_selection_list.dart b/lib/features/countrySelection/presentation/widgets/country_selection_list.dart index 0466980..5f11f8c 100644 --- a/lib/features/countrySelection/presentation/widgets/country_selection_list.dart +++ b/lib/features/countrySelection/presentation/widgets/country_selection_list.dart @@ -17,7 +17,7 @@ class CountrySelectionList extends StatelessWidget { final radioBloc = context.read(); return BlocBuilder( builder: (context, state) { - int selectedIndex = 0; + int selectedIndex = -1; if (state is RadioSelectionChanged) { selectedIndex = state.selectedIndex; } diff --git a/lib/features/login/presentation/bloc/login_bloc.dart b/lib/features/login/presentation/bloc/login_bloc.dart index 5a3a9e0..1ae720f 100644 --- a/lib/features/login/presentation/bloc/login_bloc.dart +++ b/lib/features/login/presentation/bloc/login_bloc.dart @@ -56,13 +56,20 @@ class LoginBloc extends Bloc { emit(LoginFieldsState(areFieldsFilled)); } + // Method to reset text fields + void resetFields() { + phoneNumberTextField.clear(); + passwordTextField.clear(); + countrySelectionTextField.clear(); + } + // Mock API function, replace with actual API call Future _mockLoginApi( - String email, + String phoneNumber, String password, String countryResidence, ) async { - return email == "1234567891" && password == "123456"; + return phoneNumber == "1234567891" && password == "123456"; } @override diff --git a/lib/features/login/presentation/pages/login_screen.dart b/lib/features/login/presentation/pages/login_screen.dart index 1d23678..dbf1805 100644 --- a/lib/features/login/presentation/pages/login_screen.dart +++ b/lib/features/login/presentation/pages/login_screen.dart @@ -1,29 +1,40 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import '../../../../shared/components/bloc/password_field/password_visibility_bloc.dart'; +import '../../../../shared/components/exit_app_dialog.dart'; +import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart'; import '../bloc/login_bloc.dart'; import 'login_layout.dart'; class LoginScreen extends StatelessWidget { - const LoginScreen({super.key}); + final String fromScreen; + const LoginScreen({super.key, required this.fromScreen}); @override Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: true, - body: MultiBlocProvider( - // Define the providers for the OnboardingBloc and other blocs - providers: [ - BlocProvider( - // Create an instance of the OnboardingBloc - create: (context) => LoginBloc(), - ), - BlocProvider( - create: (context) => PasswordVisibilityBloc(), - ), - ], - child: const LoginLayout(), + final radioBloc = context.read(); + return WillPopScope( + onWillPop: () async { + if (fromScreen == "welcome" || fromScreen == "registerStep") { + exitAppDialog(context); + return false; + } else { + radioBloc.resetSelection(); + return true; + } + }, + child: Scaffold( + resizeToAvoidBottomInset: true, + body: MultiBlocProvider( + // Define the providers for the OnboardingBloc and other blocs + providers: [ + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => LoginBloc(), + ), + ], + child: const LoginLayout(), + ), ), ); } diff --git a/lib/features/login/presentation/widgets/bottom_section.dart b/lib/features/login/presentation/widgets/bottom_section.dart index 9cd4dc0..dbc49b8 100644 --- a/lib/features/login/presentation/widgets/bottom_section.dart +++ b/lib/features/login/presentation/widgets/bottom_section.dart @@ -11,6 +11,7 @@ import '../../../../core/styles/app_color.dart'; import '../../../../core/styles/app_text.dart'; import '../../../../shared/components/button_widget.dart'; import '../../../../shared/components/text_widget.dart'; +import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart'; import '../bloc/login_bloc.dart'; import '../bloc/login_event.dart'; import '../bloc/login_state.dart'; @@ -20,6 +21,7 @@ class BottomSection extends StatelessWidget { @override Widget build(BuildContext context) { + final radioBloc = context.read(); return Column( children: [ const Gap(12), @@ -39,8 +41,10 @@ class BottomSection extends StatelessWidget { if (state is LoginLoading) { Loader.loader(context); } else if (state is LoginSuccess) { - goRouter.pop(); successToastMessage(context, "login successful !"); + goRouter.pop(); + + goRouter.goNamed(RouteName.biometricScreen); } else if (state is LoginFailure) { goRouter.pop(); errorToastMessage( @@ -93,7 +97,10 @@ class BottomSection extends StatelessWidget { const Gap(5), ButtonWidget().textBtn( function: () { - goRouter.goNamed(RouteName.loginScreen); + radioBloc.resetSelection(); + goRouter.pushNamed(RouteName.registerStepScreen, pathParameters: { + "fromScreentype": "login", + }); }, text: TextWidget().tex14W700(AppText.signUpText, clr: AppColor.textLabelColor, diff --git a/lib/features/login/presentation/widgets/login_form.dart b/lib/features/login/presentation/widgets/login_form.dart index 1957354..e8f5537 100644 --- a/lib/features/login/presentation/widgets/login_form.dart +++ b/lib/features/login/presentation/widgets/login_form.dart @@ -16,6 +16,9 @@ class LoginForm extends StatelessWidget { Widget build(BuildContext context) { final loginBloc = context.read(); + // Reset fields when the screen is built + loginBloc.resetFields(); + return BlocConsumer(listener: (context, state) { int selectedCountry = -1; if (state is RadioSelectionChanged) { diff --git a/lib/features/otpVerification/presentation/bloc/otp_bloc.dart b/lib/features/otpVerification/presentation/bloc/otp_bloc.dart new file mode 100644 index 0000000..021580b --- /dev/null +++ b/lib/features/otpVerification/presentation/bloc/otp_bloc.dart @@ -0,0 +1,53 @@ +// otp_bloc.dart +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:sms_autofill/sms_autofill.dart'; +import 'otp_event.dart'; +import 'otp_state.dart'; + +class OtpBloc extends Bloc { + final TextEditingController otpController = TextEditingController(); + OtpBloc() : super(OtpInitial()) { + on(_onStartListeningForOtp); + on(_onOtpCodeChanged); + on(_onOtpSubmit); + } + + void _onStartListeningForOtp( + StartListeningForOtp event, Emitter emit) { + _startListening(); + } + + void _onOtpCodeChanged(OtpCodeChanged event, Emitter emit) { + emit(OtpCodeReceived(event.code)); + if (event.code.length == 6) { + add(OtpSubmit(event.code)); + } + } + + void _onOtpSubmit(OtpSubmit event, Emitter emit) async { + emit(OtpSubmitting()); + try { + // Add your OTP verification logic here + await Future.delayed(const Duration(seconds: 2)); + if (otpController.text == "123456") { + emit(OtpSubmissionSuccess()); + } else { + emit(const OtpSubmissionFailure("Otp Invalid !")); + } // Simulate network call + } catch (e) { + emit(OtpSubmissionFailure(e.toString())); + } + } + + void _startListening() { + SmsAutoFill().listenForCode(); // Correctly call listenForCode + } + + @override + Future close() { + otpController.dispose(); + SmsAutoFill().unregisterListener(); + return super.close(); + } +} diff --git a/lib/features/otpVerification/presentation/bloc/otp_event.dart b/lib/features/otpVerification/presentation/bloc/otp_event.dart new file mode 100644 index 0000000..4d6c5c5 --- /dev/null +++ b/lib/features/otpVerification/presentation/bloc/otp_event.dart @@ -0,0 +1,29 @@ +// otp_event.dart +import 'package:equatable/equatable.dart'; + +abstract class OtpEvent extends Equatable { + const OtpEvent(); + + @override + List get props => []; +} + +class OtpCodeChanged extends OtpEvent { + final String code; + + const OtpCodeChanged(this.code); + + @override + List get props => [code]; +} + +class OtpSubmit extends OtpEvent { + final String code; + + const OtpSubmit(this.code); + + @override + List get props => [code]; +} + +class StartListeningForOtp extends OtpEvent {} diff --git a/lib/features/otpVerification/presentation/bloc/otp_state.dart b/lib/features/otpVerification/presentation/bloc/otp_state.dart new file mode 100644 index 0000000..88f23f6 --- /dev/null +++ b/lib/features/otpVerification/presentation/bloc/otp_state.dart @@ -0,0 +1,33 @@ +// otp_state.dart +import 'package:equatable/equatable.dart'; + +abstract class OtpState extends Equatable { + const OtpState(); + + @override + List get props => []; +} + +class OtpInitial extends OtpState {} + +class OtpCodeReceived extends OtpState { + final String code; + + const OtpCodeReceived(this.code); + + @override + List get props => [code]; +} + +class OtpSubmitting extends OtpState {} + +class OtpSubmissionSuccess extends OtpState {} + +class OtpSubmissionFailure extends OtpState { + final String error; + + const OtpSubmissionFailure(this.error); + + @override + List get props => [error]; +} diff --git a/lib/features/otpVerification/presentation/pages/otp_layout.dart b/lib/features/otpVerification/presentation/pages/otp_layout.dart new file mode 100644 index 0000000..46cd8a6 --- /dev/null +++ b/lib/features/otpVerification/presentation/pages/otp_layout.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:tanami_app/features/otpVerification/presentation/widgets/otp_fill_section.dart'; + +import '../widgets/otp_top_section.dart'; + +class OtpLayout extends StatelessWidget { + const OtpLayout({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: ListView( + children: const [ + OtpTopSection(), + OtpFillSection(), + ], + )); + } +} diff --git a/lib/features/otpVerification/presentation/pages/otp_screen.dart b/lib/features/otpVerification/presentation/pages/otp_screen.dart new file mode 100644 index 0000000..fbfc730 --- /dev/null +++ b/lib/features/otpVerification/presentation/pages/otp_screen.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:tanami_app/features/otpVerification/presentation/bloc/otp_bloc.dart'; +import 'package:tanami_app/features/otpVerification/presentation/pages/otp_layout.dart'; + +import '../bloc/otp_event.dart'; + +class OtpScreen extends StatelessWidget { + const OtpScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: true, + body: MultiBlocProvider( + providers: [ + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => OtpBloc()..add(StartListeningForOtp()), + ), + ], + child: const OtpLayout(), + ), + ); + } +} diff --git a/lib/features/otpVerification/presentation/widgets/otp_fill_section.dart b/lib/features/otpVerification/presentation/widgets/otp_fill_section.dart new file mode 100644 index 0000000..2bf78f3 --- /dev/null +++ b/lib/features/otpVerification/presentation/widgets/otp_fill_section.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:sms_autofill/sms_autofill.dart'; +import 'package:tanami_app/core/routes/routes.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/shared/components/loader.dart'; +import 'package:tanami_app/shared/components/toast_message.dart'; + +import '../bloc/otp_bloc.dart'; +import '../bloc/otp_event.dart'; +import '../bloc/otp_state.dart'; + +class OtpFillSection extends StatelessWidget { + const OtpFillSection({super.key}); + + @override + Widget build(BuildContext context) { + return BlocConsumer( + listener: (context, state) { + if (state is OtpSubmitting) { + Loader.loader(context); + } else if (state is OtpSubmissionSuccess) { + goRouter.pop(); + successToastMessage(context, 'OTP Verified Successfully!'); + } else if (state is OtpSubmissionFailure) { + goRouter.pop(); + errorToastMessage(context, 'OTP Verification Failed: ${state.error}'); + } + }, + builder: (context, state) { + final otpBloc = context.read(); + + return Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + PinFieldAutoFill( + controller: otpBloc.otpController, + currentCode: otpBloc.otpController.text, + decoration: BoxLooseDecoration( + textStyle: GoogleFonts.dmSans( + fontSize: 22, + color: AppColor.otpTextColor, + fontWeight: FontWeight.w700, + ), + bgColorBuilder: const FixedColorBuilder(AppColor.fillColor), + radius: const Radius.circular(12), + strokeColorBuilder: const FixedColorBuilder( + AppColor.strokeColor, + )), + codeLength: 6, + onCodeChanged: (code) { + if (code != null) { + otpBloc.otpController.text = code; + otpBloc.add(OtpCodeChanged(code)); + } + }, + autoFocus: true, + ), + ], + ), + ); + }, + ); + } +} diff --git a/lib/features/otpVerification/presentation/widgets/otp_top_section.dart b/lib/features/otpVerification/presentation/widgets/otp_top_section.dart new file mode 100644 index 0000000..ff3df0f --- /dev/null +++ b/lib/features/otpVerification/presentation/widgets/otp_top_section.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:gap/gap.dart'; + +import '../../../../core/styles/app_color.dart'; +import '../../../../core/styles/app_images.dart'; +import '../../../../core/styles/app_text.dart'; +import '../../../../shared/components/text_widget.dart'; + +class OtpTopSection extends StatelessWidget { + const OtpTopSection({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Gap(85), + Center( + child: SvgPicture.asset( + AppImages.weclomeLogo, + ), + ), + const Gap(125), + TextWidget().tex20W700( + AppText.checkYourMessages, + clr: AppColor.charcoalColor, + ), + const Gap(25), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 35), + child: TextWidget().tex14W500( + AppText.referToSameOtpMessage, + clr: AppColor.smokeGrayColor, + ), + ), + ], + ); + } +} diff --git a/lib/features/register/presentation/bloc/register_bloc.dart b/lib/features/register/presentation/bloc/register_bloc.dart new file mode 100644 index 0000000..13d3edf --- /dev/null +++ b/lib/features/register/presentation/bloc/register_bloc.dart @@ -0,0 +1,74 @@ +import 'package:bloc/bloc.dart'; +import 'package:flutter/material.dart'; +import 'register_event.dart'; +import 'register_state.dart'; + +class RegisterBloc extends Bloc { + final GlobalKey formKey = GlobalKey(); + final TextEditingController countrySelectionTextField = + TextEditingController(); + final TextEditingController phoneNumberTextField = TextEditingController(); + final TextEditingController passwordTextField = TextEditingController(); + + GlobalKey getFormKey() { + return formKey; + } + + RegisterBloc() : super(RegisterInitial()) { + phoneNumberTextField.addListener(_onFormFieldChanged); + passwordTextField.addListener(_onFormFieldChanged); + countrySelectionTextField.addListener(_onFormFieldChanged); + on(_onLoginFormChanged); + on((event, emit) async { + if (!formKey.currentState!.validate()) { + return; + } + emit(RegisterLoading()); + try { + // Simulate API call + await Future.delayed(const Duration(seconds: 2)); + // Replace the next line with actual API call + final isSuccess = await _mockLoginApi( + event.phoneNumber, event.password, event.countryResidence); + if (isSuccess) { + emit(RegisterSuccess()); + } else { + emit(const RegisterFailure( + "Register failed. Please check your credentials.")); + } + } catch (e) { + emit(RegisterFailure(e.toString())); + } + }); + } + void _onFormFieldChanged() { + add(RegisterFormChanged( + phoneNumberTextField.text, + countrySelectionTextField.text, + )); + } + + void _onLoginFormChanged( + RegisterFormChanged event, Emitter emit) { + final areFieldsFilled = + event.phoneNumber.isNotEmpty && event.country.isNotEmpty; + emit(RegisterFieldsState(areFieldsFilled)); + } + + // Mock API function, replace with actual API call + Future _mockLoginApi( + String phoneNumber, + String password, + String countryResidence, + ) async { + return true; + } + + @override + Future close() { + phoneNumberTextField.dispose(); + passwordTextField.dispose(); + countrySelectionTextField.dispose(); + return super.close(); + } +} diff --git a/lib/features/register/presentation/bloc/register_event.dart b/lib/features/register/presentation/bloc/register_event.dart new file mode 100644 index 0000000..d7a46e1 --- /dev/null +++ b/lib/features/register/presentation/bloc/register_event.dart @@ -0,0 +1,33 @@ +import 'package:equatable/equatable.dart'; + +abstract class RegisterEvent extends Equatable { + const RegisterEvent(); + + @override + List get props => []; +} + +class RegisterSubmitted extends RegisterEvent { + final String phoneNumber; + final String password; + final String countryResidence; + + const RegisterSubmitted( + this.phoneNumber, + this.password, + this.countryResidence, + ); + + @override + List get props => [phoneNumber, password, countryResidence]; +} + +class RegisterFormChanged extends RegisterEvent { + final String phoneNumber; + final String country; + + const RegisterFormChanged(this.phoneNumber, this.country); + + @override + List get props => [phoneNumber, country]; +} diff --git a/lib/features/register/presentation/bloc/register_state.dart b/lib/features/register/presentation/bloc/register_state.dart new file mode 100644 index 0000000..8f23bcb --- /dev/null +++ b/lib/features/register/presentation/bloc/register_state.dart @@ -0,0 +1,32 @@ +import 'package:equatable/equatable.dart'; + +abstract class RegisterState extends Equatable { + const RegisterState(); + + @override + List get props => []; +} + +class RegisterInitial extends RegisterState {} + +class RegisterLoading extends RegisterState {} + +class RegisterSuccess extends RegisterState {} + +class RegisterFailure extends RegisterState { + final String error; + + const RegisterFailure(this.error); + + @override + List get props => [error]; +} + +class RegisterFieldsState extends RegisterState { + final bool areFieldsFilled; + + const RegisterFieldsState(this.areFieldsFilled); + + @override + List get props => [areFieldsFilled]; +} diff --git a/lib/features/register/presentation/pages/register_layout.dart b/lib/features/register/presentation/pages/register_layout.dart new file mode 100644 index 0000000..c059f6c --- /dev/null +++ b/lib/features/register/presentation/pages/register_layout.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:tanami_app/features/register/presentation/widgets/register_bottom_section.dart'; +import 'package:tanami_app/features/register/presentation/widgets/register_form.dart'; +import 'package:tanami_app/features/register/presentation/widgets/register_top_section.dart'; + +class RegisterLayout extends StatelessWidget { + const RegisterLayout({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: ListView( + // + children: const [ + RegisterTopSection(), + RegisterForm(), + RegisterBottomSection(), + ], + )); + } +} diff --git a/lib/features/register/presentation/pages/register_screen.dart b/lib/features/register/presentation/pages/register_screen.dart new file mode 100644 index 0000000..6e0a7ad --- /dev/null +++ b/lib/features/register/presentation/pages/register_screen.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:tanami_app/features/register/presentation/bloc/register_bloc.dart'; + +import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart'; +import 'register_layout.dart'; + +class RegisterScreen extends StatelessWidget { + const RegisterScreen({super.key}); + + @override + Widget build(BuildContext context) { + final radioBloc = context.read(); + return WillPopScope( + onWillPop: () async { + radioBloc.resetSelection(); + return true; // Allow the pop to happen + }, + child: Scaffold( + resizeToAvoidBottomInset: true, + body: MultiBlocProvider( + providers: [ + BlocProvider( + // Create an instance of the OnboardingBloc + create: (context) => RegisterBloc(), + ), + ], + child: const RegisterLayout(), + ), + ), + ); + } +} diff --git a/lib/features/register/presentation/pages/register_step_layout.dart b/lib/features/register/presentation/pages/register_step_layout.dart new file mode 100644 index 0000000..0c656ea --- /dev/null +++ b/lib/features/register/presentation/pages/register_step_layout.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/features/register/presentation/widgets/register_step_count.dart'; + +import '../widgets/register_step_bottom_section.dart'; +import '../widgets/register_step_top_section.dart'; + +class RegisterStepLayout extends StatelessWidget { + const RegisterStepLayout({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: ListView( + children: const [ + RegisterStepTopSection(), + Gap(20), + RegisterStepCount(), + RegisterStepBottomSection(), + ], + )); + } +} diff --git a/lib/features/register/presentation/pages/register_step_screen.dart b/lib/features/register/presentation/pages/register_step_screen.dart new file mode 100644 index 0000000..e818e9c --- /dev/null +++ b/lib/features/register/presentation/pages/register_step_screen.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +import '../../../../shared/components/exit_app_dialog.dart'; +import 'register_step_layout.dart'; + +class RegisterStepScreen extends StatelessWidget { + final String fromScreen; + const RegisterStepScreen({ + super.key, + required this.fromScreen, + }); + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + if (fromScreen == "welcome" || fromScreen == "login") { + exitAppDialog(context); + return false; + } else { + return true; + } + }, + child: const Scaffold( + resizeToAvoidBottomInset: true, + body: RegisterStepLayout(), + ), + ); + } +} diff --git a/lib/features/register/presentation/widgets/register_bottom_section.dart b/lib/features/register/presentation/widgets/register_bottom_section.dart new file mode 100644 index 0000000..df9c3bb --- /dev/null +++ b/lib/features/register/presentation/widgets/register_bottom_section.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/shared/components/loader.dart'; +import 'package:tanami_app/shared/components/toast_message.dart'; + +import '../../../../core/routes/route_name.dart'; +import '../../../../core/routes/routes.dart'; +import '../../../../core/styles/app_color.dart'; +import '../../../../core/styles/app_text.dart'; +import '../../../../shared/components/button_widget.dart'; +import '../../../../shared/components/text_widget.dart'; +import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart'; +import '../bloc/register_bloc.dart'; +import '../bloc/register_event.dart'; +import '../bloc/register_state.dart'; + +class RegisterBottomSection extends StatelessWidget { + const RegisterBottomSection({super.key}); + + @override + Widget build(BuildContext context) { + final radioBloc = context.read(); + return Column( + children: [ + const Gap(90), + Image.asset( + AppImages.stage1Image, + width: 75, + height: 12, + ), + const Gap(36), + BlocConsumer( + listener: (context, state) { + if (state is RegisterLoading) { + Loader.loader(context); + } else if (state is RegisterSuccess) { + successToastMessage(context, "successful !"); + goRouter.pop(); + + goRouter.pushNamed(RouteName.otpScreen); + } else if (state is RegisterFailure) { + goRouter.pop(); + errorToastMessage( + context, + state.error, + ); + } + }, + builder: (context, state) { + bool isButtonEnabled = false; + if (state is RegisterFieldsState) { + isButtonEnabled = state.areFieldsFilled; + } else if (state is RegisterSuccess || state is RegisterFailure) { + isButtonEnabled = true; + } + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 16, + ), + width: 1.sw, + height: 56.h, + child: ButtonWidget().elevatedBtn( + txtClr: isButtonEnabled + ? AppColor.plainWhite + : AppColor.inactiveBtnTxtColor, + function: () { + isButtonEnabled + ? context.read().add( + RegisterSubmitted( + context + .read() + .phoneNumberTextField + .text, + context + .read() + .passwordTextField + .text, + ""), + ) + : null; + }, + text: AppText.nextText, + clr: isButtonEnabled + ? AppColor.primaryColor2 + : AppColor.inactiveBtnColor, + ), + ); + }, + ), + const Gap(5), + ButtonWidget().textBtn( + function: () { + radioBloc.resetSelection(); + goRouter.pop(); + }, + text: TextWidget().tex14W700(AppText.backText, + clr: AppColor.textLabelColor, + textDecoration: TextDecoration.underline)), + ], + ); + } +} diff --git a/lib/features/register/presentation/widgets/register_form.dart b/lib/features/register/presentation/widgets/register_form.dart new file mode 100644 index 0000000..e9e52ea --- /dev/null +++ b/lib/features/register/presentation/widgets/register_form.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/core/utils/constant/country_flag_data.dart'; + +import '../../../../shared/components/form_label_textfield.dart'; +import '../../../countrySelection/presentation/bloc/choose_country_bloc.dart'; +import '../../../countrySelection/presentation/bloc/choose_country_state.dart'; +import '../bloc/register_bloc.dart'; + +class RegisterForm extends StatelessWidget { + const RegisterForm({super.key}); + + @override + Widget build(BuildContext context) { + final loginBloc = context.read(); + int selectedCountry = -1; + return BlocConsumer(listener: (context, state) { + if (state is RadioSelectionChanged) { + selectedCountry = state.selectedIndex; + loginBloc.countrySelectionTextField.text = countryName[selectedCountry]; + } + }, builder: (context, state) { + if (state is RadioSelectionChanged) { + selectedCountry = state.selectedIndex; + } else { + selectedCountry = -1; + } + return Form( + key: loginBloc.formKey, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 14, + ), + child: Align( + alignment: Alignment.topLeft, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Gap(50), + FormLabelTextField( + prefixWidget: selectedCountry == -1 + ? null + : Image.asset( + countryFlag[selectedCountry], + width: 20, + height: 20, + ), + hintText: AppText.chooseCountry, + title: AppText.countryOfResidence, + type: "country selection", + textEditingController: loginBloc.countrySelectionTextField, + ), + const Gap(20), + FormLabelTextField( + prefixWidget: selectedCountry == -1 + ? null + : Image.asset( + countryFlag[selectedCountry], + width: 20, + height: 20, + ), + hintText: "+0 (000) 000 00 00", + title: AppText.phoneNumber, + type: "phone number", + textEditingController: loginBloc.phoneNumberTextField, + ), + ], + ), + ), + ), + ); + }); + } +} diff --git a/lib/features/register/presentation/widgets/register_step_bottom_section.dart b/lib/features/register/presentation/widgets/register_step_bottom_section.dart new file mode 100644 index 0000000..e1bcd60 --- /dev/null +++ b/lib/features/register/presentation/widgets/register_step_bottom_section.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/routes/route_name.dart'; +import 'package:tanami_app/core/routes/routes.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/shared/components/button_widget.dart'; + +import '../../../../core/styles/app_text.dart'; +import '../../../../shared/components/text_widget.dart'; + +class RegisterStepBottomSection extends StatelessWidget { + const RegisterStepBottomSection({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 40.0), + child: Column( + children: [ + Container( + margin: const EdgeInsets.symmetric( + horizontal: 16, + ), + width: 1.sw, + height: 56.h, + child: ButtonWidget().elevatedBtn( + function: () { + goRouter.pushNamed( + RouteName.registerScreen, + ); + }, + text: AppText.getStarted, + txtClr: AppColor.plainWhite, + clr: AppColor.primaryColor2, + ), + ), + const Gap(16), + ButtonWidget().textBtn( + function: () { + goRouter.goNamed(RouteName.loginScreen, pathParameters: { + "fromScreen": "registerStep", + }); + }, + text: TextWidget().tex14W700( + AppText.loginText, + clr: AppColor.darkGreyColor, + textDecoration: TextDecoration.underline, + )) + ], + ), + ); + } +} diff --git a/lib/features/register/presentation/widgets/register_step_count.dart b/lib/features/register/presentation/widgets/register_step_count.dart new file mode 100644 index 0000000..528596f --- /dev/null +++ b/lib/features/register/presentation/widgets/register_step_count.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/utils/constant/register_step_data.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +class RegisterStepCount extends StatelessWidget { + const RegisterStepCount({super.key}); + + @override + Widget build(BuildContext context) { + return ListView.builder( + shrinkWrap: true, + itemCount: 3, + itemBuilder: (context, index) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 27, + vertical: 5, + ), + child: ListTile( + isThreeLine: true, + leading: SvgPicture.asset(stepImage[index]), + title: TextWidget().tex14W700( + title[index], + clr: AppColor.textLabelColor, + txtAlign: TextAlign.start, + ), + subtitle: TextWidget().tex14W500( + description[index], + clr: AppColor.textLabelColor, + txtAlign: TextAlign.start, + ), + ), + ); + }, + ); + } +} diff --git a/lib/features/register/presentation/widgets/register_step_top_section.dart b/lib/features/register/presentation/widgets/register_step_top_section.dart new file mode 100644 index 0000000..7f4bb24 --- /dev/null +++ b/lib/features/register/presentation/widgets/register_step_top_section.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +class RegisterStepTopSection extends StatelessWidget { + const RegisterStepTopSection({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Gap(85), + Center( + child: SvgPicture.asset( + AppImages.weclomeLogo, + ), + ), + const Gap(30), + TextWidget().tex20W700( + AppText.getStarted, + clr: AppColor.charcoalColor, + ), + const Gap(10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 75), + child: TextWidget().tex14W500( + AppText.setupYourTanamiAccountToBegin, + clr: AppColor.smokeGrayColor, + ), + ), + ], + ); + } +} diff --git a/lib/features/register/presentation/widgets/register_top_section.dart b/lib/features/register/presentation/widgets/register_top_section.dart new file mode 100644 index 0000000..d6e71c0 --- /dev/null +++ b/lib/features/register/presentation/widgets/register_top_section.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; +import 'package:tanami_app/shared/components/text_widget.dart'; + +class RegisterTopSection extends StatelessWidget { + const RegisterTopSection({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Gap(85), + Center( + child: SvgPicture.asset( + AppImages.weclomeLogo, + ), + ), + const Gap(60), + TextWidget().tex20W700( + AppText.welcome, + clr: AppColor.charcoalColor, + ), + const Gap(10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 75), + child: TextWidget().tex14W500( + AppText.selectYourCountryOfResidence, + clr: AppColor.smokeGrayColor, + ), + ), + ], + ); + } +} diff --git a/lib/features/welcome/presentation/widgets/login_signup_button.dart b/lib/features/welcome/presentation/widgets/login_signup_button.dart index 3542f8b..ef12d97 100644 --- a/lib/features/welcome/presentation/widgets/login_signup_button.dart +++ b/lib/features/welcome/presentation/widgets/login_signup_button.dart @@ -25,7 +25,11 @@ class LoginSignUpButton extends StatelessWidget { width: 1.sw, height: 56.h, child: ButtonWidget().elevatedBtn( - function: () {}, + function: () { + goRouter.goNamed(RouteName.registerStepScreen, pathParameters: { + "fromScreentype": "welcome", + }); + }, text: AppText.signUpText, txtClr: AppColor.plainWhite, clr: AppColor.primaryColor, @@ -34,11 +38,15 @@ class LoginSignUpButton extends StatelessWidget { const Gap(16), ButtonWidget().textBtn( function: () { - goRouter.goNamed(RouteName.loginScreen); + goRouter.goNamed(RouteName.loginScreen, pathParameters: { + "fromScreen": "welcome", + }); }, - text: TextWidget().tex14W700(AppText.loginText, - clr: AppColor.darkGreyColor, - textDecoration: TextDecoration.underline)) + text: TextWidget().tex14W700( + AppText.loginText, + clr: AppColor.darkGreyColor, + textDecoration: TextDecoration.underline, + )) ], ), ); diff --git a/lib/main.dart b/lib/main.dart index dda583a..70a04f9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'core/routes/routes.dart'; import 'core/utils/connectivity/network_connectivity.dart'; import 'features/countrySelection/presentation/bloc/choose_country_bloc.dart'; +import 'shared/components/bloc/password_field/password_visibility_bloc.dart'; /* CREATED BY - JAYESH JAIN DATE - 24-05-2024 @@ -53,7 +54,10 @@ class _MyAppState extends State with WidgetsBindingObserver { providers: [ BlocProvider( create: (context) => RadioBloc(), - ) + ), + BlocProvider( + create: (context) => PasswordVisibilityBloc(), + ), ], child: ScreenUtilInit( builder: (BuildContext context, Widget? child) => MaterialApp.router( diff --git a/lib/shared/components/exit_app_dialog.dart b/lib/shared/components/exit_app_dialog.dart new file mode 100644 index 0000000..2112358 --- /dev/null +++ b/lib/shared/components/exit_app_dialog.dart @@ -0,0 +1,119 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:gap/gap.dart'; +import 'package:tanami_app/core/styles/app_color.dart'; +import 'package:tanami_app/core/styles/app_images.dart'; +import 'package:tanami_app/core/styles/app_text.dart'; + +exitAppDialog( + context, +) { + return showDialog( + context: context, + builder: (context) => Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AlertDialog( + insetPadding: const EdgeInsets.symmetric(horizontal: 16), + backgroundColor: const Color(0XFFFFFFFF), + //contentPadding: EdgeInsets.fromLTRB(96, 32, 96, 28), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), + side: BorderSide(color: Color(0XFFFFFFFF)), + ), + content: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + //sizedBoxHeight(32.h), + Align( + alignment: Alignment.center, + child: CircleAvatar( + radius: 25, + backgroundColor: AppColor.inactiveBtnColor, + child: Center( + child: SvgPicture.asset( + AppImages.exitAppIcon, + width: 30, + height: 30, + fit: BoxFit.contain, + color: AppColor.primaryColor, + ), + ), + ), + ), + SizedBox( + height: 22.h, + ), + Align( + alignment: Alignment.center, + child: Text( + AppText.areYouSureYouWantToExitText, + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.black, + fontSize: 22.sp, + //fontWeight: FontWeight.w600, + ), + ), + ), + + Gap(21.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Container( + height: 48.h, + width: 140.w, + decoration: BoxDecoration( + border: Border.all( + color: AppColor.primaryColor, + ), + borderRadius: BorderRadius.circular(10.h), + color: AppColor.plainWhite, + ), + child: Center( + child: Text( + AppText.cancelText, + style: TextStyle( + color: AppColor.primaryColor, fontSize: 18.sp), + ), + ), + ), + ), + Gap(15.w), + InkWell( + onTap: () { + SystemNavigator.pop(); + Navigator.pop(context); + }, + child: Container( + height: 48.h, + width: 140.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.h), + color: AppColor.primaryColor), + child: Center( + child: Text( + AppText.exitText, + style: TextStyle( + color: AppColor.plainWhite, fontSize: 18.sp), + ), + ), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ); +} diff --git a/lib/shared/components/text_widget.dart b/lib/shared/components/text_widget.dart index 609bfa0..6d79bbc 100644 --- a/lib/shared/components/text_widget.dart +++ b/lib/shared/components/text_widget.dart @@ -13,23 +13,15 @@ class TextWidget { } //Text Size 14 - Widget tex14W700(String text, {Color? clr, TextDecoration? textDecoration}) { - return Text(text, - textAlign: TextAlign.center, - style: GoogleFonts.dmSans( - fontSize: 14, - fontWeight: FontWeight.w700, - decoration: textDecoration ?? TextDecoration.none, - color: clr ?? AppColor.plainWhite)); - } Widget tex14W500( String text, { Color? clr, TextDecoration? textDecoration, + TextAlign? txtAlign, }) { return Text(text, - textAlign: TextAlign.center, + textAlign: txtAlign ?? TextAlign.center, style: GoogleFonts.dmSans( fontSize: 14, fontWeight: FontWeight.w500, @@ -37,6 +29,17 @@ class TextWidget { color: clr ?? AppColor.plainWhite)); } + Widget tex14W700(String text, + {Color? clr, TextDecoration? textDecoration, TextAlign? txtAlign}) { + return Text(text, + textAlign: txtAlign ?? TextAlign.center, + style: GoogleFonts.dmSans( + fontSize: 14, + fontWeight: FontWeight.w700, + decoration: textDecoration ?? TextDecoration.none, + color: clr ?? AppColor.plainWhite)); + } + //Text Size 15 Widget tex15W500( String text, { diff --git a/pubspec.lock b/pubspec.lock index dcd9ae0..1397c28 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -808,6 +808,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" + pin_input_text_field: + dependency: transitive + description: + name: pin_input_text_field + sha256: "8d6fc670aa673a4df5976086f0e8039972a5b2bcb783c8db8dd3b9b4b072ca90" + url: "https://pub.dev" + source: hosted + version: "4.5.1" platform: dependency: transitive description: @@ -941,6 +949,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + sms_autofill: + dependency: "direct main" + description: + name: sms_autofill + sha256: "43139a175fb3c57ff103ac4b82f2aa70b6c45cf93539d7974c2556810f355363" + url: "https://pub.dev" + source: hosted + version: "2.3.1" source_gen: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 335c34f..5f4b1ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -74,6 +74,9 @@ dependencies: #Style control_style: ^0.1.0 + #OTP Autofill + sms_autofill: ^2.3.1 + dev_dependencies: flutter_test: sdk: flutter @@ -92,5 +95,9 @@ flutter: - assets/images/auth_screen/svg/ - assets/images/auth_screen/png/ - assets/images/country_flag/ - - assets/images/country_flag/svg/ - assets/images/country_flag/png/ + - assets/images/biometric_screen/ + - assets/images/biometric_screen/png/ + - assets/images/biometric_screen/svg/ + - assets/images/dialog/ + - assets/images/dialog/svg/