diff --git a/assets/fonts/DoctorApp.ttf b/assets/fonts/DoctorApp.ttf new file mode 100644 index 0000000..4ef2028 Binary files /dev/null and b/assets/fonts/DoctorApp.ttf differ diff --git a/assets/fonts/Poppins/Poppins-Bold.ttf b/assets/fonts/Poppins/Poppins-Bold.ttf new file mode 100644 index 0000000..b94d47f Binary files /dev/null and b/assets/fonts/Poppins/Poppins-Bold.ttf differ diff --git a/assets/fonts/Poppins/Poppins-Medium.ttf b/assets/fonts/Poppins/Poppins-Medium.ttf new file mode 100644 index 0000000..e90e87e Binary files /dev/null and b/assets/fonts/Poppins/Poppins-Medium.ttf differ diff --git a/assets/fonts/Poppins/Poppins-Regular.ttf b/assets/fonts/Poppins/Poppins-Regular.ttf new file mode 100644 index 0000000..be06e7f Binary files /dev/null and b/assets/fonts/Poppins/Poppins-Regular.ttf differ diff --git a/assets/fonts/Poppins/Poppins-SemiBold.ttf b/assets/fonts/Poppins/Poppins-SemiBold.ttf new file mode 100644 index 0000000..8987d80 Binary files /dev/null and b/assets/fonts/Poppins/Poppins-SemiBold.ttf differ diff --git a/assets/fonts/Work_Sans/OFL.txt b/assets/fonts/Work_Sans/OFL.txt new file mode 100644 index 0000000..5c0354e --- /dev/null +++ b/assets/fonts/Work_Sans/OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2014-2015 Wei Huang (wweeiihhuuaanngg@gmail.com) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/assets/fonts/Work_Sans/WorkSans-Black.ttf b/assets/fonts/Work_Sans/WorkSans-Black.ttf new file mode 100644 index 0000000..fb74420 Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-Black.ttf differ diff --git a/assets/fonts/Work_Sans/WorkSans-Bold.ttf b/assets/fonts/Work_Sans/WorkSans-Bold.ttf new file mode 100644 index 0000000..7caa359 Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-Bold.ttf differ diff --git a/assets/fonts/Work_Sans/WorkSans-ExtraBold.ttf b/assets/fonts/Work_Sans/WorkSans-ExtraBold.ttf new file mode 100644 index 0000000..fd4b912 Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-ExtraBold.ttf differ diff --git a/assets/fonts/Work_Sans/WorkSans-ExtraLight.ttf b/assets/fonts/Work_Sans/WorkSans-ExtraLight.ttf new file mode 100644 index 0000000..b97cf8c Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-ExtraLight.ttf differ diff --git a/assets/fonts/Work_Sans/WorkSans-Light.ttf b/assets/fonts/Work_Sans/WorkSans-Light.ttf new file mode 100644 index 0000000..3e981fb Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-Light.ttf differ diff --git a/assets/fonts/Work_Sans/WorkSans-Medium.ttf b/assets/fonts/Work_Sans/WorkSans-Medium.ttf new file mode 100644 index 0000000..7a2645b Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-Medium.ttf differ diff --git a/assets/fonts/Work_Sans/WorkSans-Regular.ttf b/assets/fonts/Work_Sans/WorkSans-Regular.ttf new file mode 100644 index 0000000..0ac4520 Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-Regular.ttf differ diff --git a/assets/fonts/Work_Sans/WorkSans-SemiBold.ttf b/assets/fonts/Work_Sans/WorkSans-SemiBold.ttf new file mode 100644 index 0000000..589a5f5 Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-SemiBold.ttf differ diff --git a/assets/fonts/Work_Sans/WorkSans-Thin.ttf b/assets/fonts/Work_Sans/WorkSans-Thin.ttf new file mode 100644 index 0000000..011fcd3 Binary files /dev/null and b/assets/fonts/Work_Sans/WorkSans-Thin.ttf differ diff --git a/assets/images/login/more_icon.png b/assets/images/login/more_icon.png new file mode 100644 index 0000000..b696d34 Binary files /dev/null and b/assets/images/login/more_icon.png differ diff --git a/assets/images/login/verify_face.svg b/assets/images/login/verify_face.svg new file mode 100644 index 0000000..e50d1a6 --- /dev/null +++ b/assets/images/login/verify_face.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/images/login/verify_sms.svg b/assets/images/login/verify_sms.svg new file mode 100644 index 0000000..ae5fa9f --- /dev/null +++ b/assets/images/login/verify_sms.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/images/login/verify_thumb.svg b/assets/images/login/verify_thumb.svg new file mode 100644 index 0000000..e626baf --- /dev/null +++ b/assets/images/login/verify_thumb.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/images/login/verify_whatsapp.svg b/assets/images/login/verify_whatsapp.svg new file mode 100644 index 0000000..09ac85c --- /dev/null +++ b/assets/images/login/verify_whatsapp.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/images/patient/admission_req.png b/assets/images/patient/admission_req.png new file mode 100644 index 0000000..b233508 Binary files /dev/null and b/assets/images/patient/admission_req.png differ diff --git a/assets/images/patient/ic_ref_arrow_left.png b/assets/images/patient/ic_ref_arrow_left.png new file mode 100644 index 0000000..09e05ab Binary files /dev/null and b/assets/images/patient/ic_ref_arrow_left.png differ diff --git a/assets/images/patient/ic_ref_arrow_up.png b/assets/images/patient/ic_ref_arrow_up.png new file mode 100644 index 0000000..8294cfe Binary files /dev/null and b/assets/images/patient/ic_ref_arrow_up.png differ diff --git a/assets/images/patient/refer_patient.png b/assets/images/patient/refer_patient.png new file mode 100644 index 0000000..ac3aea6 Binary files /dev/null and b/assets/images/patient/refer_patient.png differ diff --git a/assets/images/patient/ucaf.png b/assets/images/patient/ucaf.png new file mode 100644 index 0000000..f729359 Binary files /dev/null and b/assets/images/patient/ucaf.png differ diff --git a/assets/images/patient/vital_signs/Obese_BMI-r.png b/assets/images/patient/vital_signs/Obese_BMI-r.png new file mode 100644 index 0000000..50b3282 Binary files /dev/null and b/assets/images/patient/vital_signs/Obese_BMI-r.png differ diff --git a/assets/images/patient/vital_signs/Obese_BMI.png b/assets/images/patient/vital_signs/Obese_BMI.png new file mode 100644 index 0000000..540d4bc Binary files /dev/null and b/assets/images/patient/vital_signs/Obese_BMI.png differ diff --git a/assets/images/patient/vital_signs/blood_pressure.png b/assets/images/patient/vital_signs/blood_pressure.png new file mode 100644 index 0000000..9670187 Binary files /dev/null and b/assets/images/patient/vital_signs/blood_pressure.png differ diff --git a/assets/images/patient/vital_signs/health_BMI-r.png b/assets/images/patient/vital_signs/health_BMI-r.png new file mode 100644 index 0000000..96189d3 Binary files /dev/null and b/assets/images/patient/vital_signs/health_BMI-r.png differ diff --git a/assets/images/patient/vital_signs/health_BMI.png b/assets/images/patient/vital_signs/health_BMI.png new file mode 100644 index 0000000..c87a042 Binary files /dev/null and b/assets/images/patient/vital_signs/health_BMI.png differ diff --git a/assets/images/patient/vital_signs/heart_rate.png b/assets/images/patient/vital_signs/heart_rate.png new file mode 100644 index 0000000..7601719 Binary files /dev/null and b/assets/images/patient/vital_signs/heart_rate.png differ diff --git a/assets/images/patient/vital_signs/height.png b/assets/images/patient/vital_signs/height.png new file mode 100644 index 0000000..e176c45 Binary files /dev/null and b/assets/images/patient/vital_signs/height.png differ diff --git a/assets/images/patient/vital_signs/ovrweight_BMI-r.png b/assets/images/patient/vital_signs/ovrweight_BMI-r.png new file mode 100644 index 0000000..ff24fc6 Binary files /dev/null and b/assets/images/patient/vital_signs/ovrweight_BMI-r.png differ diff --git a/assets/images/patient/vital_signs/ovrweight_BMI.png b/assets/images/patient/vital_signs/ovrweight_BMI.png new file mode 100644 index 0000000..da8e67b Binary files /dev/null and b/assets/images/patient/vital_signs/ovrweight_BMI.png differ diff --git a/assets/images/patient/vital_signs/oxg.png b/assets/images/patient/vital_signs/oxg.png new file mode 100644 index 0000000..344344e Binary files /dev/null and b/assets/images/patient/vital_signs/oxg.png differ diff --git a/assets/images/patient/vital_signs/painScale.png b/assets/images/patient/vital_signs/painScale.png new file mode 100644 index 0000000..36b6b9f Binary files /dev/null and b/assets/images/patient/vital_signs/painScale.png differ diff --git a/assets/images/patient/vital_signs/respiration_rate.png b/assets/images/patient/vital_signs/respiration_rate.png new file mode 100644 index 0000000..ff695de Binary files /dev/null and b/assets/images/patient/vital_signs/respiration_rate.png differ diff --git a/assets/images/patient/vital_signs/temperature.png b/assets/images/patient/vital_signs/temperature.png new file mode 100644 index 0000000..9953a13 Binary files /dev/null and b/assets/images/patient/vital_signs/temperature.png differ diff --git a/assets/images/patient/vital_signs/underweight_BMI-r.png b/assets/images/patient/vital_signs/underweight_BMI-r.png new file mode 100644 index 0000000..2f633b4 Binary files /dev/null and b/assets/images/patient/vital_signs/underweight_BMI-r.png differ diff --git a/assets/images/patient/vital_signs/underweight_BMI.png b/assets/images/patient/vital_signs/underweight_BMI.png new file mode 100644 index 0000000..83b0260 Binary files /dev/null and b/assets/images/patient/vital_signs/underweight_BMI.png differ diff --git a/assets/images/patient/vital_signs/weight.png b/assets/images/patient/vital_signs/weight.png new file mode 100644 index 0000000..4a3bd2c Binary files /dev/null and b/assets/images/patient/vital_signs/weight.png differ diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index cb952f2..1038617 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -2,6 +2,49 @@ "mohemm": "Mohemm", "english": "English", "arabic": "عربي", - "login": "تسجيل الدخول" - + "login": "تسجيل الدخول", + "drSulaiman": "سليمان الحبيب", + "welcomeTo": "مرحبا بك في", + "userID" : "معرف المستخدم", + "password" : "كلمة المرور", + "branch" : "فرع", + "pleaseEnterLoginDetails": "الرجاء إدخال التفاصيل أدناه لتسجيل الدخول", + "username": "اسم المستخدم", + "welcomeBack": "مرحبا بعودتك", + "wouldYouLikeToLoginWithCurrentUsername": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟", + "lastLoginDetails": "تفاصيل تسجيل الدخول الأخير:", + "verificationType": "نوع التحقق:", + "pleaseVerify": "ارجوك تحقق", + "pleaseVerifyForBio": "الرجاء التحقق من تسجيل الدخول باستخدام أحد هذه الخيارات", + "verifyThroughFace": "تحقق من خلال الوجه", + "verifyThroughFingerprint": "تحقق من خلال بصمة الإصبع", + "verifyThroughSMS": "تحقق من خلال الرسائل القصيرة", + "verifyThroughWhatsapp": "تحقق من خلال Whatsapp", + "useAnotherAccount": "استخدم حسابا آخر", + "pleaseEnterTheVerificationCodeSentTo": "الرجاء إدخال رمز التحقق المرسل إلى ", + "theVerificationCodeWillExpireIn": "ستنتهي صلاحية رمز التحقق في ", + "goodMorning": "صباح الخير", + "markAttendance": "علامة الحضور", + "timeLeftToday": "الوقت المتبقي اليوم", + "checkIn": "تحقق في", + "workList": "قائمة العمل", + "doNotUseRecentPassword": "لا تستخدم كلمة مرور حديثة", + "atLeastOneLowercase": "حرف صغير واحد على الأقل", + "atLeastOneUppercase": "حرف كبير واحد على الأقل", + "atLeastOneNumeric": "رقم واحد على الأقل", + "minimum8Characters": "8 أحرف على الأقل", + "doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة", + "itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص", + "confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور", + "sms": "رسالة قصيرة", + "fingerPrint": "بصمة", + "face": "التعرف على الوجه", + "whatsapp": "واتس اب", + "reject": "يرفض", + "approve": "يوافق", + "cancel": "إلغاء", + "otp": "OTP", + "verification": "تَحَقّق", + "resend": "إعادة إرسال", + "codeExpire": "انتهت صلاحية رمز التحقق" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index afb883f..27757e5 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -2,6 +2,49 @@ "mohemm": "Mohemm", "english": "English", "arabic": "عربي", - "login": "Login" - + "login": "Login", + "drSulaiman" : "Dr Sulaiman Al Habib", + "welcomeTo": "Welcome to", + "userID" : "User ID", + "password" : "Password", + "branch" : "Branch", + "pleaseEnterLoginDetails": "Please enter the detail below to login", + "username": "Username", + "welcomeBack": "Welcome back", + "wouldYouLikeToLoginWithCurrentUsername": "Would you like to login with current Username?", + "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", + "verifyThroughWhatsapp": "Verify Through Whatsapp", + "useAnotherAccount": "Use Another Account", + "pleaseEnterTheVerificationCodeSentTo": "Please enter the verification code sent to ", + "theVerificationCodeWillExpireIn": "The verification code will expire in ", + "goodMorning": "Good Morning", + "markAttendance": "Mark Attendance", + "timeLeftToday": "Time Left Today", + "checkIn": "Check In", + "workList": "Work List", + "doNotUseRecentPassword": "Do not use recent password", + "atLeastOneLowercase": "At least one lowercase", + "atLeastOneUppercase": "At least one uppercase", + "atLeastOneNumeric": "At least one numeric", + "minimum8Characters": "Minimum 8 characters", + "doNotAddRepeatingLetters": "Do not add repeating letters", + "itShouldContainSpecialCharacter": "It should contain special character", + "confirmPasswordMustMatch": "Confirm password must match", + "sms": "SMS", + "fingerPrint": "Fingerprint", + "face": "Face", + "whatsapp": "Whatsapp", + "reject": "Reject", + "approve": "Approve", + "cancel": "Cancel", + "otp": "OTP", + "verification": "Verification", + "resend": "Resend", + "codeExpire": "The verification code has been expired" } \ No newline at end of file diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 92e4416..48c23d2 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -13,6 +13,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 9D12EA470E69A39F3F4EEEAC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBDA1EC0585A028F26394B8F /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -31,6 +32,7 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 27FAD59055A271CDB6345D20 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -42,6 +44,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CBDA1EC0585A028F26394B8F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E8F2C56CA7A126F5FC598365 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + FF2E7CCDDEE1BDF1A3E7D477 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -49,12 +54,21 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9D12EA470E69A39F3F4EEEAC /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 5070F4CF6F638C91B59F4B67 /* Frameworks */ = { + isa = PBXGroup; + children = ( + CBDA1EC0585A028F26394B8F /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -72,6 +86,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + CACFC9B4D329C2F774D03EE9 /* Pods */, + 5070F4CF6F638C91B59F4B67 /* Frameworks */, ); sourceTree = ""; }; @@ -98,6 +114,16 @@ path = Runner; sourceTree = ""; }; + CACFC9B4D329C2F774D03EE9 /* Pods */ = { + isa = PBXGroup; + children = ( + FF2E7CCDDEE1BDF1A3E7D477 /* Pods-Runner.debug.xcconfig */, + 27FAD59055A271CDB6345D20 /* Pods-Runner.release.xcconfig */, + E8F2C56CA7A126F5FC598365 /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -105,12 +131,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + CDED494F0D32669A035C1EA5 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 2CEBFA1962BF46DCB0A31085 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -169,6 +197,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 2CEBFA1962BF46DCB0A31085 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -197,6 +242,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + CDED494F0D32669A035C1EA5 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -288,6 +355,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = KT58FV5WJU; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -416,6 +484,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = KT58FV5WJU; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -438,6 +507,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = KT58FV5WJU; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/lib/config/routes.dart b/lib/config/routes.dart index eca978f..3938565 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -1,25 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:hmg_nurses/ui/login/splash_page.dart'; - - +import 'package:hmg_nurses/ui/login/login_method_page.dart'; +import 'package:hmg_nurses/ui/login/login_page.dart'; class AppRoutes { - //Login static const String splash = "/splash"; static const String registerSelection = "/registerSelection"; - static const String loginVerifyAccount = "/loginVerifyAccount"; + static const String loginMethodsPage = "/loginMethodsPage"; static const String login = "/login"; - - static final Map routes = { - //Login - splash: (BuildContext context) => SplashPage(), - // login: (BuildContext context) => LoginScreen(), - - - + login: (BuildContext context) => const LoginPage(), + loginMethodsPage: (BuildContext context) => const LoginMethodsPage(), }; } diff --git a/lib/dialogs/otp_dialog.dart b/lib/dialogs/otp_dialog.dart index 28b1fc0..4355884 100644 --- a/lib/dialogs/otp_dialog.dart +++ b/lib/dialogs/otp_dialog.dart @@ -1,15 +1,15 @@ import 'dart:async'; -import 'package:easy_localization/src/public_ext.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:hmg_nurses/classes/colors.dart'; import 'package:hmg_nurses/extensions/int_extensions.dart'; import 'package:hmg_nurses/extensions/string_extensions.dart'; +import 'package:hmg_nurses/generated/locale_keys.g.dart'; import 'package:hmg_nurses/widgets/button/default_button.dart'; import 'package:hmg_nurses/widgets/otp_widget.dart'; - final ValueNotifier otpFieldClear = ValueNotifier(""); class OtpDialog { @@ -17,18 +17,13 @@ class OtpDialog { final int? mobileNo; final Function(String, TextEditingController _pinPutController) onSuccess; final Function onFailure; - final BuildContext context; final Function onResendCode; int remainingTime = 120; Future? timer; - static BuildContext? _context; - - static bool? _loading; - - OtpDialog(this.context, this.type, this.mobileNo, this.onSuccess, this.onFailure, {required this.onResendCode}); + OtpDialog({required this.type, required this.mobileNo, required this.onSuccess, required this.onFailure, required this.onResendCode}); GlobalKey? verifyAccountForm = GlobalKey(); @@ -53,7 +48,6 @@ class OtpDialog { // ProjectViewModel projectProvider; String displayTime = ''; - String? _code; dynamic setState; bool stopTimer = false; @@ -75,7 +69,7 @@ class OtpDialog { } return Container( - padding: EdgeInsets.all(21), + padding: const EdgeInsets.all(21), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -92,38 +86,33 @@ class OtpDialog { width: 50, ), 12.height, - "LocaleKeys.otp.tr()".toText14(), - "LocaleKeys.verification.tr()".toText24(isBold: true), + LocaleKeys.otp.tr().toText14(), + LocaleKeys.verification.tr().toText24(isBold: true), 6.height, - ("LocaleKeys.pleaseEnterTheVerificationCodeSentTo.tr()" + ' xxxxxxxx' + mobileNo.toString().substring(mobileNo.toString().length - 3)).toText16(), + ('${LocaleKeys.pleaseEnterTheVerificationCodeSentTo.tr()} xxxxxxxx${mobileNo.toString().substring(mobileNo.toString().length - 3)}').toText16(), 18.height, ValueListenableBuilder( builder: (BuildContext context, String value, Widget? child) { - // This builder will only get called when the _counter - // is updated. return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: OTPWidget( - autoFocus: true, - controller: _pinPutController, - defaultBorderColor: const Color(0xffD8D8D8), - maxLength: 4, - onTextChanged: (text) {}, - pinBoxColor: Colors.white, - onDone: (code) => _onOtpCallBack(code, null), - textBorderColor: const Color(0xffD8D8D8), - pinBoxWidth: 60, - pinBoxHeight: 60, - pinTextStyle: const TextStyle(fontSize: 24.0, color: MyColors.darkTextColor), - pinTextAnimatedSwitcherTransition: ProvidedPinBoxTextAnimation.scalingTransition, - pinTextAnimatedSwitcherDuration: const Duration(milliseconds: 300), - pinBoxRadius: 10, - keyboardType: TextInputType.number, - ), + Center( + child: OTPWidget( + autoFocus: true, + controller: _pinPutController, + defaultBorderColor: const Color(0xffD8D8D8), + maxLength: 4, + onTextChanged: (text) {}, + pinBoxColor: Colors.white, + onDone: (code) => _onOtpCallBack(code, null), + textBorderColor: const Color(0xffD8D8D8), + pinBoxWidth: 60, + pinBoxHeight: 60, + pinTextStyle: const TextStyle(fontSize: 24.0, color: MyColors.darkTextColor), + pinTextAnimatedSwitcherTransition: ProvidedPinBoxTextAnimation.scalingTransition, + pinTextAnimatedSwitcherDuration: const Duration(milliseconds: 300), + pinBoxRadius: 10, + keyboardType: TextInputType.number, ), ), 10.height, @@ -131,7 +120,7 @@ class OtpDialog { ? Row( children: [ Expanded( - child: "LocaleKeys.codeExpire.tr()".toText16( + child: LocaleKeys.codeExpire.tr().toText16( color: MyColors.redColor, ), ), @@ -146,7 +135,7 @@ class OtpDialog { ) : RichText( text: TextSpan( - text: "LocaleKeys.theVerificationCodeWillExpireIn.tr()" + '\n', + text: '${LocaleKeys.theVerificationCodeWillExpireIn.tr()}\n', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: MyColors.darkTextColor, letterSpacing: -0.48), children: [ TextSpan( @@ -163,7 +152,7 @@ class OtpDialog { ), 18.height, DefaultButton( - stopTimer ? "LocaleKeys.resend.tr()" : "LocaleKeys.cancel.tr()", + stopTimer ? LocaleKeys.resend.tr() : LocaleKeys.cancel.tr(), () async { if (stopTimer) { hideSMSBox(context); @@ -177,8 +166,8 @@ class OtpDialog { colors: stopTimer ? null : [ - MyColors.pinkDarkColor, - MyColors.pinkDarkColor, + MyColors.redColor, + MyColors.redColor, ], ), ], @@ -211,16 +200,6 @@ class OtpDialog { ); } - // String validateCodeDigit(value) { - // if (value.isEmpty) { - // return ' '; - // } else if (value.length == 3) { - // print(value); - // } else { - // return null; - // } - // } - String getSecondsAsDigitalClock(int inputSeconds) { int secNum = int.parse(inputSeconds.toString()); // don't forget the second param int hours = (secNum / 3600).floor(); @@ -228,9 +207,9 @@ class OtpDialog { double seconds = secNum - hours * 3600 - minutes * 60; String minutesString = ""; String secondsString = ""; - minutesString = minutes < 10 ? "0" + minutes.toString() : minutes.toString(); - secondsString = seconds < 10 ? "0" + seconds.toStringAsFixed(0) : seconds.toStringAsFixed(0); - return minutesString + ":" + secondsString; + minutesString = minutes < 10 ? "0$minutes" : minutes.toString(); + secondsString = seconds < 10 ? "0${seconds.toStringAsFixed(0)}" : seconds.toStringAsFixed(0); + return "$minutesString:$secondsString"; } void startTimer(setState) { diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 113e677..73e4320 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -6,15 +6,113 @@ import 'dart:ui'; import 'package:easy_localization/easy_localization.dart' show AssetLoader; -class CodegenLoader extends AssetLoader { +class CodegenLoader extends AssetLoader{ const CodegenLoader(); @override - Future> load(String fullPath, Locale locale) { + Future> load(String fullPath, Locale locale ) { return Future.value(mapLocales[locale.toString()]); } - static const Map ar_SA = {"mohemm": "Mohemm", "english": "English", "arabic": "عربي", "login": "تسجيل الدخول"}; - static const Map en_US = {"mohemm": "Mohemm", "english": "English", "arabic": "عربي", "login": "Login"}; - static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; + static const Map ar_SA = { + "mohemm": "Mohemm", + "english": "English", + "arabic": "عربي", + "login": "تسجيل الدخول", + "drSulaiman": "سليمان الحبيب", + "welcomeTo": "مرحبا بك في", + "userID": "معرف المستخدم", + "password": "كلمة المرور", + "branch": "فرع", + "pleaseEnterLoginDetails": "الرجاء إدخال التفاصيل أدناه لتسجيل الدخول", + "username": "اسم المستخدم", + "welcomeBack": "مرحبا بعودتك", + "wouldYouLikeToLoginWithCurrentUsername": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟", + "lastLoginDetails": "تفاصيل تسجيل الدخول الأخير:", + "verificationType": "نوع التحقق:", + "pleaseVerify": "ارجوك تحقق", + "pleaseVerifyForBio": "الرجاء التحقق من تسجيل الدخول باستخدام أحد هذه الخيارات", + "verifyThroughFace": "تحقق من خلال الوجه", + "verifyThroughFingerprint": "تحقق من خلال بصمة الإصبع", + "verifyThroughSMS": "تحقق من خلال الرسائل القصيرة", + "verifyThroughWhatsapp": "تحقق من خلال Whatsapp", + "useAnotherAccount": "استخدم حسابا آخر", + "pleaseEnterTheVerificationCodeSentTo": "الرجاء إدخال رمز التحقق المرسل إلى ", + "theVerificationCodeWillExpireIn": "ستنتهي صلاحية رمز التحقق في ", + "goodMorning": "صباح الخير", + "markAttendance": "علامة الحضور", + "timeLeftToday": "الوقت المتبقي اليوم", + "checkIn": "تحقق في", + "workList": "قائمة العمل", + "doNotUseRecentPassword": "لا تستخدم كلمة مرور حديثة", + "atLeastOneLowercase": "حرف صغير واحد على الأقل", + "atLeastOneUppercase": "حرف كبير واحد على الأقل", + "atLeastOneNumeric": "رقم واحد على الأقل", + "minimum8Characters": "8 أحرف على الأقل", + "doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة", + "itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص", + "confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور", + "sms": "رسالة قصيرة", + "fingerPrint": "بصمة", + "face": "التعرف على الوجه", + "whatsapp": "واتس اب", + "reject": "يرفض", + "approve": "يوافق", + "cancel": "إلغاء", + "otp": "OTP", + "verification": "تَحَقّق", + "resend": "إعادة إرسال", + "codeExpire": "انتهت صلاحية رمز التحقق" +}; +static const Map en_US = { + "mohemm": "Mohemm", + "english": "English", + "arabic": "عربي", + "login": "Login", + "drSulaiman": "Dr Sulaiman Al Habib", + "welcomeTo": "Welcome to", + "userID": "User ID", + "password": "Password", + "branch": "Branch", + "pleaseEnterLoginDetails": "Please enter the detail below to login", + "username": "Username", + "welcomeBack": "Welcome back", + "wouldYouLikeToLoginWithCurrentUsername": "Would you like to login with current Username?", + "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", + "verifyThroughWhatsapp": "Verify Through Whatsapp", + "useAnotherAccount": "Use Another Account", + "pleaseEnterTheVerificationCodeSentTo": "Please enter the verification code sent to ", + "theVerificationCodeWillExpireIn": "The verification code will expire in ", + "goodMorning": "Good Morning", + "markAttendance": "Mark Attendance", + "timeLeftToday": "Time Left Today", + "checkIn": "Check In", + "workList": "Work List", + "doNotUseRecentPassword": "Do not use recent password", + "atLeastOneLowercase": "At least one lowercase", + "atLeastOneUppercase": "At least one uppercase", + "atLeastOneNumeric": "At least one numeric", + "minimum8Characters": "Minimum 8 characters", + "doNotAddRepeatingLetters": "Do not add repeating letters", + "itShouldContainSpecialCharacter": "It should contain special character", + "confirmPasswordMustMatch": "Confirm password must match", + "sms": "SMS", + "fingerPrint": "Fingerprint", + "face": "Face", + "whatsapp": "Whatsapp", + "reject": "Reject", + "approve": "Approve", + "cancel": "Cancel", + "otp": "OTP", + "verification": "Verification", + "resend": "Resend", + "codeExpire": "The verification code has been expired" +}; +static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/main.dart b/lib/main.dart index e7941d0..3bff34a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,6 +12,9 @@ import 'package:sizer/sizer.dart'; import 'generated/codegen_loader.g.dart'; + +GlobalKey navigatorKey = GlobalKey(); + Logger logger = Logger( // filter: null, // Use the default LogFilter (-> only log in debug mode) printer: PrettyPrinter( @@ -71,6 +74,7 @@ class MyApp extends StatelessWidget { ) { List> delegates = context.localizationDelegates; return MaterialApp( + key: navigatorKey, theme: AppTheme.getTheme( EasyLocalization.of(context)?.locale.languageCode == "ar", ), @@ -78,7 +82,7 @@ class MyApp extends StatelessWidget { localizationsDelegates: delegates, supportedLocales: context.supportedLocales, locale: context.locale, - initialRoute: AppRoutes.splash, + initialRoute: AppRoutes.login, routes: AppRoutes.routes, ); }, diff --git a/lib/models/get_mobile_login_info_list_model.dart b/lib/models/get_mobile_login_info_list_model.dart new file mode 100644 index 0000000..a2f7799 --- /dev/null +++ b/lib/models/get_mobile_login_info_list_model.dart @@ -0,0 +1,64 @@ +class GetMobileLoginInfoListModel { + int? iD; + int? employeeID; + int? channelID; + int? companyID; + String? deviceType; + String? deviceToken; + int? language; + int? gender; + int? loginType; + String? createdOn; + String? editedOn; + String? employeeName; + bool? businessCardPrivilege; + + GetMobileLoginInfoListModel( + {this.iD, + this.employeeID, + this.channelID, + this.companyID, + this.deviceType, + this.deviceToken, + this.language, + this.gender, + this.loginType, + this.createdOn, + this.editedOn, + this.employeeName, + this.businessCardPrivilege}); + + GetMobileLoginInfoListModel.fromJson(Map json) { + iD = json['ID']; + employeeID = json['EmployeeID']; + channelID = json['ChannelID']; + companyID = json['CompanyID']; + deviceType = json['DeviceType']; + deviceToken = json['DeviceToken']; + language = json['Language']; + gender = json['Gender']; + loginType = json['LoginType']; + createdOn = json['CreatedOn']; + editedOn = json['EditedOn']; + employeeName = json['EmployeeName']; + businessCardPrivilege = json['BusinessCardPrivilege']; + } + + Map toJson() { + Map data = Map(); + data['ID'] = iD; + data['EmployeeID'] = employeeID; + data['ChannelID'] = channelID; + data['CompanyID'] = companyID; + data['DeviceType'] = deviceType; + data['DeviceToken'] = deviceToken; + data['Language'] = language; + data['Gender'] = gender; + data['LoginType'] = loginType; + data['CreatedOn'] = createdOn; + data['EditedOn'] = editedOn; + data['EmployeeName'] = employeeName; + data['BusinessCardPrivilege'] = businessCardPrivilege; + return data; + } +} diff --git a/lib/ui/a.dart b/lib/ui/a.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/ui/login/login_method_page.dart b/lib/ui/login/login_method_page.dart new file mode 100644 index 0000000..0ac6632 --- /dev/null +++ b/lib/ui/login/login_method_page.dart @@ -0,0 +1,295 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:hmg_nurses/classes/colors.dart'; +import 'package:hmg_nurses/classes/utils.dart'; +import 'package:hmg_nurses/dialogs/otp_dialog.dart'; +import 'package:hmg_nurses/extensions/int_extensions.dart'; +import 'package:hmg_nurses/extensions/string_extensions.dart'; +import 'package:hmg_nurses/generated/locale_keys.g.dart'; +import 'package:hmg_nurses/widgets/button/default_button.dart'; +import 'package:local_auth/local_auth.dart'; +import 'package:sizer/sizer.dart'; + +// WhatsApp 2 +// SMS 1 +// Face ID 3 +// Finger Print 4 + +class LoginMethodsPage extends StatefulWidget { + const LoginMethodsPage({Key? key}) : super(key: key); + + @override + LoginMethodsPageState createState() => LoginMethodsPageState(); +} + +class LoginMethodsPageState extends State { + final LocalAuthentication localAuth = LocalAuthentication(); + List _availableBioMetricType = []; + + int selectedFlag = 0; + bool isNeedVerifyWithFaceIDAndBiometrics = false; + + bool lastLoginCheck = false; + + @override + void initState() { + _getAvailableBiometrics(); + super.initState(); + } + + String getVerificationType(int type) { + if (type == 1) { + return LocaleKeys.sms.tr(); + } else if (type == 2) { + return LocaleKeys.whatsapp.tr(); + } else if (type == 3) { + return LocaleKeys.face.tr(); + } else if (type == 4) { + return LocaleKeys.fingerPrint.tr(); + } + return ""; + } + + Future _getAvailableBiometrics() async { + try { + _availableBioMetricType = await localAuth.getAvailableBiometrics(); + } on PlatformException catch (e) { + // AppToast.showErrorToast(message: e.message); + if (kDebugMode) { + print(e); + } + } + if (mounted) setState(() {}); + } + + Future loginWithFaceIDAndBiometrics() async { + bool authenticated = false; + try { + authenticated = await localAuth.authenticate( + localizedReason: 'Scan your fingerprint to authenticate', + ); + } on PlatformException catch (e) { + if (kDebugMode) { + print(e); + } + Utils.hideLoading(context); + Utils.showToast("Please enable your Touch or Face ID"); + } + return authenticated; + } + + Widget _loginOptionButton(String title, String icon, int flag, int? loginIndex) { + bool isDisable = ((flag == 3 && !checkBiometricIsAvailable(BiometricType.face)) || (flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint))); + return InkWell( + onTap: isDisable + ? null + : () async { + if (flag == 0) { + setState(() { + // isMoreOption = true; + }); + } else { + if (flag == 3 || flag == 4) { + bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + if (!authenticateWithFaceAndTouchID) { + return; + } else { + isNeedVerifyWithFaceIDAndBiometrics = true; + selectedFlag = flag; + setState(() { + return; + }); + } + } else { + if (isNeedVerifyWithFaceIDAndBiometrics) { + // performApiCall(_title, _icon, selectedFlag, _flag); + // TODO: CALL API AND THEN SHOW DIALOG + + OtpDialog( + type: 1, + mobileNo: 0504278212, + onSuccess: (string, TextEditingController pinPutController) {}, + onFailure: () {}, + onResendCode: () {}, + ).displayDialog(context); + } else { + // performApiCall(_title, _icon, _flag, _flag); + + // TODO: CALL API AND THEN SHOW DIALOG + OtpDialog( + type: 1, + mobileNo: 0504278212, + onSuccess: (string, TextEditingController pinPutController) {}, + onFailure: () {}, + onResendCode: () {}, + ).displayDialog(context); + } + } + } + }, + child: Container( + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 15, top: 28), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: isDisable ? Colors.grey.withOpacity(0.3) : Colors.white, + border: Border.all(color: MyColors.lightGreyEFColor, width: 1), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SvgPicture.asset( + icon, + height: 38, + width: 38, + color: isDisable ? MyColors.darkTextColor.withOpacity(0.7) : null, + ), + title.toText14() + ], + ), + ), + ); + } + + Widget getButton(int flag) { + switch (flag) { + case 1: + return _loginOptionButton(LocaleKeys.verifyThroughSMS.tr(), 'assets/images/login/verify_sms.svg', flag, null); + case 2: + return _loginOptionButton(LocaleKeys.verifyThroughWhatsapp.tr(), 'assets/images/login/verify_whatsapp.svg', flag, null); + case 3: + return _loginOptionButton(LocaleKeys.verifyThroughFace.tr(), 'assets/images/login/verify_face.svg', flag, BiometricType.face.index); + case 4: + return _loginOptionButton(LocaleKeys.verifyThroughFingerprint.tr(), 'assets/images/login/verify_thumb.svg', flag, BiometricType.fingerprint.index); + default: + return const SizedBox(); + } + } + + bool checkBiometricIsAvailable(BiometricType biometricType) { + bool isAvailable = false; + for (int i = 0; i < _availableBioMetricType.length; i++) { + if (biometricType == _availableBioMetricType[i]) { + isAvailable = true; + break; + } + } + return isAvailable; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), + onPressed: () => Navigator.pop(context), + ), + // actions: [Center(child: "Employee Digital ID".toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() {})), 21.width], + ), + body: ListView( + padding: const EdgeInsets.all(21), + physics: const BouncingScrollPhysics(), + children: [ + if (lastLoginCheck) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.welcomeBack.tr().toText12(), + "Faiz Hashmi".toText24(isBold: true), + 10.height, + LocaleKeys.wouldYouLikeToLoginWithCurrentUsername.tr().toText18(), + Container( + height: 72, + margin: const EdgeInsets.only(top: 23, bottom: 23), + alignment: Alignment.center, + padding: const EdgeInsets.only(left: 17, right: 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.white, + border: Border.all( + color: const Color(0xffefefef), + width: 1, + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + LocaleKeys.lastLoginDetails.tr().toText16(), + //TODO: DATE + // DateUtil.formatDateToDate(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!), false).toText12(), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + LocaleKeys.verificationType.tr().toText10(color: MyColors.grey57Color), + //TODO: VERIFICATION TYPE + // getVerificationType(mobileLoginInfoListModel!.loginType!).toText12(), + const Expanded(child: SizedBox()), + //TODO: DATE + + // DateUtil.formatDateToTime(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!)).toText12(), + ], + ) + ], + ), + ), + ], + ), + if (!lastLoginCheck) + Text( + LocaleKeys.pleaseVerifyForBio.tr(), + style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.w600), + ), + if (isNeedVerifyWithFaceIDAndBiometrics) Text(LocaleKeys.pleaseVerifyForBio.tr()), + GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13, mainAxisSpacing: 9), + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.only(top: 9), + shrinkWrap: true, + children: [ + if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(3), + if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(4), + getButton(2), + getButton(1), + ], + ), + SizedBox(height: 10.h), + ], + ), + bottomSheet: !lastLoginCheck + ? null + : Container( + height: 10.h, + color: MyColors.backgroundColor, + width: double.infinity, + child: Center( + child: FractionallySizedBox( + widthFactor: 0.9, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 4.w), + child: DefaultButton(LocaleKeys.useAnotherAccount.tr(), () {}, colors: const [MyColors.redColor, MyColors.redColor]), + ), + SizedBox(height: 3.h) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/login/login_page.dart b/lib/ui/login/login_page.dart new file mode 100644 index 0000000..007201a --- /dev/null +++ b/lib/ui/login/login_page.dart @@ -0,0 +1,103 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_nurses/classes/colors.dart'; +import 'package:hmg_nurses/config/routes.dart'; +import 'package:hmg_nurses/generated/locale_keys.g.dart'; +import 'package:hmg_nurses/widgets/button/default_button.dart'; +import 'package:hmg_nurses/widgets/cupertino_picker.dart'; +import 'package:hmg_nurses/widgets/input_widget.dart'; +import 'package:sizer/sizer.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({Key? key}) : super(key: key); + + @override + State createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + final loginFormKey = GlobalKey(); + var projectIdController = TextEditingController(); + var userIdController = TextEditingController(); + var passwordController = TextEditingController(); + + SizedBox buildSpacer20h() => SizedBox(height: 3.h); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 10.h), + Padding( + padding: EdgeInsets.only(left: 8.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + LocaleKeys.welcomeTo.tr(), + style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600, fontFamily: 'Poppins'), + ), + Text( + LocaleKeys.drSulaiman.tr(), + style: TextStyle(color: MyColors.blackColor, fontWeight: FontWeight.bold, fontSize: 24.sp, fontFamily: 'Poppins'), + ), + Text( + "Nurses App", + style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600, color: MyColors.redColor), + ), + ], + ), + ), + SizedBox(height: 4.h), + Form( + key: loginFormKey, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 8.w), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + buildSpacer20h(), + CustomTextField(LocaleKeys.userID.tr(), userIdController, isEnableBorder: true, ), + buildSpacer20h(), + CustomTextField(LocaleKeys.password.tr(), passwordController, isTextIsPassword: true), + buildSpacer20h(), + CustomTextField( + LocaleKeys.branch.tr(), + projectIdController, + hasSelection: true, + isEnable: false, + onClick: () => CustomCupertinoPicker.showCupertinoPicker(context, [], () {}), + ), + buildSpacer20h() + ]), + ), + ) + ], + ), + ), + bottomSheet: Container( + height: 12.h, + color: MyColors.backgroundColor, + width: double.infinity, + child: Center( + child: FractionallySizedBox( + widthFactor: 0.9, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 4.w), + child: DefaultButton(LocaleKeys.login.tr(), () { + Navigator.pushNamed(context, AppRoutes.loginMethodsPage); + }, colors: const [MyColors.redColor, MyColors.redColor]), + ), + SizedBox(height: 3.h) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/login/login_vm.dart b/lib/ui/login/login_vm.dart new file mode 100644 index 0000000..1b5f238 --- /dev/null +++ b/lib/ui/login/login_vm.dart @@ -0,0 +1,7 @@ + +import 'package:flutter/cupertino.dart'; + +class LoginVM extends ChangeNotifier { + + +} \ No newline at end of file diff --git a/lib/widgets/cupertino_picker.dart b/lib/widgets/cupertino_picker.dart new file mode 100644 index 0000000..c45ef8b --- /dev/null +++ b/lib/widgets/cupertino_picker.dart @@ -0,0 +1,71 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_nurses/generated/locale_keys.g.dart'; +import 'package:sizer/sizer.dart'; + +class CustomCupertinoPicker { + static TextStyle textStyle(context) => TextStyle(color: Theme.of(context).primaryColor); + + static int cupertinoPickerIndex = 0; + + static buildPickerItems(context, List items, onSelectFun) { + return CupertinoPicker( + magnification: 1.5, + scrollController: FixedExtentScrollController(initialItem: cupertinoPickerIndex), + itemExtent: 25, + looping: false, + onSelectedItemChanged: (int index) { + cupertinoPickerIndex = index; + }, + children: items.map((item) { + return Text( + '${item.facilityName}', + style: TextStyle(fontSize: 12.sp), + ); + }).toList(), + ); + } + + static showCupertinoPicker(context, List items, onSelectFun) { + showModalBottomSheet( + isDismissible: false, + context: context, + builder: (BuildContext builder) { + return Container( + height: 40.h, + color: const Color(0xfff7f7f7), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + color: const Color(0xfff7f7f7), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + CupertinoButton( + child: Text(LocaleKeys.userID.tr(), style: textStyle(context)), + onPressed: () { + Navigator.pop(context); + }, + ), + CupertinoButton( + child: Text( + LocaleKeys.userID.tr(), + style: textStyle(context), + ), + onPressed: () { + Navigator.pop(context); + onSelectFun(cupertinoPickerIndex); + }, + ) + ], + ), + ), + Container(height: 3.h, color: const Color(0xfff7f7f7), child: buildPickerItems(context, items, onSelectFun)) + ], + ), + ); + }); + } +} diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index 45d1417..8795a2d 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -2,10 +2,11 @@ import 'package:flutter/material.dart'; import 'package:hmg_nurses/classes/colors.dart'; import 'package:hmg_nurses/extensions/int_extensions.dart'; import 'package:hmg_nurses/extensions/widget_extensions.dart'; +import 'package:sizer/sizer.dart'; -class InputWidget extends StatefulWidget { +class CustomTextField extends StatefulWidget { final String labelText; - final String hintText; + final String? hintText; final TextEditingController controller; final VoidCallback? suffixTap; final bool isEnable; @@ -18,19 +19,21 @@ class InputWidget extends StatefulWidget { final double verticalPadding; final double horizontalPadding; final Function(String)? onChange; + final Function? onClick; - InputWidget( + const CustomTextField( this.labelText, - this.hintText, this.controller, { Key? key, this.isTextIsPassword = false, this.suffixTap, + this.hintText, this.isEnable = true, this.hasSelection = false, this.isEnableBorder = true, this.lines = 1, this.onChange, + this.onClick, this.isInputTypeNum = false, this.isBackgroundEnable = false, this.verticalPadding = 15, @@ -38,12 +41,10 @@ class InputWidget extends StatefulWidget { }) : super(key: key); @override - _InputWidgetState createState() { - return _InputWidgetState(); - } + CustomTextFieldState createState() => CustomTextFieldState(); } -class _InputWidgetState extends State { +class CustomTextFieldState extends State { late bool isObscureText; @override @@ -64,31 +65,34 @@ class _InputWidgetState extends State { alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), - color: widget.isBackgroundEnable ? Color(0xffF7F7F7) : Colors.white, - border: Border.all( - color: widget.isEnableBorder ? Color(0xffefefef) : Colors.transparent, - width: 1, - ), + color: widget.isBackgroundEnable ? const Color(0xffF7F7F7) : Colors.white, + border: Border.all(color: widget.isEnableBorder ? Colors.grey.shade300 : Colors.transparent, width: 1), ), child: InkWell( - onTap: widget.hasSelection ? () {} : null, + onTap: widget.hasSelection + ? () { + widget.onClick!(); + } + : null, child: Row( children: [ Expanded( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, children: [ Text( widget.labelText, - style: const TextStyle( - fontSize: 11, + style: TextStyle( + fontSize: 9.sp, fontWeight: FontWeight.w600, - color: Color(0xff2B353E), + color: const Color(0xff2B353E), letterSpacing: -0.44, ), ), TextField( + autofocus: false, enabled: widget.isEnable, scrollPadding: EdgeInsets.zero, keyboardType: widget.isInputTypeNum ? TextInputType.number : TextInputType.text, @@ -133,7 +137,7 @@ class _InputWidgetState extends State { }); }) ], - if (widget.hasSelection) Icon(Icons.keyboard_arrow_down_outlined), + if (widget.hasSelection) const Icon(Icons.keyboard_arrow_down_outlined), ], ), ), diff --git a/pubspec.lock b/pubspec.lock index 72e9cac..3203415 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -116,6 +116,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.7" flutter_svg: dependency: "direct main" description: @@ -182,6 +189,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + local_auth: + dependency: "direct main" + description: + name: local_auth + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + local_auth_android: + dependency: transitive + description: + name: local_auth_android + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.15" + local_auth_ios: + dependency: transitive + description: + name: local_auth_ios + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.10" + local_auth_platform_interface: + dependency: transitive + description: + name: local_auth_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" + local_auth_windows: + dependency: transitive + description: + name: local_auth_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" logger: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index c593a83..5aaa270 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,6 +49,7 @@ dependencies: auto_size_text: ^3.0.0 shimmer: ^2.0.0 sizer: ^2.0.15 + local_auth: ^2.1.2 dev_dependencies: flutter_test: @@ -74,4 +75,25 @@ flutter: assets: - assets/ - - assets/langs/ \ No newline at end of file + - assets/langs/ + - assets/images/login/ + - assets/images/patient/ + + + + fonts: + + - family: Poppins + fonts: + - asset: assets/fonts/Poppins/Poppins-Regular.ttf + weight: 400 + - asset: assets/fonts/Poppins/Poppins-Medium.ttf + weight: 500 + - asset: assets/fonts/Poppins/Poppins-SemiBold.ttf + weight: 600 + - asset: assets/fonts/Poppins/Poppins-Bold.ttf + weight: 700 + - asset: assets/fonts/Poppins/Poppins-Bold.ttf + weight: 800 + - asset: assets/fonts/Poppins/Poppins-Bold.ttf + weight: 900