From 40e9ab864a2dc371dd588c7ae78a0bd731d155b3 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Tue, 12 Jan 2021 11:36:42 +0300 Subject: [PATCH] login changes --- android/app/build.gradle | 4 +- android/app/google-services.json | 39 + android/build.gradle | 1 + android/google-services.json | 39 + android/gradle.properties | 3 +- assets/images/login/101.png | Bin 0 -> 3484 bytes assets/images/login/102.png | Bin 0 -> 3991 bytes assets/images/login/103.png | Bin 0 -> 2377 bytes assets/images/login/104.png | Bin 0 -> 4981 bytes assets/images/login/fileNum.png | Bin 0 -> 1515 bytes assets/images/login/forget.png | Bin 0 -> 1980 bytes assets/images/login/id.png | Bin 0 -> 1308 bytes assets/images/login/more_icon.png | Bin 0 -> 488 bytes assets/images/login/nationalID.png | Bin 0 -> 2834 bytes lib/client/base_app_client.dart | 24 +- lib/config/config.dart | 10 +- lib/config/localized_values.dart | 35 + lib/config/shared_pref_kay.dart | 2 + lib/core/model/imei_details.dart | 88 ++ lib/core/model/insert_imei_model.dart | 92 ++ lib/core/service/auth_service.dart | 29 + lib/core/service/medicine_service.dart | 1 - lib/core/viewModel/auth_view_model.dart | 76 +- lib/core/viewModel/imei_view_model.dart | 21 + lib/core/viewModel/project_view_model.dart | 7 +- lib/locator.dart | 5 + lib/main.dart | 51 +- .../auth/activation_Code_req_model.dart | 21 +- .../check_activation_code_request_model.dart | 29 +- lib/screens/auth/login_screen.dart | 149 +-- .../auth/verification_methods_screen.dart | 2 +- lib/screens/dashboard_screen.dart | 9 + .../reschedule-leaves/reschedule_leave.dart | 4 +- lib/util/helpers.dart | 17 +- lib/util/translations_delegate_base.dart | 53 +- lib/widgets/auth/known_user_login.dart | 4 +- lib/widgets/auth/login_form.dart | 35 +- lib/widgets/auth/verification_methods.dart | 861 ++++++++++++++---- lib/widgets/otp/sms-popup.dart | 346 +++++++ pubspec.lock | 28 + pubspec.yaml | 4 +- 41 files changed, 1702 insertions(+), 387 deletions(-) create mode 100644 android/app/google-services.json create mode 100644 android/google-services.json create mode 100644 assets/images/login/101.png create mode 100644 assets/images/login/102.png create mode 100644 assets/images/login/103.png create mode 100644 assets/images/login/104.png create mode 100644 assets/images/login/fileNum.png create mode 100644 assets/images/login/forget.png create mode 100644 assets/images/login/id.png create mode 100644 assets/images/login/more_icon.png create mode 100644 assets/images/login/nationalID.png create mode 100644 lib/core/model/imei_details.dart create mode 100644 lib/core/model/insert_imei_model.dart create mode 100644 lib/core/service/auth_service.dart create mode 100644 lib/core/viewModel/imei_view_model.dart create mode 100644 lib/widgets/otp/sms-popup.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index ae87782e..da345fc2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -44,6 +44,7 @@ android { versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + multiDexEnabled true } buildTypes { @@ -72,9 +73,10 @@ dependencies { implementation 'com.opentok.android:opentok-android-sdk:2.16.5' //permissions implementation 'pub.devrel:easypermissions:0.4.0' - +implementation 'com.google.firebase:firebase-core:9.6.1' //retrofit implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1' + apply plugin: 'com.google.gms.google-services' } diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..3c00f05c --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "1008895414777", + "project_id": "doctorapp-9f172", + "storage_bucket": "doctorapp-9f172.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1008895414777:android:d00fe21d6955c21b1f6d28", + "android_client_info": { + "package_name": "com.example.doctor_app_flutter" + } + }, + "oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCNncEIj8ehVUSxV89rx0x1NaWp8t1YVkw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 357c6a1a..ea0f0026 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.3.2' } } diff --git a/android/google-services.json b/android/google-services.json new file mode 100644 index 00000000..3c00f05c --- /dev/null +++ b/android/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "1008895414777", + "project_id": "doctorapp-9f172", + "storage_bucket": "doctorapp-9f172.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1008895414777:android:d00fe21d6955c21b1f6d28", + "android_client_info": { + "package_name": "com.example.doctor_app_flutter" + } + }, + "oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCNncEIj8ehVUSxV89rx0x1NaWp8t1YVkw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "1008895414777-3mg88j5ocs5r1au7rf4sh3f4pgsri2f2.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties index 38c8d454..9c0729c9 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,5 @@ -org.gradle.jvmargs=-Xmx1536M + android.enableR8=true android.useAndroidX=true android.enableJetifier=true +org.gradle.jvmargs=-Xmx4608m diff --git a/assets/images/login/101.png b/assets/images/login/101.png new file mode 100644 index 0000000000000000000000000000000000000000..90c1c575a19e47ad913fbe1e2be3f9182be3f826 GIT binary patch literal 3484 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 ZIgsNVRcpaEn4PP#nej=?ebiaz{{cCP0nY#c literal 0 HcmV?d00001 diff --git a/assets/images/login/103.png b/assets/images/login/103.png new file mode 100644 index 0000000000000000000000000000000000000000..3326814bc80e6682a73f4a36f62f4cbd5b15f36d GIT binary patch literal 2377 zcmaJ@cT`hZ9)1bvMh9FeHrhNAR9qlU2qYMRkkBNE5Rj2(Ade72ib;?FYQV7(P{9$g zuF4=55QgT`22>Df!wf3oAO{uO*Fr4%_8{fU!T52S?aRlY}z1+)gOP zEHcm`X|#kVmhnVFP|L`U5+%r}XjtjzEeOP4Xob>+GQkDI$=PBY0gKmeX)%z={Qsc> z!Ix;MECBkC-v3D~WhIFrTmU2$B}k&-gNwmvQ;8|=5{NAmNmwFL{9+aTV?{ENG*%=A z-QBfSa{{e*@`M~wqIAuLZBuw( z*Fyg)-vXBNRV@U@SFt!)3{HEv|8>}lOR$5q!!Oo_Ctu7D31P=eU~8LCIi3N4CDq<^ zH=N^s8Ds4cK8b(m$_7)nbmh>oA#W>;fzd&iOpEumRzFtDe;bj%JDq;W%+NRF zqy??ahrXRQbH#!s)`eE-nk%pt#ybtH@{Z`|{eGisT|*v!_t@={k2SYy9g`yEzeC9d zwR0&o^~JY}Cxn?E7(};cAPSM{3LwFisQ^kBeAQ48UjHQ4-q&>!oU{^QB7H12&HD&B z<{D3RgxWKG_5)gN88jnRDbN=GbjcoA-{ALg*DT}CpBvXa>lneRe>DQ4Qn*pzw}{A zf~LsA<424Y7c(mP+dr5jtmt~J-xN`}UcIKHtX;X{QdoTJg{;W<0wr=?)E3*(kU`YF zrdXUV2p|!tg=#IKsr;rr47mH{mW+fS?Ceiru!?a!VK>PA(e;9M&= zVzu#(u)Z$Zt#bw2dOP*1w+XW^jFvn}Y`dKOsylKV0fo%!$C+PT-A$^@aoLfS5p?P9 zyn9%;(ZqDbypi+ezud3pKHK|P{hT$de$bt0l`gb8;^OtXZn4eSK*I8-nV5P8e>#+>C+m+g63uCHYj=eYN z-5b(Vv^4AXkr~@z7!jnC&($#7_k^1tt+-amsCT8c*Tw}rtx{h0cYeO7<7Z7mg#%(z zb^f--)ayB7lTAfkrS2nx1Brbzdd`J9j~rAf;WcFln5dVOvcLE3iyuqJQTaDDc0Kz9 zWUZoJq=9d8Y4tEb?uFY^RT+f4QHGfRtR>3bD->I%>zv;7hKWBB)~Vk4xd z1j7NX`;NDTYJT&6e2VMb(JE^#Jz{^Zuh=;`JkF~~{gedhpB8L%3H>%zCvRJ*4zotG z#IO*SMZEBhZ_kS+mp4EZ#o*WEPuUT?(DRuuO0TYexZ>P0ul6YpA8A-ySE)mMf&b~% zv@vM3@?K`39mUM*W?N`&@R>UHM^ZNR*jUBGNlwPg{?zeboDT%&s)Li$;`Y50_yvxy z>E==!gQ&SCk0c|eRWt5UryZRp&Z_*g@vZC}lxwFB$Y;#F^>4v-N?vj?q^$4JDR-Z( zOOVvAF1<5~P&=vy7^K5Dj0$rSTp#;rd=62m6SS_Ff=LOt>%^eZLB-mh6|f8Wz8w+R zUc%{{Je~4*ouN);%EiKV%^@KNTHkG_;IXY&Z`DWfd;CczyXsPGc zyVD%+N}8Xgptkwvkq?%pLFGI9d-f00J*_Kd>w`Z~eGgbp8Q5INFHw$dD&%4+%bL^X z0y)!3Co{&FH~t(=)pbm<)Wag-JM!~Q2_P9y6i7Xw3VFkY99pw DG{ouR literal 0 HcmV?d00001 diff --git a/assets/images/login/104.png b/assets/images/login/104.png new file mode 100644 index 0000000000000000000000000000000000000000..ad55ff74ccab0ca8b0e74beefb641f0d55274f09 GIT binary patch literal 4981 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 literal 0 HcmV?d00001 diff --git a/assets/images/login/fileNum.png b/assets/images/login/fileNum.png new file mode 100644 index 0000000000000000000000000000000000000000..386299b71c8891a99fa03ee33616a4045bb7e1a7 GIT binary patch literal 1515 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAnN?apKg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+AuIMt7V2nltlRYSS9D@>Lr5I=vCwv0Ch7k*w|MTBqnF4mMA2p zrf25aD!t#mUr8Y|#a1cY)Yrhbz&SM|)1#^=HMq(zB)KX(*)m1R-cG@$!U||WZfZ%Q zLPc&)Ua?h$trFN=Dz9|8 z>y;bpKhp88yV>WRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<-In3$Ab zT4JjNbScCOxdm`z^NOLt1Pn0!io^naLp=kKmtYEgeeo;J&4sHjE(uCSxEHIz#UYgi zsro^w#rdU0$-sz9QwCX8VC7ttnpl!w6q28x0}I7~jQo=P;*9(P1!reas97jzglFcZ z|Z5PA)9>IEf-+ybD@E~!PCWvMA{Mftf3U~gMx;&h9l zD^ByEdQ)(^#n26>UVWfr^g)q}6xlE#UXa%Gads*vRAZsrY^%^n9k zcf{5=9M^iR@z7VtELDWFc}ms!)#sf3Q^LMiCHPP6KK@VbbEor_C!9MB{)V01{(6p0 zlXbxAESu#5@xdOt{OJp|&kAerJgnsyeR=NGkK3eLQ?`zJe92QOY`BS%J!ACvQ>vKLOUft&R{Q3GL*V6<# zOQuc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuk#7M#1QqR!L zz|zP>N5ROz&|KfZT;I@G*TB%qz|6|nQUMB-fVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7I$DAX(zG{Q6U zQu51-HNkp(eXTt6ic1pnl2bihY?Xkf=w)W6SeY0Z8=JbAy1E)!8XFqAT3Q-g8aNv} zS~xj6IXPNdy213iEv!_1oxXPkT zDaO(tEs6~a3{4IK42}vM4GID*9%_$1)!wgt7akkI`KiVyDk5-(+Q}Vj>v(qCN_INU zcx&GFFMb-c(Bec%j}L6Sdsbx@+*rR{WlQv?4kKpGIFCp+HMNgUDi%6jgJ$rOxZilDsn=b#%Wm_aNYgar+ zlMc6o00)x-2MePBOA`afrKc9VT4(#HY0mWv))C|0a(QV`XVK0%|0K+0LSJ3Yn)>Va z)f>yhR)%C06l|!D6+6!tdL*G@+Nvw_9nw73hAqx8S>nY15*%(~o`_+S%#lHoW?}Yf4peUS8j`=g%`UGFB}8Jb(WD%<@4Zj& zRyLa1BgSHGZa&LHt>*UEjhi<=-j#p-`t@5!juhR!2W(`sxLGo1LCrWwdYF)gf(SYWlV6OyrcwDXu#-tSl`r8gF2m zJ$v>%mY?hH?91$B&s&%GS|?HbM&ABin+%?;{{8OVyRSO}G%g%G*!XyVadmaK*IjNs zef`q!TefXmc3t@S^XDtBgeD{=HeS1aJu@NUz}4S(_wgGZVSl{q@ynMlV|gA)-N z+xd4)*s9bsx4R$`m^&sE9N1n}>8@;liX}T-_f6W9WY65>4=2->UhlhlHT3@Nw$qyw zCwko2XJ=;CCb3AUzrSBVh2sqC!kLQ~E3b)*t;^jX&3dhO0Os)=Qv18 z1m!&tt4451Ut&O;y^e?6;{`nJHO*c2NmK0aKGi;^eB-8~j+`N%RJ{INlX=XQAGRmR gbDjS5c|Q{mgUjL{4U(<*w}a|aPgg&ebxsLQ02Xi>SO5S3 literal 0 HcmV?d00001 diff --git a/assets/images/login/id.png b/assets/images/login/id.png new file mode 100644 index 0000000000000000000000000000000000000000..9260cf11180d8e60b98b933e0fc6841698ddac67 GIT binary patch literal 1308 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAnN?apKg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+AuIMt7V2nltlRYSS9D@>Lr5I=vCwv0Ch7k*w|MTBqnF4mMA2p zrf25aD!t#mUr8Y|#a1cY)Yrhbz&SM|)1#^=HMq(zB)KX(*)m1R-cG@$!U||WZfZ%Q zLPc&)Ua?h$trFN=Dz9|8 z>y;bpKhp88yV>WRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<-In3$Ab zT4JjNbScCOxdm`z^NOLt1Pn0!io^naLp=kKmtYEgeeo;J&4sHjE(uCSxEHIz#UYgi zsro^w#rdU0$-sz9QwCX8VC7ttnpl!w6q28x0}I7~jQo=P;*9(P1!reas97jzglFcZ z12bv3duGcJdP9C8bQHoK%2WtOF;xE1B+DuBIhm5JLe z&N$73>P^Az78jg)^?{Dj2SqMYWW$7jDG0=bCtV;1p7>MqfGNHRn6zK^f9z&pVC?a9 zaSW-rmGtNTe|zS&jKa*a46!O=R0koXr7Mcj2q1a^w}S&Whkv=Oj0#rwr5&dwIEf#U`A^ar%?vmqXdoJf*s$P zK2~c;OIz?A(JuHYHeGd6MvdeOM+I+@3r`%Tydo{-?$a-u^su}u!CQO zH{uF6b91k>M2ddL*`6kcJN-wdGdxmK5MzDh?ocDoUdOjZqc_6as4;@ocMVrZWy6e_ z0ngOTc3j!ev60bmh04@pf-wpoxFurFdvprtG)T^Bxms|do}DdR`NAUUDG^Lwp-Wk= zG(1`}N5cCX!$!HNn!U|xi2*AW+LtHH@zU5)vEYl4#xb^E9hzYi&NM|A$wnP(=$h#1 z@TYysCT$KJp00i_>zopr04ad7(EtDd literal 0 HcmV?d00001 diff --git a/assets/images/login/more_icon.png b/assets/images/login/more_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b696d345a329b1fc4d647bf3802be648ecea8b66 GIT binary patch literal 488 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 localizedValues = { 'en': "There is no Chief Complaint", 'ar': "ليس هناك شكوى رئيس" }, + "more-verify": { + "en": "More Verification Options", + "ar": "المزيد من خيارات التحقق" + }, + "welcome-back": {"en": "Welcome back!", "ar": "مرحبا بعودتك!"}, + "account-info": { + "en": "Would you like to login with current username?", + "ar": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟" + }, + "another-acc": {"en": "Use Another Account", "ar": "استخدم حسابا آخر"}, + "verify-login-with": { + "en": "Please choose one of the following options to verify", + "ar": "الرجاء اختيار احدى الخيارات التالية للتحقق من البيانات" + }, + "register-user": {"en": "Register", "ar": "تسجيل"}, + "verify-with-fingerprint": {"en": "Fingerprint", "ar": "بصمة"}, + "verify-with-faceid": {"en": "Face ID", "ar": "معرف الوجه"}, + "verify-with-sms": {"en": "SMS", "ar": "الرسائل القصيرة"}, + "verify-with-whatsapp": {"en": "Whatsapp", "ar": " الواتس اب"}, + "last-login": {"en": "LAST LOGIN AT:", "ar": "آخر تسجيل دخول"}, + "last-login-with": {"en": "VERIFICATION TYPE:", "ar": "نوع التحقق:"}, + "verify-fingerprint": { + "en": + "To activate the fingerprint login service, please verify data by using one of the following options.", + "ar": + "لتفعيل خدمة الدخول بالبصمة، يرجى اختيار احدى القنوات التالية للتحقق من البيانات" + }, + "verification_message": { + "en": "Please enter the Verification Code sent to", + "ar": "الرجاء ادخال رمز التحقق الذي تم إرساله إلى" + }, + "validation_message": { + "en": "The verification code expires in", + "ar": "تنتهي صلاحية رمز التحقق خلال" + }, }; diff --git a/lib/config/shared_pref_kay.dart b/lib/config/shared_pref_kay.dart index e483c7d1..1520207f 100644 --- a/lib/config/shared_pref_kay.dart +++ b/lib/config/shared_pref_kay.dart @@ -10,3 +10,5 @@ final DOCTOR_PROFILE = 'doctorProfile'; final LIVE_CARE_PATIENT = 'livecare-patient-profile'; final LOGGED_IN_USER = 'loggedUser'; final DASHBOARD_DATA = 'dashboard-data'; +final OTP_TYPE = 'otp-type'; +final LAST_LOGIN_USER = 'last-login-user'; diff --git a/lib/core/model/imei_details.dart b/lib/core/model/imei_details.dart new file mode 100644 index 00000000..2cb0cd97 --- /dev/null +++ b/lib/core/model/imei_details.dart @@ -0,0 +1,88 @@ +class GetIMEIDetailsModel { + String iMEI; + int logInTypeID; + bool outSA; + String mobile; + String identificationNo; + int doctorID; + String doctorName; + String doctorNameN; + int clinicID; + String clinicDescription; + String clnicDescriptionN; + String projectName; + String genderDescription; + String genderDescriptionN; + String titleDescription; + String titleDescriptionN; + bool biometricEnabled; + int preferredLanguage; + bool isActive; + + GetIMEIDetailsModel( + {this.iMEI, + this.logInTypeID, + this.outSA, + this.mobile, + this.identificationNo, + this.doctorID, + this.doctorName, + this.doctorNameN, + this.clinicID, + this.clinicDescription, + this.clnicDescriptionN, + this.projectName, + this.genderDescription, + this.genderDescriptionN, + this.titleDescription, + this.titleDescriptionN, + this.biometricEnabled, + this.preferredLanguage, + this.isActive}); + + GetIMEIDetailsModel.fromJson(Map json) { + iMEI = json['IMEI']; + logInTypeID = json['LogInTypeID']; + outSA = json['OutSA']; + mobile = json['Mobile']; + identificationNo = json['IdentificationNo']; + doctorID = json['DoctorID']; + doctorName = json['DoctorName']; + doctorNameN = json['DoctorNameN']; + clinicID = json['ClinicID']; + clinicDescription = json['ClinicDescription']; + clnicDescriptionN = json['ClnicDescriptionN']; + projectName = json['ProjectName']; + genderDescription = json['Gender_Description']; + genderDescriptionN = json['Gender_DescriptionN']; + titleDescription = json['Title_Description']; + titleDescriptionN = json['Title_DescriptionN']; + biometricEnabled = json['BiometricEnabled']; + preferredLanguage = json['PreferredLanguage']; + isActive = json['IsActive']; + } + + Map toJson() { + final Map data = new Map(); + data['IMEI'] = this.iMEI; + data['LogInTypeID'] = this.logInTypeID; + data['OutSA'] = this.outSA; + data['Mobile'] = this.mobile; + data['IdentificationNo'] = this.identificationNo; + data['DoctorID'] = this.doctorID; + data['DoctorName'] = this.doctorName; + data['DoctorNameN'] = this.doctorNameN; + data['ClinicID'] = this.clinicID; + data['ClinicDescription'] = this.clinicDescription; + data['ClnicDescriptionN'] = this.clnicDescriptionN; + data['ProjectName'] = this.projectName; + data['Gender_Description'] = this.genderDescription; + data['Gender_DescriptionN'] = this.genderDescriptionN; + data['Title_Description'] = this.titleDescription; + data['Title_DescriptionN'] = this.titleDescriptionN; + data['BiometricEnabled'] = this.biometricEnabled; + data['PreferredLanguage'] = this.preferredLanguage; + data['IsActive'] = this.isActive; + return data; + } +} diff --git a/lib/core/model/insert_imei_model.dart b/lib/core/model/insert_imei_model.dart new file mode 100644 index 00000000..c2285d92 --- /dev/null +++ b/lib/core/model/insert_imei_model.dart @@ -0,0 +1,92 @@ +class InsertIMEIDetailsModel { + String iMEI; + int logInTypeID; + bool outSA; + String mobileNo; + String identificationNo; + int doctorID; + String doctorName; + String doctorNameN; + int clinicID; + String clinicDescription; + String clinicDescriptionN; + String projectName; + int projectID; + String genderDescription; + String genderDescriptionN; + String titleDescription; + String titleDescriptionN; + bool bioMetricEnabled; + int preferredLanguage; + bool isActive; + + InsertIMEIDetailsModel( + {this.iMEI, + this.logInTypeID, + this.outSA, + this.mobileNo, + this.identificationNo, + this.doctorID, + this.doctorName, + this.doctorNameN, + this.clinicID, + this.clinicDescription, + this.clinicDescriptionN, + this.projectName, + this.projectID, + this.genderDescription, + this.genderDescriptionN, + this.titleDescription, + this.titleDescriptionN, + this.bioMetricEnabled, + this.preferredLanguage, + this.isActive}); + + InsertIMEIDetailsModel.fromJson(Map json) { + iMEI = json['IMEI']; + logInTypeID = json['LogInTypeID']; + outSA = json['OutSA']; + mobileNo = json['MobileNo']; + identificationNo = json['IdentificationNo']; + doctorID = json['DoctorID']; + doctorName = json['DoctorName']; + doctorNameN = json['DoctorNameN']; + clinicID = json['ClinicID']; + clinicDescription = json['ClinicDescription']; + clinicDescriptionN = json['ClinicDescriptionN']; + projectName = json['ProjectName']; + projectID = json['ProjectID']; + genderDescription = json['GenderDescription']; + genderDescriptionN = json['GenderDescriptionN']; + titleDescription = json['TitleDescription']; + titleDescriptionN = json['TitleDescriptionN']; + bioMetricEnabled = json['BioMetricEnabled']; + preferredLanguage = json['PreferredLanguage']; + isActive = json['IsActive']; + } + + Map toJson() { + final Map data = new Map(); + data['IMEI'] = this.iMEI; + data['LogInTypeID'] = this.logInTypeID; + data['OutSA'] = this.outSA; + data['MobileNo'] = this.mobileNo; + data['IdentificationNo'] = this.identificationNo; + data['DoctorID'] = this.doctorID; + data['DoctorName'] = this.doctorName; + data['DoctorNameN'] = this.doctorNameN; + data['ClinicID'] = this.clinicID; + data['ClinicDescription'] = this.clinicDescription; + data['ClinicDescriptionN'] = this.clinicDescriptionN; + data['ProjectName'] = this.projectName; + data['ProjectID'] = this.projectID; + data['GenderDescription'] = this.genderDescription; + data['GenderDescriptionN'] = this.genderDescriptionN; + data['TitleDescription'] = this.titleDescription; + data['TitleDescriptionN'] = this.titleDescriptionN; + data['BioMetricEnabled'] = this.bioMetricEnabled; + data['PreferredLanguage'] = this.preferredLanguage; + data['IsActive'] = this.isActive; + return data; + } +} diff --git a/lib/core/service/auth_service.dart b/lib/core/service/auth_service.dart new file mode 100644 index 00000000..e116ccdd --- /dev/null +++ b/lib/core/service/auth_service.dart @@ -0,0 +1,29 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/service/base/base_service.dart'; +import 'package:doctor_app_flutter/models/dashboard/dashboard_model.dart'; + +class AuthService extends BaseService { + List _imeiDetails = []; + List get dashboardItemsList => _imeiDetails; + + Future selectDeviceImei(imei) async { + try { + // dynamic localRes; + await baseAppClient.post(SELECT_DEVICE_IMEI, + onSuccess: (dynamic response, int statusCode) { + _imeiDetails = []; + response['List_DoctorDeviceDetails'].forEach((v) { + _imeiDetails.add(GetIMEIDetailsModel.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: {"IMEI": imei, "TokenID": "@dm!n"}); + //return Future.value(localRes); + } catch (error) { + hasError = true; + super.error = error; + } + } +} diff --git a/lib/core/service/medicine_service.dart b/lib/core/service/medicine_service.dart index df23172f..f205dab1 100644 --- a/lib/core/service/medicine_service.dart +++ b/lib/core/service/medicine_service.dart @@ -14,7 +14,6 @@ class MedicineService extends BaseService { PharmaciesItemsRequestModel(); PharmaciesListRequestModel _listRequestModel = PharmaciesListRequestModel(); - Future getMedicineItem(String itemName) async { _itemsRequestModel.pHRItemName = itemName; await baseAppClient.post( diff --git a/lib/core/viewModel/auth_view_model.dart b/lib/core/viewModel/auth_view_model.dart index 47ffe730..00089ef9 100644 --- a/lib/core/viewModel/auth_view_model.dart +++ b/lib/core/viewModel/auth_view_model.dart @@ -1,4 +1,10 @@ import 'package:doctor_app_flutter/client/base_app_client.dart'; +import 'package:doctor_app_flutter/core/enum/viewstate.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/model/insert_imei_model.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; +import 'package:doctor_app_flutter/locator.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; @@ -12,8 +18,9 @@ import '../../models/doctor/user_model.dart'; DrAppSharedPreferances sharedPref = new DrAppSharedPreferances(); enum APP_STATUS { LOADING, UNAUTHENTICATED, AUTHENTICATED } -class AuthViewModel with ChangeNotifier { +class AuthViewModel extends BaseViewModel { List doctorsClinicList = []; + String selectedClinicName; bool isLogin = false; bool isLoading = true; @@ -71,35 +78,29 @@ class AuthViewModel with ChangeNotifier { } } - Future insertDeviceImei(imei) async { - try { - dynamic localRes; - - await baseAppClient.post(INSERT_DEVICE_IMEI, - onSuccess: (dynamic response, int statusCode) { - localRes = response; - }, onFailure: (String error, int statusCode) { - throw error; - }, body: imei); - return Future.value(localRes); - } catch (error) { - print(error); - throw error; - } - } + Future insertDeviceImei(request) async { + var loggedIn = await sharedPref.getObj(LOGGED_IN_USER); + + request['IMEI'] = DEVICE_TOKEN; + request['LogInTypeID'] = await sharedPref.getInt(OTP_TYPE); + request['BioMetricEnabled'] = true; + request['MobileNo'] = loggedIn['MobileNumber']; + InsertIMEIDetailsModel nRequest = InsertIMEIDetailsModel.fromJson(request); + nRequest.genderDescription = request['Gender_Description']; + nRequest.genderDescriptionN = request['Gender_DescriptionN']; + nRequest.genderDescriptionN = request['Gender_DescriptionN']; + nRequest.titleDescription = request['Title_Description']; + nRequest.titleDescriptionN = request['Title_DescriptionN']; + nRequest.projectID = await sharedPref.getInt(PROJECT_ID); - Future selectDeviceImei(imei) async { try { - dynamic localRes; - await baseAppClient.post(SELECT_DEVICE_IMEI, + var localRes; + await baseAppClient.post(INSERT_DEVICE_IMEI, onSuccess: (dynamic response, int statusCode) { localRes = response; - }, onFailure: (String error, int statusCode) { - throw error; - }, body: imei); + }, onFailure: (String error, int statusCode) {}, body: nRequest.toJson()); return Future.value(localRes); } catch (error) { - print(error); throw error; } } @@ -120,7 +121,8 @@ class AuthViewModel with ChangeNotifier { } } - Future sendActivationCodeForDoctorApp(ActivationCodeModel activationCodeModel) async { + Future sendActivationCodeForDoctorApp( + ActivationCodeModel activationCodeModel) async { try { var localRes; await baseAppClient.post(SEND_ACTIVATION_CODE_FOR_DOCTOR_APP, @@ -158,22 +160,22 @@ class AuthViewModel with ChangeNotifier { } } - - Future checkActivationCodeForDoctorApp(CheckActivationCodeRequestModel checkActivationCodeRequestModel) async { + Future checkActivationCodeForDoctorApp( + CheckActivationCodeRequestModel checkActivationCodeRequestModel) async { try { dynamic localRes; await baseAppClient.post(CHECK_ACTIVATION_CODE_FOR_DOCTOR_APP, onSuccess: (dynamic response, int statusCode) { - localRes = response; - selectedClinicName = - ClinicModel.fromJson(response['List_DoctorsClinic'][0]).clinicName; - - response['List_DoctorsClinic'].forEach((v) { - doctorsClinicList.add(new ClinicModel.fromJson(v)); - }); - }, onFailure: (String error, int statusCode) { - throw error; - }, body: checkActivationCodeRequestModel.toJson()); + localRes = response; + selectedClinicName = + ClinicModel.fromJson(response['List_DoctorsClinic'][0]).clinicName; + + response['List_DoctorsClinic'].forEach((v) { + doctorsClinicList.add(new ClinicModel.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + throw error; + }, body: checkActivationCodeRequestModel.toJson()); return Future.value(localRes); } catch (error) { print(error); diff --git a/lib/core/viewModel/imei_view_model.dart b/lib/core/viewModel/imei_view_model.dart new file mode 100644 index 00000000..29253b1d --- /dev/null +++ b/lib/core/viewModel/imei_view_model.dart @@ -0,0 +1,21 @@ +import 'package:doctor_app_flutter/client/base_app_client.dart'; +import 'package:doctor_app_flutter/core/enum/viewstate.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; +import 'package:doctor_app_flutter/locator.dart'; + +class IMEIViewModel extends BaseViewModel { + AuthService _authService = locator(); + List get imeiDetails => _authService.dashboardItemsList; + + Future selectDeviceImei(imei) async { + setState(ViewState.Busy); + await _authService.selectDeviceImei(imei); + if (_authService.hasError) { + error = _authService.error; + setState(ViewState.Error); + } else + setState(ViewState.Idle); + } +} diff --git a/lib/core/viewModel/project_view_model.dart b/lib/core/viewModel/project_view_model.dart index 1448fb47..aed67d83 100644 --- a/lib/core/viewModel/project_view_model.dart +++ b/lib/core/viewModel/project_view_model.dart @@ -24,6 +24,7 @@ class ProjectViewModel with ChangeNotifier { List doctorClinicsList = []; bool isLoading = false; bool isError = false; + bool isLogin = false; String error = ''; BaseAppClient baseAppClient = BaseAppClient(); @@ -56,7 +57,9 @@ class ProjectViewModel with ChangeNotifier { currentLanguage = await sharedPref.getString(APP_Language); _appLocale = Locale(currentLanguage ?? 'en'); _isArabic = currentLanguage != null - ? currentLanguage == 'ar' ? true : false + ? currentLanguage == 'ar' + ? true + : false : false; notifyListeners(); } @@ -69,7 +72,7 @@ class ProjectViewModel with ChangeNotifier { sharedPref.setString(APP_Language, 'ar'); } else if (lan != "ar" && currentLanguage != lan) { _appLocale = Locale("en"); - _isArabic = false; + _isArabic = false; currentLanguage = 'en'; sharedPref.setString(APP_Language, 'en'); } diff --git a/lib/locator.dart b/lib/locator.dart index a4ca7289..f939effc 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,10 +1,13 @@ +import 'package:doctor_app_flutter/core/service/auth_service.dart'; import 'package:doctor_app_flutter/core/service/dasboard_service.dart'; import 'package:doctor_app_flutter/core/service/medical_file_service.dart'; import 'package:doctor_app_flutter/core/service/patient_service.dart'; import 'package:doctor_app_flutter/core/service/prescription_service.dart'; import 'package:doctor_app_flutter/core/service/procedure_service.dart'; import 'package:doctor_app_flutter/core/service/sickleave_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/auth_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/dashboard_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/imei_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/medical_file_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/patient_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/prescription_view_model.dart'; @@ -54,9 +57,11 @@ void setupLocator() { locator.registerLazySingleton(() => MedicalFileService()); locator.registerLazySingleton(() => AdmissionRequestService()); locator.registerLazySingleton(() => UcafService()); + locator.registerLazySingleton(() => AuthService()); /// View Model locator.registerFactory(() => DoctorReplayViewModel()); + locator.registerFactory(() => IMEIViewModel()); locator.registerFactory(() => ScheduleViewModel()); locator.registerFactory(() => ReferralPatientViewModel()); locator.registerFactory(() => ReferredPatientViewModel()); diff --git a/lib/main.dart b/lib/main.dart index 3df44a70..1283da1e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -41,32 +41,31 @@ class MyApp extends StatelessWidget { ), ], child: Consumer( - builder: (context,projectProvider,child) => MaterialApp( - showSemanticsDebugger: false, - title: 'Flutter Demo', - locale: projectProvider.appLocal, - localizationsDelegates: [ - TranslationBaseDelegate(), - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: [ - const Locale('ar', ''), // Arabic - const Locale('en', ''), // English - ], - theme: ThemeData( - primarySwatch: Colors.grey, - primaryColor: Colors.grey, - buttonColor: HexColor('#B8382C'), - fontFamily: 'WorkSans', - dividerColor: Colors.grey[350], - backgroundColor: Color.fromRGBO(255,255,255, 1), - ), - initialRoute: INIT_ROUTE, - routes: routes, - debugShowCheckedModeBanner: false, - ) - ), + builder: (context, projectProvider, child) => MaterialApp( + showSemanticsDebugger: false, + title: 'Flutter Demo', + locale: projectProvider.appLocal, + localizationsDelegates: [ + TranslationBaseDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: [ + const Locale('ar', ''), // Arabic + const Locale('en', ''), // English + ], + theme: ThemeData( + primarySwatch: Colors.grey, + primaryColor: Colors.grey, + buttonColor: HexColor('#B8382C'), + fontFamily: 'WorkSans', + dividerColor: Colors.grey[350], + backgroundColor: Color.fromRGBO(255, 255, 255, 1), + ), + initialRoute: INIT_ROUTE, + routes: routes, + debugShowCheckedModeBanner: false, + )), ); }); }, diff --git a/lib/models/auth/activation_Code_req_model.dart b/lib/models/auth/activation_Code_req_model.dart index f8f48cd8..1a9510e8 100644 --- a/lib/models/auth/activation_Code_req_model.dart +++ b/lib/models/auth/activation_Code_req_model.dart @@ -8,17 +8,18 @@ class ActivationCodeModel { String password; int facilityId; String generalid; - + String otpSendType; ActivationCodeModel( {this.mobileNumber, - this.zipCode, - this.channel, - this.languageID, - this.versionID, - this.memberID, - this.password, - this.facilityId, - this.generalid}); + this.zipCode, + this.channel, + this.languageID, + this.versionID, + this.memberID, + this.password, + this.facilityId, + this.otpSendType, + this.generalid}); ActivationCodeModel.fromJson(Map json) { mobileNumber = json['MobileNumber']; @@ -29,6 +30,7 @@ class ActivationCodeModel { memberID = json['MemberID']; password = json['Password']; facilityId = json['facilityId']; + otpSendType = json['OTP_SendType']; generalid = json['generalid']; } @@ -42,6 +44,7 @@ class ActivationCodeModel { data['MemberID'] = this.memberID; data['Password'] = this.password; data['facilityId'] = this.facilityId; + data['OTP_SendType'] = otpSendType; data['generalid'] = this.generalid; return data; } diff --git a/lib/models/auth/check_activation_code_request_model.dart b/lib/models/auth/check_activation_code_request_model.dart index 856f1c43..9bb3d4f6 100644 --- a/lib/models/auth/check_activation_code_request_model.dart +++ b/lib/models/auth/check_activation_code_request_model.dart @@ -12,21 +12,22 @@ class CheckActivationCodeRequestModel { String activationCode; String vidaAuthTokenID; String vidaRefreshTokenID; - + int oTPSendType; CheckActivationCodeRequestModel( {this.mobileNumber, - this.zipCode, - this.doctorID, - this.iPAdress, - this.channel, - this.languageID, - this.projectID, - this.versionID, - this.generalid, - this.logInTokenID, - this.activationCode, - this.vidaAuthTokenID, - this.vidaRefreshTokenID}); + this.zipCode, + this.doctorID, + this.iPAdress, + this.channel, + this.languageID, + this.projectID, + this.versionID, + this.generalid, + this.logInTokenID, + this.activationCode, + this.vidaAuthTokenID, + this.vidaRefreshTokenID, + this.oTPSendType}); CheckActivationCodeRequestModel.fromJson(Map json) { mobileNumber = json['MobileNumber']; @@ -42,6 +43,7 @@ class CheckActivationCodeRequestModel { activationCode = json['activationCode']; vidaAuthTokenID = json['VidaAuthTokenID']; vidaRefreshTokenID = json['VidaRefreshTokenID']; + oTPSendType = json['OTP_SendType']; } Map toJson() { @@ -59,6 +61,7 @@ class CheckActivationCodeRequestModel { data['activationCode'] = this.activationCode; data['VidaAuthTokenID'] = this.vidaAuthTokenID; data['VidaRefreshTokenID'] = this.vidaRefreshTokenID; + data['OTP_SendType'] = this.oTPSendType; return data; } } diff --git a/lib/screens/auth/login_screen.dart b/lib/screens/auth/login_screen.dart index 5b495abb..1ed441e4 100644 --- a/lib/screens/auth/login_screen.dart +++ b/lib/screens/auth/login_screen.dart @@ -1,7 +1,17 @@ import 'dart:async'; +import 'dart:io'; import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; +import 'package:doctor_app_flutter/core/service/auth_service.dart'; +import 'package:doctor_app_flutter/core/viewModel/auth_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/imei_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../lookups/auth_lookup.dart'; @@ -23,21 +33,48 @@ class _LoginsreenState extends State { Future _prefs = SharedPreferences.getInstance(); String platformImei; - Future platformImeiFuture; - - bool _isLoading = false; - - Future getSharedPref() async { - sharedPref.getString('platformImei').then((imei) { - platformImei = imei; - }); - } - + // Future platformImeiFuture; + final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); + bool _isLoading = true; + ProjectViewModel projectViewModel; + AuthService authService = AuthService(); @override void initState() { super.initState(); - platformImeiFuture = _prefs.then((SharedPreferences prefs) { - return (prefs.getString('platformImei')); + + _firebaseMessaging.setAutoInitEnabled(true); + if (Platform.isIOS) { + _firebaseMessaging.requestNotificationPermissions(); + } + + _firebaseMessaging.getToken().then((String token) async { + if (DEVICE_TOKEN == "" && projectViewModel.isLogin == false) { + DEVICE_TOKEN = token; + changeLoadingStata(true); + authService.selectDeviceImei(DEVICE_TOKEN).then((value) { + print(authService.dashboardItemsList); + + if (authService.dashboardItemsList.length > 0) { + sharedPref.setObj( + LAST_LOGIN_USER, authService.dashboardItemsList[0]); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: null, + ))); + } else { + changeLoadingStata(false); + } + //changeLoadingStata(false); + }); + } else { + changeLoadingStata(false); + } + + // else if (projectViewModel.isLogin) { + // getNotificationCount(token); + // } + }).catchError((err) { + print(err); }); } @@ -56,54 +93,46 @@ class _LoginsreenState extends State { @override Widget build(BuildContext context) { - getSharedPref(); - return AppScaffold( - isLoading: _isLoading, - isShowAppBar: false, - body: SafeArea( - child: ListView(children: [ - FutureBuilder( - future: platformImeiFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return DrAppCircularProgressIndeicator(); - default: - if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return Container( - margin: EdgeInsetsDirectional.fromSTEB(30, 0, 30, 30), - alignment: Alignment.topLeft, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - (platformImei == null) - ? Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - AuthHeader(loginType.knownUser), - LoginForm( - changeLoadingStata: - changeLoadingStata, - ), - ], - ) - : Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - AuthHeader(loginType.unknownUser), - KnownUserLogin(), - ], + projectViewModel = Provider.of(context); + + return BaseView( + onModelReady: (model) => {}, + builder: (_, model, w) => AppScaffold( + baseViewModel: model, + isShowAppBar: false, + body: SafeArea( + child: (_isLoading == false) + ? ListView(children: [ + Container( + margin: + EdgeInsetsDirectional.fromSTEB(30, 0, 30, 30), + alignment: Alignment.topLeft, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + AuthHeader(loginType.knownUser), + LoginForm( + changeLoadingStata: changeLoadingStata, ), - ])); - } - } - }), - ]), - ), - ); + ], + ) + + // : Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // AuthHeader(loginType.unknownUser), + // KnownUserLogin(), + // ], + // ), + ])) + ]) + : Center(child: CircularProgressIndicator()), + ), + )); } } diff --git a/lib/screens/auth/verification_methods_screen.dart b/lib/screens/auth/verification_methods_screen.dart index 2b411dc0..0045f032 100644 --- a/lib/screens/auth/verification_methods_screen.dart +++ b/lib/screens/auth/verification_methods_screen.dart @@ -42,7 +42,7 @@ class _VerificationMethodsScreenState extends State { Widget build(BuildContext context) { return AppScaffold( isLoading: _isLoading, - isShowAppBar: false, + isShowAppBar: false, body: ListView(children: [ Container( margin: EdgeInsetsDirectional.fromSTEB(30, 0, 30, 0), diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index 20f22382..adc912d6 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -1,3 +1,4 @@ +import 'package:doctor_app_flutter/config/config.dart'; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; import 'package:doctor_app_flutter/config/size_config.dart'; import 'package:doctor_app_flutter/core/viewModel/dashboard_view_model.dart'; @@ -58,6 +59,14 @@ class _DashboardScreenState extends State { if (_isInit) { projectsProvider = Provider.of(context); projectsProvider.getDoctorClinicsList(); + + if (DEVICE_TOKEN != '') { + var request = await sharedPref.getObj(DOCTOR_PROFILE); + authProvider.insertDeviceImei(request).then((value) { + print(value['ReturnValue']); + changeIsLoading(false); + }); + } } _isInit = false; } diff --git a/lib/screens/reschedule-leaves/reschedule_leave.dart b/lib/screens/reschedule-leaves/reschedule_leave.dart index 6f3299d1..5d546c04 100644 --- a/lib/screens/reschedule-leaves/reschedule_leave.dart +++ b/lib/screens/reschedule-leaves/reschedule_leave.dart @@ -792,7 +792,7 @@ class _RescheduleLeaveScreen extends State { "doctorId": this.profile['DoctorID'], "dateTimeFrom": fromDate, "dateTimeTo": toDate, - "date": df.format(DateTime.now()), + "date": offTime == '1' ? fromDate : df.format(DateTime.now()), "reasonId": reason == null ? model.allOffTime[0]['code'] : reason, "coveringDoctorId": doctorID == null ? model.coveringDoctors[0]['doctorID'] : doctorID, @@ -846,7 +846,7 @@ class _RescheduleLeaveScreen extends State { "doctorId": this.profile['DoctorID'], "dateTimeFrom": fromDate, "dateTimeTo": toDate, - "date": df.format(DateTime.now()), + "date": offTime == '1' ? fromDate : df.format(DateTime.now()), "reasonId": reason == null ? model.allOffTime[0]['code'] : reason, "coveringDoctorId": doctorID == null ? model.coveringDoctors[0]['doctorID'] : doctorID, diff --git a/lib/util/helpers.dart b/lib/util/helpers.dart index 9a398949..a7229ca2 100644 --- a/lib/util/helpers.dart +++ b/lib/util/helpers.dart @@ -346,15 +346,17 @@ class Helpers { } logout() async { + DEVICE_TOKEN = ""; String lang = await sharedPref.getString(APP_Language); await clearSharedPref(); sharedPref.setString(APP_Language, lang); Navigator.of(AppGlobal.CONTEX).pushReplacementNamed(LOGIN); + // TODO Fix it // Navigator.of(AppGlobal.CONTEX).popUntil((ModalRoute.withName(LOGIN))); } - String parseHtmlString(String htmlString) { + String parseHtmlString(String htmlString) { final document = parse(htmlString); final String parsedString = parse(document.body.text).documentElement.text; @@ -380,11 +382,11 @@ class Helpers { hintText: selectedText != null ? selectedText : hintText, suffixIcon: isDropDown ? suffixIcon != null - ? suffixIcon - : Icon( - Icons.arrow_drop_down, - color: dropDownColor != null ? dropDownColor : Colors.black, - ) + ? suffixIcon + : Icon( + Icons.arrow_drop_down, + color: dropDownColor != null ? dropDownColor : Colors.black, + ) : null, hintStyle: TextStyle( fontSize: 14, @@ -394,7 +396,8 @@ class Helpers { } static BoxDecoration containerBorderDecoration( - Color containerColor, Color borderColor, {double borderWidth = -1}) { + Color containerColor, Color borderColor, + {double borderWidth = -1}) { return BoxDecoration( color: containerColor, shape: BoxShape.rectangle, diff --git a/lib/util/translations_delegate_base.dart b/lib/util/translations_delegate_base.dart index b167b48e..600b5f33 100644 --- a/lib/util/translations_delegate_base.dart +++ b/lib/util/translations_delegate_base.dart @@ -544,15 +544,60 @@ class TranslationBase { localizedValues['referralEmptyMsg'][locale.languageCode]; String get referralSuccessMsg => localizedValues['referralSuccessMsg'][locale.languageCode]; - String get diagnoseType => localizedValues['diagnoseType'][locale.languageCode]; + String get diagnoseType => + localizedValues['diagnoseType'][locale.languageCode]; String get condition => localizedValues['condition'][locale.languageCode]; String get id => localizedValues['id'][locale.languageCode]; String get quantity => localizedValues['quantity'][locale.languageCode]; String get codeNo => localizedValues['codeNo'][locale.languageCode]; String get covered => localizedValues['covered'][locale.languageCode]; - String get approvalRequired => localizedValues['approvalRequired'][locale.languageCode]; - String get uncoveredByDoctor => localizedValues['uncoveredByDoctor'][locale.languageCode]; - String get chiefComplaintEmptyMsg => localizedValues['chiefComplaintEmptyMsg'][locale.languageCode]; + String get approvalRequired => + localizedValues['approvalRequired'][locale.languageCode]; + String get uncoveredByDoctor => + localizedValues['uncoveredByDoctor'][locale.languageCode]; + String get chiefComplaintEmptyMsg => + localizedValues['chiefComplaintEmptyMsg'][locale.languageCode]; + + String get moreVerification => + localizedValues['more-verify'][locale.languageCode]; + + String get welcomeBack => + localizedValues['welcome-back'][locale.languageCode]; + + String get accountInfo => + localizedValues['account-info'][locale.languageCode]; + + String get useAnotherAccount => + localizedValues['another-acc'][locale.languageCode]; + + String get verifyLoginWith => + localizedValues['verify-login-with'][locale.languageCode]; + + String get register => localizedValues['register-user'][locale.languageCode]; + + String get verifyFingerprint => + localizedValues['verify-with-fingerprint'][locale.languageCode]; + + String get verifyFaceID => + localizedValues['verify-with-faceid'][locale.languageCode]; + + String get verifySMS => + localizedValues['verify-with-sms'][locale.languageCode]; + + String get verifyWhatsApp => + localizedValues['verify-with-whatsapp'][locale.languageCode]; + + String get lastLoginAt => localizedValues['last-login'][locale.languageCode]; + + String get lastLoginWith => + localizedValues['last-login-with'][locale.languageCode]; + + String get verifyFingerprint2 => + localizedValues['verify-fingerprint'][locale.languageCode]; + String get verificationMessage => + localizedValues['verification_message'][locale.languageCode]; + String get validationMessage => + localizedValues['validation_message'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/auth/known_user_login.dart b/lib/widgets/auth/known_user_login.dart index 4df37d66..b181aed8 100644 --- a/lib/widgets/auth/known_user_login.dart +++ b/lib/widgets/auth/known_user_login.dart @@ -70,8 +70,8 @@ class _KnownUserLoginState extends State { @override Widget build(BuildContext context) { AuthViewModel authProv = Provider.of(context); - var imeiModel = {'IMEI': _platformImei}; - _loginTypeFuture = authProv.selectDeviceImei(imeiModel); + // var imeiModel = {'IMEI': _platformImei}; + // _loginTypeFuture = authProv.selectDeviceImei(imeiModel); return FutureBuilder( future: Future.wait([_loggedUserFuture, _loginTypeFuture]), builder: (BuildContext context, AsyncSnapshot snapshot) { diff --git a/lib/widgets/auth/login_form.dart b/lib/widgets/auth/login_form.dart index 808b1763..3aac5cdd 100644 --- a/lib/widgets/auth/login_form.dart +++ b/lib/widgets/auth/login_form.dart @@ -224,26 +224,29 @@ class _LoginFormState extends State { } login(context, AuthViewModel authProv, Function changeLoadingStata) { - FocusScopeNode currentFocus = FocusScope.of(context); - changeLoadingStata(true); + showLoading(); if (loginFormKey.currentState.validate()) { loginFormKey.currentState.save(); sharedPref.setInt(PROJECT_ID, userInfo.projectID); authProv.login(userInfo).then((res) { - changeLoadingStata(false); - + //changeLoadingStata(false); + hideLoading(); if (res['MessageStatus'] == 1) { // insertDeviceImei(res, authProv); saveObjToString(LOGGED_IN_USER, res); + sharedPref.remove(LAST_LOGIN_USER); sharedPref.setString(TOKEN, res['LogInTokenID']); print("token" + res['LogInTokenID']); - Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (BuildContext context) => VerificationMethodsScreen(password: userInfo.password,))); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: userInfo.password, + ))); } else { // handel error helpers.showErrorToast(res['ErrorEndUserMessage']); } }).catchError((err) { - print('$err'); + hideLoading(); changeLoadingStata(false); helpers.showErrorToast(err); }); @@ -273,7 +276,11 @@ class _LoginFormState extends State { if (res['MessageStatus'] == 1) { setSharedPref('platformImei', _platformImei); saveObjToString(LOGGED_IN_USER, preRes); - Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (BuildContext context) => VerificationMethodsScreen(password: userInfo.password,))); + + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (BuildContext context) => VerificationMethodsScreen( + password: userInfo.password, + ))); // save imei on shared preferance } else { @@ -350,4 +357,18 @@ class _LoginFormState extends State { primaryFocus.unfocus(); } + + showLoading() { + showDialog( + context: context, + builder: (BuildContext context) { + return Center( + child: CircularProgressIndicator(), + ); + }); + } + + hideLoading() { + Navigator.pop(context); + } } diff --git a/lib/widgets/auth/verification_methods.dart b/lib/widgets/auth/verification_methods.dart index 32c541a3..0de81fdf 100644 --- a/lib/widgets/auth/verification_methods.dart +++ b/lib/widgets/auth/verification_methods.dart @@ -1,11 +1,22 @@ import 'dart:io' show Platform; import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; +import 'package:doctor_app_flutter/core/model/imei_details.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/models/auth/activation_Code_req_model.dart'; -import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; +import 'package:doctor_app_flutter/models/auth/check_activation_code_request_model.dart'; +import 'package:doctor_app_flutter/models/doctor/clinic_model.dart'; +import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart'; +import 'package:doctor_app_flutter/models/doctor/profile_req_Model.dart'; import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/otp/sms-popup.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_button.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/rounded_container_widget.dart'; import 'package:flutter/material.dart'; -import 'package:hexcolor/hexcolor.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; +import 'package:local_auth/local_auth.dart'; import 'package:provider/provider.dart'; import '../../config/size_config.dart'; @@ -40,6 +51,17 @@ class _VerificationMethodsState extends State { Future _loggedUserFuture; var _loggedUser; var verificationMethod; + GetIMEIDetailsModel user; + final LocalAuthentication auth = LocalAuthentication(); + var _availableBiometrics; + ProjectViewModel projectsProvider; + var isMoreOption = false; + var onlySMSBox = false; + static BuildContext _context; + var loginTokenID; + + bool authenticated; + @override void initState() { super.initState(); @@ -50,6 +72,13 @@ class _VerificationMethodsState extends State { sharedPref.getObj(LOGGED_IN_USER).then((userInfo) { _loggedUser = userInfo; }); + sharedPref.getObj(LAST_LOGIN_USER).then((lastLogin) { + if (lastLogin != null) { + user = GetIMEIDetailsModel.fromJson(lastLogin); + } + }); + + print(user); } @override @@ -63,6 +92,7 @@ class _VerificationMethodsState extends State { @override Widget build(BuildContext context) { AuthViewModel authProv = Provider.of(context); + projectsProvider = Provider.of(context); return FutureBuilder( future: Future.wait([_loggedUserFuture]), builder: (BuildContext context, AsyncSnapshot snapshot) { @@ -75,66 +105,205 @@ class _VerificationMethodsState extends State { return Text('Error: ${snapshot.error}'); } else { return Container( - width: SizeConfig.realScreenWidth * 0.80, + width: SizeConfig.realScreenWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - hideSilentMethods() - ? TranslationBase.of(context).firstStep - : TranslationBase.of(context).pleaseChoose, - style: TextStyle( - fontSize: 3.5 * SizeConfig.textMultiplier, - ), - ), - SizedBox( - height: 20, - ), Container( - height: SizeConfig.realScreenHeight * 0.6, - child: CustomScrollView( - primary: false, - slivers: [ - SliverPadding( - padding: const EdgeInsets.all(0), - sliver: SliverGrid.count( - // childAspectRatio: 0.7, - crossAxisSpacing: 0, - mainAxisSpacing: 5, - crossAxisCount: 2, - children: [ - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildFingerprintMethod( - context, authProv), - replacement: - buildWhatsAppMethod(context, authProv), - ), - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildFaceIDMethod(context, authProv), - replacement: - buildSMSMethod(context, authProv), - ), - Visibility( - visible: - hideSilentMethods() ? false : true, - child: buildWhatsAppMethod( - context, authProv)), - Visibility( - visible: hideSilentMethods() ? false : true, - child: buildSMSMethod(context, authProv), - ), - ], - ), - ), - ], - ), - // height: 500, - ), - SizedBox( - // height: 20, - ) + height: SizeConfig.realScreenHeight * 0.6, + child: Column( + children: [ + user != null && isMoreOption == false + ? Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context) + .welcomeBack + + ' ' + + user.doctorName, + fontSize: + SizeConfig.textMultiplier * 3.5, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context) + .accountInfo, + fontSize: + SizeConfig.textMultiplier * 2.5, + ), + SizedBox( + height: 20, + ), + Card( + color: Colors.grey[300], + child: Row( + children: [ + Flexible( + child: ListTile( + title: Text( + TranslationBase.of(context) + .lastLoginAt, + textAlign: TextAlign.center, + overflow: + TextOverflow.ellipsis, + ), + subtitle: Text( + // user. != null + // ? formatDate(Helpers + // .convertStringToDate( + // user + // .)) + // : user != + // null + // ? formatDate(Helpers + // .convertStringToDate(user + // .createdOn)) + //: + '--', + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + )), + Flexible( + child: ListTile( + title: Text( + TranslationBase.of( + context) + .lastLoginWith, + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + subtitle: Text( + getType(user.logInTypeID, + context), + overflow: + TextOverflow.ellipsis, + textAlign: + TextAlign.center), + )) + ], + )), + ], + ) + : Column( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + this.onlySMSBox == false + ? AppText( + TranslationBase.of(context) + .verifyLoginWith, + fontSize: SizeConfig + .textMultiplier * + 3.5, + textAlign: TextAlign.left, + ) + : AppText( + TranslationBase.of(context) + .verifyFingerprint2, + fontSize: SizeConfig + .textMultiplier * + 2.5, + textAlign: TextAlign.start, + ), + ]), + user != null && isMoreOption == false + ? Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: InkWell( + onTap: () => { + authenticateUser( + 3, + BiometricType + .face + .index, + authProv) + }, + child: getButton( + user.logInTypeID, + authProv))), + Expanded( + child: + getButton(5, authProv)) + ]) + ]) + : Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + onlySMSBox == false + ? Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: getButton( + 3, authProv)), + Expanded( + child: getButton( + 2, authProv)) + ], + ) + : SizedBox(), + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Expanded( + child: + getButton(1, authProv)), + Expanded( + child: getButton(4, authProv)) + ], + ), + ]), + Expanded( + flex: 1, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + user != null + ? Row( + children: [ + Expanded( + child: Button( + title: + TranslationBase.of(context) + .useAnotherAccount, + onTap: () { + Navigator.of(context) + .pushNamed(LOGIN); + }, + )), + ], + ) + : SizedBox(), + ], + ), + ) + ], + )) ], ), ); @@ -143,119 +312,6 @@ class _VerificationMethodsState extends State { }); } - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: buildSMSMethod Methods widget - */ - Center buildSMSMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_sms_icon.png', - TranslationBase.of(context).sms, () { - sendActivationCodeByOtpNotificationType(1, authProv); - }); - } - - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build WhatsApp Methods widget - */ - Center buildWhatsAppMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_whatsapp_icon.png', - TranslationBase.of(context).whatsApp, () { - sendActivationCodeByOtpNotificationType(2, authProv); - }); - } - -/* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build FaceID Methods widget - */ - Center buildFaceIDMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_faceid_icon.png', - TranslationBase.of(context).faceId, () { - sendActivationCodeByOtpNotificationType(3, authProv); - }); - } - -/* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build Fingerprint Methods widget - */ - Center buildFingerprintMethod(BuildContext context, AuthViewModel authProv) { - return buildVerificationMethod( - context, - 'assets/images/verification_fingerprint_icon.png', - TranslationBase.of(context).fingerprint, () { - sendActivationCodeByOtpNotificationType(4, authProv); - }); - } - - /* - *@author: Elham Rababah - *@Date:28/5/2020 - *@param: BuildContext context, AuthProvider authProv - *@return: Center widget - *@desc: build Verification Methods widget - */ - Center buildVerificationMethod(context, url, dec, Function fun) { - return Center( - child: InkWell( - onTap: fun, - child: Container( - // height: SizeConfig.heightMultiplier *2, - height: SizeConfig.heightMultiplier * 19, - width: SizeConfig.widthMultiplier * 37, - - padding: EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all( - width: 1, - color: HexColor( - '#CCCCCC') // <--- border width here - ), - borderRadius: BorderRadius.all(Radius.circular(10))), - child: Column( - children: [ - Container( - margin: EdgeInsetsDirectional.only( - top: SizeConfig.heightMultiplier * 0.5), - child: Image.asset( - url, - height: SizeConfig.heightMultiplier * 10, - fit: BoxFit.cover, - ), - ), - SizedBox( - height: 10, - ), - Text( - dec, - style: TextStyle(fontSize: SizeConfig.textMultiplier * 2), - ) - ], - ), - ), - ), - ); - } - bool hideSilentMethods() { return verificationMethod == 4 || verificationMethod == 3 ? true : false; } @@ -267,64 +323,473 @@ class _VerificationMethodsState extends State { *@return: *@desc: send Activation Code By Otp Notification Type */ - sendActivationCodeByOtpNotificationType(oTPSendType, AuthViewModel authProv) async { + sendActivationCodeByOtpNotificationType( + oTPSendType, AuthViewModel authProv) async { // TODO : build enum for verfication method if (oTPSendType == 1 || oTPSendType == 2) { widget.changeLoadingStata(true); int projectID = await sharedPref.getInt(PROJECT_ID); ActivationCodeModel activationCodeModel = ActivationCodeModel( + // facilityId: projectID != null ? projectID : 15, //user.projectID, + // generalid: "Cs2020@2016\$2958", + // memberID: _loggedUser != null + // ? _loggedUser['List_MemberInformation'][0]['MemberID'] + // : user.doctorID, + // zipCode: _loggedUser != null + // ? _loggedUser['ZipCode'] + // : user.outSA == true + // ? '966' + // : '971', + // mobileNumber: + // _loggedUser != null ? _loggedUser['MobileNumber'] : user.mobile, facilityId: projectID, generalid: "Cs2020@2016\$2958", memberID: _loggedUser['List_MemberInformation'][0]['MemberID'], zipCode: _loggedUser['ZipCode'], mobileNumber: _loggedUser['MobileNumber'], - + otpSendType: oTPSendType.toString(), password: widget.password); - Map model = { - - "OTP_SendType": oTPSendType - }; - try { authProv .sendActivationCodeForDoctorApp(activationCodeModel) .then((res) { - widget.changeLoadingStata(false); - - if (res['MessageStatus'] == 1) { - print("VerificationCode : "+ res["VerificationCode"]); - sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); - sharedPref.setString(VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); - sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); - Navigator.of(context).pushReplacementNamed(VERIFY_ACCOUNT, - arguments: {'model': model}); - } else { - print(res['ErrorEndUserMessage']); - helpers.showErrorToast(res['ErrorEndUserMessage']); - } - }) - .catchError((err) { + widget.changeLoadingStata(false); + + if (res['MessageStatus'] == 1) { + print("VerificationCode : " + res["VerificationCode"]); + sharedPref.setString(VIDA_AUTH_TOKEN_ID, res["VidaAuthTokenID"]); + sharedPref.setString( + VIDA_REFRESH_TOKEN_ID, res["VidaRefreshTokenID"]); + sharedPref.setString(LOGIN_TOKEN_ID, res["LogInTokenID"]); + this.startSMSService(oTPSendType, authProv); + } else { + print(res['ErrorEndUserMessage']); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { print('$err'); widget.changeLoadingStata(false); helpers.showErrorToast(); }); } catch (e) {} - - } else { // TODO route to this page with parameters to inicate we should present 2 option if (Platform.isAndroid && oTPSendType == 3) { helpers.showErrorToast('Your device not support this feature'); } else { - Navigator.of(context).push(MaterialPageRoute( - builder: (BuildContext context) => - VerificationMethodsScreen(password: widget.password,))); + // Navigator.of(context).push(MaterialPageRoute( + // builder: (BuildContext context) => + // VerificationMethodsScreen(password: widget.password,))); // Navigator.of(context).pushNamed(VERIFICATION_METHODS, // arguments: {'verificationMethod': oTPSendType}); } } } + + Widget getButton(flag, authProv) { + switch (flag) { + case 2: + return InkWell( + onTap: () => {authenticateUser(2, true, authProv)}, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(30, 15, 30, 15), + child: Column( + children: [ + Image.asset( + 'assets/images/login/104.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyWhatsApp, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 1: + return InkWell( + onTap: () => {authenticateUser(1, true, authProv)}, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/login/103.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + projectsProvider.isArabic + ? SizedBox( + height: 20, + ) + : SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifySMS, + fontSize: projectsProvider.isArabic + ? SizeConfig.textMultiplier * 1.8 + : SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 3: + return InkWell( + onTap: () => { + authenticateUser(3, BiometricType.fingerprint.index, authProv) + }, + child: RoundedContainer( + backgroundColor: BiometricType.fingerprint.index == 1 + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + children: [ + Image.asset( + 'assets/images/login/102.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyFingerprint, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + case 4: + return InkWell( + onTap: () => + {authenticateUser(4, BiometricType.face.index, authProv)}, + child: RoundedContainer( + backgroundColor: checkIfBiometricAvailable(BiometricType.face) + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 15, 5, 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/login/101.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).verifyFaceID, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + break; + + default: + return InkWell( + onTap: () => { + setState(() { + isMoreOption = true; + }) + }, + child: RoundedContainer( + backgroundColor: BiometricType.fingerprint.index == 1 + ? Colors.white + : Colors.white.withOpacity(.7), + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB(5, 0, 5, 5), + child: Column( + children: [ + Image.asset( + 'assets/images/login/more_icon.png', + height: SizeConfig.imageSizeMultiplier * 13, + width: SizeConfig.imageSizeMultiplier * 16, + ), + projectsProvider.isArabic + ? SizedBox( + height: 15, + ) + : SizedBox( + height: 10, + ), + AppText( + TranslationBase.of(context).moreVerification, + fontSize: SizeConfig.textMultiplier * 2, + textAlign: TextAlign.center, + ) + ], + ), + ))); + } + } + + getType(type, context) { + switch (type) { + case 1: + return TranslationBase.of(context).verifySMS; + break; + case 3: + return TranslationBase.of(context).verifyFingerprint; + break; + case 4: + return TranslationBase.of(context).verifyFaceID; + break; + case 2: + return TranslationBase.of(context).verifyWhatsApp; + break; + default: + return TranslationBase.of(context).verifySMS; + break; + } + } + + bool checkIfBiometricAvailable(BiometricType biometricType) { + bool isAvailable = false; + if (_availableBiometrics != null) { + for (var i = 0; i < _availableBiometrics.length; i++) { + if (biometricType == _availableBiometrics[i]) isAvailable = true; + } + } + return isAvailable; + } + + formatDate(date) { + return DateFormat('MMM dd, yyy, kk:mm').format(date); + } + + authenticateUser(type, isActive, authProv) { + //GifLoaderDialogUtils.showMyDialog(context); + // if (type == 2 || type == 3) { + // fingrePrintBefore = type; + // } + //this.selectedOption = fingrePrintBefore != null ? fingrePrintBefore : type; + + switch (type) { + case 1: + this.loginWithSMS(1, isActive, authProv); + break; + case 2: + this.loginWithSMS(2, isActive, authProv); + + break; + case 3: + this.loginWithFingurePrintFace(3, isActive, authProv); + break; + case 4: + this.loginWithFingurePrintFace(4, isActive, authProv); + break; + default: + break; + } + // sharedPref.setInt(LAST_LOGIN, + // this.selectedOption); //this.cs.sharedService.setStorage(this.selectedOption, AuthenticationService.LAST_LOGIN); + } + + loginWithSMS(type, isActive, authProv) { + this.sendActivationCode(type, authProv); + // //if (!el.disabled) { + // if (this.user != null) { + // this.checkUserAuthentication(type); + // } else { + // // if (this.loginTokenID != null) { + // this.sendActivationCode(type, authProv); + // // } else { + // //this.checkUserAuthentication(type); + // // } + // } + } + + // checkUserAuthentication(type) { + // // showLoader(true); + // // var req = getCommonRequest(type: type); + // // req.logInTokenID = ""; + + // // var request = CheckPatientAuthenticationReq.fromJson(req.toJson()); + + // // sharedPref.setObject(REGISTER_DATA_FOR_REGISTER, request); + // // authService + // // .checkPatientAuthentication(request) + // // .then((value) => { + // // GifLoaderDialogUtils.hideDialog(context), + // // if (value['isSMSSent']) + // // { + // // sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']), + // // this.loginTokenID = value['LogInTokenID'], + // // sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), + // // // Future.delayed(Duration(seconds: 1), () { + // // this.sendActivationCode(type) + // // // }) + // // } + // // else + // // { + // // if (value['IsAuthenticated']) {this.checkActivationCode()} + // // } + // // }) + // // .catchError((err) { + // // print(err); + // // GifLoaderDialogUtils.hideDialog(context); + // // }); + // } + Future _getAvailableBiometrics() async { + var availableBiometrics; + try { + availableBiometrics = await auth.getAvailableBiometrics(); + } on PlatformException catch (e) { + print(e); + } + if (!mounted) return; + + setState(() { + _availableBiometrics = availableBiometrics; + }); + } + + sendActivationCode(type, authProv) async { + sendActivationCodeByOtpNotificationType(type, authProv); + } + + startSMSService(type, authProv) { + sharedPref.setInt(OTP_TYPE, type); + new SMSOTP( + context, + type, + _loggedUser['MobileNumber'], + (value) { + showDialog( + context: context, + builder: (BuildContext context) { + return Center( + child: CircularProgressIndicator(), + ); + }); + + this.checkActivationCode(authProv, value: value); + }, + () => { + Navigator.pop(context), + print('Faild..'), + }, + ).displayDialog(context); + } + + loginWithFingurePrintFace(type, isActive, authProv) async { + if (isActive == 1) { + // this.startBiometricLoginIfAvailable(); + authenticated = await auth.authenticateWithBiometrics( + localizedReason: 'Scan your fingerprint to authenticate', + useErrorDialogs: true, + stickyAuth: true); + if (user.logInTypeID == 1 || user.logInTypeID == 2) { + this.onlySMSBox = true; + } else { + this.checkActivationCode(authProv); + } + + // if (authenticated == true) { + // if (user != null && (user.logInTypeID == 4 || user.logInTypeID == 3)) { + // //this.checkActivationCode(); + // } else { + // // var request = this.getCommonRequest(type: type); + // // this.getMobileInfo(request); + // } + // } + } + } + + checkActivationCode(AuthViewModel authProv, {value}) async { + CheckActivationCodeRequestModel checkActivationCodeForDoctorApp = + new CheckActivationCodeRequestModel( + zipCode: _loggedUser['ZipCode'], + mobileNumber: _loggedUser['MobileNumber'], + projectID: await sharedPref.getInt(PROJECT_ID), + logInTokenID: await sharedPref.getString(LOGIN_TOKEN_ID), + activationCode: value, + oTPSendType: await sharedPref.getInt(OTP_TYPE), + generalid: "Cs2020@2016\$2958"); + + authProv + .checkActivationCodeForDoctorApp(checkActivationCodeForDoctorApp) + .then((res) async { + widget.changeLoadingStata(false); + if (res['MessageStatus'] == 1) { + sharedPref.setString(TOKEN, res['AuthenticationTokenID']); + if (res['List_DoctorProfile'] != null) { + loginProcessCompleted(res['List_DoctorProfile'][0], authProv); + } else { + ClinicModel clinic = + ClinicModel.fromJson(res['List_DoctorsClinic'][0]); + getDocProfiles(clinic, authProv); + } + } else { + //changeLoadingStata(false); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { + //changeLoadingStata(false); + helpers.showErrorToast(err); + }); + } + + loginProcessCompleted(Map profile, authProv) { + var doctor = DoctorProfileModel.fromJson(profile); + authProv.setDoctorProfile(doctor); + sharedPref.setObj(DOCTOR_PROFILE, profile); + projectsProvider.isLogin = true; + Navigator.of(context).pushReplacementNamed(HOME); + } + + getDocProfiles(ClinicModel clinicInfo, authProv) { + ProfileReqModel docInfo = new ProfileReqModel( + doctorID: clinicInfo.doctorID, + clinicID: clinicInfo.clinicID, + license: true, + projectID: clinicInfo.projectID, + tokenID: '', + languageID: 2); + authProv.getDocProfiles(docInfo.toJson()).then((res) { + if (res['MessageStatus'] == 1) { + loginProcessCompleted(res['DoctorProfileList'][0], authProv); + } else { + // changeLoadingStata(false); + helpers.showErrorToast(res['ErrorEndUserMessage']); + } + }).catchError((err) { + // changeLoadingStata(false); + helpers.showErrorToast(err); + }); + } } diff --git a/lib/widgets/otp/sms-popup.dart b/lib/widgets/otp/sms-popup.dart new file mode 100644 index 00000000..dfcb33cd --- /dev/null +++ b/lib/widgets/otp/sms-popup.dart @@ -0,0 +1,346 @@ +import 'dart:async'; + +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/util/translations_delegate_base.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'dart:math'; + +import 'package:provider/provider.dart'; + +class SMSOTP { + final type; + final mobileNo; + final Function onSuccess; + final Function onFailure; + final context; + + int remainingTime = 600; + + Future timer; + + static BuildContext _context; + + static bool _loading; + + SMSOTP( + this.context, + this.type, + this.mobileNo, + this.onSuccess, + this.onFailure, + ); + + final verifyAccountForm = GlobalKey(); + + TextEditingController digit1 = TextEditingController(text: ""); + TextEditingController digit2 = TextEditingController(text: ""); + TextEditingController digit3 = TextEditingController(text: ""); + TextEditingController digit4 = TextEditingController(text: ""); + + Map verifyAccountFormValue = { + 'digit1': '', + 'digit2': '', + 'digit3': '', + 'digit4': '', + }; + final focusD1 = FocusNode(); + final focusD2 = FocusNode(); + final focusD3 = FocusNode(); + final focusD4 = FocusNode(); + String errorMsg; + ProjectViewModel projectProvider; + String displayTime = ''; + + displayDialog(BuildContext context) async { + return showDialog( + context: context, + builder: (context) { + projectProvider = Provider.of(context); + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + IconButton( + icon: Icon(Icons.close), + onPressed: () { + Navigator.pop(context); + this.onFailure(); + }, + ) + ], + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0))), + content: StatefulBuilder(builder: (context, setState) { + if (displayTime == '') { + startTimer(setState); + } + return Container( + color: Colors.white, + height: SizeConfig.realScreenHeight * 0.5, + width: SizeConfig.realScreenWidth * 0.8, + child: Center( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + type == 1 + ? Image.asset('assets/images/login/103.png') + : Image.asset('assets/images/login/104.png'), + Padding( + padding: EdgeInsets.only(top: 5), + child: AppText( + TranslationBase.of(context).verificationMessage + + ' XXXXXX' + + mobileNo + .toString() + .substring(mobileNo.toString().length - 3), + textAlign: TextAlign.center, + )), + Form( + key: verifyAccountForm, + child: Padding( + padding: EdgeInsets.only(top: 20), + child: Directionality( + textDirection: TextDirection.ltr, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + textInputAction: TextInputAction.next, + style: buildTextStyle(), + autofocus: true, + maxLength: 1, + controller: digit1, + textAlign: TextAlign.center, + keyboardType: TextInputType.number, + decoration: buildInputDecoration(context), + onSaved: (val) {}, + validator: validateCodeDigit, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD2); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD2); + verifyAccountFormValue['digit1'] = + val.trim(); + checkValue(); + } + }, + ), + ), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD2, + textInputAction: TextInputAction.next, + maxLength: 1, + controller: digit2, + textAlign: TextAlign.center, + style: buildTextStyle(), + keyboardType: TextInputType.number, + decoration: buildInputDecoration(context), + onSaved: (val) {}, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD3); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD3); + verifyAccountFormValue['digit2'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit), + ), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD3, + textInputAction: TextInputAction.next, + maxLength: 1, + controller: digit3, + textAlign: TextAlign.center, + style: buildTextStyle(), + keyboardType: TextInputType.number, + decoration: + buildInputDecoration(context), + onSaved: (val) {}, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD4); + verifyAccountFormValue['digit3'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit)), + Container( + width: SizeConfig.realScreenWidth * 0.15, + child: TextFormField( + focusNode: focusD4, + maxLength: 1, + textAlign: TextAlign.center, + style: buildTextStyle(), + controller: digit4, + keyboardType: TextInputType.number, + decoration: + buildInputDecoration(context), + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) { + if (val.length == 1) { + verifyAccountFormValue['digit4'] = + val.trim(); + checkValue(); + } + }, + validator: validateCodeDigit)), + ], + )), + ), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: AppText( + TranslationBase.of(context).validationMessage + + ' ' + + displayTime, + color: Colors.red, + textAlign: TextAlign.center, + )) + ], + ))), + ); + }), + ); + }); + } + + TextStyle buildTextStyle() { + return TextStyle( + fontSize: SizeConfig.textMultiplier * 3, + ); + } + + InputDecoration buildInputDecoration(BuildContext context) { + return InputDecoration( + counterText: " ", + // ts/images/password_icon.png + // contentPadding: EdgeInsets.only(top: 20, bottom: 20), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).primaryColor), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor), + ), + ); + } + + String validateCodeDigit(value) { + if (value.isEmpty) { + return ' '; + } else if (value.length == 3) { + print(value); + } else { + return null; + } + } + + checkValue() { + //print(verifyAccountFormValue); + if (verifyAccountForm.currentState.validate()) { + onSuccess(digit1.text.toString() + + digit2.text.toString() + + digit3.text.toString() + + digit4.text.toString()); + } + } + + getSecondsAsDigitalClock(int inputSeconds) { + var sec_num = + int.parse(inputSeconds.toString()); // don't forget the second param + var hours = (sec_num / 3600).floor(); + var minutes = ((sec_num - hours * 3600) / 60).floor(); + var seconds = sec_num - hours * 3600 - minutes * 60; + var minutesString = ""; + var secondsString = ""; + minutesString = + minutes < 10 ? "0" + minutes.toString() : minutes.toString(); + secondsString = + seconds < 10 ? "0" + seconds.toString() : seconds.toString(); + return minutesString + ":" + secondsString; + } + + startTimer(setState) { + this.remainingTime--; + setState(() { + displayTime = this.getSecondsAsDigitalClock(this.remainingTime); + }); + + timer = Future.delayed(Duration(seconds: 1), () { + if (this.remainingTime > 0) { + startTimer(setState); + } else { + Navigator.pop(context); + } + }); + } + + static void showLoadingDialog(BuildContext context, bool _loading) async { + _context = context; + + if (_loading == false) { + Navigator.of(context).pop(); + return; + } + _loading = true; + await showDialog( + context: _context, + barrierDismissible: false, + builder: (BuildContext context) { + return SimpleDialog( + elevation: 0.0, + backgroundColor: Colors.transparent, + children: [ + Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.black), + ), + ) + ], + ); + }); + } + + static void hideSMSBox(context) { + Navigator.pop(context); + } +} diff --git a/pubspec.lock b/pubspec.lock index 7f1d8c1d..4d8e049b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -316,6 +316,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.2.1" + firebase_core: + dependency: transitive + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.3" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1+1" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + url: "https://pub.dartlang.org" + source: hosted + version: "7.0.3" fixnum: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 57ed4cbb..e0e4ce33 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,8 @@ dependencies: #Dependency Injection get_it: ^4.0.2 + #firebase + firebase_messaging: ^7.0.0 #Autocomplete TextField autocomplete_textfield: ^1.7.3 @@ -93,7 +95,7 @@ flutter: assets: - assets/images/ - assets/images/dashboard/ - + - assets/images/login/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware.