From 07d4aadc4e1218b1c48d66915ae4a227ac0b6fa4 Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Tue, 27 Sep 2022 09:46:31 +0300 Subject: [PATCH 1/3] added survey screen --- assets/images/bad.svg | 3 + assets/images/good.svg | 3 + assets/images/normal.svg | 3 + assets/images/poor.svg | 3 + assets/images/xcellent.svg | 3 + assets/langs/ar-SA.json | 4 + assets/langs/en-US.json | 4 + lib/config/routes.dart | 3 + lib/extensions/string_extensions.dart | 5 ++ lib/extensions/widget_extensions.dart | 7 +- lib/generated/codegen_loader.g.dart | 8 ++ lib/generated/locale_keys.g.dart | 4 + lib/ui/landing/survey_screen.dart | 111 ++++++++++++++++++++++++++ lib/ui/landing/widget/app_drawer.dart | 4 +- pubspec.yaml | 1 + 15 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 assets/images/bad.svg create mode 100644 assets/images/good.svg create mode 100644 assets/images/normal.svg create mode 100644 assets/images/poor.svg create mode 100644 assets/images/xcellent.svg create mode 100644 lib/ui/landing/survey_screen.dart diff --git a/assets/images/bad.svg b/assets/images/bad.svg new file mode 100644 index 0000000..1a71742 --- /dev/null +++ b/assets/images/bad.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/good.svg b/assets/images/good.svg new file mode 100644 index 0000000..690d4d0 --- /dev/null +++ b/assets/images/good.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/normal.svg b/assets/images/normal.svg new file mode 100644 index 0000000..1885ab6 --- /dev/null +++ b/assets/images/normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/poor.svg b/assets/images/poor.svg new file mode 100644 index 0000000..95ce430 --- /dev/null +++ b/assets/images/poor.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/xcellent.svg b/assets/images/xcellent.svg new file mode 100644 index 0000000..eab98b3 --- /dev/null +++ b/assets/images/xcellent.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index b4f7eb6..8dea962 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -402,6 +402,10 @@ "itemCreation": "أنشاء عنصر", "stamp": "ختم", "addFavoriteList": "هل تريد اضافة {name} لقائمة المفضله", + "feedbackUserExperience": "هذا للحصول على تعليقات حول تجربة المستخدم", + "rateUI": ".1 كيف تريد تقييم التطبيق", + "submitSurvey":"ارسال الاستبيان", + "typeHere": "اكتب هنا", "profile": { "reset_password": { "label": "Reset Password", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 7e0d3f7..c365621 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -402,6 +402,10 @@ "itemCreation": "Item Creation", "stamp": "Stamp", "addFavoriteList": "Do you want to add {name} in your favorite list", + "feedbackUserExperience": "This is to get the feedback about the user experience", + "rateUI": "1. How would you rate this UI?", + "submitSurvey":"Submit Survey", + "typeHere": "Type here", "profile": { "reset_password": { "label": "Reset Password", diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 5f78298..544f9ac 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -4,6 +4,7 @@ import 'package:mohem_flutter_app/ui/attendance/monthly_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/attendance/vacation_rule_screen.dart'; import 'package:mohem_flutter_app/ui/bottom_sheets/attendence_details_bottom_sheet.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; +import 'package:mohem_flutter_app/ui/landing/survey_screen.dart'; import 'package:mohem_flutter_app/ui/landing/today_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/leave_balance/add_leave_balance_screen.dart'; import 'package:mohem_flutter_app/ui/leave_balance/leave_balance_screen.dart'; @@ -76,6 +77,7 @@ class AppRoutes { static const String subMenuScreen = "/submenuScreen"; static const String addEitScreen = "/addeitScreen"; static const String initialRoute = login; + static const String survey = "/survey"; //Work List static const String workList = "/workList"; @@ -162,6 +164,7 @@ class AppRoutes { verifyLogin: (context) => VerifyLoginScreen(), verifyLastLogin: (context) => VerifyLastLoginScreen(), dashboard: (context) => DashboardScreen(), + survey: (context) => SurveyScreen(), subMenuScreen: (context) => SubMenuScreen(), newPassword: (context) => NewPasswordScreen(), diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 556d011..5fa9f8b 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -78,6 +78,11 @@ extension EmailValidator on String { style: TextStyle(fontSize: 18, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.08), ); + Widget toText19({Color? color, bool isBold = false}) => Text( + this, + style: TextStyle(fontSize: 19, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.14), + ); + Widget toText20({Color? color, bool isBold = false}) => Text( this, style: TextStyle(fontSize: 20, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4), diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index dc3bdb7..fb39dd7 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -55,7 +55,7 @@ extension WidgetExtensions on Widget { offset: const Offset(0, -3), ), ], - ), + ),alignment: Alignment.center, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, @@ -69,7 +69,7 @@ extension WidgetExtensions on Widget { ); } - Widget objectContainerBorderView({String title = "", String note = "", bool disablePadding = false, double radius = 15, Color? color, Color borderColor = MyColors.lightGreyEFColor}) { + Widget objectContainerBorderView({String title = "", String note = "", bool disablePadding = false, double radius = 15, Color? color, Color borderColor = MyColors.lightGreyEFColor,bool disableWidth = false,bool isAlignment = false }) { return Container( padding: disablePadding ? EdgeInsets.zero : const EdgeInsets.only(top: 15, bottom: 15, left: 14, right: 14), decoration: BoxDecoration( @@ -77,9 +77,10 @@ extension WidgetExtensions on Widget { color: color, border: Border.all( color: borderColor, - width: 1, + width: disableWidth ? 2 : 1, ), ), + alignment: isAlignment? Alignment.center : null, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index c4e2891..f48e420 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -418,6 +418,10 @@ class CodegenLoader extends AssetLoader{ "itemCreation": "أنشاء عنصر", "stamp": "ختم", "addFavoriteList": "هل تريد اضافة {name} لقائمة المفضله", + "feedbackUserExperience": "هذا للحصول على تعليقات حول تجربة المستخدم", + "rateUI": ".1 كيف تريد تقييم التطبيق", + "Submit Survey": "ارسال الاستبيان", + "typeHere": "اكتب هنا", "profile": { "reset_password": { "label": "Reset Password", @@ -856,6 +860,10 @@ static const Map en_US = { "itemCreation": "Item Creation", "stamp": "Stamp", "addFavoriteList": "Do you want to add {name} in your favorite list", + "feedbackUserExperience": "This is to get the feedback about the user experience", + "rateUI": "1. How would you rate this UI?", + "Submit Survey": "Submit Survey", + "typeHere": "Type here", "profile": { "reset_password": { "label": "Reset Password", diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 16ceab4..1bbf8b2 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -403,6 +403,10 @@ abstract class LocaleKeys { static const itemCreation = 'itemCreation'; static const stamp = 'stamp'; static const addFavoriteList = 'addFavoriteList'; + static const feedbackUserExperience = 'feedbackUserExperience'; + static const rateUI = 'rateUI'; + static const submitSurvey = 'submitSurvey'; + static const typeHere = 'typeHere'; static const profile_reset_password_label = 'profile.reset_password.label'; static const profile_reset_password_username = 'profile.reset_password.username'; static const profile_reset_password_password = 'profile.reset_password.password'; diff --git a/lib/ui/landing/survey_screen.dart b/lib/ui/landing/survey_screen.dart new file mode 100644 index 0000000..16e6cec --- /dev/null +++ b/lib/ui/landing/survey_screen.dart @@ -0,0 +1,111 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:flutter_rating_bar/flutter_rating_bar.dart'; +import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; + +class SurveyScreen extends StatefulWidget { + const SurveyScreen({Key? key}) : super(key: key); + + @override + _SurveyScreenState createState() => _SurveyScreenState(); +} + +class _SurveyScreenState extends State { + String reviewText = ""; + int _selectedIndex = -1; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: MyColors.backgroundColor, + body: Column( + children: [ + Expanded( + child: ListView( + scrollDirection: Axis.vertical, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 124.height, + LocaleKeys.feedbackUserExperience.tr().toText19(), + 27.height, + LocaleKeys.rateUI.tr().toText16(), + 22.height, + Row( + children: [ + RatingBar.builder( + initialRating: 3, + minRating: 1, + direction: Axis.horizontal, + allowHalfRating: true, + itemCount: 5, + itemPadding: EdgeInsets.symmetric(horizontal: 12), + itemBuilder: (context, _) => Icon( + Icons.star, + color: Colors.amber, + ), + onRatingUpdate: (rating) {}, + ) + ], + ).paddingOnly(left: 22, right: 22, top: 12, bottom: 12).objectContainerView(disablePadding: true), + 39.height, + LocaleKeys.rateUI.tr().toText16(), + 10.height, + GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5, crossAxisSpacing: 7, mainAxisSpacing: 7), + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.only(top: 0), + shrinkWrap: true, + children: [ + optionUI("poor.svg", 0), + optionUI("bad.svg", 1), + optionUI("normal.svg", 2), + optionUI("good.svg", 3), + optionUI("xcellent.svg", 4), + ], + ), + 27.height, + DynamicTextFieldWidget( + LocaleKeys.description.tr(), + LocaleKeys.typeHere.tr(), + lines: 3, + ), + 150.height + ], + ).paddingOnly(left: 21, right: 21), + ], + )), + DefaultButton(LocaleKeys.submitSurvey.tr(), () async {}).insideContainer, + ], + )); + } + + Widget optionUI(String icon, int index) { + return (_selectedIndex == index + ? SvgPicture.asset( + 'assets/images/' + icon, + height: 32, + width: 32, + ).objectContainerBorderView(disablePadding: true, borderColor: MyColors.textMixColor, disableWidth: true, isAlignment: true) + : SvgPicture.asset( + 'assets/images/' + icon, + height: 32, + width: 32, + ).objectContainerView( + disablePadding: true, + )) + .onPress(() { + _selectedIndex = index; + setState(() {}); + }); + } +} diff --git a/lib/ui/landing/widget/app_drawer.dart b/lib/ui/landing/widget/app_drawer.dart index 2971b24..ea66aed 100644 --- a/lib/ui/landing/widget/app_drawer.dart +++ b/lib/ui/landing/widget/app_drawer.dart @@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; @@ -83,7 +84,8 @@ class _AppDrawerState extends State { }), menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())), menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog())), - menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {}), + menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,); + },), ], ).expanded, const Divider( diff --git a/pubspec.yaml b/pubspec.yaml index ee15638..e4f6dfc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -73,6 +73,7 @@ dependencies: qr_flutter: ^4.0.0 url_launcher: ^6.0.15 share: 2.0.4 + flutter_rating_bar: ^4.0.1 dev_dependencies: flutter_test: From 8ce3a09375c6382c84d458da710dfac66f8802ba Mon Sep 17 00:00:00 2001 From: devmirza121 Date: Tue, 27 Sep 2022 14:21:21 +0300 Subject: [PATCH 2/3] Login with face and finger fixed --- assets/langs/ar-SA.json | 1 + assets/langs/en-US.json | 1 + lib/api/login_api_client.dart | 2 +- lib/dialogs/otp_dialog.dart | 2 +- lib/generated/locale_keys.g.dart | 1 + lib/ui/login/verify_last_login_screen.dart | 157 ++++++++++++-------- lib/ui/login/verify_login_screen.dart | 158 ++++++++++++--------- 7 files changed, 196 insertions(+), 126 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index b4f7eb6..bf408fc 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -11,6 +11,7 @@ "lastLoginDetails": "تفاصيل تسجيل الدخول الأخير:", "verificationType": "نوع التحقق:", "pleaseVerify": "ارجوك تحقق", + "pleaseVerifyForBio": "الرجاء التحقق من تسجيل الدخول باستخدام أحد هذه الخيارات", "verifyThroughFace": "تحقق من خلال الوجه", "verifyThroughFingerprint": "تحقق من خلال بصمة الإصبع", "verifyThroughSMS": "تحقق من خلال الرسائل القصيرة", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 7e0d3f7..d128c31 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -11,6 +11,7 @@ "lastLoginDetails": "Last Login Details:", "verificationType": "Verification Type:", "pleaseVerify": "Please Verify", + "pleaseVerifyForBio": "Please verify login with one of the following options", "verifyThroughFace": "Verify Through Face", "verifyThroughFingerprint": "Verify Through Fingerprint", "verifyThroughSMS": "Verify Through SMS", diff --git a/lib/api/login_api_client.dart b/lib/api/login_api_client.dart index 79b7783..3cdda6d 100644 --- a/lib/api/login_api_client.dart +++ b/lib/api/login_api_client.dart @@ -23,7 +23,7 @@ class LoginApiClient { postParams["DeviceType"] = deviceType; return await ApiClient().postJsonForObject((json) { GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return (responseData.mohemmGetMobileLoginInfoList?.length ?? 0) > 0 ? responseData.mohemmGetMobileLoginInfoList!.first : null; + return (responseData.mohemmGetMobileLoginInfoList?.length ?? 0) > 0 ? (responseData.mohemmGetMobileLoginInfoList!.first) : null; }, url, postParams); } diff --git a/lib/dialogs/otp_dialog.dart b/lib/dialogs/otp_dialog.dart index b761f00..bea34f3 100644 --- a/lib/dialogs/otp_dialog.dart +++ b/lib/dialogs/otp_dialog.dart @@ -87,7 +87,7 @@ class OtpDialog { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SvgPicture.asset( - type == 1 ? "assets/images/login/verify_sms.svg" : "assets/images/login/verify_whatsapp.svg", + type == 1 ? "assets/images/login/verify_sms.svg" :type==2? "assets/images/login/verify_thumb.svg":type==3? "assets/images/login/verify_face.svg":'assets/images/login/verify_whatsapp.svg', height: 50, width: 50, ), diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 16ceab4..031378d 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -13,6 +13,7 @@ abstract class LocaleKeys { static const lastLoginDetails = 'lastLoginDetails'; static const verificationType = 'verificationType'; static const pleaseVerify = 'pleaseVerify'; + static const pleaseVerifyForBio = 'pleaseVerifyForBio'; static const verifyThroughFace = 'verifyThroughFace'; static const verifyThroughFingerprint = 'verifyThroughFingerprint'; static const verifyThroughSMS = 'verifyThroughSMS'; diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index f47b2a4..faaf76e 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -22,6 +22,11 @@ import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +// WhatsApp 4 +// SMS 1 +// Face ID 3 +// Finger Print 2 + class VerifyLastLoginScreen extends StatefulWidget { VerifyLastLoginScreen({Key? key}) : super(key: key); @@ -36,6 +41,10 @@ class _VerifyLastLoginScreenState extends State { List _availableBioMetricType = []; GetMobileLoginInfoListModel? mobileLoginInfoListModel; + //For face and finger print verification + int selectedFlag = 0; + bool isNeedVerifyWithFaceIDAndBiometrics = false; + @override void initState() { _getAvailableBiometrics(); @@ -47,6 +56,7 @@ class _VerifyLastLoginScreenState extends State { Widget build(BuildContext context) { mobileLoginInfoListModel ??= ModalRoute.of(context)!.settings.arguments as GetMobileLoginInfoListModel; String empName = AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!; + print("selectedFlag1: " + mobileLoginInfoListModel!.loginType.toString()); return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, @@ -110,15 +120,16 @@ class _VerifyLastLoginScreenState extends State { ), ), LocaleKeys.pleaseVerify.tr().toText16(), + if (isNeedVerifyWithFaceIDAndBiometrics) LocaleKeys.pleaseVerifyForBio.tr().toText12(), GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13, mainAxisSpacing: 9), physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.only(top: 9), shrinkWrap: true, children: [ - getButton(3), + if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(3), + if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(2), getButton(4), - getButton(2), getButton(1), ], ) @@ -164,7 +175,7 @@ class _VerifyLastLoginScreenState extends State { DefaultButton( LocaleKeys.useAnotherAccount.tr(), () { - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false,arguments: false); + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false, arguments: false); }, ).insideContainer, ], @@ -221,62 +232,32 @@ class _VerifyLastLoginScreenState extends State { // isMoreOption = true; }); } else { - try { - Utils.showLoading(context); - if (_flag == 4 || _flag == 3) { - bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); - if (authenticateWithFaceAndTouchID) { - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); - return; + if (_flag == 2 || _flag == 3) { + bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + if (!authenticateWithFaceAndTouchID) { + return; + } else { + if (mobileLoginInfoListModel!.loginType == 2 || mobileLoginInfoListModel!.loginType == 3) { + bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + if (!authenticateWithFaceAndTouchID) { + return; + } else { + performApiCall(_title, _icon, _flag, isDirectLogin: true); + } } else { - Utils.hideLoading(context); - return; + isNeedVerifyWithFaceIDAndBiometrics = true; + selectedFlag = _flag; + setState(() { + return; + }); } } - await LoginApiClient().checkMobileAppVersion(); - await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); - BasicMemberInformationModel? memberInformationModel = await LoginApiClient().mohemmSendActivationCodeByOTPNotificationType( - checkBiometricIsAvailable(BiometricType.fingerprint) ? 1 : 0, AppState().memberLoginList?.pMOBILENUMBER, _flag, AppState().getUserName); - Utils.hideLoading(context); - OtpDialog( - context, - _flag, - int.tryParse(AppState().memberLoginList?.pMOBILENUMBER ?? ""), - (value) async { - Utils.showLoading(context); - try { - GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(false, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); - GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( - AppState().memberLoginList?.pEMAILADDRESS ?? "", - genericResponseModel?.pSESSIONID ?? 0, - genericResponseModel?.memberInformationList![0].eMPLOYEENAME ?? "", - _flag, - AppState().memberLoginList?.pMOBILENUMBER ?? "", - AppState().getUserName!, - mobileLoginInfoListModel!.deviceToken!, - Platform.isAndroid ? "android" : "ios"); - if (genericResponseModel?.errorMessage != null) { - Utils.showToast(genericResponseModel?.errorMessage ?? ""); - // Navigator.pop(context); - } - Utils.hideLoading(context); - Navigator.pop(context); - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); - } catch (ex) { - Utils.hideLoading(context); - Utils.handleException(ex, context, null); - } - }, - () => { - Navigator.pop(context), - }, - ).displayDialog(context); - } catch (ex) { - Utils.hideLoading(context); - Utils.handleException(ex, context, null); + } else { + if (isNeedVerifyWithFaceIDAndBiometrics) + performApiCall(_title, _icon, selectedFlag); + else + performApiCall(_title, _icon, _flag); } - - // authenticateUser(_flag, isActive: _loginIndex); } }, child: Container( @@ -305,14 +286,14 @@ class _VerifyLastLoginScreenState extends State { Widget getButton(int flag) { switch (flag) { - case 2: - return _loginOptionButton(LocaleKeys.verifyThroughWhatsapp.tr(), 'assets/images/login/verify_whatsapp.svg', flag, null); case 1: return _loginOptionButton(LocaleKeys.verifyThroughSMS.tr(), 'assets/images/login/verify_sms.svg', flag, null); - case 4: + case 2: return _loginOptionButton(LocaleKeys.verifyThroughFingerprint.tr(), 'assets/images/login/verify_thumb.svg', flag, BiometricType.fingerprint.index); case 3: return _loginOptionButton(LocaleKeys.verifyThroughFace.tr(), 'assets/images/login/verify_face.svg', flag, BiometricType.face.index); + case 4: + return _loginOptionButton(LocaleKeys.verifyThroughWhatsapp.tr(), 'assets/images/login/verify_whatsapp.svg', flag, null); default: return const SizedBox(); } @@ -328,6 +309,66 @@ class _VerifyLastLoginScreenState extends State { } return isAvailable; } + + Future performApiCall(String _title, String _icon, int _flag, {bool isDirectLogin = false}) async { + try { + if (isDirectLogin) + setState(() { + Utils.showLoading(context); + }); + else + Utils.showLoading(context); + await LoginApiClient().checkMobileAppVersion(); + await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); + if (!isDirectLogin) + BasicMemberInformationModel? memberInformationModel = await LoginApiClient() + .mohemmSendActivationCodeByOTPNotificationType(checkBiometricIsAvailable(BiometricType.fingerprint) ? 1 : 0, AppState().memberLoginList?.pMOBILENUMBER, _flag, AppState().getUserName); + if (isDirectLogin) performDirectApiCall(_title, _icon, _flag, ""); + if (!isDirectLogin) Utils.hideLoading(context); + if (!isDirectLogin) + OtpDialog( + context, + _flag, + int.tryParse(AppState().memberLoginList?.pMOBILENUMBER ?? ""), + (value) async { + Utils.showLoading(context); + performDirectApiCall(_title, _icon, _flag, value); + }, + () => { + Navigator.pop(context), + }, + ).displayDialog(context); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + Future performDirectApiCall(String _title, String _icon, int _flag, String value, {bool isDirectLogin = false}) async { + try { + GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(false, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); + GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( + AppState().memberLoginList?.pEMAILADDRESS ?? "", + genericResponseModel?.pSESSIONID ?? 0, + genericResponseModel?.memberInformationList![0].eMPLOYEENAME ?? "", + _flag, + AppState().memberLoginList?.pMOBILENUMBER ?? "", + AppState().getUserName!, + mobileLoginInfoListModel!.deviceToken!, + Platform.isAndroid ? "android" : "ios"); + if (genericResponseModel?.errorMessage != null) { + Utils.showToast(genericResponseModel?.errorMessage ?? ""); + // Navigator.pop(context); + } + Utils.hideLoading(context); + Navigator.pop(context); + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + // // formatDate(date) { // return date; diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index d03fb71..1d66df9 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -13,6 +13,7 @@ import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/dialogs/otp_dialog.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/basic_member_information_model.dart'; @@ -20,6 +21,11 @@ import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; import 'package:mohem_flutter_app/models/privilege_list_model.dart'; +// WhatsApp 4 +// SMS 1 +// Face ID 3 +// Finger Print 2 + class VerifyLoginScreen extends StatefulWidget { VerifyLoginScreen({Key? key}) : super(key: key); @@ -35,6 +41,10 @@ class _VerifyLoginScreenState extends State { String? firebaseToken; + //For face and finger print verification + int selectedFlag = 0; + bool isNeedVerifyWithFaceIDAndBiometrics = false; + @override void initState() { _getAvailableBiometrics(); @@ -59,15 +69,16 @@ class _VerifyLoginScreenState extends State { physics: const BouncingScrollPhysics(), children: [ LocaleKeys.pleaseVerify.tr().toText16(), + if (isNeedVerifyWithFaceIDAndBiometrics) LocaleKeys.pleaseVerifyForBio.tr().toText12(), GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13, mainAxisSpacing: 9), physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.only(top: 9), shrinkWrap: true, children: [ - getButton(3), + if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(3), + if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(2), getButton(4), - getButton(2), getButton(1), ], ) @@ -500,6 +511,7 @@ class _VerifyLoginScreenState extends State { // } // + Future loginWithFaceIDAndBiometrics() async { IOSAuthMessages iosStrings = const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID'); @@ -525,69 +537,22 @@ class _VerifyLoginScreenState extends State { // isMoreOption = true; }); } else { - try { - Utils.showLoading(context); - if (_flag == 4 || _flag == 3) { - bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); - if (!authenticateWithFaceAndTouchID) { + if (_flag == 2 || _flag == 3) { + bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + if (!authenticateWithFaceAndTouchID) { + return; + } else { + isNeedVerifyWithFaceIDAndBiometrics = true; + selectedFlag = _flag; + setState(() { return; - } + }); } - await LoginApiClient().checkMobileAppVersion(); - await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); - BasicMemberInformationModel? memberInformationModel = await LoginApiClient().mohemmSendActivationCodeByOTPNotificationType( - checkBiometricIsAvailable(BiometricType.fingerprint) ? 1 : 0, AppState().memberLoginList?.pMOBILENUMBER, _flag, AppState().getUserName); - Utils.hideLoading(context); - OtpDialog( - context, - _flag, - int.tryParse(AppState().memberLoginList?.pMOBILENUMBER ?? ""), - (value) async { - Utils.showLoading(context); - try { - GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(true, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); - GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( - AppState().memberLoginList?.pEMAILADDRESS ?? "", - genericResponseModel?.pSESSIONID ?? 0, - genericResponseModel?.memberInformationList![0].eMPLOYEENAME ?? "", - _flag, - AppState().memberLoginList?.pMOBILENUMBER ?? "", - AppState().getUserName!, - firebaseToken!, - Platform.isAndroid ? "android" : "ios"); - if (genericResponseModel?.errorMessage != null) { - Utils.showToast(genericResponseModel?.errorMessage ?? ""); - } else { - AppState().setPrivilegeListModel = genericResponseModel!.privilegeList ?? []; - AppState().setMemberInformationListModel = genericResponseModel.memberInformationList?.first; - MemberInformationListModel.saveToPrefs(genericResponseModel.memberInformationList ?? []); - genericResponseModel.privilegeList!.forEach((element) { - print(element.serviceName.toString() + " " + element.previlege.toString()); // Check availability - }); - PrivilegeListModel.saveToPrefs(genericResponseModel.privilegeList ?? []); - AppState().setMohemmWifiSSID = genericResponseModel.mohemmWifiSSID; - AppState().setMohemmWifiPassword = genericResponseModel.mohemmWifiPassword; - Utils.saveStringFromPrefs(SharedPrefsConsts.username, AppState().getUserName!); - Utils.saveStringFromPrefs(SharedPrefsConsts.password, AppState().password!); - Utils.saveStringFromPrefs(SharedPrefsConsts.mohemmWifiSSID, genericResponseModel.mohemmWifiSSID!); - Utils.saveStringFromPrefs(SharedPrefsConsts.mohemmWifiPassword, genericResponseModel.mohemmWifiPassword!); - } - Utils.hideLoading(context); - Navigator.pop(context); - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); - } catch (ex) { - print(ex); - Utils.hideLoading(context); - Utils.handleException(ex, context, null); - } - }, - () => { - Navigator.pop(context), - }, - ).displayDialog(context); - } catch (ex) { - Utils.hideLoading(context); - Utils.handleException(ex, context, null); + } else { + if (isNeedVerifyWithFaceIDAndBiometrics) + performApiCall(_title, _icon, selectedFlag); + else + performApiCall(_title, _icon, _flag); } } }, @@ -617,14 +582,14 @@ class _VerifyLoginScreenState extends State { Widget getButton(int flag) { switch (flag) { - case 2: - return _loginOptionButton(LocaleKeys.verifyThroughWhatsapp.tr(), 'assets/images/login/verify_whatsapp.svg', flag, null); case 1: return _loginOptionButton(LocaleKeys.verifyThroughSMS.tr(), 'assets/images/login/verify_sms.svg', flag, null); - case 4: + case 2: return _loginOptionButton(LocaleKeys.verifyThroughFingerprint.tr(), 'assets/images/login/verify_thumb.svg', flag, BiometricType.fingerprint.index); case 3: return _loginOptionButton(LocaleKeys.verifyThroughFace.tr(), 'assets/images/login/verify_face.svg', flag, BiometricType.face.index); + case 4: + return _loginOptionButton(LocaleKeys.verifyThroughWhatsapp.tr(), 'assets/images/login/verify_whatsapp.svg', flag, null); default: return const SizedBox(); } @@ -640,6 +605,67 @@ class _VerifyLoginScreenState extends State { } return isAvailable; } + + Future performApiCall(String _title, String _icon, int _flag) async { + try { + Utils.showLoading(context); + await LoginApiClient().checkMobileAppVersion(); + await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); + BasicMemberInformationModel? memberInformationModel = await LoginApiClient() + .mohemmSendActivationCodeByOTPNotificationType(checkBiometricIsAvailable(BiometricType.fingerprint) ? 1 : 0, AppState().memberLoginList?.pMOBILENUMBER, _flag, AppState().getUserName); + Utils.hideLoading(context); + OtpDialog( + context, + _flag, + int.tryParse(AppState().memberLoginList?.pMOBILENUMBER ?? ""), + (value) async { + Utils.showLoading(context); + try { + GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(true, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); + GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( + AppState().memberLoginList?.pEMAILADDRESS ?? "", + genericResponseModel?.pSESSIONID ?? 0, + genericResponseModel?.memberInformationList![0].eMPLOYEENAME ?? "", + _flag, + AppState().memberLoginList?.pMOBILENUMBER ?? "", + AppState().getUserName!, + firebaseToken!, + Platform.isAndroid ? "android" : "ios"); + if (genericResponseModel?.errorMessage != null) { + Utils.showToast(genericResponseModel?.errorMessage ?? ""); + } else { + AppState().setPrivilegeListModel = genericResponseModel!.privilegeList ?? []; + AppState().setMemberInformationListModel = genericResponseModel.memberInformationList?.first; + MemberInformationListModel.saveToPrefs(genericResponseModel.memberInformationList ?? []); + genericResponseModel.privilegeList!.forEach((element) { + print(element.serviceName.toString() + " " + element.previlege.toString()); // Check availability + }); + PrivilegeListModel.saveToPrefs(genericResponseModel.privilegeList ?? []); + AppState().setMohemmWifiSSID = genericResponseModel.mohemmWifiSSID; + AppState().setMohemmWifiPassword = genericResponseModel.mohemmWifiPassword; + Utils.saveStringFromPrefs(SharedPrefsConsts.username, AppState().getUserName!); + Utils.saveStringFromPrefs(SharedPrefsConsts.password, AppState().password!); + Utils.saveStringFromPrefs(SharedPrefsConsts.mohemmWifiSSID, genericResponseModel.mohemmWifiSSID!); + Utils.saveStringFromPrefs(SharedPrefsConsts.mohemmWifiPassword, genericResponseModel.mohemmWifiPassword!); + } + Utils.hideLoading(context); + Navigator.pop(context); + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + }, + () => { + Navigator.pop(context), + }, + ).displayDialog(context); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } // // formatDate(date) { // return date; From c664125c8f0e36698974c4be81f45c70451c7e15 Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Tue, 27 Sep 2022 14:53:48 +0300 Subject: [PATCH 3/3] fix issues --- lib/ui/my_team/view_attendance.dart | 240 ++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) diff --git a/lib/ui/my_team/view_attendance.dart b/lib/ui/my_team/view_attendance.dart index 7d8a6e0..b3f123e 100644 --- a/lib/ui/my_team/view_attendance.dart +++ b/lib/ui/my_team/view_attendance.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/monthly_attendance_api_client.dart'; import 'package:mohem_flutter_app/api/my_team/my_team_api_client.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; @@ -9,9 +10,11 @@ import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/get_day_hours_type_details_list_model.dart'; +import 'package:mohem_flutter_app/models/get_schedule_shifts_details_list_model.dart'; import 'package:mohem_flutter_app/models/get_time_card_summary_list_model.dart'; import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart'; import 'package:month_picker_dialog/month_picker_dialog.dart'; import 'package:pie_chart/pie_chart.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; @@ -44,6 +47,7 @@ class _ViewAttendanceState extends State { GetTimeCardSummaryList? getTimeCardSummaryList; GetAttendanceTracking? attendanceTracking; GetEmployeeSubordinatesList? getEmployeeSubordinates; + GetScheduleShiftsDetailsList? getScheduleShiftsDetailsList; @override void initState() { @@ -68,6 +72,18 @@ class _ViewAttendanceState extends State { } } + Future getScheduleShiftsDetails(index, pRTPID) async { + try { + Utils.showLoading(context); + getScheduleShiftsDetailsList = await MonthlyAttendanceApiClient().getScheduleShiftsDetails(pRTPID); + Utils.hideLoading(context); + //setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + final CalendarController _calendarController = CalendarController(); final List _colorList = [Color(0xff2AB2AB), Color(0xff202529)]; @@ -269,6 +285,7 @@ class _ViewAttendanceState extends State { shape: BoxShape.circle, ), dataSource: MeetingDataSource(_getDataSource()), + onTap: calendarTapped, monthViewSettings: const MonthViewSettings( dayFormat: 'EEE', showTrailingAndLeadingDates: false, @@ -388,6 +405,229 @@ class _ViewAttendanceState extends State { ); } + + void calendarTapped(CalendarTapDetails details) async { + dynamic index = details.date?.day; + if (index != null) { + index = index - 1; + } + pRTPID = getDayHoursTypeDetailsList[index].rTPID; + await getScheduleShiftsDetails(index, pRTPID); + dynamic value = getScheduleShiftsDetailsList!.pERCENTAGE; + dynamic percentage; + if (value!.indexOf('%') == 3) { + percentage = int.parse(value!.substring(0, 3)); + } else if (value!.indexOf('%') == 2) { + percentage = int.parse(value!.substring(0, 2)); + } else if (value!.indexOf('%') == 1 && value!.indexOf('%') != 0 && value!.indexOf('%') != "") { + percentage = int.parse(value!.substring(0, 1)); + } else if (value!.indexOf('%') == 0 || value!.indexOf('%') == "") { + percentage = 0; + } + showModalBottomSheet( + context: context, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)), + isScrollControlled: true, + backgroundColor: MyColors.backgroundBlackColor, + builder: (_) { + return DraggableScrollableSheet( + maxChildSize: 0.9, + expand: false, + builder: (_, controller) { + dynamic dmyString = getScheduleShiftsDetailsList!.sCHEDULEDATE; + DateTime dateTime1 = DateFormat("MM/dd/yyyy hh:mm:ss a").parse(dmyString); + return Column( + children: [ + Container( + width: 49, + height: 7, + margin: const EdgeInsets.symmetric(vertical: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(25), + color: MyColors.darkGreyColor, + ), + ), + Expanded( + child: ListView.builder( + controller: controller, + itemCount: 1, + itemBuilder: (_, i) => Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.vertical( + top: Radius.circular(25.0), + ), + color: MyColors.backgroundBlackColor, + ), + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "${DateFormat("MMMM-dd-yyyy").format(dateTime1).replaceAll('-', " ")}".toText24(isBold: true, color: Colors.white), + LocaleKeys.attendanceDetails.tr().toText16(color: MyColors.greyACColor), + 12.height, + CircularStepProgressBar( + totalSteps: 16 * 4, + currentStep: percentage, + width: 224, + height: 236, + selectedColor: MyColors.gradiantEndColor, + unselectedColor: MyColors.grey70Color, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + "${getScheduleShiftsDetailsList!.pERCENTAGE}".toText44(color: Colors.white, isBold: true), + LocaleKeys.completed.tr().toText11(color: MyColors.greyACColor), + 28.height, + LocaleKeys.shiftTime.tr().toText11(color: MyColors.greyACColor), + "${getScheduleShiftsDetailsList!.sHTNAME}".toText22(color: Colors.white, isBold: true), + ], + ).center, + ).center, + ], + ).paddingOnly(left: 21, right: 21, top: 27, bottom: 37), + Stack( + children: [ + Container( + width: double.infinity, + decoration: const BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), + padding: const EdgeInsets.only(left: 31, right: 31, top: 30, bottom: 29), + child: Column( + children: [ + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.actualCheckIn.tr().toText11( + color: MyColors.grey67Color, + ), + "${getScheduleShiftsDetailsList!.sHTACTUALSTARTTIME}" != "" + ? "${getScheduleShiftsDetailsList!.sHTACTUALSTARTTIME}".toText22(color: Colors.black, isBold: true) + : "__".toText22(color: Colors.black, isBold: true), + ], + ).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.actualCheckOut.tr().toText11( + color: MyColors.grey67Color, + ), + "${getScheduleShiftsDetailsList!.sHTACTUALENDTIME}" != "" + ? "${getScheduleShiftsDetailsList!.sHTACTUALENDTIME}".toText22(color: Colors.black, isBold: true) + : "__".toText22(color: Colors.black, isBold: true), + ], + ).expanded, + ], + ), + 25.height, + const Divider( + height: 1, + thickness: 1, + color: MyColors.lightGreyEFColor, + ), + 25.height, + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.approvedCheckIn.tr().toText11( + color: MyColors.grey67Color, + ), + "${getScheduleShiftsDetailsList!.aPPROVEDSTARTTIME}" != "" + ? "${getScheduleShiftsDetailsList!.aPPROVEDSTARTTIME}".toText22(color: MyColors.greenColor, isBold: true) + : "__".toText22(color: MyColors.greenColor, isBold: true), + ], + ).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.approvedCheckOut.tr().toText11( + color: MyColors.grey67Color, + ), + "${getScheduleShiftsDetailsList!.aPPROVEDENDTIME}" != "" + ? "${getScheduleShiftsDetailsList!.aPPROVEDENDTIME}".toText22(color: MyColors.greenColor, isBold: true) + : "__".toText22(color: MyColors.greenColor, isBold: true), + ], + ).expanded, + ], + ), + 25.height, + const Divider( + height: 1, + thickness: 1, + color: MyColors.lightGreyEFColor, + ), + 25.height, + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.lateIn.tr().toText11( + color: MyColors.grey67Color, + ), + "${getDayHoursTypeDetailsList[index].lATEINHRS}".toText22(color: MyColors.redColor, isBold: true), + ], + ).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.excess.tr().toText11( + color: MyColors.grey67Color, + ), + "${getDayHoursTypeDetailsList[index].eXCESSHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true), + ], + ).expanded, + ], + ), + 25.height, + const Divider( + height: 1, + thickness: 1, + color: MyColors.lightGreyEFColor, + ), + 25.height, + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.shortage.tr().toText11( + color: MyColors.grey67Color, + ), + "${getDayHoursTypeDetailsList[index].sHORTAGEHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true), + ], + ).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.earlyOut.tr().toText11( + color: MyColors.grey67Color, + ), + "${getDayHoursTypeDetailsList[index].eARLYOUTHRS}".toText22(color: Colors.black, isBold: true), + ], + ).expanded, + ], + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ), + ], + ); + }, + ); + }, + ); + } List _getDataSource() { List meetings = []; return meetings;