From ea15bd915222d1b29fe493ea699e05b0c931ba36 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Mon, 1 Sep 2025 17:01:38 +0300 Subject: [PATCH 1/6] bottom sheet --- .gitignore | 1 + assets/langs/ar-SA.json | 9 +- assets/langs/en-US.json | 7 +- lib/extensions/string_extensions.dart | 10 +- lib/generated/locale_keys.g.dart | 5 + lib/presentation/authantication/login.dart | 229 +++++++++++------- lib/theme/colors.dart | 26 +- .../bottomsheet/generic_bottom_sheet.dart | 145 +++++++++++ 8 files changed, 321 insertions(+), 111 deletions(-) create mode 100644 lib/widgets/bottomsheet/generic_bottom_sheet.dart diff --git a/.gitignore b/.gitignore index 79c113f..3ada50c 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +/android/ diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 8ff2eb4..361413e 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -776,5 +776,12 @@ "validPassportNumber": "يرجى إدخال رقم جواز سفر صالح", "continuePlan": "متابعة خطة العلاج؟", "aboutApp": "حول التطبيق", - "dontHaveAccount": "ليس لديك حساب؟" + "dontHaveAccount": "ليس لديك حساب؟", + "receiveOtpToast": "أين تود تلقي رمز التحقق OTP؟", + "enterPhoneNumber": "أدخل رقم الهاتف", + "enterEmailDesc": "أدخل عنوان بريدك الإلكتروني لإكمال عملية إنشاء ملف طبي", + "enterPhoneDesc": "أدخل رقم هاتفك لتلقي رمز التحقق ", + "pleaseChooseOption": "الرجاء اختيار من الخيارات أدناه لتلقي رمز التحقق OTP" + + } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 423c67b..a8c263c 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -772,5 +772,10 @@ "aboutApp": "About the app", "aboutPoints": "Online Appointment Booking & rescheduling, Insurance approval status, Find A doctor, Ask your doctor, Medical prescriptions, Lab results, Hospitals contact numbers, Doctor profiles, Hospitals locations, Pharmacies Locations, Hospital's Virtual Tour, Official Social Media, Vaccines Schedule, Health Calculators, Other Services", "termsConditions": "These Online Services Terms of Use (Service Terms) govern certain online services provided by Dr Sulaiman Al Habib Medical Services Group Company (HMG, we, us, our)...", - "dontHaveAccount": "Don't have an account?" + "dontHaveAccount": "Don't have an account?", + "receiveOtpToast": "Where would you like to receive OTP?", + "enterPhoneNumber": "Enter Phone Number", + "enterEmailDesc": "Enter your email address to complete the process of creating a medical file", + "enterPhoneDesc": "Enter your phone number to receive OTP verification code", + "pleaseChooseOption": "Please select from the below options to receive OTP" } \ No newline at end of file diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 2e74d25..2722901 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -198,31 +198,31 @@ extension EmailValidator on String { Widget toText20({Color? color, bool isBold = false}) => Text( this, - style: TextStyle(fontSize: 20.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: 0.64), + style: TextStyle(fontSize: 20.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -1), ); Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text( this, maxLines: maxlines, - style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 21.fSize, letterSpacing: 0.64, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)), + style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 21.fSize, letterSpacing: -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)), ); Widget toText22({Color? color, bool isBold = false, bool isCenter = false}) => Text( this, textAlign: isCenter ? TextAlign.center : null, - style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.fSize, letterSpacing: 0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), + style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), ); Widget toText24({Color? color, bool isBold = false, bool isCenter = false}) => Text( this, textAlign: isCenter ? TextAlign.center : null, - style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: 0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), + style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), ); Widget toText32({Color? color, bool isBold = false, bool isCenter = false}) => Text( this, textAlign: isCenter ? TextAlign.center : null, - style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.fSize, letterSpacing: 0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), + style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), ); Widget toText44({Color? color, bool isBold = false}) => Text( diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index b2d7492..6b1ada7 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -775,5 +775,10 @@ abstract class LocaleKeys { static const continuePlan = 'continuePlan'; static const aboutApp = 'aboutApp'; static const dontHaveAccount = 'dontHaveAccount'; + static const receiveOtpToast = 'receiveOtpToast'; + static const enterPhoneNumber = 'enterPhoneNumber'; + static const enterEmailDesc = 'enterEmailDesc'; + static const enterPhoneDesc = 'enterPhoneDesc'; + static const pleaseChooseOption = 'pleaseChooseOption'; } diff --git a/lib/presentation/authantication/login.dart b/lib/presentation/authantication/login.dart index 150d446..84e1da3 100644 --- a/lib/presentation/authantication/login.dart +++ b/lib/presentation/authantication/login.dart @@ -3,16 +3,16 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; +import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; -import 'package:hmg_patient_app_new/widgets/language_switcher.dart'; -import 'package:sizer/sizer.dart'; // Import sizer class LoginScreen extends StatefulWidget { @override @@ -32,98 +32,145 @@ class _LoginScreen extends State { @override Widget build(BuildContext context) { - return Sizer(// Wrap with Sizer - builder: (context, orientation, deviceType) { - return Scaffold( - appBar: CustomAppBar( - onBackPressed: () { - // Navigator.of(context).pop(); - }, - onLanguageChanged: (String value) { - print(value); - context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); - }, - ), - body: GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside - }, - child: SingleChildScrollView( - child: Padding( - padding: EdgeInsets.only(left: 6.w, right: 6.w), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 45.w, height: 22.h, repeat: true, fit: BoxFit.cover), - SizedBox(height: 19.h), // Adjusted to sizer unit - Text( - LocaleKeys.welcomeToDrSulaiman.tr(), - style: context.dynamicTextStyle( - fontSize: 22.sp, - fontWeight: FontWeight.w600, - color: AppColors.textColor, - letterSpacing: -0.4, - height: 40 / 28, - ), - ), - SizedBox(height: 4.h), // Adjusted to sizer unit (approx 32px) - TextInputWidget( - labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}", - hintText: "xxxxxxxxx", - controller: TextEditingController(), - keyboardType: TextInputType.number, - isEnable: true, - prefix: null, - autoFocus: true, - isBorderAllowed: false, - isAllowLeadingIcon: true, - padding: EdgeInsets.symmetric(vertical: 1.h, horizontal: 2.w), - leadingIcon: AppAssets.student_card, - errorMessage: "Please enter a valid national ID or file number", - hasError: true, - ), - SizedBox(height: 2.h), // Adjusted to sizer unit (approx 16px) - CustomButton( - text: LocaleKeys.login.tr(), - icon: AppAssets.login1, - iconColor: Colors.white, - onPressed: () {}, - ), - SizedBox(height: 1.8.h), // Adjusted to sizer unit (approx 14px) - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: context.dynamicTextStyle( - color: Colors.black, - fontSize: 14.sp, // Adjusted to sizer unit - height: 26 / 16, // This height is a ratio, may need re-evaluation - fontWeight: FontWeight.w500, - ), - children: [ - TextSpan(text: LocaleKeys.dontHaveAccount.tr(), style: context.dynamicTextStyle()), - TextSpan(text: " "), - TextSpan( - text: LocaleKeys.registernow.tr(), - style: context.dynamicTextStyle( - color: AppColors.primaryRedColor, - fontSize: 14.sp, // Adjusted to sizer unit - height: 26 / 16, // Ratio - fontWeight: FontWeight.w500, - ), - recognizer: TapGestureRecognizer()..onTap = () {}, - ), - ], + return Scaffold( + appBar: CustomAppBar( + onBackPressed: () { + // Navigator.of(context).pop(); + }, + onLanguageChanged: (String value) { + print(value); + context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); + }, + ), + body: GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside + }, + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(left: 6.h, right: 6.h), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 45.h, height: 22.h, repeat: true, fit: BoxFit.cover), + SizedBox(height: 19.h), // Adjusted to sizer unit + LocaleKeys.welcomeToDrSulaiman.tr().toText24(), + SizedBox(height: 4.h), // Adjusted to sizer unit (approx 32px) + TextInputWidget( + labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}", + hintText: "xxxxxxxxx", + controller: TextEditingController(), + keyboardType: TextInputType.number, + isEnable: true, + prefix: null, + autoFocus: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + padding: EdgeInsets.symmetric(vertical: 1.h, horizontal: 2.h), + leadingIcon: AppAssets.student_card, + errorMessage: "Please enter a valid national ID or file number", + hasError: true, + ), + SizedBox(height: 2.h), // Adjusted to sizer unit (approx 16px) + CustomButton( + text: LocaleKeys.login.tr(), + icon: AppAssets.login1, + iconColor: Colors.white, + onPressed: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + isDismissible: false, + useSafeArea: true, + backgroundColor: Colors.transparent, + enableDrag: false, + builder: (bottomSheetContext) => StatefulBuilder( + builder: (BuildContext context, StateSetter setModalState) { + return Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom), + child: SingleChildScrollView( + child: GenericBottomSheet( + countryCode: "selectedCountry.countryCode", + initialPhoneNumber: "", + textController: TextEditingController(), + isEnableCountryDropdown: true, + onCountryChange: (value) {}, + onChange: (String? value) {}, + buttons: [ + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: CustomButton( + text: "TranslationBase.of(context).sendOTPSMS", + onPressed: () {}, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedBorderColor, + textColor: AppColors.whiteColor, + icon: AppAssets.message, + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: "LocaleKeys.oR.tr()".toText16(), + ), + ], + ), + Padding( + padding: const EdgeInsets.only(bottom: 10, top: 10), + child: CustomButton( + text: "LocaleKeys.sendOTPWHATSAPP.tr(),", + onPressed: () {}, + backgroundColor: Colors.white, + borderColor: AppColors.borderOnlyColor, + textColor: AppColors.textColor, + icon: AppAssets.whatsapp, + ), + ), + ], + ), + )); + }, ), - ).withVerticalPadding(2.h), // Adjusted to sizer unit - ), - ], - ), + ); + }, + ), + SizedBox(height: 1.8.h), // Adjusted to sizer unit (approx 14px) + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: context.dynamicTextStyle( + color: Colors.black, + fontSize: 14.fSize, // Adjusted to sizer unit + height: 26 / 16, // This height is a ratio, may need re-evaluation + fontWeight: FontWeight.w500, + ), + children: [ + TextSpan(text: LocaleKeys.dontHaveAccount.tr(), style: context.dynamicTextStyle()), + TextSpan(text: " "), + TextSpan( + text: LocaleKeys.registernow.tr(), + style: context.dynamicTextStyle( + color: AppColors.primaryRedColor, + fontSize: 14.fSize, // Adjusted to sizer unit + height: 26 / 16, // Ratio + fontWeight: FontWeight.w500, + ), + recognizer: TapGestureRecognizer()..onTap = () {}, + ), + ], + ), + ).withVerticalPadding(2.h), // Adjusted to sizer unit + ), + ], ), ), ), - ); - }); + ), + ); } } diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index 4987ffe..d20c5f2 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -8,7 +8,6 @@ class AppColors { static const buttonColor = Color(0xFF6A46F5); static const splashBgColor = Color(0xFF3C355D); - static const blackColor = Color(0xFF000000); static const lightGray = Color(0xFFF4F5F7); static const lightPurple = Color(0xFFB7A3E6); static const scaffoldBgColor = Color(0xFFF8F8F8); @@ -28,19 +27,20 @@ class AppColors { static const Color bgGreenColor = Color(0xFF18C273); static const Color textColor = Color(0xFF2E3039); static const Color borderOnlyColor = Color(0xFF2E3039); + static const blackColor = textColor; //Chips -static const Color successColor = Color(0xff18C273); -static const Color errorColor = Color(0xFFED1C2B); -static const Color alertColor = Color(0xFFD48D05); -static const Color infoColor = Color(0xFF0B85F7); -static const Color warningColor = Color(0xFFFFCC00); -static const Color greyColor = Color(0xFFEFEFF0); + static const Color successColor = Color(0xff18C273); + static const Color errorColor = Color(0xFFED1C2B); + static const Color alertColor = Color(0xFFD48D05); + static const Color infoColor = Color(0xFF0B85F7); + static const Color warningColor = Color(0xFFFFCC00); + static const Color greyColor = Color(0xFFEFEFF0); -static const Color successLightColor = Color(0xFF18C27326); -static const Color errorLightColor = Color(0xFFED1C2B1A); -static const Color alertLightColor = Color(0xFFD48D0526); -static const Color infoLightColor = Color(0xFF0B85F726); -static const Color warningLightColor = Color(0xFFFFCC0026); -static const Color greyLightColor = Color(0xFFEFEFF026); + static const Color successLightColor = Color(0xFF18C27326); + static const Color errorLightColor = Color(0xFFED1C2B1A); + static const Color alertLightColor = Color(0xFFD48D0526); + static const Color infoLightColor = Color(0xFF0B85F726); + static const Color warningLightColor = Color(0xFFFFCC0026); + static const Color greyLightColor = Color(0xFFEFEFF026); } diff --git a/lib/widgets/bottomsheet/generic_bottom_sheet.dart b/lib/widgets/bottomsheet/generic_bottom_sheet.dart new file mode 100644 index 0000000..13a02a5 --- /dev/null +++ b/lib/widgets/bottomsheet/generic_bottom_sheet.dart @@ -0,0 +1,145 @@ +import 'dart:io'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; + +class GenericBottomSheet extends StatefulWidget { + String? countryCode; + String? initialPhoneNumber; + final List buttons; + TextEditingController? textController; + final bool isForEmail; + Function(Country)? onCountryChange; + final bool isEnableCountryDropdown; + final bool isFromSavedLogin; + Function(String?)? onChange; + // FocusNode myFocusNode; + + GenericBottomSheet( + {this.countryCode = "", + this.initialPhoneNumber = "", + required this.buttons, + this.textController, + this.isForEmail = false, + this.onCountryChange, + this.isEnableCountryDropdown = false, + this.isFromSavedLogin = false, + this.onChange, + // required this.myFocusNode + }); + + @override + _GenericBottomSheetState createState() => _GenericBottomSheetState(); +} + +class _GenericBottomSheetState extends State { + @override + void initState() { + super.initState(); + + if (!widget.isForEmail) { + widget.textController = TextEditingController(text: widget.initialPhoneNumber); + } + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + top: false, + bottom: Platform.isIOS ? false : true, + child: GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: Directionality( + textDirection: Directionality.of(context), + child: Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: Color(0xFFF8F8FA), + borderRadius: const BorderRadius.vertical(top: Radius.circular(16)), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // Title + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: widget.isFromSavedLogin + ? LocaleKeys.receiveOtpToast.tr().toText24() + : widget.isForEmail + ? LocaleKeys.enterEmail.tr().toText24() + : LocaleKeys.enterPhoneNumber.tr().toText24()), + InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Padding( + padding: const EdgeInsets.only(top: 10), + child: Utils.buildSvgWithAssets( + icon: AppAssets.cross_circle, + ), + )), + ], + ), + const SizedBox(height: 8), + // Subtitle + widget.isFromSavedLogin + ? LocaleKeys.pleaseChooseOption.tr().toText16() + : widget.isForEmail + ? LocaleKeys.enterEmailDesc.tr().toText16() + : LocaleKeys.enterPhoneDesc.tr().toText16(), + + if (widget.isFromSavedLogin) + ...[] + else ...[ + widget.textController != null + ? TextInputWidget( + labelText: widget.isForEmail ? LocaleKeys.email : LocaleKeys.phoneNumber, + hintText: widget.isForEmail ? "demo@gmail.com" : "5xxxxxxxx", + controller: widget.textController!, + padding: EdgeInsets.only(top: 8, bottom: 8, left: 8, right: 8), + keyboardType: widget.isForEmail ? TextInputType.emailAddress : TextInputType.number, + onChange: (value) { + widget.textController!.text = value!; + if (widget.onChange != null) { + widget.onChange!(value); + } + }, + isEnable: true, + // focusNode: widget.myFocusNode, + isReadOnly: widget.isFromSavedLogin, + prefix: widget.isForEmail ? null : widget.countryCode, + isBorderAllowed: false, + isAllowLeadingIcon: true, + isCountryDropDown: widget.isEnableCountryDropdown, + leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone, + ) + : SizedBox(), + ], + + SizedBox(height: 24), + ...widget.buttons, + ], + ), + ), + ), + ), + ); + } +} From a4da9db6c371f2ce504c734ffb1f905c19cf8f87 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 2 Sep 2025 08:55:19 +0300 Subject: [PATCH 2/6] register & changes --- lib/extensions/string_extensions.dart | 27 +- lib/main.dart | 7 +- lib/presentation/authantication/login.dart | 2 +- lib/presentation/authantication/register.dart | 385 ++++++++++++++++++ 4 files changed, 405 insertions(+), 16 deletions(-) create mode 100644 lib/presentation/authantication/register.dart diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 2722901..1fdd9e7 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -165,18 +165,15 @@ extension EmailValidator on String { int? maxlines, TextAlign? textAlign, }) => - Text( - this, - maxLines: maxlines, - textAlign: isCenter ? TextAlign.center : null, - style: TextStyle( - color: color ?? AppColors.blackColor, - fontSize: 16.fSize, - letterSpacing: 0.64, - fontWeight: isBold ? FontWeight.bold : FontWeight.normal, - decoration: isUnderLine ? TextDecoration.underline : null, - ), - ); + Text(this, + maxLines: maxlines, + textAlign: isCenter ? TextAlign.center : null, + style: TextStyle( + color: color ?? AppColors.blackColor, + fontSize: 16.fSize, + letterSpacing: 0.64, + fontWeight: isBold ? FontWeight.bold : FontWeight.normal, + decoration: isUnderLine ? TextDecoration.underline : null)); Widget toText17({Color? color, bool isBold = false, bool isCenter = false}) => Text( this, @@ -219,6 +216,12 @@ extension EmailValidator on String { style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), ); + Widget toText28({Color? color, bool isBold = false, bool isCenter = false}) => Text( + this, + textAlign: isCenter ? TextAlign.center : null, + style: TextStyle(height: 23 / 28, color: color ?? AppColors.blackColor, fontSize: 28.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal), + ); + Widget toText32({Color? color, bool isBold = false, bool isCenter = false}) => Text( this, textAlign: isCenter ? TextAlign.center : null, diff --git a/lib/main.dart b/lib/main.dart index 1996653..ee8beaa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/utils/size_config.dart'; import 'package:hmg_patient_app_new/providers/authentication_view_model.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/theme/app_theme.dart'; @@ -77,20 +78,20 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return SafeArea( - top: false, // Set to true if you want to avoid the notch area as well + top: false, bottom: Platform.isIOS ? false : true, child: LayoutBuilder( builder: (context, constraints) { return Sizer( builder: (context, orientation, deviceType) { - // SizeConfig().init(constraints, orientation); + SizeConfig().init(constraints, orientation); return MaterialApp( title: 'Dr. AlHabib', builder: (context, mchild) { return MediaQuery( data: MediaQuery.of(context).copyWith( textScaler: TextScaler.linear(1.0), - ), //set desired text scale factor here + ), child: mchild!); }, showSemanticsDebugger: false, diff --git a/lib/presentation/authantication/login.dart b/lib/presentation/authantication/login.dart index 84e1da3..ac599b0 100644 --- a/lib/presentation/authantication/login.dart +++ b/lib/presentation/authantication/login.dart @@ -54,7 +54,7 @@ class _LoginScreen extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 45.h, height: 22.h, repeat: true, fit: BoxFit.cover), - SizedBox(height: 19.h), // Adjusted to sizer unit + SizedBox(height: 20.h), // Adjusted to sizer unit LocaleKeys.welcomeToDrSulaiman.tr().toText24(), SizedBox(height: 4.h), // Adjusted to sizer unit (approx 32px) TextInputWidget( diff --git a/lib/presentation/authantication/register.dart b/lib/presentation/authantication/register.dart new file mode 100644 index 0000000..bd4cb78 --- /dev/null +++ b/lib/presentation/authantication/register.dart @@ -0,0 +1,385 @@ +import 'dart:convert'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:provider/provider.dart'; + +class Register extends StatefulWidget { + final Function? changePageViewIndex; + + const Register({Key? key, this.changePageViewIndex}) : super(key: key); + + @override + _Register createState() => _Register(); +} + +class _Register extends State { + @override + void initState() { + getPatientOccupationList(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + onBackPressed: () {}, + onLanguageChanged: (String value) {}, + ), + body: Column( + children: [ + Expanded( + child: ListView( + padding: EdgeInsets.all(21), + physics: BouncingScrollPhysics(), + children: [ + SizedBox(height: 10), + Padding( + padding: EdgeInsets.all(10), + child: Text( + LocaleKeys.enterNationalId.tr(), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.64, height: 23 / 16), + )), + SizedBox(height: 10), + PhoneNumberSelectorWidget(onNumberChange: (value) => {}, onCountryChange: (value) => ), + SizedBox(height: 12), + TextInputWidget(labelText: LocaleKeys.nationalIdNumber.tr(), hintText: "Xxxxxxxxx", controller: TextEditingController()), + SizedBox(height: 20), + Row( + children: [ + Expanded( + child: Row( + children: [ + Radio( + value: 1, + groupValue: isHijri, + onChanged: (value) { + }, + ), + Text(LocaleKeys.hijriDate.tr()), + ], + ), + ), + Expanded( + child: Row( + children: [ + Radio( + value: 0, + groupValue: isHijri, + onChanged: (value) { + }, + ), + Text(LocaleKeys.gregorianDate.tr()), + ], + ), + ), + ], + ), + Row(children: [ + Container( + width: SizeConfig.realScreenWidth! * .89, + child: isHijri == 1 + ? Directionality( + textDirection: TextDirection.ltr, + child: inputWidget(TranslationBase.of(context).dob, "DD/MM/YYYYY", dob, + isNumber: false, + suffix: Icon( + Icons.calendar_today, + size: 16, + ))) + : Container( + child: InkWell( + onTap: () { + if (isHijri != null) _selectDate(context); + }, + child: Directionality( + textDirection: TextDirection.ltr, + child: inputWidget(TranslationBase.of(context).dob, "DD/MM/YYYYY", dobEn, + isNumber: false, + isEnable: false, + suffix: Icon( + Icons.calendar_today, + size: 16, + )))))), + ]) + ], + ), + ), + Container( + width: double.maxFinite, + // height: 80.0, + color: Colors.white, + // margin: EdgeInsets.only(bottom: 50.0), + child: Row( + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.all(10), + child: DefaultButton(TranslationBase.of(context).cancel, () { + Navigator.of(context).pop(); + locator().loginRegistration.registration_cancel(step: 'enter details'); + }, textColor: Colors.white, color: Color(0xffD02127))), + ), + Expanded( + child: Padding( + padding: EdgeInsets.all(10), + child: DefaultButton(TranslationBase.of(context).next, () { + startRegistration(); + locator().loginRegistration.registration_enter_details(); + }, textColor: Colors.white, color: isButtonDisabled == true ? Colors.grey : Color(0xff359846))), + ), + ], + ), + ) + ], + ), + ); + } + + Future _selectDate(BuildContext context) async { + DatePicker.showDatePicker( + context, + showTitleActions: true, + minTime: DateTime(DateTime.now().year - 100, 1, 1), + maxTime: DateTime.now(), + onConfirm: (date) { + selectedDate = date; + setState(() { + final intl.DateFormat dateFormat = intl.DateFormat('dd/MM/yyyy'); + dobEn.text = dateFormat.format(date); + }); + }, + currentTime: DateTime.now(), + ); + } + + Widget inputWidget(String _labelText, String _hintText, TextEditingController _controller, {String? prefix, bool isEnable = true, bool hasSelection = false, bool isNumber = true, Icon? suffix}) { + return Container( + padding: EdgeInsets.only(left: 16, right: 16, bottom: 15, top: 15), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: Colors.white, + border: Border.all( + color: Color(0xffefefef), + width: 1, + ), + ), + child: InkWell( + onTap: hasSelection ? () {} : null, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _labelText, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Color(0xff2B353E), + letterSpacing: -0.44, + ), + ), + TextField( + enabled: isEnable, + scrollPadding: EdgeInsets.zero, + keyboardType: isNumber ? TextInputType.numberWithOptions(signed: true) : TextInputType.datetime, + controller: _controller, + onChanged: (value) => {validateForm()}, + style: TextStyle( + fontSize: 14, + height: 21 / 14, + fontWeight: FontWeight.w400, + color: Color(0xff2B353E), + letterSpacing: -0.44, + ), + decoration: InputDecoration( + isDense: true, + hintText: _hintText, + hintStyle: TextStyle( + fontSize: 14, + height: 21 / 14, + fontWeight: FontWeight.w400, + color: Color(0xff575757), + letterSpacing: -0.56, + ), + prefixIconConstraints: BoxConstraints(minWidth: 50), + prefixIcon: prefix == null + ? null + : Text( + "+" + prefix, + style: TextStyle( + fontSize: 14, + height: 21 / 14, + fontWeight: FontWeight.w500, + color: Color(0xff2E303A), + letterSpacing: -0.56, + ), + ), + contentPadding: EdgeInsets.zero, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ], + ), + ), + if (hasSelection) Icon(Icons.keyboard_arrow_down_outlined), + if (suffix != null) suffix + ], + ), + ), + ); + } + + startRegistration() { + final intl.DateFormat dateFormat = intl.DateFormat('dd/MM/yyyy'); + if (isButtonDisabled == false) { + var request = CheckPatientForRegistration(); + request.patientMobileNumber = int.parse(mobileNo); + request.zipCode = countryCode; + request.patientOutSA = countryCode == '966' ? 0 : 1; + + request.patientIdentificationID = int.parse(nationalIDorFile.text); + request.patientID = 0; + request.isRegister = true; + request.dob = isHijri == 1 ? dob.text : dateFormat.format(selectedDate); + request.isHijri = isHijri; + this.checkPatientForRegisteration(request); + } + } + + checkPatientForRegisteration(request) { + int languageID = Provider.of(context, listen: false).isArabic ? 1 : 2; + GifLoaderDialogUtils.showMyDialog(context); + this.authService.checkPatientForRegisteration(request, languageID).then((response) => {checkUserStatus(response, request)}).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + ConfirmDialog dialog = new ConfirmDialog( + context: context, + confirmMessage: err, + okText: TranslationBase.of(context).confirm, + cancelText: TranslationBase.of(context).cancel_nocaps, + okFunction: () => { + ConfirmDialog.closeAlertDialog(context), + Navigator.of(context).push(FadePage(page: Register())), + }, + cancelFunction: () => {ConfirmDialog.closeAlertDialog(context)}); + dialog.showAlertDialog(context); + }); + } + + void validateForm() { + if (util.validateIDBox(nationalIDorFile.text, loginType) == true && + mobileNo.length >= 9 && + util.isSAUDIIDValid(nationalIDorFile.text, loginType) == true && + isHijri != null && + (dobEn.text != null || dob.text != null)) { + setState(() { + isButtonDisabled = false; + }); + } else { + setState(() { + isButtonDisabled = true; + }); + } + } + + checkUserStatus(response, CheckPatientForRegistration request) async { + GifLoaderDialogUtils.hideDialog(context); + if (response is Map) { + var nRequest = request.toJson(); + nRequest['LogInTokenID'] = response['LogInTokenID']; + if (response['hasFile'] == true) { + ConfirmDialog dialog = new ConfirmDialog( + context: context, + confirmMessage: response['ErrorEndUserMessage'], + okText: TranslationBase.of(context).ok, + cancelText: TranslationBase.of(context).cancel, + okFunction: () { + AlertDialogBox.closeAlertDialog(context); + sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, nRequest); + LoginRegistration.loginMethod = 1; // 1=NationalID, by default from Registration + Navigator.of(context).push(FadePage(page: Login())); + }, + cancelFunction: () {}) + .showAlertDialog(context); + } else { + final intl.DateFormat dateFormat = intl.DateFormat('dd/MM/yyyy'); + nRequest['forRegister'] = true; + nRequest['isRegister'] = true; + nRequest["PatientIdentificationID"] = nRequest["PatientIdentificationID"].toString(); + nRequest['dob'] = isHijri == 1 ? dob.text : dateFormat.format(selectedDate); + nRequest['isHijri'] = isHijri; + sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, nRequest); + sharedPref.setString(LOGIN_TOKEN_ID, response['LogInTokenID']); + if (request.patientOutSA == 0) { + this.chekUserData(response['LogInTokenID']); + } else { + Navigator.of(context).push(FadePage(page: ConfirmLogin(changePageViewIndex: widget.changePageViewIndex, fromRegistration: true, isDubai: true))); + } + } + } else { + // if (response['ErrorCode'] == '-986') { + //AppToast.showErrorToast(message: response); + AlertDialogBox( + context: context, + confirmMessage: response, + okText: TranslationBase.of(context).ok, + okFunction: () { + AlertDialogBox.closeAlertDialog(context); + Navigator.of(context).pop(); + }).showAlertDialog(context); + //} + } + } + + chekUserData(loginToken) { + // let m = hijri(this.dateOfBirth).locale('en'); + // // const dateHijri = m.format('iDD/iMM/iYYYY'); + // const request = { + // PatientIdentificationID: this.id.toString(), + // // TokenID: token, + // DOB: this.dateOption === '1' ? this.dateOfBirth : moment(this.dateOfBirth).format('DD/MM/YYYY'), + // IsHijri: Number(this.dateOption) + // } + + final intl.DateFormat dateFormat = intl.DateFormat('dd/MM/yyyy'); + GifLoaderDialogUtils.showMyDialog(context); + var request = CheckUserStatusRequest(); + request.patientIdentificationID = nationalIDorFile.text; + request.dOB = isHijri == 1 ? dob.text : dateFormat.format(selectedDate); + request.isHijri = isHijri; + request.patientOutSA = countryCode == '966' ? 0 : 1; + this.authService.checkUserStatus(request).then((result) => { + GifLoaderDialogUtils.hideDialog(context), + if (result is Map) + { + result = CheckUserStatusResponse.fromJson(result as Map), + sharedPref.setObject(NHIC_DATA, result), + // widget.changePageViewIndex!(1), + Navigator.of(context).push(FadePage(page: ConfirmLogin(changePageViewIndex: widget.changePageViewIndex, fromRegistration: true))), + } + else + { + AppToast.showErrorToast(message: result != null ? result : TranslationBase.of(context).somethingWentWrong), + } + }); + } + + getPatientOccupationList() async { + patientOccupationList.clear(); + await authService.getPatientOccupationList().then((result) { + sharedPref.setString(PATIENT_OCCUPATION_LIST, json.encode(result['GetOccupationLst'])); + }).catchError((err) { + AppToast.showErrorToast(message: err); + }); + } +} From 6f98690929142b52aa105ba14ffb0065db71640b Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 2 Sep 2025 09:29:59 +0300 Subject: [PATCH 3/6] register & changes --- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- lib/extensions/string_extensions.dart | 61 ++ lib/generated/locale_keys.g.dart | 3 +- lib/presentation/authantication/login.dart | 23 +- lib/presentation/authantication/register.dart | 964 +++++++++++------- lib/providers/authentication_view_model.dart | 5 +- 7 files changed, 660 insertions(+), 402 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 16373bf..ebcee14 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -782,7 +782,8 @@ "enterPhoneNumber": "أدخل رقم الهاتف", "enterEmailDesc": "أدخل عنوان بريدك الإلكتروني لإكمال عملية إنشاء ملف طبي", "enterPhoneDesc": "أدخل رقم هاتفك لتلقي رمز التحقق ", - "pleaseChooseOption": "الرجاء اختيار من الخيارات أدناه لتلقي رمز التحقق OTP" + "pleaseChooseOption": "الرجاء اختيار من الخيارات أدناه لتلقي رمز التحقق OTP", + "prepareToElevate": "هل أنت مستعد لتحسين صحتك ورفاهتك؟" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 1c78177..b45c697 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -778,5 +778,6 @@ "enterPhoneDesc": "Enter your phone number to receive OTP verification code", "pleaseChooseOption": "Please select from the below options to receive OTP" "dontHaveAccount": "Don't have an account?", - "loginOrRegister": "Login or Register" + "loginOrRegister": "Login or Register", + "prepareToElevate": "Prepared to elevate your health and well-being?" } \ No newline at end of file diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index b9d4ba8..ec9ff99 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -1,3 +1,4 @@ +import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/cupertino.dart'; @@ -219,6 +220,13 @@ extension EmailValidator on String { style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), ); + Widget toText28({Color? color, bool isBold = false, bool isCenter = false, TextScaler? textScaler}) => Text( + this, + textAlign: isCenter ? TextAlign.center : null, + textScaler: textScaler, + style: TextStyle(height: 40 / 28, color: color ?? AppColors.blackColor, fontSize: 28.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal), + ); + Widget toText32({Color? color, bool isBold = false, bool isCenter = false}) => Text( this, textAlign: isCenter ? TextAlign.center : null, @@ -365,3 +373,56 @@ class FontUtils { return isArabic ? 'Cairo' : 'Poppins'; } } + + +extension CountryExtension on Country { + String get displayName { + switch (this) { + case Country.saudiArabia: + return "Kingdom Of Saudi Arabia"; + case Country.unitedArabEmirates: + return "United Arab Emirates"; + } + } + + String get nameArabic { + switch (this) { + case Country.saudiArabia: + return "المملكة العربية السعودية"; + case Country.unitedArabEmirates: + return "الإمارات العربية المتحدة"; + } + } + + String get iconPath { + switch (this) { + case Country.saudiArabia: + return "assets/images/svg/ksa.svg"; + case Country.unitedArabEmirates: + return "assets/images/svg/uae.svg"; + } + } + + String get countryCode { + switch (this) { + case Country.saudiArabia: + return "966"; + case Country.unitedArabEmirates: + return "971"; + } + } + + static Country fromDisplayName(String name) { + switch (name) { + case "Kingdom Of Saudi Arabia": + case "المملكة العربية السعودية": + return Country.saudiArabia; + case "United Arab Emirates": + case "الإمارات العربية المتحدة": + return Country.unitedArabEmirates; + default: + throw Exception("Invalid country name"); + } + } +} + diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index e818aa4..819fb22 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -774,12 +774,13 @@ abstract class LocaleKeys { static const validPassportNumber = 'validPassportNumber'; static const continuePlan = 'continuePlan'; static const aboutApp = 'aboutApp'; + static const loginOrRegister = 'loginOrRegister'; static const dontHaveAccount = 'dontHaveAccount'; static const receiveOtpToast = 'receiveOtpToast'; static const enterPhoneNumber = 'enterPhoneNumber'; static const enterEmailDesc = 'enterEmailDesc'; static const enterPhoneDesc = 'enterPhoneDesc'; static const pleaseChooseOption = 'pleaseChooseOption'; - static const loginOrRegister = 'loginOrRegister'; + static const prepareToElevate = 'prepareToElevate'; } diff --git a/lib/presentation/authantication/login.dart b/lib/presentation/authantication/login.dart index 3e9273b..3ac0d63 100644 --- a/lib/presentation/authantication/login.dart +++ b/lib/presentation/authantication/login.dart @@ -3,16 +3,16 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; -import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart' hide Sizer; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; -import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:sizer/sizer.dart'; class LoginScreen extends StatefulWidget { @override @@ -41,8 +41,7 @@ class _LoginScreen extends State { // Navigator.of(context).pop(); }, onLanguageChanged: (String value) { - print(value); - context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); + // context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); }, ), body: GestureDetector( @@ -51,13 +50,13 @@ class _LoginScreen extends State { }, child: SingleChildScrollView( child: Padding( - padding: EdgeInsets.only(left: 6.w, right: 6.w), + padding: EdgeInsets.only(left: 6.sp, right: 6.sp), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 45.w, height: 22.h, repeat: true, fit: BoxFit.cover), - SizedBox(height: 19.h), // Adjusted to sizer unit + Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 45.w, height: 22.sp, repeat: true, fit: BoxFit.cover), + SizedBox(height: 19.sp), // Adjusted to sizer unit LocaleKeys.welcomeToDrSulaiman.tr().toText22(isBold: true, color: AppColors.textColor), // Text( // LocaleKeys.welcomeToDrSulaiman.tr(), @@ -69,7 +68,7 @@ class _LoginScreen extends State { // height: 40 / 28, // ), // ), - SizedBox(height: 4.h), // Adjusted to sizer unit (approx 32px) + SizedBox(height: 4.sp), // Adjusted to sizer unit (approx 32px) TextInputWidget( labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}", hintText: "xxxxxxxxx", @@ -80,19 +79,19 @@ class _LoginScreen extends State { autoFocus: true, isBorderAllowed: false, isAllowLeadingIcon: true, - padding: EdgeInsets.symmetric(vertical: 1.h, horizontal: 2.w), + padding: EdgeInsets.symmetric(vertical: 1.sp, horizontal: 2.w), leadingIcon: AppAssets.student_card, errorMessage: "Please enter a valid national ID or file number", hasError: true, ), - SizedBox(height: 2.h), // Adjusted to sizer unit (approx 16px) + SizedBox(height: 2.sp), // Adjusted to sizer unit (approx 16px) CustomButton( text: LocaleKeys.login.tr(), icon: AppAssets.login1, iconColor: Colors.white, onPressed: () {}, ), - SizedBox(height: 1.8.h), // Adjusted to sizer unit (approx 14px) + SizedBox(height: 2.sp), // Adjusted to sizer unit (approx 14px) Center( child: RichText( textAlign: TextAlign.center, @@ -118,7 +117,7 @@ class _LoginScreen extends State { ), ], ), - ).withVerticalPadding(2.h), // Adjusted to sizer unit + ).withVerticalPadding(2.sp), // Adjusted to sizer unit ), ], ), diff --git a/lib/presentation/authantication/register.dart b/lib/presentation/authantication/register.dart index bd4cb78..9b900b5 100644 --- a/lib/presentation/authantication/register.dart +++ b/lib/presentation/authantication/register.dart @@ -1,385 +1,579 @@ -import 'dart:convert'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; -import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; -import 'package:hmg_patient_app_new/widgets/input_widget.dart'; -import 'package:provider/provider.dart'; - -class Register extends StatefulWidget { - final Function? changePageViewIndex; - - const Register({Key? key, this.changePageViewIndex}) : super(key: key); - - @override - _Register createState() => _Register(); -} - -class _Register extends State { - @override - void initState() { - getPatientOccupationList(); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar( - onBackPressed: () {}, - onLanguageChanged: (String value) {}, - ), - body: Column( - children: [ - Expanded( - child: ListView( - padding: EdgeInsets.all(21), - physics: BouncingScrollPhysics(), - children: [ - SizedBox(height: 10), - Padding( - padding: EdgeInsets.all(10), - child: Text( - LocaleKeys.enterNationalId.tr(), - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.64, height: 23 / 16), - )), - SizedBox(height: 10), - PhoneNumberSelectorWidget(onNumberChange: (value) => {}, onCountryChange: (value) => ), - SizedBox(height: 12), - TextInputWidget(labelText: LocaleKeys.nationalIdNumber.tr(), hintText: "Xxxxxxxxx", controller: TextEditingController()), - SizedBox(height: 20), - Row( - children: [ - Expanded( - child: Row( - children: [ - Radio( - value: 1, - groupValue: isHijri, - onChanged: (value) { - }, - ), - Text(LocaleKeys.hijriDate.tr()), - ], - ), - ), - Expanded( - child: Row( - children: [ - Radio( - value: 0, - groupValue: isHijri, - onChanged: (value) { - }, - ), - Text(LocaleKeys.gregorianDate.tr()), - ], - ), - ), - ], - ), - Row(children: [ - Container( - width: SizeConfig.realScreenWidth! * .89, - child: isHijri == 1 - ? Directionality( - textDirection: TextDirection.ltr, - child: inputWidget(TranslationBase.of(context).dob, "DD/MM/YYYYY", dob, - isNumber: false, - suffix: Icon( - Icons.calendar_today, - size: 16, - ))) - : Container( - child: InkWell( - onTap: () { - if (isHijri != null) _selectDate(context); - }, - child: Directionality( - textDirection: TextDirection.ltr, - child: inputWidget(TranslationBase.of(context).dob, "DD/MM/YYYYY", dobEn, - isNumber: false, - isEnable: false, - suffix: Icon( - Icons.calendar_today, - size: 16, - )))))), - ]) - ], - ), - ), - Container( - width: double.maxFinite, - // height: 80.0, - color: Colors.white, - // margin: EdgeInsets.only(bottom: 50.0), - child: Row( - children: [ - Expanded( - child: Padding( - padding: EdgeInsets.all(10), - child: DefaultButton(TranslationBase.of(context).cancel, () { - Navigator.of(context).pop(); - locator().loginRegistration.registration_cancel(step: 'enter details'); - }, textColor: Colors.white, color: Color(0xffD02127))), - ), - Expanded( - child: Padding( - padding: EdgeInsets.all(10), - child: DefaultButton(TranslationBase.of(context).next, () { - startRegistration(); - locator().loginRegistration.registration_enter_details(); - }, textColor: Colors.white, color: isButtonDisabled == true ? Colors.grey : Color(0xff359846))), - ), - ], - ), - ) - ], - ), - ); - } - - Future _selectDate(BuildContext context) async { - DatePicker.showDatePicker( - context, - showTitleActions: true, - minTime: DateTime(DateTime.now().year - 100, 1, 1), - maxTime: DateTime.now(), - onConfirm: (date) { - selectedDate = date; - setState(() { - final intl.DateFormat dateFormat = intl.DateFormat('dd/MM/yyyy'); - dobEn.text = dateFormat.format(date); - }); - }, - currentTime: DateTime.now(), - ); - } - - Widget inputWidget(String _labelText, String _hintText, TextEditingController _controller, {String? prefix, bool isEnable = true, bool hasSelection = false, bool isNumber = true, Icon? suffix}) { - return Container( - padding: EdgeInsets.only(left: 16, right: 16, bottom: 15, top: 15), - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - color: Colors.white, - border: Border.all( - color: Color(0xffefefef), - width: 1, - ), - ), - child: InkWell( - onTap: hasSelection ? () {} : null, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _labelText, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Color(0xff2B353E), - letterSpacing: -0.44, - ), - ), - TextField( - enabled: isEnable, - scrollPadding: EdgeInsets.zero, - keyboardType: isNumber ? TextInputType.numberWithOptions(signed: true) : TextInputType.datetime, - controller: _controller, - onChanged: (value) => {validateForm()}, - style: TextStyle( - fontSize: 14, - height: 21 / 14, - fontWeight: FontWeight.w400, - color: Color(0xff2B353E), - letterSpacing: -0.44, - ), - decoration: InputDecoration( - isDense: true, - hintText: _hintText, - hintStyle: TextStyle( - fontSize: 14, - height: 21 / 14, - fontWeight: FontWeight.w400, - color: Color(0xff575757), - letterSpacing: -0.56, - ), - prefixIconConstraints: BoxConstraints(minWidth: 50), - prefixIcon: prefix == null - ? null - : Text( - "+" + prefix, - style: TextStyle( - fontSize: 14, - height: 21 / 14, - fontWeight: FontWeight.w500, - color: Color(0xff2E303A), - letterSpacing: -0.56, - ), - ), - contentPadding: EdgeInsets.zero, - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - ), - ), - ], - ), - ), - if (hasSelection) Icon(Icons.keyboard_arrow_down_outlined), - if (suffix != null) suffix - ], - ), - ), - ); - } - - startRegistration() { - final intl.DateFormat dateFormat = intl.DateFormat('dd/MM/yyyy'); - if (isButtonDisabled == false) { - var request = CheckPatientForRegistration(); - request.patientMobileNumber = int.parse(mobileNo); - request.zipCode = countryCode; - request.patientOutSA = countryCode == '966' ? 0 : 1; - - request.patientIdentificationID = int.parse(nationalIDorFile.text); - request.patientID = 0; - request.isRegister = true; - request.dob = isHijri == 1 ? dob.text : dateFormat.format(selectedDate); - request.isHijri = isHijri; - this.checkPatientForRegisteration(request); - } - } - - checkPatientForRegisteration(request) { - int languageID = Provider.of(context, listen: false).isArabic ? 1 : 2; - GifLoaderDialogUtils.showMyDialog(context); - this.authService.checkPatientForRegisteration(request, languageID).then((response) => {checkUserStatus(response, request)}).catchError((err) { - GifLoaderDialogUtils.hideDialog(context); - ConfirmDialog dialog = new ConfirmDialog( - context: context, - confirmMessage: err, - okText: TranslationBase.of(context).confirm, - cancelText: TranslationBase.of(context).cancel_nocaps, - okFunction: () => { - ConfirmDialog.closeAlertDialog(context), - Navigator.of(context).push(FadePage(page: Register())), - }, - cancelFunction: () => {ConfirmDialog.closeAlertDialog(context)}); - dialog.showAlertDialog(context); - }); - } - - void validateForm() { - if (util.validateIDBox(nationalIDorFile.text, loginType) == true && - mobileNo.length >= 9 && - util.isSAUDIIDValid(nationalIDorFile.text, loginType) == true && - isHijri != null && - (dobEn.text != null || dob.text != null)) { - setState(() { - isButtonDisabled = false; - }); - } else { - setState(() { - isButtonDisabled = true; - }); - } - } - - checkUserStatus(response, CheckPatientForRegistration request) async { - GifLoaderDialogUtils.hideDialog(context); - if (response is Map) { - var nRequest = request.toJson(); - nRequest['LogInTokenID'] = response['LogInTokenID']; - if (response['hasFile'] == true) { - ConfirmDialog dialog = new ConfirmDialog( - context: context, - confirmMessage: response['ErrorEndUserMessage'], - okText: TranslationBase.of(context).ok, - cancelText: TranslationBase.of(context).cancel, - okFunction: () { - AlertDialogBox.closeAlertDialog(context); - sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, nRequest); - LoginRegistration.loginMethod = 1; // 1=NationalID, by default from Registration - Navigator.of(context).push(FadePage(page: Login())); - }, - cancelFunction: () {}) - .showAlertDialog(context); - } else { - final intl.DateFormat dateFormat = intl.DateFormat('dd/MM/yyyy'); - nRequest['forRegister'] = true; - nRequest['isRegister'] = true; - nRequest["PatientIdentificationID"] = nRequest["PatientIdentificationID"].toString(); - nRequest['dob'] = isHijri == 1 ? dob.text : dateFormat.format(selectedDate); - nRequest['isHijri'] = isHijri; - sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, nRequest); - sharedPref.setString(LOGIN_TOKEN_ID, response['LogInTokenID']); - if (request.patientOutSA == 0) { - this.chekUserData(response['LogInTokenID']); - } else { - Navigator.of(context).push(FadePage(page: ConfirmLogin(changePageViewIndex: widget.changePageViewIndex, fromRegistration: true, isDubai: true))); - } - } - } else { - // if (response['ErrorCode'] == '-986') { - //AppToast.showErrorToast(message: response); - AlertDialogBox( - context: context, - confirmMessage: response, - okText: TranslationBase.of(context).ok, - okFunction: () { - AlertDialogBox.closeAlertDialog(context); - Navigator.of(context).pop(); - }).showAlertDialog(context); - //} - } - } - - chekUserData(loginToken) { - // let m = hijri(this.dateOfBirth).locale('en'); - // // const dateHijri = m.format('iDD/iMM/iYYYY'); - // const request = { - // PatientIdentificationID: this.id.toString(), - // // TokenID: token, - // DOB: this.dateOption === '1' ? this.dateOfBirth : moment(this.dateOfBirth).format('DD/MM/YYYY'), - // IsHijri: Number(this.dateOption) - // } - - final intl.DateFormat dateFormat = intl.DateFormat('dd/MM/yyyy'); - GifLoaderDialogUtils.showMyDialog(context); - var request = CheckUserStatusRequest(); - request.patientIdentificationID = nationalIDorFile.text; - request.dOB = isHijri == 1 ? dob.text : dateFormat.format(selectedDate); - request.isHijri = isHijri; - request.patientOutSA = countryCode == '966' ? 0 : 1; - this.authService.checkUserStatus(request).then((result) => { - GifLoaderDialogUtils.hideDialog(context), - if (result is Map) - { - result = CheckUserStatusResponse.fromJson(result as Map), - sharedPref.setObject(NHIC_DATA, result), - // widget.changePageViewIndex!(1), - Navigator.of(context).push(FadePage(page: ConfirmLogin(changePageViewIndex: widget.changePageViewIndex, fromRegistration: true))), - } - else - { - AppToast.showErrorToast(message: result != null ? result : TranslationBase.of(context).somethingWentWrong), - } - }); - } - - getPatientOccupationList() async { - patientOccupationList.clear(); - await authService.getPatientOccupationList().then((result) { - sharedPref.setString(PATIENT_OCCUPATION_LIST, json.encode(result['GetOccupationLst'])); - }).catchError((err) { - AppToast.showErrorToast(message: err); - }); - } -} +// import'dart:convert'; +// +// import 'package:easy_localization/easy_localization.dart'; +// import 'package:flutter/gestures.dart'; +// import 'package:flutter_svg/flutter_svg.dart'; +// import 'package:hijri_gregorian_calendar/hijri_gregorian_calendar.dart'; +// import 'package:hmg_patient_app/config/config.dart'; +// import 'package:hmg_patient_app/config/shared_pref_kay.dart'; +// import 'package:hmg_patient_app/config/size_config.dart'; +// import 'package:hmg_patient_app/core/service/client/base_app_client.dart'; +// import 'package:hmg_patient_app/core/viewModels/project_view_model.dart'; +// import 'package:hmg_patient_app/models/Appointments/toDoCountProviderModel.dart'; +// import 'package:hmg_patient_app/models/Authentication/check_activation_code_response.dart'; +// import 'package:hmg_patient_app/models/Authentication/check_paitent_authentication_req.dart'; +// import 'package:hmg_patient_app/models/Authentication/check_user_status_reponse.dart'; +// import 'package:hmg_patient_app/models/Authentication/check_user_status_req.dart'; +// import 'package:hmg_patient_app/models/Authentication/checkpatient_for_registration.dart'; +// import 'package:hmg_patient_app/models/Authentication/register_info_response.dart'; +// import 'package:hmg_patient_app/models/Authentication/send_activation_request.dart'; +// import 'package:hmg_patient_app/new_ui/new_ext.dart'; +// import 'package:hmg_patient_app/new_ui/otp/otp_validation_bootmsheet_widget.dart'; +// import 'package:hmg_patient_app/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart'; +// import 'package:hmg_patient_app/pages/login/login-type.dart'; +// import 'package:hmg_patient_app/pages/login/register-info.dart'; +// import 'package:hmg_patient_app/pages/login/register.dart'; +// import 'package:hmg_patient_app/pages/login/register_new_step_2.dart'; +// import 'package:hmg_patient_app/pages/login/user-login-agreement-page.dart'; +// import 'package:hmg_patient_app/pages/login/welcome.dart'; +// import 'package:hmg_patient_app/services/authentication/auth_provider.dart'; +// import 'package:hmg_patient_app/theme/colors.dart'; +// import 'package:hmg_patient_app/uitl/app_shared_preferences.dart'; +// import 'package:hmg_patient_app/uitl/app_toast.dart'; +// import 'package:hmg_patient_app/uitl/font_utils.dart'; +// import 'package:hmg_patient_app/uitl/gif_loader_dialog_utils.dart'; +// import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; +// import 'package:hmg_patient_app/uitl/utils.dart'; +// import 'package:hmg_patient_app/uitl/utils_new.dart'; +// import 'package:hmg_patient_app/widgets/drawer/langauge_picker.dart'; +// import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart'; +// import 'package:flutter/material.dart'; +// import 'package:hmg_patient_app/widgets/otp/sms-popup.dart'; +// import 'package:hmg_patient_app/widgets/text/app_texts_widget.dart'; +// import 'package:hmg_patient_app_new/core/app_state.dart'; +// import 'package:hmg_patient_app_new/core/enums.dart'; +// import 'package:hmg_patient_app_new/core/utils/utils.dart'; +// import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +// import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +// import 'package:hmg_patient_app_new/widgets/dropdown_widget.dart'; +// import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +// import 'package:provider/provider.dart'; +// +// import '../../core/viewModels/appointment_rate_view_model.dart'; +// import '../../locator.dart'; +// import '../../models/Authentication/authenticated_user.dart'; +// import '../../models/Authentication/select_device_imei_res.dart'; +// import '../../models/InPatientServices/get_admission_info_response_model.dart'; +// import '../../models/InPatientServices/get_admission_request_info_response_model.dart'; +// import '../../new_ui/exception_widget/ExceptionBottomSheet.dart'; +// import '../../services/clinic_services/get_clinic_service.dart'; +// import '../../widgets/dialogs/alert_dialog.dart'; +// import '../../widgets/dialogs/confirm_dialog.dart'; +// import '../../widgets/transitions/fade_page.dart'; +// import 'package:intl/intl.dart' as intl; +// +// import '../landing/landing_page.dart'; +// import '../rateAppointment/rate_appointment_doctor.dart'; +// +// class RegisterNew extends StatefulWidget { +// @override +// _RegisterNew createState() => _RegisterNew(); +// } +// +// class _RegisterNew extends State { +// @override +// void initState() { +// super.initState(); +// } +// +// @override +// void dispose() { +// super.dispose(); +// } +// +// @override +// Widget build(BuildContext context) { +// +// AppState appState = getIt.get(); +// return Scaffold( +// body: GestureDetector( +// onTap: () { +// FocusScope.of(context).unfocus(); +// }, +// child: ScrollConfiguration( +// behavior: ScrollConfiguration.of(context).copyWith(overscroll: false, physics: const ClampingScrollPhysics()), +// child: NotificationListener( +// onNotification: (notification) { +// notification.disallowIndicator(); +// return true; +// }, +// child: SingleChildScrollView( +// physics: ClampingScrollPhysics(), +// padding: EdgeInsets.only( +// left: 24, +// right: 24, +// ), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Utils.showLottie( +// context: context, +// assetPath: 'assets/animations/lottie/register.json', +// width: MediaQuery +// .of(context) +// .size +// .width * 0.45, +// height: MediaQuery +// .of(context) +// .size +// .height * 0.22, +// fit: BoxFit.cover, +// repeat: true), +// SizedBox(height: 8), +// LocaleKeys.prepareToElevate.tr().toText28( +// textScaler: TextScaler.linear(MediaQuery.textScalerOf(context).scale(1)), +// ), +// SizedBox(height: 24), +// Directionality( +// textDirection: Directionality.of(context), +// child: Container( +// decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), +// padding: EdgeInsets.only(left: 16, right: 16, top: 0, bottom: 0), +// child: Column( +// children: [ +// DropdownWidget( +// labelText: LocaleKeys.country.tr(), +// hintText: LocaleKeys.ksa.tr(), +// isEnable: true, +// selectedValue: AppStat.selectedLanguage == "ar" ? selectedCountry.nameArabic : selectedCountry.displayName, +// dropdownItems: Country.values.map((e) => "ar" ? e.displayName : e.displayName).toList(), +// +// // dropdownItems: Country.values.map((e) => (e.name).first).toList(), +// // dropdownItems: Country.values.map((e) => "ar" ? e.nameArabic : e.displayName).toList(), +// // selectedValue: context.selectedLanguage == "ar" ? selectedCountry.nameArabic : selectedCountry.displayName, +// // selectionType: SelectionType.dropdown, +// onChange: (val) { +// if (val != null) { +// } +// }, +// isBorderAllowed: false, +// isAllowLeadingIcon: true, +// hasSelectionCustomIcon: true, +// removePadding: true, +// isLeadingCountry: true, +// isAllowRadius: false, +// padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), +// selectionCustomIcon: "assets/images/svg/arrow-down.svg", +// leadingIcon: selectedCountry.iconPath, +// ).withVerticalPadding(8), +// Divider(height: 1), +// Directionality( +// textDirection: TextDirection.ltr, +// child: newInputWidget(TranslationBase +// .of(context) +// .nationalIdNumber, "xxxxxxxxx", nationalIDorFile, +// isEnable: true, +// prefix: null, +// removePadding: true, +// isAllowRadius: false, +// hasSelection: false, +// isBorderAllowed: false, +// isAllowLeadingIcon: true, +// autoFocus: true, +// padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), +// leadingIcon: "assets/images/svg/student-card.svg", +// onChange: (value) { +// print(value); +// }).withVerticalPadding(8), +// ), +// Divider(height: 1), +// Directionality( +// textDirection: TextDirection.ltr, +// child: newInputWidget(TranslationBase +// .of(context) +// .dob, "11 July, 1994", nationalIDorFile, +// isEnable: true, +// prefix: null, +// hasSelection: true, +// removePadding: true, +// isBorderAllowed: false, +// isAllowLeadingIcon: true, +// hasSelectionCustomIcon: true, +// selectionType: SelectionType.calendar, +// selectedValue: selectedDOB != null +// ? isHijri == 1 +// ? Utils.formatHijriDateToDisplay(selectedDOB!.toIso8601String()) +// : Utils.formatDateToDisplay(selectedDOB.toString()) +// : null, +// selectionCustomIcon: "assets/images/svg/calendar.svg", +// lang: context.selectedLanguage, +// padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), +// leadingIcon: "assets/images/svg/birthday-cake.svg", +// onChange: (value) { +// selectedDOB = DateTime.parse(value!); +// if (isHijri == 1) { +// var hijriDate = HijriGregConverter.gregorianToHijri(DateTime.parse(value)); +// selectedDOB = DateTime(hijriDate.year, hijriDate.month, hijriDate.day); +// } else { +// selectedDOB = DateTime.parse(value); +// } +// print(selectedDOB!.toIso8601String()); +// setState(() {}); +// }, +// onCalendarTypeChanged: (bool value) { +// if (value) { +// isHijri = 0; +// } else { +// isHijri = 1; +// } +// }).withVerticalPadding(8), +// ), +// ], +// ), +// ), +// ), +// SizedBox(height: 25), +// GestureDetector( +// onTap: () { +// setState(() { +// isTermsAccepted = !isTermsAccepted; +// }); +// }, +// child: Row( +// children: [ +// AnimatedContainer( +// duration: const Duration(milliseconds: 200), +// height: 24, +// width: 24, +// decoration: BoxDecoration( +// color: isTermsAccepted ? const Color(0xFFE92227) : Colors.transparent, +// borderRadius: BorderRadius.circular(6), +// border: Border.all( +// color: isTermsAccepted ? const Color(0xFFE92227) : Colors.grey, +// width: 2, +// ), +// ), +// child: isTermsAccepted ? const Icon(Icons.check, size: 16, color: Colors.white) : null, +// ), +// SizedBox(width: 12), +// Expanded( +// child: Text( +// TranslationBase +// .of(context) +// .iAcceptTermsConditions, +// style: context.dynamicTextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), +// ), +// ), +// ], +// ), +// ), +// SizedBox(height: 25), +// CustomButton( +// text: TranslationBase +// .of(context) +// .register, +// icon: "assets/images/svg/note-edit.svg", +// onPressed: () { +// // bool isValid = Utils.validateIqama(nationalIDorFile.text); +// if (nationalIDorFile == null || nationalIDorFile.text.isEmpty) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .pleaseEnterNationalId, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// // Utils.showErrorToast(TranslationBase.of(context).pleaseEnterNationalId); +// return; +// } +// if ((!Utils.validateIqama(nationalIDorFile.text) && selectedCountry.countryCode == '966') || +// (!Utils.validateUaeNationalId(nationalIDorFile.text) && selectedCountry.countryCode == '971')) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .incorrectNationalId, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// return; +// } +// if (selectedCountry == null || selectedCountry.countryCode.isEmpty) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .pleaseSelectCountry, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// return; +// } +// +// if (selectedDOB == null) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .pleaseSelectDOB, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// return; +// } +// if (!isTermsAccepted) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .pleaseAcceptTermsConditions, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// return; +// } +// +// if (phoneController != null) { +// phoneController.clear(); +// } +// showModalBottomSheet( +// context: context, +// isScrollControlled: true, +// isDismissible: false, +// backgroundColor: Colors.transparent, +// builder: (bottomSheetContext) => +// Padding( +// padding: EdgeInsets.only(bottom: MediaQuery +// .of(bottomSheetContext) +// .viewInsets +// .bottom), +// child: SingleChildScrollView( +// child: GenericBottomSheet( +// countryCode: selectedCountry.countryCode, +// initialPhoneNumber: "", +// textController: phoneController, +// onChange: (String? value) { +// mobileNo = value!; +// }, +// buttons: [ +// Padding( +// padding: const EdgeInsets.only(bottom: 10), +// child: CustomButton( +// text: TranslationBase +// .of(context) +// .sendOTPSMS, +// onPressed: () { +// if (mobileNo.isEmpty) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .pleaseEnterMobile, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// } else if (!Utils.validateMobileNumber(mobileNo)) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .pleaseEnterValidMobile, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// } else { +// registerUser(1); +// } +// }, +// backgroundColor: CustomColors.bgRedColor, +// borderColor: CustomColors.bgRedBorderColor, +// textColor: Colors.white, +// icon: "assets/images/svg/message.svg", +// ), +// ), +// Row( +// crossAxisAlignment: CrossAxisAlignment.center, +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Padding( +// padding: const EdgeInsets.symmetric(horizontal: 8), +// child: AppText( +// TranslationBase +// .of(context) +// .oR, +// fontSize: 16, +// fontFamily: context.fontFamily, +// color: Color(0xFF2E3039), +// fontWeight: FontWeight.w500, +// ), +// ), +// ], +// ), +// Padding( +// padding: const EdgeInsets.only(bottom: 10, top: 10), +// child: CustomButton( +// text: TranslationBase +// .of(context) +// .sendOTPWHATSAPP, +// onPressed: () { +// if (mobileNo.isEmpty) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .pleaseEnterMobile, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// } else if (!Utils.validateMobileNumber(mobileNo)) { +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: TranslationBase +// .of(context) +// .pleaseEnterValidMobile, +// showCancel: false, +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// ), +// ); +// } else { +// registerUser(4); +// } +// // int? val = Utils.onOtpBtnPressed(OTPType.whatsapp, mobileNo, context); +// // registerUser(val); +// }, +// backgroundColor: Colors.white, +// borderColor: Color(0xFF2E3039), +// textColor: Color(0xFF2E3039), +// icon: "assets/images/svg/whatsapp.svg", +// ), +// ), +// ], +// myFocusNode: myFocusNode, +// ), +// ), +// ), +// ); +// Future.delayed(Duration(milliseconds: 500), () { +// myFocusNode.requestFocus(); +// }); +// }, +// fontFamily: context.fontFamily, +// ), +// SizedBox(height: 14), +// Center( +// child: RichText( +// textAlign: TextAlign.center, +// text: TextSpan( +// style: context.dynamicTextStyle( +// color: Colors.black, +// fontSize: 16, +// height: 26 / 16, +// fontWeight: FontWeight.w500, +// ), +// children: [ +// TextSpan(text: TranslationBase +// .of(context) +// .alreadyHaveAccount, style: context.dynamicTextStyle()), +// TextSpan(text: " "), +// TextSpan( +// text: TranslationBase +// .of(context) +// .loginNow, +// style: context.dynamicTextStyle( +// color: CustomColors.bgRedColor, +// fontSize: 16, +// height: 26 / 16, +// fontWeight: FontWeight.w500, +// ), +// recognizer: TapGestureRecognizer() +// ..onTap = () { +// Navigator.of(context).pop(); +// }, +// ), +// ], +// ), +// ), +// ), +// SizedBox(height: 30), +// ], +// ), +// ), +// ), +// ),) +// ); +// } +// +// Widget showProgress({String? title, String? status, Color? color, bool isNeedBorder = true}) { +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Row( +// children: [ +// Container( +// width: 26, +// height: 26, +// decoration: containerRadius(color!, 200), +// child: Icon( +// Icons.done, +// color: Colors.white, +// size: 16, +// ), +// ), +// if (isNeedBorder) +// Expanded( +// child: Padding( +// padding: const EdgeInsets.all(8.0), +// child: mDivider(Colors.grey), +// )), +// ], +// ), +// mHeight(8), +// Text( +// title!, +// style: TextStyle( +// fontSize: 11, +// fontWeight: FontWeight.w600, +// letterSpacing: -0.44, +// ), +// ), +// mHeight(2), +// Container( +// padding: EdgeInsets.all(5), +// decoration: containerRadius(color.withOpacity(0.2), 4), +// child: Text( +// status!, +// style: TextStyle( +// fontSize: 8, +// fontWeight: FontWeight.w600, +// letterSpacing: -0.32, +// color: color, +// ), +// ), +// ), +// ], +// ) +// ], +// ); +// } +// } diff --git a/lib/providers/authentication_view_model.dart b/lib/providers/authentication_view_model.dart index af542ac..ecc3e04 100644 --- a/lib/providers/authentication_view_model.dart +++ b/lib/providers/authentication_view_model.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; class AuthenticationViewModel extends ChangeNotifier { - // Add properties and methods related to authentication here -} \ No newline at end of file +// Add properties and methods related to authentication here +} From 8f1e4500cc212b626509482cae4d65d1eda1c559 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 2 Sep 2025 12:17:34 +0300 Subject: [PATCH 4/6] register & Exception bottom sheet, country dropdown. --- assets/langs/ar-SA.json | 6 +- assets/langs/en-US.json | 8 +- lib/extensions/string_extensions.dart | 13 +- lib/generated/locale_keys.g.dart | 4 + lib/main.dart | 3 - lib/presentation/authentication/login.dart | 177 ++-- lib/presentation/authentication/register.dart | 790 +++++------------- lib/presentation/home/landing_page.dart | 5 +- lib/providers/authentication_view_model.dart | 6 - lib/theme/colors.dart | 1 + lib/widgets/appbar/app_bar_widget.dart | 65 +- .../bottomsheet/exception_bottom_sheet.dart | 111 +++ .../dropdown/country_dropdown_widget.dart | 165 ++++ .../{ => dropdown}/dropdown_widget.dart | 88 +- lib/widgets/input_widget.dart | 47 +- lib/widgets/language_switcher.dart | 7 +- pubspec.lock | 30 +- 17 files changed, 721 insertions(+), 805 deletions(-) delete mode 100644 lib/providers/authentication_view_model.dart create mode 100644 lib/widgets/bottomsheet/exception_bottom_sheet.dart create mode 100644 lib/widgets/dropdown/country_dropdown_widget.dart rename lib/widgets/{ => dropdown}/dropdown_widget.dart (56%) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index ebcee14..57f9bcd 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -783,7 +783,11 @@ "enterEmailDesc": "أدخل عنوان بريدك الإلكتروني لإكمال عملية إنشاء ملف طبي", "enterPhoneDesc": "أدخل رقم هاتفك لتلقي رمز التحقق ", "pleaseChooseOption": "الرجاء اختيار من الخيارات أدناه لتلقي رمز التحقق OTP", - "prepareToElevate": "هل أنت مستعد لتحسين صحتك ورفاهتك؟" + "prepareToElevate": "هل أنت مستعد لتحسين صحتك ورفاهتك؟", + "iAcceptTermsConditions": "أوافق على الشروط والأحكام", + "alreadyHaveAccount": "هل لديك حساب بالفعل؟", + "loginNow": "تسجيل الدخول الآن", + "notice": "إشعار" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b45c697..311db65 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -776,8 +776,12 @@ "enterPhoneNumber": "Enter Phone Number", "enterEmailDesc": "Enter your email address to complete the process of creating a medical file", "enterPhoneDesc": "Enter your phone number to receive OTP verification code", - "pleaseChooseOption": "Please select from the below options to receive OTP" + "pleaseChooseOption": "Please select from the below options to receive OTP", "dontHaveAccount": "Don't have an account?", "loginOrRegister": "Login or Register", - "prepareToElevate": "Prepared to elevate your health and well-being?" + "prepareToElevate": "Prepared to elevate your health and well-being?", + "iAcceptTermsConditions": "I Accept the Terms and Conditions", + "alreadyHaveAccount": "Already have an account?", + "loginNow": "Login Now", + "notice": "Notice" } \ No newline at end of file diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index ec9ff99..187939e 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -1,3 +1,4 @@ +import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:auto_size_text/auto_size_text.dart'; @@ -233,6 +234,12 @@ extension EmailValidator on String { style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), ); + Widget toText36({Color? color, bool isBold = false, bool isCenter = false}) => Text( + this, + textAlign: isCenter ? TextAlign.center : null, + style: TextStyle(height: 47 / 36, color: color ?? AppColors.blackColor, fontSize: 36.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal), + ); + Widget toText44({Color? color, bool isBold = false}) => Text( this, style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.fSize, letterSpacing: -0.4, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), @@ -374,7 +381,6 @@ class FontUtils { } } - extension CountryExtension on Country { String get displayName { switch (this) { @@ -397,9 +403,9 @@ extension CountryExtension on Country { String get iconPath { switch (this) { case Country.saudiArabia: - return "assets/images/svg/ksa.svg"; + return AppAssets.ksa; case Country.unitedArabEmirates: - return "assets/images/svg/uae.svg"; + return AppAssets.uae; } } @@ -425,4 +431,3 @@ extension CountryExtension on Country { } } } - diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 819fb22..f219526 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -782,5 +782,9 @@ abstract class LocaleKeys { static const enterPhoneDesc = 'enterPhoneDesc'; static const pleaseChooseOption = 'pleaseChooseOption'; static const prepareToElevate = 'prepareToElevate'; + static const iAcceptTermsConditions = 'iAcceptTermsConditions'; + static const alreadyHaveAccount = 'alreadyHaveAccount'; + static const loginNow = 'loginNow'; + static const notice = 'notice'; } diff --git a/lib/main.dart b/lib/main.dart index 31c5c56..a9afd60 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,9 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; -import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/utils/size_config.dart'; -import 'package:hmg_patient_app_new/providers/authentication_view_model.dart'; import 'package:hmg_patient_app_new/providers/bottom_navigation_provider.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; @@ -22,7 +20,6 @@ import 'firebase_options.dart'; var globalMessengerKey = GlobalKey(); final navigatorKey = GlobalKey(); - @pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index da85baa..87f40ca 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -1,18 +1,17 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/gestures.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; -import 'package:hmg_patient_app_new/core/utils/size_utils.dart' hide Sizer; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/authentication/register.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; -import 'package:sizer/sizer.dart'; class LoginScreen extends StatefulWidget { @override @@ -32,98 +31,92 @@ class _LoginScreen extends State { @override Widget build(BuildContext context) { - return Sizer(// Wrap with Sizer - builder: (context, orientation, deviceType) { - return Scaffold( - backgroundColor: AppColors.bgScaffoldColor, - appBar: CustomAppBar( - onBackPressed: () { - }, - onLanguageChanged: (String value) { - // context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); - }, - ), - body: GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside - }, - child: SingleChildScrollView( - child: Padding( - padding: EdgeInsets.only(left: 6.sp, right: 6.sp), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 45.w, height: 22.sp, repeat: true, fit: BoxFit.cover), - SizedBox(height: 19.sp), // Adjusted to sizer unit - LocaleKeys.welcomeToDrSulaiman.tr().toText22(isBold: true, color: AppColors.textColor), - // Text( - // LocaleKeys.welcomeToDrSulaiman.tr(), - // style: context.dynamicTextStyle( - // fontSize: 22, - // fontWeight: FontWeight.w600, - // color: AppColors.textColor, - // letterSpacing: -0.4, - // height: 40 / 28, - // ), - // ), - SizedBox(height: 4.sp), // Adjusted to sizer unit (approx 32px) - TextInputWidget( - labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}", - hintText: "xxxxxxxxx", - controller: TextEditingController(), - keyboardType: TextInputType.number, - isEnable: true, - prefix: null, - autoFocus: true, - isBorderAllowed: false, - isAllowLeadingIcon: true, - padding: EdgeInsets.symmetric(vertical: 1.sp, horizontal: 2.w), - leadingIcon: AppAssets.student_card, - errorMessage: "Please enter a valid national ID or file number", - hasError: true, - ), - SizedBox(height: 2.sp), // Adjusted to sizer unit (approx 16px) - CustomButton( - text: LocaleKeys.login.tr(), - icon: AppAssets.login1, - iconColor: Colors.white, - onPressed: () {}, - ), - SizedBox(height: 2.sp), // Adjusted to sizer unit (approx 14px) - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: context.dynamicTextStyle( - color: Colors.black, - fontSize: 14.sp, // Adjusted to sizer unit - height: 26 / 16, // This height is a ratio, may need re-evaluation - fontWeight: FontWeight.w500, - ), - children: [ - TextSpan(text: LocaleKeys.dontHaveAccount.tr(), style: context.dynamicTextStyle()), - TextSpan(text: " "), - TextSpan( - text: LocaleKeys.registernow.tr(), - style: context.dynamicTextStyle( - color: AppColors.primaryRedColor, - fontSize: 14.sp, // Adjusted to sizer unit - height: 26 / 16, // Ratio - fontWeight: FontWeight.w500, - ), - recognizer: TapGestureRecognizer()..onTap = () {}, - ), - ], + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + appBar: CustomAppBar( + onBackPressed: () { + Navigator.of(context).pop(); + }, + onLanguageChanged: (String value) { + // context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); + }, + ), + body: GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside + }, + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 24.h), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Utils.showLottie(context: context, assetPath: AppAnimations.login, width: 200.h, height: 200.h, repeat: true, fit: BoxFit.cover), + SizedBox(height: 130.h), // Adjusted to sizer unit + LocaleKeys.welcomeToDrSulaiman.tr().toText32(isBold: true, color: AppColors.textColor), + SizedBox(height: 32.h), + TextInputWidget( + labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}", + hintText: "xxxxxxxxx", + controller: TextEditingController(), + keyboardType: TextInputType.number, + isEnable: true, + prefix: null, + autoFocus: true, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 10.h), + leadingIcon: AppAssets.student_card, + errorMessage: "Please enter a valid national ID or file number", + hasError: true, + ), + SizedBox(height: 16.h), // Adjusted to sizer unit (approx 16px) + CustomButton( + text: LocaleKeys.login.tr(), + icon: AppAssets.login1, + iconColor: Colors.white, + onPressed: () {}, + ), + SizedBox(height: 10.h), // Adjusted to sizer unit (approx 14px) + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: context.dynamicTextStyle( + color: Colors.black, + fontSize: 14.fSize, // Adjusted to sizer unit + height: 26 / 16, // This height is a ratio, may need re-evaluation + fontWeight: FontWeight.w500, ), - ).withVerticalPadding(2.sp), // Adjusted to sizer unit - ), - ], - ), + children: [ + TextSpan(text: LocaleKeys.dontHaveAccount.tr(), style: context.dynamicTextStyle()), + TextSpan(text: " "), + TextSpan( + text: LocaleKeys.registernow.tr(), + style: context.dynamicTextStyle( + color: AppColors.primaryRedColor, + fontSize: 14.fSize, // Adjusted to sizer unit + height: 26 / 16, // Ratio + fontWeight: FontWeight.w500, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.of(context).push( + MaterialPageRoute(builder: (BuildContext context) => RegisterNew()), + ); + }, + ), + ], + ), + ).withVerticalPadding(2), // Adjusted to sizer unit + ), + ], ), ), ), - ); - }); + ), + ); } } diff --git a/lib/presentation/authentication/register.dart b/lib/presentation/authentication/register.dart index 9b900b5..5564c46 100644 --- a/lib/presentation/authentication/register.dart +++ b/lib/presentation/authentication/register.dart @@ -1,579 +1,211 @@ -// import'dart:convert'; -// -// import 'package:easy_localization/easy_localization.dart'; -// import 'package:flutter/gestures.dart'; -// import 'package:flutter_svg/flutter_svg.dart'; -// import 'package:hijri_gregorian_calendar/hijri_gregorian_calendar.dart'; -// import 'package:hmg_patient_app/config/config.dart'; -// import 'package:hmg_patient_app/config/shared_pref_kay.dart'; -// import 'package:hmg_patient_app/config/size_config.dart'; -// import 'package:hmg_patient_app/core/service/client/base_app_client.dart'; -// import 'package:hmg_patient_app/core/viewModels/project_view_model.dart'; -// import 'package:hmg_patient_app/models/Appointments/toDoCountProviderModel.dart'; -// import 'package:hmg_patient_app/models/Authentication/check_activation_code_response.dart'; -// import 'package:hmg_patient_app/models/Authentication/check_paitent_authentication_req.dart'; -// import 'package:hmg_patient_app/models/Authentication/check_user_status_reponse.dart'; -// import 'package:hmg_patient_app/models/Authentication/check_user_status_req.dart'; -// import 'package:hmg_patient_app/models/Authentication/checkpatient_for_registration.dart'; -// import 'package:hmg_patient_app/models/Authentication/register_info_response.dart'; -// import 'package:hmg_patient_app/models/Authentication/send_activation_request.dart'; -// import 'package:hmg_patient_app/new_ui/new_ext.dart'; -// import 'package:hmg_patient_app/new_ui/otp/otp_validation_bootmsheet_widget.dart'; -// import 'package:hmg_patient_app/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart'; -// import 'package:hmg_patient_app/pages/login/login-type.dart'; -// import 'package:hmg_patient_app/pages/login/register-info.dart'; -// import 'package:hmg_patient_app/pages/login/register.dart'; -// import 'package:hmg_patient_app/pages/login/register_new_step_2.dart'; -// import 'package:hmg_patient_app/pages/login/user-login-agreement-page.dart'; -// import 'package:hmg_patient_app/pages/login/welcome.dart'; -// import 'package:hmg_patient_app/services/authentication/auth_provider.dart'; -// import 'package:hmg_patient_app/theme/colors.dart'; -// import 'package:hmg_patient_app/uitl/app_shared_preferences.dart'; -// import 'package:hmg_patient_app/uitl/app_toast.dart'; -// import 'package:hmg_patient_app/uitl/font_utils.dart'; -// import 'package:hmg_patient_app/uitl/gif_loader_dialog_utils.dart'; -// import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; -// import 'package:hmg_patient_app/uitl/utils.dart'; -// import 'package:hmg_patient_app/uitl/utils_new.dart'; -// import 'package:hmg_patient_app/widgets/drawer/langauge_picker.dart'; -// import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart'; -// import 'package:flutter/material.dart'; -// import 'package:hmg_patient_app/widgets/otp/sms-popup.dart'; -// import 'package:hmg_patient_app/widgets/text/app_texts_widget.dart'; -// import 'package:hmg_patient_app_new/core/app_state.dart'; -// import 'package:hmg_patient_app_new/core/enums.dart'; -// import 'package:hmg_patient_app_new/core/utils/utils.dart'; -// import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; -// import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; -// import 'package:hmg_patient_app_new/widgets/dropdown_widget.dart'; -// import 'package:hmg_patient_app_new/widgets/input_widget.dart'; -// import 'package:provider/provider.dart'; -// -// import '../../core/viewModels/appointment_rate_view_model.dart'; -// import '../../locator.dart'; -// import '../../models/Authentication/authenticated_user.dart'; -// import '../../models/Authentication/select_device_imei_res.dart'; -// import '../../models/InPatientServices/get_admission_info_response_model.dart'; -// import '../../models/InPatientServices/get_admission_request_info_response_model.dart'; -// import '../../new_ui/exception_widget/ExceptionBottomSheet.dart'; -// import '../../services/clinic_services/get_clinic_service.dart'; -// import '../../widgets/dialogs/alert_dialog.dart'; -// import '../../widgets/dialogs/confirm_dialog.dart'; -// import '../../widgets/transitions/fade_page.dart'; -// import 'package:intl/intl.dart' as intl; -// -// import '../landing/landing_page.dart'; -// import '../rateAppointment/rate_appointment_doctor.dart'; -// -// class RegisterNew extends StatefulWidget { -// @override -// _RegisterNew createState() => _RegisterNew(); -// } -// -// class _RegisterNew extends State { -// @override -// void initState() { -// super.initState(); -// } -// -// @override -// void dispose() { -// super.dispose(); -// } -// -// @override -// Widget build(BuildContext context) { -// -// AppState appState = getIt.get(); -// return Scaffold( -// body: GestureDetector( -// onTap: () { -// FocusScope.of(context).unfocus(); -// }, -// child: ScrollConfiguration( -// behavior: ScrollConfiguration.of(context).copyWith(overscroll: false, physics: const ClampingScrollPhysics()), -// child: NotificationListener( -// onNotification: (notification) { -// notification.disallowIndicator(); -// return true; -// }, -// child: SingleChildScrollView( -// physics: ClampingScrollPhysics(), -// padding: EdgeInsets.only( -// left: 24, -// right: 24, -// ), -// child: Column( -// mainAxisSize: MainAxisSize.min, -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Utils.showLottie( -// context: context, -// assetPath: 'assets/animations/lottie/register.json', -// width: MediaQuery -// .of(context) -// .size -// .width * 0.45, -// height: MediaQuery -// .of(context) -// .size -// .height * 0.22, -// fit: BoxFit.cover, -// repeat: true), -// SizedBox(height: 8), -// LocaleKeys.prepareToElevate.tr().toText28( -// textScaler: TextScaler.linear(MediaQuery.textScalerOf(context).scale(1)), -// ), -// SizedBox(height: 24), -// Directionality( -// textDirection: Directionality.of(context), -// child: Container( -// decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), -// padding: EdgeInsets.only(left: 16, right: 16, top: 0, bottom: 0), -// child: Column( -// children: [ -// DropdownWidget( -// labelText: LocaleKeys.country.tr(), -// hintText: LocaleKeys.ksa.tr(), -// isEnable: true, -// selectedValue: AppStat.selectedLanguage == "ar" ? selectedCountry.nameArabic : selectedCountry.displayName, -// dropdownItems: Country.values.map((e) => "ar" ? e.displayName : e.displayName).toList(), -// -// // dropdownItems: Country.values.map((e) => (e.name).first).toList(), -// // dropdownItems: Country.values.map((e) => "ar" ? e.nameArabic : e.displayName).toList(), -// // selectedValue: context.selectedLanguage == "ar" ? selectedCountry.nameArabic : selectedCountry.displayName, -// // selectionType: SelectionType.dropdown, -// onChange: (val) { -// if (val != null) { -// } -// }, -// isBorderAllowed: false, -// isAllowLeadingIcon: true, -// hasSelectionCustomIcon: true, -// removePadding: true, -// isLeadingCountry: true, -// isAllowRadius: false, -// padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), -// selectionCustomIcon: "assets/images/svg/arrow-down.svg", -// leadingIcon: selectedCountry.iconPath, -// ).withVerticalPadding(8), -// Divider(height: 1), -// Directionality( -// textDirection: TextDirection.ltr, -// child: newInputWidget(TranslationBase -// .of(context) -// .nationalIdNumber, "xxxxxxxxx", nationalIDorFile, -// isEnable: true, -// prefix: null, -// removePadding: true, -// isAllowRadius: false, -// hasSelection: false, -// isBorderAllowed: false, -// isAllowLeadingIcon: true, -// autoFocus: true, -// padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), -// leadingIcon: "assets/images/svg/student-card.svg", -// onChange: (value) { -// print(value); -// }).withVerticalPadding(8), -// ), -// Divider(height: 1), -// Directionality( -// textDirection: TextDirection.ltr, -// child: newInputWidget(TranslationBase -// .of(context) -// .dob, "11 July, 1994", nationalIDorFile, -// isEnable: true, -// prefix: null, -// hasSelection: true, -// removePadding: true, -// isBorderAllowed: false, -// isAllowLeadingIcon: true, -// hasSelectionCustomIcon: true, -// selectionType: SelectionType.calendar, -// selectedValue: selectedDOB != null -// ? isHijri == 1 -// ? Utils.formatHijriDateToDisplay(selectedDOB!.toIso8601String()) -// : Utils.formatDateToDisplay(selectedDOB.toString()) -// : null, -// selectionCustomIcon: "assets/images/svg/calendar.svg", -// lang: context.selectedLanguage, -// padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), -// leadingIcon: "assets/images/svg/birthday-cake.svg", -// onChange: (value) { -// selectedDOB = DateTime.parse(value!); -// if (isHijri == 1) { -// var hijriDate = HijriGregConverter.gregorianToHijri(DateTime.parse(value)); -// selectedDOB = DateTime(hijriDate.year, hijriDate.month, hijriDate.day); -// } else { -// selectedDOB = DateTime.parse(value); -// } -// print(selectedDOB!.toIso8601String()); -// setState(() {}); -// }, -// onCalendarTypeChanged: (bool value) { -// if (value) { -// isHijri = 0; -// } else { -// isHijri = 1; -// } -// }).withVerticalPadding(8), -// ), -// ], -// ), -// ), -// ), -// SizedBox(height: 25), -// GestureDetector( -// onTap: () { -// setState(() { -// isTermsAccepted = !isTermsAccepted; -// }); -// }, -// child: Row( -// children: [ -// AnimatedContainer( -// duration: const Duration(milliseconds: 200), -// height: 24, -// width: 24, -// decoration: BoxDecoration( -// color: isTermsAccepted ? const Color(0xFFE92227) : Colors.transparent, -// borderRadius: BorderRadius.circular(6), -// border: Border.all( -// color: isTermsAccepted ? const Color(0xFFE92227) : Colors.grey, -// width: 2, -// ), -// ), -// child: isTermsAccepted ? const Icon(Icons.check, size: 16, color: Colors.white) : null, -// ), -// SizedBox(width: 12), -// Expanded( -// child: Text( -// TranslationBase -// .of(context) -// .iAcceptTermsConditions, -// style: context.dynamicTextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), -// ), -// ), -// ], -// ), -// ), -// SizedBox(height: 25), -// CustomButton( -// text: TranslationBase -// .of(context) -// .register, -// icon: "assets/images/svg/note-edit.svg", -// onPressed: () { -// // bool isValid = Utils.validateIqama(nationalIDorFile.text); -// if (nationalIDorFile == null || nationalIDorFile.text.isEmpty) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .pleaseEnterNationalId, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// // Utils.showErrorToast(TranslationBase.of(context).pleaseEnterNationalId); -// return; -// } -// if ((!Utils.validateIqama(nationalIDorFile.text) && selectedCountry.countryCode == '966') || -// (!Utils.validateUaeNationalId(nationalIDorFile.text) && selectedCountry.countryCode == '971')) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .incorrectNationalId, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// return; -// } -// if (selectedCountry == null || selectedCountry.countryCode.isEmpty) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .pleaseSelectCountry, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// return; -// } -// -// if (selectedDOB == null) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .pleaseSelectDOB, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// return; -// } -// if (!isTermsAccepted) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .pleaseAcceptTermsConditions, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// return; -// } -// -// if (phoneController != null) { -// phoneController.clear(); -// } -// showModalBottomSheet( -// context: context, -// isScrollControlled: true, -// isDismissible: false, -// backgroundColor: Colors.transparent, -// builder: (bottomSheetContext) => -// Padding( -// padding: EdgeInsets.only(bottom: MediaQuery -// .of(bottomSheetContext) -// .viewInsets -// .bottom), -// child: SingleChildScrollView( -// child: GenericBottomSheet( -// countryCode: selectedCountry.countryCode, -// initialPhoneNumber: "", -// textController: phoneController, -// onChange: (String? value) { -// mobileNo = value!; -// }, -// buttons: [ -// Padding( -// padding: const EdgeInsets.only(bottom: 10), -// child: CustomButton( -// text: TranslationBase -// .of(context) -// .sendOTPSMS, -// onPressed: () { -// if (mobileNo.isEmpty) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .pleaseEnterMobile, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// } else if (!Utils.validateMobileNumber(mobileNo)) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .pleaseEnterValidMobile, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// } else { -// registerUser(1); -// } -// }, -// backgroundColor: CustomColors.bgRedColor, -// borderColor: CustomColors.bgRedBorderColor, -// textColor: Colors.white, -// icon: "assets/images/svg/message.svg", -// ), -// ), -// Row( -// crossAxisAlignment: CrossAxisAlignment.center, -// mainAxisAlignment: MainAxisAlignment.center, -// children: [ -// Padding( -// padding: const EdgeInsets.symmetric(horizontal: 8), -// child: AppText( -// TranslationBase -// .of(context) -// .oR, -// fontSize: 16, -// fontFamily: context.fontFamily, -// color: Color(0xFF2E3039), -// fontWeight: FontWeight.w500, -// ), -// ), -// ], -// ), -// Padding( -// padding: const EdgeInsets.only(bottom: 10, top: 10), -// child: CustomButton( -// text: TranslationBase -// .of(context) -// .sendOTPWHATSAPP, -// onPressed: () { -// if (mobileNo.isEmpty) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .pleaseEnterMobile, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// } else if (!Utils.validateMobileNumber(mobileNo)) { -// context.showBottomSheet( -// child: ExceptionBottomSheet( -// message: TranslationBase -// .of(context) -// .pleaseEnterValidMobile, -// showCancel: false, -// onOkPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// ); -// } else { -// registerUser(4); -// } -// // int? val = Utils.onOtpBtnPressed(OTPType.whatsapp, mobileNo, context); -// // registerUser(val); -// }, -// backgroundColor: Colors.white, -// borderColor: Color(0xFF2E3039), -// textColor: Color(0xFF2E3039), -// icon: "assets/images/svg/whatsapp.svg", -// ), -// ), -// ], -// myFocusNode: myFocusNode, -// ), -// ), -// ), -// ); -// Future.delayed(Duration(milliseconds: 500), () { -// myFocusNode.requestFocus(); -// }); -// }, -// fontFamily: context.fontFamily, -// ), -// SizedBox(height: 14), -// Center( -// child: RichText( -// textAlign: TextAlign.center, -// text: TextSpan( -// style: context.dynamicTextStyle( -// color: Colors.black, -// fontSize: 16, -// height: 26 / 16, -// fontWeight: FontWeight.w500, -// ), -// children: [ -// TextSpan(text: TranslationBase -// .of(context) -// .alreadyHaveAccount, style: context.dynamicTextStyle()), -// TextSpan(text: " "), -// TextSpan( -// text: TranslationBase -// .of(context) -// .loginNow, -// style: context.dynamicTextStyle( -// color: CustomColors.bgRedColor, -// fontSize: 16, -// height: 26 / 16, -// fontWeight: FontWeight.w500, -// ), -// recognizer: TapGestureRecognizer() -// ..onTap = () { -// Navigator.of(context).pop(); -// }, -// ), -// ], -// ), -// ), -// ), -// SizedBox(height: 30), -// ], -// ), -// ), -// ), -// ),) -// ); -// } -// -// Widget showProgress({String? title, String? status, Color? color, bool isNeedBorder = true}) { -// return Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Row( -// children: [ -// Container( -// width: 26, -// height: 26, -// decoration: containerRadius(color!, 200), -// child: Icon( -// Icons.done, -// color: Colors.white, -// size: 16, -// ), -// ), -// if (isNeedBorder) -// Expanded( -// child: Padding( -// padding: const EdgeInsets.all(8.0), -// child: mDivider(Colors.grey), -// )), -// ], -// ), -// mHeight(8), -// Text( -// title!, -// style: TextStyle( -// fontSize: 11, -// fontWeight: FontWeight.w600, -// letterSpacing: -0.44, -// ), -// ), -// mHeight(2), -// Container( -// padding: EdgeInsets.all(5), -// decoration: containerRadius(color.withOpacity(0.2), 4), -// child: Text( -// status!, -// style: TextStyle( -// fontSize: 8, -// fontWeight: FontWeight.w600, -// letterSpacing: -0.32, -// color: color, -// ), -// ), -// ), -// ], -// ) -// ], -// ); -// } -// } +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart' show CustomButton; +import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart'; +import 'package:hmg_patient_app_new/widgets/dropdown/dropdown_widget.dart'; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; + +class RegisterNew extends StatefulWidget { + @override + _RegisterNew createState() => _RegisterNew(); +} + +class _RegisterNew extends State { + bool isTermsAccepted = true; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + AppState appState = getIt.get(); + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + appBar: CustomAppBar( + onBackPressed: () { + Navigator.of(context).pop(); + }, + onLanguageChanged: (String value) { + // context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); + }, + ), + body: GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith(overscroll: false, physics: const ClampingScrollPhysics()), + child: NotificationListener( + onNotification: (notification) { + notification.disallowIndicator(); + return true; + }, + child: SingleChildScrollView( + physics: ClampingScrollPhysics(), + padding: EdgeInsets.symmetric(horizontal: 24.h), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Utils.showLottie(context: context, assetPath: 'assets/animations/lottie/register.json', width: 200.h, height: 200.h, fit: BoxFit.cover, repeat: true), + SizedBox(height: 16.h), + LocaleKeys.prepareToElevate.tr().toText32(isBold: true), + SizedBox(height: 24.h), + Directionality( + textDirection: Directionality.of(context), + child: Container( + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), + padding: EdgeInsets.symmetric(horizontal: 16.h), + child: Column( + children: [ + CustomCountryDropdown( + countryList: Country.values, + onCountryChange: (Country? value) {}, + isRtl: Directionality.of(context) == TextDirection.LTR, + ).withVerticalPadding(8.h), + + // DropdownWidget( + // labelText: LocaleKeys.country.tr(), + // hintText: LocaleKeys.ksa.tr(), + // isEnable: true, + // selectedValue: appState.getLanguageID(context) == "1" ? "selectedCountry.nameArabic" : "selectedCountry.displayName", + // dropdownItems: Country.values.map((e) => appState.getLanguageID(context) == " 1" ? e.displayName : e.displayName).toList(), + // onChange: (val) { + // if (val != null) {} + // }, + // isBorderAllowed: false, + // hasSelectionCustomIcon: true, + // isAllowRadius: false, + // padding: EdgeInsets.symmetric(vertical: 8.h), + // selectionCustomIcon: AppAssets.arrow_down, + // ).withVerticalPadding(8), + Divider(height: 1.h), + TextInputWidget( + labelText: LocaleKeys.nationalIdNumber.tr(), + hintText: "xxxxxxxxx", + controller: TextEditingController(), + isEnable: true, + prefix: null, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + + autoFocus: true, + padding: EdgeInsets.symmetric(vertical: 8.h), + leadingIcon: AppAssets.student_card, + onChange: (value) { + print(value); + }).withVerticalPadding(8), + Divider(height: 1), + TextInputWidget( + labelText: LocaleKeys.dob.tr(), + hintText: "11 July, 1994", + controller: TextEditingController(), + isEnable: true, + prefix: null, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + padding: EdgeInsets.symmetric(vertical: 8.h), + leadingIcon: AppAssets.birthday_cake, + onChange: (value) {}, + ).withVerticalPadding(8), + ], + ), + ), + ), + SizedBox(height: 25.h), + GestureDetector( + onTap: () {}, + child: Row( + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 200), + height: 24.h, + width: 24.h, + decoration: BoxDecoration( + color: isTermsAccepted ? const Color(0xFFE92227) : Colors.transparent, + borderRadius: BorderRadius.circular(6), + border: Border.all( + color: isTermsAccepted ? const Color(0xFFE92227) : Colors.grey, + width: 2.h, + ), + ), + child: isTermsAccepted ? Icon(Icons.check, size: 16.fSize, color: Colors.white) : null, + ), + SizedBox(width: 12.h), + Expanded( + child: Text( + LocaleKeys.iAcceptTermsConditions.tr(), + style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), + ), + ), + ], + ), + ), + SizedBox(height: 25.h), + CustomButton( + text: "Register", + icon: AppAssets.note_edit, + onPressed: () {}, + ), + SizedBox(height: 14), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: context.dynamicTextStyle( + color: Colors.black, + fontSize: 16.fSize, + height: 26 / 16, + fontWeight: FontWeight.w500, + ), + children: [ + TextSpan(text: LocaleKeys.alreadyHaveAccount.tr(), style: context.dynamicTextStyle()), + TextSpan(text: " "), + TextSpan( + text: LocaleKeys.loginNow.tr(), + style: context.dynamicTextStyle( + color: AppColors.primaryRedColor, + fontSize: 16.fSize, + height: 26 / 16, + fontWeight: FontWeight.w500, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.of(context).pop(); + }, + ), + ], + ), + ), + ), + SizedBox(height: 30), + ], + ), + ), + ),) + , + ) + ); + } +} diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index feb7f69..dd9f85c 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/extensions/int_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart'; @@ -44,8 +45,8 @@ class _LandingPageState extends State { CustomButton( text: LocaleKeys.loginOrRegister.tr(context: context), onPressed: () { - Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (BuildContext context) => LandingPage()), + Navigator.of(context).push( + MaterialPageRoute(builder: (BuildContext context) => LoginScreen()), ); }, backgroundColor: Color(0xffFEE9EA), diff --git a/lib/providers/authentication_view_model.dart b/lib/providers/authentication_view_model.dart deleted file mode 100644 index 1641148..0000000 --- a/lib/providers/authentication_view_model.dart +++ /dev/null @@ -1,6 +0,0 @@ - -import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/core/app_state.dart'; -class AuthenticationViewModel extends ChangeNotifier { -// Add properties and methods related to authentication here -} diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index b7a1fb4..252d887 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -30,6 +30,7 @@ class AppColors { static const Color textColor = Color(0xFF2E3039); static const Color borderOnlyColor = Color(0xFF2E3039); static const blackColor = textColor; + static const inputLabelTextColor = Color(0xff898A8D); //Chips static const Color successColor = Color(0xff18C273); diff --git a/lib/widgets/appbar/app_bar_widget.dart b/lib/widgets/appbar/app_bar_widget.dart index dde02ed..2fdbc94 100644 --- a/lib/widgets/appbar/app_bar_widget.dart +++ b/lib/widgets/appbar/app_bar_widget.dart @@ -1,7 +1,9 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/widgets/language_switcher.dart'; import '../../generated/locale_keys.g.dart'; @@ -24,45 +26,44 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { return AppBar( backgroundColor: Colors.transparent, leading: null, - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - // Arrow Back with click handler - Expanded( - child: Align( - alignment: Alignment.centerLeft, - child: GestureDetector( - onTap: onBackPressed, - child: Utils.buildSvgWithAssets( - icon: AppAssets.arrow_back, - width: 32, - height: 32, + automaticallyImplyLeading: false, + title: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Align( + alignment: Alignment.centerLeft, + child: GestureDetector( + onTap: onBackPressed, + child: Utils.buildSvgWithAssets(icon: AppAssets.arrow_back, width: 32.h, height: 32.h), ), ), ), - ), - // Logo - Utils.buildSvgWithAssets( - icon: AppAssets.habiblogo, - ), + // Logo + Utils.buildSvgWithAssets( + icon: AppAssets.habiblogo, + ), - // Language Selector - Expanded( - child: Align( - alignment: Alignment.centerRight, - child: LanguageSelector( - currentLanguage: context.locale.languageCode, - showOnlyIcon: false, - onLanguageChanged: onLanguageChanged, - languages: [ - {'code': 'ar', 'name': LocaleKeys.arabic.tr()}, - {'code': 'en', 'name': LocaleKeys.english.tr()} - ], + // Language Selector + Expanded( + child: Align( + alignment: Alignment.centerRight, + child: LanguageSelector( + currentLanguage: context.locale.languageCode, + showOnlyIcon: false, + onLanguageChanged: onLanguageChanged, + languages: [ + {'code': 'ar', 'name': LocaleKeys.arabic.tr()}, + {'code': 'en', 'name': LocaleKeys.english.tr()} + ], + ), ), ), - ), - ], + ], + ), ), centerTitle: true, ); diff --git a/lib/widgets/bottomsheet/exception_bottom_sheet.dart b/lib/widgets/bottomsheet/exception_bottom_sheet.dart new file mode 100644 index 0000000..f0ea651 --- /dev/null +++ b/lib/widgets/bottomsheet/exception_bottom_sheet.dart @@ -0,0 +1,111 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; + +class ExceptionBottomSheet extends StatelessWidget { + String message; + bool showOKButton; + bool showCancel; + Function() onOkPressed; + Function()? onCancelPressed; + + ExceptionBottomSheet({Key? key, required this.message, this.showOKButton = true, this.showCancel = false, required this.onOkPressed, this.onCancelPressed}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SafeArea( + bottom: Platform.isIOS ? false : true, // Adjust for iOS to avoid bottom padding + child: GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside + }, + child: Builder(builder: (context) { + return Directionality( + textDirection: Directionality.of(context), + child: Container( + padding: EdgeInsets.all(24.h), + decoration: BoxDecoration( + color: Color(0xFFF8F8FA), + borderRadius: const BorderRadius.vertical(top: Radius.circular(16)), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocaleKeys.notice.tr().toText28(), + InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Utils.buildSvgWithAssets(icon: AppAssets.cross_circle), + ) + ], + ), + SizedBox(height: 10.h), + (message ?? "").toText16(isBold: false, color: AppColors.textColor), + SizedBox(height: 10.h), + SizedBox(height: 24.h), + if (showOKButton && showCancel) + Row( + children: [ + Expanded( + child: CustomButton( + text: LocaleKeys.cancel.tr(), + onPressed: onCancelPressed != null + ? onCancelPressed! + : () { + Navigator.of(context).pop(); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + icon: AppAssets.cancel, + iconColor: AppColors.primaryRedColor, + ), + ), + SizedBox(width: 5.h), + Expanded( + child: CustomButton( + text: showCancel ? LocaleKeys.confirm.tr() : LocaleKeys.ok.tr(), + onPressed: onOkPressed, + backgroundColor: AppColors.bgGreenColor, + borderColor: AppColors.bgGreenColor, + textColor: Colors.white, + icon: AppAssets.confirm, + ), + ), + ], + ), + if (showOKButton && !showCancel) + Padding( + padding: EdgeInsets.only(bottom: 10.h), + child: CustomButton( + text: LocaleKeys.ok.tr(), + onPressed: onOkPressed, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedBorderColor, + textColor: Colors.white, + icon: AppAssets.confirm, + ), + ), + ], + ), + ), + ); + }), + ), + ); + } +} diff --git a/lib/widgets/dropdown/country_dropdown_widget.dart b/lib/widgets/dropdown/country_dropdown_widget.dart new file mode 100644 index 0000000..81ac60a --- /dev/null +++ b/lib/widgets/dropdown/country_dropdown_widget.dart @@ -0,0 +1,165 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; + +class CustomCountryDropdown extends StatefulWidget { + final List countryList; + final Function(Country)? onCountryChange; + final bool isRtl; + + const CustomCountryDropdown({ + Key? key, + required this.countryList, + this.onCountryChange, + required this.isRtl, + }) : super(key: key); + + @override + _CustomCountryDropdownState createState() => _CustomCountryDropdownState(); +} + +class _CustomCountryDropdownState extends State { + Country? selectedCountry; + late OverlayEntry _overlayEntry; + bool _isDropdownOpen = false; + + @override + void initState() { + super.initState(); + selectedCountry = Country.saudiArabia; + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + if (_isDropdownOpen) { + _closeDropdown(); + } else { + _openDropdown(); + } + }, + child: Container( + height: 40.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 10.h), + child: Row( + children: [ + Utils.buildSvgWithAssets(icon: selectedCountry != null ? selectedCountry!.iconPath : AppAssets.ksa, width: 40.h, height: 40.h), + SizedBox(width: 8.h), + Utils.buildSvgWithAssets(icon: _isDropdownOpen ? AppAssets.dropdow_icon : AppAssets.dropdow_icon), + SizedBox(width: 4.h), + Text( + selectedCountry != null ? selectedCountry!.displayName : "Select Country", + style: TextStyle( + fontSize: 14.fSize, + height: 21 / 14, + fontWeight: FontWeight.w500, + letterSpacing: -0.2, + ), + ), + ], + ), + ), + ); + } + + void _openDropdown() { + RenderBox renderBox = context.findRenderObject() as RenderBox; + Offset offset = renderBox.localToGlobal(Offset.zero); + + _overlayEntry = OverlayEntry( + builder: (context) => Stack( + children: [ + // Dismiss dropdown when tapping outside + Positioned.fill( + child: GestureDetector( + onTap: _closeDropdown, + behavior: HitTestBehavior.translucent, + child: Container(), + ), + ), + Positioned( + top: offset.dy + renderBox.size.height, + left: widget.isRtl ? offset.dx + 15.h : offset.dx - 15.h, + width: renderBox.size.width, + child: Material( + child: Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: Colors.white, + borderRadius: 12, + ), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(12), + // boxShadow: [ + // BoxShadow( + // color: Color(0xFFF8F8FA), + // blurRadius: 8.h, + // offset: Offset( + // 0, + // 2, + // ), + // ), + // ], + // ), + child: Column( + children: widget.countryList + .map( + (country) => GestureDetector( + onTap: () { + setState(() { + selectedCountry = country; + }); + widget.onCountryChange?.call(country); + _closeDropdown(); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 16.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + borderRadius: 16.h, + ), + child: Row( + children: [ + Utils.buildSvgWithAssets( + icon: country.iconPath, + width: 38.h, + height: 38.h, + ), + SizedBox(width: 12.h), + Text(country.displayName, + style: TextStyle( + fontSize: 14.fSize, + height: 21 / 14, + fontWeight: FontWeight.w500, + letterSpacing: -0.2, + )), + ], + ), + ), + ), + ) + .toList(), + ), + ), + ), + ), + ], + ), + ); + + Overlay.of(context)?.insert(_overlayEntry); + setState(() { + _isDropdownOpen = true; + }); + } + + void _closeDropdown() { + _overlayEntry.remove(); + setState(() { + _isDropdownOpen = false; + }); + } +} diff --git a/lib/widgets/dropdown_widget.dart b/lib/widgets/dropdown/dropdown_widget.dart similarity index 56% rename from lib/widgets/dropdown_widget.dart rename to lib/widgets/dropdown/dropdown_widget.dart index a778f2e..268e44a 100644 --- a/lib/widgets/dropdown_widget.dart +++ b/lib/widgets/dropdown/dropdown_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart' show Icons, PopupMenuItem, showMenu, Colors; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; @@ -38,10 +39,8 @@ class DropdownWidget extends StatelessWidget { alignment: Alignment.center, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: Colors.white, - borderRadius: isAllowRadius ? 15 : null, - side: isBorderAllowed - ? BorderSide(color: const Color(0xffefefef), width: 1) - : null, + borderRadius: isAllowRadius ? 15.h : null, + side: isBorderAllowed ? BorderSide(color: const Color(0xffefefef), width: 1) : null, ), child: Column( mainAxisSize: MainAxisSize.min, @@ -57,8 +56,8 @@ class DropdownWidget extends StatelessWidget { Widget _buildLabelText() { return Text( labelText, - style: const TextStyle( - fontSize: 12, + style: TextStyle( + fontSize: 12.fSize, fontWeight: FontWeight.w500, color: Color(0xff898A8D), letterSpacing: -0.2, @@ -71,33 +70,41 @@ class DropdownWidget extends StatelessWidget { return GestureDetector( onTap: isEnable ? () async { - final renderBox = context.findRenderObject() as RenderBox; - final offset = renderBox.localToGlobal(Offset.zero); - final selected = await showMenu( - context: context, - position: RelativeRect.fromLTRB( - offset.dx, - offset.dy + renderBox.size.height, - offset.dx + renderBox.size.width, - 0, - ), - items: dropdownItems - .map( - (e) => PopupMenuItem( - value: e, - child: Text(e), - ), - ) - .toList(), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ); + final renderBox = context.findRenderObject() as RenderBox; + final offset = renderBox.localToGlobal(Offset.zero); + final selected = await showMenu( + context: context, + position: RelativeRect.fromLTRB( + offset.dx, + offset.dy + renderBox.size.height, + offset.dx + renderBox.size.width, + 0, + ), + items: dropdownItems + .map( + (e) => PopupMenuItem( + value: e, + child: Text( + e, + style: TextStyle( + fontSize: 14.fSize, + height: 21 / 14, + fontWeight: FontWeight.w500, + letterSpacing: -0.2, + ), + ), + ), + ) + .toList(), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ); - if (selected != null && onChange != null) { - onChange!(selected); - } - } + if (selected != null && onChange != null) { + onChange!(selected); + } + } : null, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -105,28 +112,21 @@ class DropdownWidget extends StatelessWidget { children: [ Expanded( child: Text( - (selectedValue == null || selectedValue!.isEmpty) - ? hintText - : selectedValue!, + (selectedValue == null || selectedValue!.isEmpty) ? hintText : selectedValue!, textAlign: TextAlign.left, textDirection: TextDirection.ltr, style: TextStyle( - fontSize: 14, + fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, - color: (selectedValue != null && selectedValue!.isNotEmpty) - ? const Color(0xff2E3039) - : const Color(0xffB0B0B0), + color: (selectedValue != null && selectedValue!.isNotEmpty) ? const Color(0xff2E3039) : const Color(0xffB0B0B0), letterSpacing: -0.2, ), ), ), - if (hasSelectionCustomIcon && selectionCustomIcon != null) - Utils.buildSvgWithAssets(icon: selectionCustomIcon!) - else - const Icon(Icons.keyboard_arrow_down_outlined), + if (hasSelectionCustomIcon && selectionCustomIcon != null) Utils.buildSvgWithAssets(icon: selectionCustomIcon!) else const Icon(Icons.keyboard_arrow_down_outlined), ], ), ); } -} \ No newline at end of file +} diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index f2446a7..ca72fe8 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; // TODO: Import AppColors if bgRedColor is defined there // import 'package:hmg_patient_app_new/core/ui_utils/app_colors.dart'; @@ -54,9 +56,7 @@ class TextInputWidget extends StatelessWidget { @override Widget build(BuildContext context) { - // Assuming AppColors.bgRedColor exists, otherwise using Colors.red - final errorColor = Colors.red; // Replace with AppColors.bgRedColor if available - + final errorColor = AppColors.primaryRedColor; return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -66,7 +66,7 @@ class TextInputWidget extends StatelessWidget { alignment: Alignment.center, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: Colors.white, - borderRadius: isAllowRadius ? 15 : null, + borderRadius: isAllowRadius ? 12 : null, side: isBorderAllowed ? BorderSide(color: hasError ? errorColor : const Color(0xffefefef), width: 1) : null, ), child: Row( @@ -88,12 +88,12 @@ class TextInputWidget extends StatelessWidget { ), if (hasError && errorMessage != null) Padding( - padding: const EdgeInsets.only(top: 4.0, left: 12.0), // Adjust padding as needed + padding: EdgeInsets.only(top: 4.h, left: 12.h), // Adjust padding as needed child: Text( errorMessage!, style: TextStyle( color: errorColor, - fontSize: 12, + fontSize: 12.fSize, ), ), ), @@ -103,21 +103,24 @@ class TextInputWidget extends StatelessWidget { Widget _buildLeadingIcon(BuildContext context) { return Container( - height: 40, - width: 40, - margin: const EdgeInsets.only(right: 10), - padding: const EdgeInsets.all(8), - decoration: const BoxDecoration(color: Color(0xFFEFEFF0), borderRadius: BorderRadius.all(Radius.circular(10))), + height: 40.h, + width: 40.h, + margin: EdgeInsets.only(right: 10.h), + padding: EdgeInsets.all(8.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + borderRadius: 10.h, + color: AppColors.greyColor, + ), child: Utils.buildSvgWithAssets(icon: leadingIcon!)); } Widget _buildLabelText() { return Text( labelText, - style: const TextStyle( - fontSize: 12, + style: TextStyle( + fontSize: 12.fSize, fontWeight: FontWeight.w500, - color: Color(0xff898A8D), + color: AppColors.inputLabelTextColor, letterSpacing: -0.2, height: 18 / 12, ), @@ -137,30 +140,30 @@ class TextInputWidget extends StatelessWidget { onChanged: onChange, focusNode: focusNode, autofocus: autoFocus, - style: const TextStyle( - fontSize: 14, + style: TextStyle( + fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, - color: Color(0xff2E3039), + color: AppColors.textColor, letterSpacing: -0.2, ), decoration: InputDecoration( isDense: true, hintText: hintText, - hintStyle: const TextStyle( - fontSize: 14, + hintStyle: TextStyle( + fontSize: 14.fSize, height: 21 / 16, fontWeight: FontWeight.w500, color: Color(0xff898A8D), letterSpacing: -0.2, ), - prefixIconConstraints: const BoxConstraints(minWidth: 45), + prefixIconConstraints: BoxConstraints(minWidth: 45.h), prefixIcon: prefix == null ? null : Text( "+" + prefix!, - style: const TextStyle( - fontSize: 14, + style: TextStyle( + fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, color: Color(0xff2E303A), diff --git a/lib/widgets/language_switcher.dart b/lib/widgets/language_switcher.dart index 4c621b7..4a81217 100644 --- a/lib/widgets/language_switcher.dart +++ b/lib/widgets/language_switcher.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; @@ -51,18 +52,18 @@ class _LanguageSelectorState extends State { widget.onLanguageChanged(newLanguage); }, child: Container( - padding: EdgeInsets.all(8), + padding: EdgeInsets.all(8.h), decoration: BoxDecoration(borderRadius: BorderRadius.circular(12)), child: Row( mainAxisSize: MainAxisSize.min, children: [ Utils.buildSvgWithAssets(icon: AppAssets.language), - const SizedBox(width: 6), + SizedBox(width: 6.h), Text( currentLangData['name']?.toUpperCase() ?? 'EN', style: context.dynamicTextStyle( fontWeight: FontWeight.w500, - fontSize: 14, + fontSize: 14.fSize, color: AppColors.primaryRedColor, letterSpacing: 0.1, isLanguageSwitcher: true, diff --git a/pubspec.lock b/pubspec.lock index c503e1b..679a57e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" audio_session: dependency: transitive description: @@ -874,26 +874,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "11.0.1" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.10" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.1" lints: dependency: transitive description: @@ -1455,10 +1455,10 @@ packages: dependency: transitive description: name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.7.4" time: dependency: transitive description: @@ -1583,18 +1583,18 @@ packages: dependency: transitive description: name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.1.4" vm_service: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.0.0" web: dependency: "direct main" description: @@ -1636,5 +1636,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.8.0-0 <4.0.0" + dart: ">=3.7.0 <4.0.0" flutter: ">=3.29.0" From 67e580447e30a07f393a2d47137fbfefec5681ed Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 2 Sep 2025 16:09:18 +0300 Subject: [PATCH 5/6] changes --- assets/langs/ar-SA.json | 7 +- assets/langs/en-US.json | 7 +- lib/extensions/context_extensions.dart | 33 +- lib/generated/locale_keys.g.dart | 3 + lib/presentation/authentication/login.dart | 76 +++- lib/presentation/authentication/register.dart | 408 +++++++++++------- lib/theme/colors.dart | 1 + lib/widgets/appbar/app_bar_widget.dart | 39 +- .../bottomsheet/generic_bottom_sheet.dart | 58 +-- lib/widgets/buttons/custom_button.dart | 76 ++-- lib/widgets/otp/otp.dart | 227 ++++++++++ 11 files changed, 679 insertions(+), 256 deletions(-) create mode 100644 lib/widgets/otp/otp.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 57f9bcd..64477a3 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -787,7 +787,8 @@ "iAcceptTermsConditions": "أوافق على الشروط والأحكام", "alreadyHaveAccount": "هل لديك حساب بالفعل؟", "loginNow": "تسجيل الدخول الآن", - "notice": "إشعار" - - + "notice": "إشعار", + "oR": "أو", + "sendOTPWHATSAPP": "أرسل لي OTP عبر واتساب", + "sendOTPSMS": "أرسل لي OTP عبر الرسائل القصيرة" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 311db65..cd15a5a 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -774,7 +774,7 @@ "termsConditions": "These Online Services Terms of Use (Service Terms) govern certain online services provided by Dr Sulaiman Al Habib Medical Services Group Company (HMG, we, us, our)...", "receiveOtpToast": "Where would you like to receive OTP?", "enterPhoneNumber": "Enter Phone Number", - "enterEmailDesc": "Enter your email address to complete the process of creating a medical file", + "enterEmailDesc": "Enter your email address to complete the process of creating a medical file", "enterPhoneDesc": "Enter your phone number to receive OTP verification code", "pleaseChooseOption": "Please select from the below options to receive OTP", "dontHaveAccount": "Don't have an account?", @@ -783,5 +783,8 @@ "iAcceptTermsConditions": "I Accept the Terms and Conditions", "alreadyHaveAccount": "Already have an account?", "loginNow": "Login Now", - "notice": "Notice" + "notice": "Notice", + "oR": "OR", + "sendOTPWHATSAPP": "Send me OTP on Whatsapp", + "sendOTPSMS": "Send me OTP on SMS" } \ No newline at end of file diff --git a/lib/extensions/context_extensions.dart b/lib/extensions/context_extensions.dart index 5783ce3..4e9da0d 100644 --- a/lib/extensions/context_extensions.dart +++ b/lib/extensions/context_extensions.dart @@ -2,15 +2,32 @@ import 'package:flutter/material.dart'; extension ContextUtils on BuildContext { double get screenHeight => MediaQuery.of(this).size.height; + double get screenWidth => MediaQuery.of(this).size.width; + ThemeData get theme => Theme.of(this); + TextTheme get textTheme => theme.textTheme; - // TextStyle get headline1 => textTheme.headline1!; - // TextStyle get headline2 => textTheme.headline2!; - // TextStyle get headline3 => textTheme.headline3!; - // TextStyle get headline4 => textTheme.headline4!; - // TextStyle get headline5 => textTheme.headline5!; - // TextStyle get headline6 => textTheme.headline6!; - // TextStyle get bodyText1 => textTheme.bodyText1!; - // TextStyle get bodyText2 => textTheme.bodyText2!; +// TextStyle get headline1 => textTheme.headline1!; +// TextStyle get headline2 => textTheme.headline2!; +// TextStyle get headline3 => textTheme.headline3!; +// TextStyle get headline4 => textTheme.headline4!; +// TextStyle get headline5 => textTheme.headline5!; +// TextStyle get headline6 => textTheme.headline6!; +// TextStyle get bodyText1 => textTheme.bodyText1!; +// TextStyle get bodyText2 => textTheme.bodyText2!; +} + +extension ShowBottomSheet on BuildContext { + Future showBottomSheet({isScrollControlled = true, isDismissible = false, required Widget child, Color? backgroundColor, enableDra = false, useSafeArea = false}) { + return showModalBottomSheet( + context: this, + isScrollControlled: isScrollControlled, + isDismissible: isDismissible, + enableDrag: enableDra, + useSafeArea: useSafeArea, + backgroundColor: backgroundColor ?? Colors.transparent, + builder: (_) => child, + ); + } } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index f219526..c5f2592 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -786,5 +786,8 @@ abstract class LocaleKeys { static const alreadyHaveAccount = 'alreadyHaveAccount'; static const loginNow = 'loginNow'; static const notice = 'notice'; + static const oR = 'oR'; + static const sendOTPWHATSAPP = 'sendOTPWHATSAPP'; + static const sendOTPSMS = 'sendOTPSMS'; } diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index 87f40ca..f74348f 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -4,12 +4,14 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/context_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/authentication/register.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; +import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; @@ -77,7 +79,22 @@ class _LoginScreen extends State { text: LocaleKeys.login.tr(), icon: AppAssets.login1, iconColor: Colors.white, - onPressed: () {}, + onPressed: () { + showLoginModel(context: context); + // if (nationIdController.text.isNotEmpty) { + + // } else { + // showBottomSheet( + // child: ExceptionBottomSheet( + // message: TranslationBase.of(context).pleaseEnterNationalIdOrFileNo, + // showCancel: false, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); + // } + }, ), SizedBox(height: 10.h), // Adjusted to sizer unit (approx 14px) Center( @@ -119,4 +136,61 @@ class _LoginScreen extends State { ), ); } + + void showLoginModel({required BuildContext context, TextEditingController? textController}) { + context.showBottomSheet( + isScrollControlled: true, + isDismissible: false, + useSafeArea: true, + backgroundColor: Colors.transparent, + child: StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) { + return Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: SingleChildScrollView( + child: GenericBottomSheet( + countryCode: "966", + initialPhoneNumber: "", + textController: TextEditingController(), + isEnableCountryDropdown: true, + onCountryChange: (value) {}, + onChange: (String? value) {}, + buttons: [ + Padding( + padding: EdgeInsets.only(bottom: 10.h), + child: CustomButton( + text: LocaleKeys.sendOTPSMS.tr(), + onPressed: () {}, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedBorderColor, + textColor: AppColors.whiteColor, + icon: AppAssets.message, + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.h), + child: LocaleKeys.oR.tr().toText16(color: AppColors.textColor), + ), + ], + ), + Padding( + padding: EdgeInsets.only(bottom: 10.h, top: 10.h), + child: CustomButton( + text: LocaleKeys.sendOTPWHATSAPP.tr(), + onPressed: () {}, + backgroundColor: Colors.white, + borderColor: AppColors.borderOnlyColor, + textColor: AppColors.textColor, + icon: AppAssets.whatsapp, + ), + ), + ], + ), + ), + ); + })); + } } diff --git a/lib/presentation/authentication/register.dart b/lib/presentation/authentication/register.dart index 5564c46..0fcad5c 100644 --- a/lib/presentation/authentication/register.dart +++ b/lib/presentation/authentication/register.dart @@ -12,10 +12,12 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; +import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart' show CustomButton; import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart'; import 'package:hmg_patient_app_new/widgets/dropdown/dropdown_widget.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:hmg_patient_app_new/widgets/otp/otp.dart'; class RegisterNew extends StatefulWidget { @override @@ -39,173 +41,275 @@ class _RegisterNew extends State { Widget build(BuildContext context) { AppState appState = getIt.get(); return Scaffold( - backgroundColor: AppColors.bgScaffoldColor, - appBar: CustomAppBar( - onBackPressed: () { - Navigator.of(context).pop(); - }, - onLanguageChanged: (String value) { - // context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); - }, - ), - body: GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); - }, - child: ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith(overscroll: false, physics: const ClampingScrollPhysics()), - child: NotificationListener( - onNotification: (notification) { - notification.disallowIndicator(); - return true; - }, - child: SingleChildScrollView( - physics: ClampingScrollPhysics(), - padding: EdgeInsets.symmetric(horizontal: 24.h), - child: Column( + backgroundColor: AppColors.bgScaffoldColor, + appBar: CustomAppBar( + onBackPressed: () { + Navigator.of(context).pop(); + }, + onLanguageChanged: (String value) { + // context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US')); + }, + ), + body: GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith(overscroll: false, physics: const ClampingScrollPhysics()), + child: NotificationListener( + onNotification: (notification) { + notification.disallowIndicator(); + return true; + }, + child: SingleChildScrollView( + physics: ClampingScrollPhysics(), + padding: EdgeInsets.symmetric(horizontal: 24.h), + child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Utils.showLottie(context: context, assetPath: 'assets/animations/lottie/register.json', width: 200.h, height: 200.h, fit: BoxFit.cover, repeat: true), - SizedBox(height: 16.h), - LocaleKeys.prepareToElevate.tr().toText32(isBold: true), - SizedBox(height: 24.h), - Directionality( - textDirection: Directionality.of(context), - child: Container( - decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), - padding: EdgeInsets.symmetric(horizontal: 16.h), - child: Column( - children: [ - CustomCountryDropdown( - countryList: Country.values, - onCountryChange: (Country? value) {}, - isRtl: Directionality.of(context) == TextDirection.LTR, - ).withVerticalPadding(8.h), - - // DropdownWidget( - // labelText: LocaleKeys.country.tr(), - // hintText: LocaleKeys.ksa.tr(), - // isEnable: true, - // selectedValue: appState.getLanguageID(context) == "1" ? "selectedCountry.nameArabic" : "selectedCountry.displayName", - // dropdownItems: Country.values.map((e) => appState.getLanguageID(context) == " 1" ? e.displayName : e.displayName).toList(), - // onChange: (val) { - // if (val != null) {} - // }, - // isBorderAllowed: false, - // hasSelectionCustomIcon: true, - // isAllowRadius: false, - // padding: EdgeInsets.symmetric(vertical: 8.h), - // selectionCustomIcon: AppAssets.arrow_down, - // ).withVerticalPadding(8), - Divider(height: 1.h), - TextInputWidget( - labelText: LocaleKeys.nationalIdNumber.tr(), - hintText: "xxxxxxxxx", - controller: TextEditingController(), - isEnable: true, - prefix: null, - isAllowRadius: true, - isBorderAllowed: false, - isAllowLeadingIcon: true, - - autoFocus: true, - padding: EdgeInsets.symmetric(vertical: 8.h), - leadingIcon: AppAssets.student_card, - onChange: (value) { - print(value); - }).withVerticalPadding(8), - Divider(height: 1), - TextInputWidget( - labelText: LocaleKeys.dob.tr(), - hintText: "11 July, 1994", - controller: TextEditingController(), - isEnable: true, - prefix: null, - isAllowRadius: true, - isBorderAllowed: false, - isAllowLeadingIcon: true, - padding: EdgeInsets.symmetric(vertical: 8.h), - leadingIcon: AppAssets.birthday_cake, - onChange: (value) {}, - ).withVerticalPadding(8), - ], + Utils.showLottie(context: context, + assetPath: 'assets/animations/lottie/register.json', + width: 200.h, + height: 200.h, + fit: BoxFit.cover, + repeat: true), + SizedBox(height: 16.h), + LocaleKeys.prepareToElevate.tr().toText32(isBold: true), + SizedBox(height: 24.h), + Directionality( + textDirection: Directionality.of(context), + child: Container( + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), + padding: EdgeInsets.symmetric(horizontal: 16.h), + child: Column( + children: [ + CustomCountryDropdown( + countryList: Country.values, + onCountryChange: (Country? value) {}, + isRtl: Directionality.of(context) == TextDirection.LTR, + ).withVerticalPadding(8.h), + Divider(height: 1.h), + TextInputWidget( + labelText: LocaleKeys.nationalIdNumber.tr(), + hintText: "xxxxxxxxx", + controller: TextEditingController(), + isEnable: true, + prefix: null, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + autoFocus: true, + padding: EdgeInsets.symmetric(vertical: 8.h), + leadingIcon: AppAssets.student_card, + onChange: (value) { + print(value); + }).withVerticalPadding(8), + Divider(height: 1), + TextInputWidget( + labelText: LocaleKeys.dob.tr(), + hintText: "11 July, 1994", + controller: TextEditingController(), + isEnable: true, + prefix: null, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + padding: EdgeInsets.symmetric(vertical: 8.h), + leadingIcon: AppAssets.birthday_cake, + onChange: (value) {}, + ).withVerticalPadding(8), + ], + ), + ), + ), + SizedBox(height: 25.h), + GestureDetector( + onTap: () {}, + child: Row( + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 200), + height: 24.h, + width: 24.h, + decoration: BoxDecoration( + color: isTermsAccepted ? const Color(0xFFE92227) : Colors.transparent, + borderRadius: BorderRadius.circular(6), + border: Border.all( + color: isTermsAccepted ? const Color(0xFFE92227) : Colors.grey, + width: 2.h, + ), + ), + child: isTermsAccepted ? Icon(Icons.check, size: 16.fSize, color: Colors.white) : null, + ), + SizedBox(width: 12.h), + Expanded( + child: Text( + LocaleKeys.iAcceptTermsConditions.tr(), + style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), + ), + ), + ], + ), + ), + SizedBox(height: 25.h), + CustomButton( + text: "Register", + icon: AppAssets.note_edit, + onPressed: () { + showRegisterModel(context: context); + }, + ), + SizedBox(height: 14), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: context.dynamicTextStyle( + color: Colors.black, + fontSize: 16.fSize, + height: 26 / 16, + fontWeight: FontWeight.w500, + ), + children: [ + TextSpan(text: LocaleKeys.alreadyHaveAccount.tr(), style: context.dynamicTextStyle()), + TextSpan(text: " "), + TextSpan( + text: LocaleKeys.loginNow.tr(), + style: context.dynamicTextStyle( + color: AppColors.primaryRedColor, + fontSize: 16.fSize, + height: 26 / 16, + fontWeight: FontWeight.w500, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.of(context).pop(); + }, + ), + ], + ), + ), + ), + SizedBox(height: 30), + ], + ), ), ), ), - SizedBox(height: 25.h), - GestureDetector( - onTap: () {}, - child: Row( - children: [ - AnimatedContainer( - duration: const Duration(milliseconds: 200), - height: 24.h, - width: 24.h, - decoration: BoxDecoration( - color: isTermsAccepted ? const Color(0xFFE92227) : Colors.transparent, - borderRadius: BorderRadius.circular(6), - border: Border.all( - color: isTermsAccepted ? const Color(0xFFE92227) : Colors.grey, - width: 2.h, + )); + } + + void showRegisterModel({required BuildContext context, TextEditingController? textController}) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + isDismissible: false, + useSafeArea: true, + backgroundColor: Colors.transparent, + builder: (bottomSheetContext) => + Padding( + padding: EdgeInsets.only(bottom: MediaQuery + .of(bottomSheetContext) + .viewInsets + .bottom), + child: SingleChildScrollView( + child: GenericBottomSheet( + countryCode: "966", + initialPhoneNumber: "", + textController: TextEditingController(), + onChange: (String? value) {}, + buttons: [ + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: CustomButton( + text: LocaleKeys.sendOTPSMS.tr(), + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute(builder: (BuildContext context) => OTPVerificationPage(phoneNumber: '12234567',))); + + + // if (mobileNo.isEmpty) { + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: TranslationBase.of(context).pleaseEnterMobile, + // showCancel: false, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); + // } else if (!Utils.validateMobileNumber(mobileNo)) { + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: TranslationBase.of(context).pleaseEnterValidMobile, + // showCancel: false, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); + // } else { + // registerUser(1); + // } + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedBorderColor, + textColor: AppColors.whiteColor, + icon: AppAssets.message, ), ), - child: isTermsAccepted ? Icon(Icons.check, size: 16.fSize, color: Colors.white) : null, - ), - SizedBox(width: 12.h), - Expanded( - child: Text( - LocaleKeys.iAcceptTermsConditions.tr(), - style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.h), + child: LocaleKeys.oR.tr().toText16(color: AppColors.textColor), + ), + ], ), - ), - ], - ), - ), - SizedBox(height: 25.h), - CustomButton( - text: "Register", - icon: AppAssets.note_edit, - onPressed: () {}, - ), - SizedBox(height: 14), - Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: context.dynamicTextStyle( - color: Colors.black, - fontSize: 16.fSize, - height: 26 / 16, - fontWeight: FontWeight.w500, - ), - children: [ - TextSpan(text: LocaleKeys.alreadyHaveAccount.tr(), style: context.dynamicTextStyle()), - TextSpan(text: " "), - TextSpan( - text: LocaleKeys.loginNow.tr(), - style: context.dynamicTextStyle( - color: AppColors.primaryRedColor, - fontSize: 16.fSize, - height: 26 / 16, - fontWeight: FontWeight.w500, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - Navigator.of(context).pop(); + Padding( + padding: EdgeInsets.only(bottom: 10.h, top: 10.h), + child: CustomButton( + text: LocaleKeys.sendOTPWHATSAPP.tr(), + onPressed: () { + // if (mobileNo.isEmpty) { + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: TranslationBase.of(context).pleaseEnterMobile, + // showCancel: false, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); + // } else if (!Utils.validateMobileNumber(mobileNo)) { + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: TranslationBase.of(context).pleaseEnterValidMobile, + // showCancel: false, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); + // } else { + // registerUser(4); + // } + // int? val = Utils.onOtpBtnPressed(OTPType.whatsapp, mobileNo, context); + // registerUser(val); }, + backgroundColor: AppColors.whiteColor, + borderColor: AppColors.borderOnlyColor, + textColor: AppColors.textColor, + icon: AppAssets.whatsapp, + ), ), ], ), ), ), - SizedBox(height: 30), - ], - ), - ), - ),) - , - ) ); } } diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index 252d887..2c8a1fc 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -29,6 +29,7 @@ class AppColors { static const Color bgGreenColor = Color(0xFF18C273); static const Color textColor = Color(0xFF2E3039); static const Color borderOnlyColor = Color(0xFF2E3039); + static const Color blackBgColor = Color(0xFF2E3039); static const blackColor = textColor; static const inputLabelTextColor = Color(0xff898A8D); diff --git a/lib/widgets/appbar/app_bar_widget.dart b/lib/widgets/appbar/app_bar_widget.dart index 2fdbc94..4bc08a9 100644 --- a/lib/widgets/appbar/app_bar_widget.dart +++ b/lib/widgets/appbar/app_bar_widget.dart @@ -11,11 +11,13 @@ import '../../generated/locale_keys.g.dart'; class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { final VoidCallback onBackPressed; final ValueChanged onLanguageChanged; + bool hideLogoAndLang; - const CustomAppBar({ + CustomAppBar({ Key? key, required this.onBackPressed, required this.onLanguageChanged, + this.hideLogoAndLang = false, }) : super(key: key); @override @@ -28,7 +30,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { leading: null, automaticallyImplyLeading: false, title: Padding( - padding: EdgeInsets.symmetric(horizontal: 10.h), + padding: EdgeInsets.symmetric(horizontal: 10.h), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ @@ -43,25 +45,26 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { ), // Logo - Utils.buildSvgWithAssets( - icon: AppAssets.habiblogo, - ), + if (!hideLogoAndLang) + Utils.buildSvgWithAssets( + icon: AppAssets.habiblogo, + ), - // Language Selector - Expanded( - child: Align( - alignment: Alignment.centerRight, - child: LanguageSelector( - currentLanguage: context.locale.languageCode, - showOnlyIcon: false, - onLanguageChanged: onLanguageChanged, - languages: [ - {'code': 'ar', 'name': LocaleKeys.arabic.tr()}, - {'code': 'en', 'name': LocaleKeys.english.tr()} - ], + if (!hideLogoAndLang) + Expanded( + child: Align( + alignment: Alignment.centerRight, + child: LanguageSelector( + currentLanguage: context.locale.languageCode, + showOnlyIcon: false, + onLanguageChanged: onLanguageChanged, + languages: [ + {'code': 'ar', 'name': LocaleKeys.arabic.tr()}, + {'code': 'en', 'name': LocaleKeys.english.tr()} + ], + ), ), ), - ), ], ), ), diff --git a/lib/widgets/bottomsheet/generic_bottom_sheet.dart b/lib/widgets/bottomsheet/generic_bottom_sheet.dart index 13a02a5..eefb187 100644 --- a/lib/widgets/bottomsheet/generic_bottom_sheet.dart +++ b/lib/widgets/bottomsheet/generic_bottom_sheet.dart @@ -3,9 +3,12 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; class GenericBottomSheet extends StatefulWidget { @@ -18,20 +21,21 @@ class GenericBottomSheet extends StatefulWidget { final bool isEnableCountryDropdown; final bool isFromSavedLogin; Function(String?)? onChange; + // FocusNode myFocusNode; - GenericBottomSheet( - {this.countryCode = "", - this.initialPhoneNumber = "", - required this.buttons, - this.textController, - this.isForEmail = false, - this.onCountryChange, - this.isEnableCountryDropdown = false, - this.isFromSavedLogin = false, - this.onChange, - // required this.myFocusNode - }); + GenericBottomSheet({ + this.countryCode = "", + this.initialPhoneNumber = "", + required this.buttons, + this.textController, + this.isForEmail = false, + this.onCountryChange, + this.isEnableCountryDropdown = false, + this.isFromSavedLogin = false, + this.onChange, + // required this.myFocusNode + }); @override _GenericBottomSheetState createState() => _GenericBottomSheetState(); @@ -64,11 +68,8 @@ class _GenericBottomSheetState extends State { child: Directionality( textDirection: Directionality.of(context), child: Container( - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - color: Color(0xFFF8F8FA), - borderRadius: const BorderRadius.vertical(top: Radius.circular(16)), - ), + padding: EdgeInsets.all(24.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.bgScaffoldColor, borderRadius: 16), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, @@ -86,18 +87,17 @@ class _GenericBottomSheetState extends State { ? LocaleKeys.enterEmail.tr().toText24() : LocaleKeys.enterPhoneNumber.tr().toText24()), InkWell( - onTap: () { - Navigator.of(context).pop(); - }, - child: Padding( - padding: const EdgeInsets.only(top: 10), - child: Utils.buildSvgWithAssets( - icon: AppAssets.cross_circle, - ), - )), + onTap: () { + Navigator.of(context).pop(); + }, + child: Padding( + padding: EdgeInsets.only(top: 10.h), + child: Utils.buildSvgWithAssets(icon: AppAssets.cross_circle), + ), + ), ], ), - const SizedBox(height: 8), + SizedBox(height: 8.h), // Subtitle widget.isFromSavedLogin ? LocaleKeys.pleaseChooseOption.tr().toText16() @@ -113,7 +113,7 @@ class _GenericBottomSheetState extends State { labelText: widget.isForEmail ? LocaleKeys.email : LocaleKeys.phoneNumber, hintText: widget.isForEmail ? "demo@gmail.com" : "5xxxxxxxx", controller: widget.textController!, - padding: EdgeInsets.only(top: 8, bottom: 8, left: 8, right: 8), + padding: EdgeInsets.all(8.h), keyboardType: widget.isForEmail ? TextInputType.emailAddress : TextInputType.number, onChange: (value) { widget.textController!.text = value!; @@ -133,7 +133,7 @@ class _GenericBottomSheetState extends State { : SizedBox(), ], - SizedBox(height: 24), + SizedBox(height: 24.h), ...widget.buttons, ], ), diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index e08189a..8a08a5e 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -43,50 +43,40 @@ class CustomButton extends StatelessWidget { @override Widget build(BuildContext context) { return GestureDetector( - onTap: isDisabled ? null : onPressed, - child: Container( - height: height, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: isDisabled ? Colors.transparent : backgroundColor, - borderRadius: borderRadius, - side: BorderSide( - width: borderWidth, - color: isDisabled ? borderColor.withOpacity(0.5) : borderColor, - )), - child: Padding( - padding: padding, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (icon != null) - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled), - ), - Text( - text, - style: context.dynamicTextStyle( - fontSize: fontSize.fSize, - color: isDisabled ? textColor.withOpacity(0.5) : textColor, - letterSpacing: -0.4, - fontWeight: fontWeight, - ), + onTap: isDisabled ? null : onPressed, + child: Container( + height: height, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: isDisabled ? Colors.transparent : backgroundColor, + borderRadius: borderRadius, + side: BorderSide( + width: borderWidth, + color: isDisabled ? borderColor.withOpacity(0.5) : borderColor, + )), + child: Padding( + padding: padding, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (icon != null) + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled), ), - ], - ), + Text( + text, + style: context.dynamicTextStyle( + fontSize: fontSize.fSize, + color: isDisabled ? textColor.withOpacity(0.5) : textColor, + letterSpacing: -0.4, + fontWeight: fontWeight, + ), + ), + ], ), - ) - - // .toSmoothContainer( - // smoothness: 1, - // side: BorderSide(width: borderWidth, color: backgroundColor), - // borderRadius: BorderRadius.circular(borderRadius * 1.2), - // foregroundDecoration: BoxDecoration( - // color: isDisabled ? backgroundColor.withOpacity(0.5) : Colors.transparent, - // borderRadius: BorderRadius.circular(borderRadius), - // ), - // ), - ); + ), + ), + ); } } diff --git a/lib/widgets/otp/otp.dart b/lib/widgets/otp/otp.dart new file mode 100644 index 0000000..5cfd3e9 --- /dev/null +++ b/lib/widgets/otp/otp.dart @@ -0,0 +1,227 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; + +class OTPVerificationPage extends StatefulWidget { + final String phoneNumber; + + const OTPVerificationPage({Key? key, required this.phoneNumber}) : super(key: key); + + @override + State createState() => _OTPVerificationPageState(); +} + +class _OTPVerificationPageState extends State { + final int _otpLength = 4; + late final List _controllers; + late final List _focusNodes; + + Timer? _resendTimer; + int _resendTime = 60; + bool _isOtpComplete = false; + + @override + void initState() { + super.initState(); + _controllers = List.generate(_otpLength, (_) => TextEditingController()); + _focusNodes = List.generate(_otpLength, (_) => FocusNode()); + _startResendTimer(); + + // Focus the first field once the screen is built + WidgetsBinding.instance.addPostFrameCallback((_) { + if (_focusNodes.isNotEmpty) { + FocusScope.of(context).requestFocus(_focusNodes[0]); + } + }); + } + + @override + void dispose() { + for (final c in _controllers) c.dispose(); + for (final f in _focusNodes) f.dispose(); + _resendTimer?.cancel(); + super.dispose(); + } + + void _startResendTimer() { + _resendTimer = Timer.periodic(const Duration(seconds: 1), (timer) { + if (_resendTime > 0) { + setState(() => _resendTime--); + } else { + timer.cancel(); + } + }); + } + + void _onOtpChanged(int index, String value) { + if (value.length == 1 && index < _otpLength - 1) { + _focusNodes[index + 1].requestFocus(); + } else if (value.isEmpty && index > 0) { + _focusNodes[index - 1].requestFocus(); + } + _checkOtpCompletion(); + } + + void _checkOtpCompletion() { + final isComplete = _controllers.every((c) => c.text.isNotEmpty); + + if (isComplete != _isOtpComplete) { + setState(() => _isOtpComplete = isComplete); + + if (isComplete) { + _verifyOtp(); + } + } + } + + void _resendOtp() { + if (_resendTime == 0) { + setState(() => _resendTime = 60); + _startResendTimer(); + autoFillOtp("1234"); + + // call resend API here + } + } + + String _getMaskedPhoneNumber() { + final phone = widget.phoneNumber; + return phone.length > 4 ? '05xxxxxx${phone.substring(phone.length - 2)}' : phone; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + hideLogoAndLang: true, + onBackPressed: () { + Navigator.of(context).pop(); + }, + onLanguageChanged: (lang) {}, + ), + body: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 24.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 40.h), + Text( + 'OTP Verification', + style: TextStyle(fontSize: 24.fSize, fontWeight: FontWeight.bold), + ), + SizedBox(height: 16.h), + Text( + 'We have sent you the OTP code on ${_getMaskedPhoneNumber()} via SMS for registration verification', + style: TextStyle(fontSize: 16.fSize, color: Colors.grey), + ), + SizedBox(height: 40.h), + + // OTP Input Fields + SizedBox( + height: 100, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: List.generate(_otpLength, (index) { + return ValueListenableBuilder( + valueListenable: _controllers[index], + builder: (context, value, _) { + final hasText = value.text.isNotEmpty; + + return AnimatedContainer( + duration: const Duration(milliseconds: 200), + curve: Curves.easeInOut, + width: 70.h, + margin: EdgeInsets.symmetric(horizontal: 4.h), + decoration: RoundedRectangleBorder() + .toSmoothCornerDecoration(color: _isOtpComplete ? AppColors.successColor : (hasText ? AppColors.blackBgColor : AppColors.whiteColor), borderRadius: 16), + child: Center( + child: TextField( + controller: _controllers[index], + focusNode: _focusNodes[index], + textAlign: TextAlign.center, + keyboardType: TextInputType.number, + maxLength: 1, + style: TextStyle( + fontSize: 40.fSize, + fontWeight: FontWeight.bold, + color: AppColors.whiteColor, + ), + decoration: InputDecoration( + counterText: '', + filled: true, + fillColor: Colors.transparent, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(18), + borderSide: BorderSide.none, + ), + ), + onChanged: (v) => _onOtpChanged(index, v), + ), + ), + ); + }, + ); + }), + ), + ), + + const SizedBox(height: 32), + + // Resend OTP + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text("Didn't receive it? "), + if (_resendTime > 0) + Text( + 'resend in (${_resendTime.toString().padLeft(2, '0')}:00). ', + style: const TextStyle(color: Colors.grey), + ) + else + GestureDetector( + onTap: _resendOtp, + child: const Text( + 'Resend', + style: TextStyle( + color: AppColors.primaryRedColor, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } + + void _verifyOtp() { + final otp = _controllers.map((c) => c.text).join(); + debugPrint('Verifying OTP: $otp'); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Verifying OTP: $otp')), + ); + } + + /// Auto fill OTP into text fields + void autoFillOtp(String otp) { + if (otp.length != _otpLength) return; + + for (int i = 0; i < _otpLength; i++) { + _controllers[i].text = otp[i]; + } + + // Move focus to the last field + _focusNodes[_otpLength - 1].requestFocus(); + + // Trigger completion check and color update + _checkOtpCompletion(); + } +} From d1e1154bdb781fdccf12e0a5b3114285a4380734 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 2 Sep 2025 17:00:03 +0300 Subject: [PATCH 6/6] changes --- lib/core/utils/utils.dart | 74 +++++-- lib/extensions/string_extensions.dart | 36 ++-- .../authentication/authentication_repo.dart | 6 +- .../authentication_view_model.dart | 193 +++++++++--------- lib/presentation/authentication/login.dart | 9 +- lib/presentation/authentication/register.dart | 4 +- lib/presentation/home/landing_page.dart | 4 +- .../medical_file/medical_file_page.dart | 1 - .../bottomsheet/generic_bottom_sheet.dart | 2 +- .../dropdown/country_dropdown_widget.dart | 8 +- 10 files changed, 193 insertions(+), 144 deletions(-) diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index bdca5ff..ed4770d 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -13,6 +13,7 @@ import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart'; @@ -59,14 +60,13 @@ class Utils { // )); return !isAddHours ? DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US") - .format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal()) + .format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.toLocal()) : DateFormat('hh:mm a', appState.isArabic() ? "ar_SA" : "en_US") - .format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add( - Duration( - hours: isAddHours ? 3 : 0, - ), - )); - ; + .format(DateTime.tryParse(startTime.contains("T") ? startTime : convertStringToDateTime(startTime))!.add( + Duration( + hours: isAddHours ? 3 : 0, + ), + )); } static String convertStringToDateTime(String dateTimeString) { @@ -209,12 +209,12 @@ class Utils { builder: (BuildContext context) => LoadingDialog(), ) .then((value) { - _isLoadingVisible = false; - }) + _isLoadingVisible = false; + }) .catchError((e) {}) .onError( (error, stackTrace) {}, - ); + ); } static void hideLoading() { @@ -236,11 +236,12 @@ class Utils { showDialog( barrierDismissible: false, context: context, - builder: (cxt) => ConfirmDialog( - title: title!, - message: message!, - onTap: onTap, - ), + builder: (cxt) => + ConfirmDialog( + title: title!, + message: message!, + onTap: onTap, + ), ); } @@ -371,7 +372,9 @@ class Utils { static String formatHijriDateToDisplay(String hijriDateString) { try { // Assuming hijriDateString is in the format yyyy-MM-dd - final datePart = hijriDateString.split("T").first; + final datePart = hijriDateString + .split("T") + .first; final parts = datePart.split('-'); if (parts.length != 3) return ""; @@ -429,8 +432,14 @@ class Utils { void Function(LottieComposition)? onLoaded, }) { return Lottie.asset(assetPath, - height: height ?? MediaQuery.of(context).size.height * 0.26, - width: width ?? MediaQuery.of(context).size.width, + height: height ?? MediaQuery + .of(context) + .size + .height * 0.26, + width: width ?? MediaQuery + .of(context) + .size + .width, fit: fit, alignment: alignment, repeat: repeat, @@ -487,9 +496,13 @@ class Utils { ], ); } + static Future isGoogleServicesAvailable() async { GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability(); - String status = availability.toString().split('.').last; + String status = availability + .toString() + .split('.') + .last; if (status == "success") { return true; } @@ -510,3 +523,26 @@ class Utils { return crypto.md5.convert(utf8.encode(input)).toString(); } } + +class ValidationUtils { + static DialogService dialogService = getIt.get(); + + + static bool isValidatePhoneAndId({ + String? nationalId, + String? phoneNumber + }) { + if (nationalId == null || nationalId.isEmpty) { + dialogService.showErrorDialog(message: "Please enter a valid national ID or file number", onOkPressed: () {}); + return false; + } + + if (phoneNumber == null || phoneNumber.isEmpty) { + dialogService.showErrorDialog(message: "Please enter a valid phone number", onOkPressed: () {}); + return false; + } + return true; + } +} + + diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 187939e..cbfac11 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -235,10 +235,12 @@ extension EmailValidator on String { ); Widget toText36({Color? color, bool isBold = false, bool isCenter = false}) => Text( - this, - textAlign: isCenter ? TextAlign.center : null, - style: TextStyle(height: 47 / 36, color: color ?? AppColors.blackColor, fontSize: 36.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal), - ); + this, + textAlign: isCenter ? TextAlign.center : null, + style: TextStyle(height: 47 / 36, color: color ?? AppColors.blackColor, fontSize: 36.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.w600 : FontWeight.normal), + ); + + Widget toText44({Color? color, bool isBold = false}) => Text( this, @@ -381,53 +383,55 @@ class FontUtils { } } -extension CountryExtension on Country { + +extension CountryExtension on CountryEnum { String get displayName { switch (this) { - case Country.saudiArabia: + case CountryEnum.saudiArabia: return "Kingdom Of Saudi Arabia"; - case Country.unitedArabEmirates: + case CountryEnum.unitedArabEmirates: return "United Arab Emirates"; } } String get nameArabic { switch (this) { - case Country.saudiArabia: + case CountryEnum.saudiArabia: return "المملكة العربية السعودية"; - case Country.unitedArabEmirates: + case CountryEnum.unitedArabEmirates: return "الإمارات العربية المتحدة"; } } String get iconPath { switch (this) { - case Country.saudiArabia: + case CountryEnum.saudiArabia: return AppAssets.ksa; - case Country.unitedArabEmirates: + case CountryEnum.unitedArabEmirates: return AppAssets.uae; } } String get countryCode { switch (this) { - case Country.saudiArabia: + case CountryEnum.saudiArabia: return "966"; - case Country.unitedArabEmirates: + case CountryEnum.unitedArabEmirates: return "971"; } } - static Country fromDisplayName(String name) { + static CountryEnum fromDisplayName(String name) { switch (name) { case "Kingdom Of Saudi Arabia": case "المملكة العربية السعودية": - return Country.saudiArabia; + return CountryEnum.saudiArabia; case "United Arab Emirates": case "الإمارات العربية المتحدة": - return Country.unitedArabEmirates; + return CountryEnum.unitedArabEmirates; default: throw Exception("Invalid country name"); } } } + diff --git a/lib/features/authentication/authentication_repo.dart b/lib/features/authentication/authentication_repo.dart index 7307013..0be6eaf 100644 --- a/lib/features/authentication/authentication_repo.dart +++ b/lib/features/authentication/authentication_repo.dart @@ -20,8 +20,7 @@ abstract class AuthenticationRepo { required CheckPatientAuthenticationReq checkPatientAuthenticationReq, }); - Future>> sendActivationCodeRegister( - {required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}); + Future>> sendActivationCodeRegister({required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}); } class AuthenticationRepoImp implements AuthenticationRepo { @@ -114,8 +113,7 @@ class AuthenticationRepoImp implements AuthenticationRepo { } @override - Future>> sendActivationCodeRegister( - {required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}) async { + Future>> sendActivationCodeRegister({required CheckPatientAuthenticationReq checkPatientAuthenticationReq, String? languageID}) async { int isOutKsa = (checkPatientAuthenticationReq.zipCode == '966' || checkPatientAuthenticationReq.zipCode == '+966') ? 0 : 1; //TODO : We will use all these from AppState directly in the ApiClient diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index ed77aca..f192db2 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/request_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_patient_authentication_request_model.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; @@ -23,9 +24,15 @@ class AuthenticationViewModel extends ChangeNotifier { final TextEditingController nationalIdController = TextEditingController(); final TextEditingController phoneNumberController = TextEditingController(); + void login() { + if (ValidationUtils.isValidatePhoneAndId(nationalId: nationalIdController.text, phoneNumber: phoneNumberController.text)) { + } else { + + } + } + Future selectDeviceImei({Function(dynamic)? onSuccess, Function(String)? onError}) async { - String firebaseToken = - "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc"; + String firebaseToken = "dOGRRszQQMGe_9wA5Hx3kO:APA91bFV5IcIJXvcCXXk0tc2ddtZgWwCPq7sGSuPr-YW7iiJpQZKgFGN9GAzCVOWL8MfheaP1slE8MdxB7lczdPBGdONQ7WbMmhgHcsUCUktq-hsapGXXqc"; final result = await authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); result.fold( @@ -40,96 +47,96 @@ class AuthenticationViewModel extends ChangeNotifier { ); } - // Future checkUserAuthentication({Function(dynamic)? onSuccess, Function(String)? onError}) async { - // CheckPatientAuthenticationReq checkPatientAuthenticationReq = RequestUtils.getCommonRequestWelcome( - // phoneNumber: '0567184134', - // otpTypeEnum: OTPTypeEnum.sms, - // deviceToken: 'dummyDeviceToken123', - // patientOutSA: true, - // loginTokenID: 'dummyLoginToken456', - // registeredData: null, - // patientId: 12345, - // nationIdText: '1234567890', - // countryCode: 'SA', - // ); - // - // final result = await authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); - // result.fold( - // (failure) async => await errorHandlerService.handleError(failure: failure), - // (apiResponse) { - // if (apiResponse.data['isSMSSent']) { - // // TODO: set this in AppState - // // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); - // // loginTokenID = value['LogInTokenID'], - // // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), - // sendActivationCode(type); - // } else { - // if (apiResponse.data['IsAuthenticated']) { - // checkActivationCode(onWrongActivationCode: (String? message) {}); - // } - // } - // }, - // ); - // } +// Future checkUserAuthentication({Function(dynamic)? onSuccess, Function(String)? onError}) async { +// CheckPatientAuthenticationReq checkPatientAuthenticationReq = RequestUtils.getCommonRequestWelcome( +// phoneNumber: '0567184134', +// otpTypeEnum: OTPTypeEnum.sms, +// deviceToken: 'dummyDeviceToken123', +// patientOutSA: true, +// loginTokenID: 'dummyLoginToken456', +// registeredData: null, +// patientId: 12345, +// nationIdText: '1234567890', +// countryCode: 'SA', +// ); +// +// final result = await authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); +// result.fold( +// (failure) async => await errorHandlerService.handleError(failure: failure), +// (apiResponse) { +// if (apiResponse.data['isSMSSent']) { +// // TODO: set this in AppState +// // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']); +// // loginTokenID = value['LogInTokenID'], +// // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), +// sendActivationCode(type); +// } else { +// if (apiResponse.data['IsAuthenticated']) { +// checkActivationCode(onWrongActivationCode: (String? message) {}); +// } +// } +// }, +// ); +// } - // Future sendActivationCode({required OTPTypeEnum otpTypeEnum}) async { - // var request = RequestUtils.getCommonRequestAuthProvider( - // otpTypeEnum: otpTypeEnum, - // registeredData: null, - // deviceToken: "dummyLoginToken456", - // mobileNumber: "0567184134", - // zipCode: "SA", - // patientOutSA: true, - // loginTokenID: "dummyLoginToken456", - // selectedOption: selectedOption, - // patientId: 12345, - // ); - // - // request.sMSSignature = await SMSOTP.getSignature(); - // selectedOption = type; - // // GifLoaderDialogUtils.showMyDialog(context); - // if (healthId != null || isDubai) { - // if (!isDubai) { - // request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob)); - // } - // request.healthId = healthId; - // request.isHijri = isHijri; - // await this.apiClient.sendActivationCodeRegister(request).then((result) { - // // GifLoaderDialogUtils.hideDialog(context); - // if (result != null && result['isSMSSent'] == true) { - // this.startSMSService(type); - // } - // }).catchError((r) { - // GifLoaderDialogUtils.hideDialog(context); - // context.showBottomSheet( - // child: ExceptionBottomSheet( - // message: r.toString(), - // onOkPressed: () { - // Navigator.of(context).pop(); - // }, - // )); - // // AppToast.showErrorToast(message: r); - // }); - // } else { - // request.dob = ""; - // request.healthId = ""; - // request.isHijri = 0; - // await this.authService.sendActivationCode(request).then((result) { - // GifLoaderDialogUtils.hideDialog(context); - // if (result != null && result['isSMSSent'] == true) { - // this.startSMSService(type); - // } - // }).catchError((r) { - // GifLoaderDialogUtils.hideDialog(context); - // context.showBottomSheet( - // child: ExceptionBottomSheet( - // message: r.toString(), - // onOkPressed: () { - // Navigator.of(context).pop(); - // }, - // )); - // // AppToast.showErrorToast(message: r.toString()); - // }); - // } - // } +// Future sendActivationCode({required OTPTypeEnum otpTypeEnum}) async { +// var request = RequestUtils.getCommonRequestAuthProvider( +// otpTypeEnum: otpTypeEnum, +// registeredData: null, +// deviceToken: "dummyLoginToken456", +// mobileNumber: "0567184134", +// zipCode: "SA", +// patientOutSA: true, +// loginTokenID: "dummyLoginToken456", +// selectedOption: selectedOption, +// patientId: 12345, +// ); +// +// request.sMSSignature = await SMSOTP.getSignature(); +// selectedOption = type; +// // GifLoaderDialogUtils.showMyDialog(context); +// if (healthId != null || isDubai) { +// if (!isDubai) { +// request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob)); +// } +// request.healthId = healthId; +// request.isHijri = isHijri; +// await this.apiClient.sendActivationCodeRegister(request).then((result) { +// // GifLoaderDialogUtils.hideDialog(context); +// if (result != null && result['isSMSSent'] == true) { +// this.startSMSService(type); +// } +// }).catchError((r) { +// GifLoaderDialogUtils.hideDialog(context); +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: r.toString(), +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// )); +// // AppToast.showErrorToast(message: r); +// }); +// } else { +// request.dob = ""; +// request.healthId = ""; +// request.isHijri = 0; +// await this.authService.sendActivationCode(request).then((result) { +// GifLoaderDialogUtils.hideDialog(context); +// if (result != null && result['isSMSSent'] == true) { +// this.startSMSService(type); +// } +// }).catchError((r) { +// GifLoaderDialogUtils.hideDialog(context); +// context.showBottomSheet( +// child: ExceptionBottomSheet( +// message: r.toString(), +// onOkPressed: () { +// Navigator.of(context).pop(); +// }, +// )); +// // AppToast.showErrorToast(message: r.toString()); +// }); +// } +// } } diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index f74348f..2771b36 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/context_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/authentication/register.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; @@ -14,6 +15,7 @@ import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:provider/provider.dart'; class LoginScreen extends StatefulWidget { @override @@ -33,6 +35,7 @@ class _LoginScreen extends State { @override Widget build(BuildContext context) { + AuthenticationViewModel authVm = context.read(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, appBar: CustomAppBar( @@ -61,7 +64,7 @@ class _LoginScreen extends State { TextInputWidget( labelText: "${LocaleKeys.nationalId.tr()} / ${LocaleKeys.fileNo.tr()}", hintText: "xxxxxxxxx", - controller: TextEditingController(), + controller: authVm.nationalIdController, keyboardType: TextInputType.number, isEnable: true, prefix: null, @@ -80,7 +83,7 @@ class _LoginScreen extends State { icon: AppAssets.login1, iconColor: Colors.white, onPressed: () { - showLoginModel(context: context); + showLoginModel(context: context, textController: authVm.phoneNumberController); // if (nationIdController.text.isNotEmpty) { // } else { @@ -150,7 +153,7 @@ class _LoginScreen extends State { child: GenericBottomSheet( countryCode: "966", initialPhoneNumber: "", - textController: TextEditingController(), + textController: textController, isEnableCountryDropdown: true, onCountryChange: (value) {}, onChange: (String? value) {}, diff --git a/lib/presentation/authentication/register.dart b/lib/presentation/authentication/register.dart index 0fcad5c..b445631 100644 --- a/lib/presentation/authentication/register.dart +++ b/lib/presentation/authentication/register.dart @@ -85,8 +85,8 @@ class _RegisterNew extends State { child: Column( children: [ CustomCountryDropdown( - countryList: Country.values, - onCountryChange: (Country? value) {}, + countryList: CountryEnum.values, + onCountryChange: (CountryEnum? value) {}, isRtl: Directionality.of(context) == TextDirection.LTR, ).withVerticalPadding(8.h), Divider(height: 1.h), diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 55abb00..f2017b2 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -51,7 +51,9 @@ class _LandingPageState extends State { CustomButton( text: LocaleKeys.loginOrRegister.tr(context: context), onPressed: () async { - await authenticationViewModel.selectDeviceImei(); + + // await authenticationViewModel.selectDeviceImei(); + Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => LoginScreen())); }, backgroundColor: Color(0xffFEE9EA), borderColor: Color(0xffFEE9EA), diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 55ca84b..ba274bf 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -40,7 +40,6 @@ class MedicalFilePage extends StatelessWidget { isAllowLeadingIcon: true, padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h), leadingIcon: AppAssets.student_card, - hasError: true, ), SizedBox(height: 16.h), Container( diff --git a/lib/widgets/bottomsheet/generic_bottom_sheet.dart b/lib/widgets/bottomsheet/generic_bottom_sheet.dart index eefb187..1d07099 100644 --- a/lib/widgets/bottomsheet/generic_bottom_sheet.dart +++ b/lib/widgets/bottomsheet/generic_bottom_sheet.dart @@ -17,7 +17,7 @@ class GenericBottomSheet extends StatefulWidget { final List buttons; TextEditingController? textController; final bool isForEmail; - Function(Country)? onCountryChange; + Function(CountryEnum)? onCountryChange; final bool isEnableCountryDropdown; final bool isFromSavedLogin; Function(String?)? onChange; diff --git a/lib/widgets/dropdown/country_dropdown_widget.dart b/lib/widgets/dropdown/country_dropdown_widget.dart index 81ac60a..5e4bddf 100644 --- a/lib/widgets/dropdown/country_dropdown_widget.dart +++ b/lib/widgets/dropdown/country_dropdown_widget.dart @@ -7,8 +7,8 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; class CustomCountryDropdown extends StatefulWidget { - final List countryList; - final Function(Country)? onCountryChange; + final List countryList; + final Function(CountryEnum)? onCountryChange; final bool isRtl; const CustomCountryDropdown({ @@ -23,14 +23,14 @@ class CustomCountryDropdown extends StatefulWidget { } class _CustomCountryDropdownState extends State { - Country? selectedCountry; + CountryEnum? selectedCountry; late OverlayEntry _overlayEntry; bool _isDropdownOpen = false; @override void initState() { super.initState(); - selectedCountry = Country.saudiArabia; + selectedCountry = CountryEnum.saudiArabia; } @override