From 4a0cc17069728268bbbb5e24d37cd37ce5893652 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Tue, 14 Jul 2020 17:35:00 +0300 Subject: [PATCH 1/4] login module started --- assets/images/habib-logo.png | Bin 0 -> 3362 bytes assets/images/logo.png | Bin 0 -> 38890 bytes lib/config/localized_values.dart | 14 +++- lib/main.dart | 15 ++-- lib/pages/landing_page.dart | 1 + lib/pages/login/welcome.dart | 75 ++++++++++++++++++++ lib/routes.dart | 15 ++++ lib/uitl/translations_delegate_base.dart | 12 +++- lib/widgets/drawer/app_drawer_widget.dart | 58 ++++++--------- lib/widgets/drawer/drawer_item_widget.dart | 37 +++++----- lib/widgets/others/app_scaffold_widget.dart | 2 +- 11 files changed, 163 insertions(+), 66 deletions(-) create mode 100644 assets/images/habib-logo.png create mode 100644 assets/images/logo.png create mode 100644 lib/pages/login/welcome.dart create mode 100644 lib/routes.dart diff --git a/assets/images/habib-logo.png b/assets/images/habib-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb6a42b026e5e9ffc31d542c3347007390e6b4a GIT binary patch literal 3362 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 literal 0 HcmV?d00001 diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0d9e4a56026c52e0ca2cf096a4dadcee98c27155 GIT binary patch literal 38890 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

%S1Pd9nP81ZiB zoZ$fXeQzaDt+dB&3@y`afK!7rMht25Bf zv|}5S$FCaE_&2KB{ewHDC+knshyQq#T0<{FC-TcVJjM0$l!=PqoeNkx_M&eOvj0p{@4sy?`FLE z5QV7aa~1{80GL-pm~-Z6L*HV_Tx*%m2VmYe(ovaRGI(nJwOzY*wGEA({hO1mM|aO$ zF#8dx;Q?WUSaPi|s;GDb2nVuJuzY*hXrl!!1u!^LB?>)1IbJ{rks_P zW^nz7;A0vB2=*WNU}5IRPiBBuWhkktn$N^80_zlpe+up67cuPoPYbVMBUKpVpGs{y zzfbR%r5N1DoA)hTwdx0l#$Zr9Bp;Q4nFsy8Lb+n>=<39FWVols?(W zA{&HUy&9(V9hk(Z<4q=bq!aock;Vt4JAPc;+`rsWyZ9TfWiFz;ZwJPh1<`>5NBUfT zK&}HHAWmk#!H+V7x{m>^SSk;Jey9Cp+kX*rL?-S-8bM~4HS*dyv%YIu*4@J7fqfH4 zE2HIYcx8-gUf(b)3k`|FCG~8_QX+MVFhM=^3mwxt1~jZ0bx#=~`!G>f^25H$d`oFf z%{RGkbXB^hn>L=!u=?bv}v zVC2BLB^QYC0E1#J>9FH8--Olrzl_Cd-Bv}#V6q}96YE&ah>H!!kkDhscNBZhtHfPQ zTx>p!4>0u3fdR^)a=X0V-V=ipMZ-tqDn6$J8WD{X+9NeRXMZiV=ugB`}WN{vQbMaW_|xbGoxx}X9Bh`c4_!p?suo)=Xlj^M~}W%H*Yp4^!kq2 z#Q5+nz`)^Dj*tdL50saSQ>tZvLGWS$NP9opy?NWSL>m?I>h(>wV>vGocN)JrtjDZD zfZ3TvpBYq&E9a5rluh7CoV$S^^(xBsEju53?D;HeU^Q-vZ0Aru4DjS6YrUejBy`gu z!`Plh+L59#>kYgOcs0P4c;}#v*Wr1-Hg%+gdHANxq5yUR=4~J&EVXXd!Wr<+iA%3xEFI9Y005PkqVG?quU1ZN617MS7lE$LSvVUx%+$%OR3mhh_T(@ps zz_Q;>N5f`-pp6cs(9MS)IW%xqeeN75N4mSA*t681|Hdu0V}ACghK5^28Dz{7t#Puqx8H;6sP*K4vey}KpCDq4ayV?ud{c3CarJ1~Ua8*~FJ6p& zmilkt9fmJ{F!a-G9e#!SjEXDbBsi;h3lt_N$f7z_m1xiI<9(LXwV_y(9Yjr=HvB$q z_iKWG`fGyz_cWTuXNaBR2166(;f>HTwngjc7k>aa_=RYE*hy&Ue>y(F%h-7+{+K}c zGNv}pS)R9x`bwKmYDgg6LpWiw&Sm_ijKa%RQ8YR^rwFGb1w47mjqZiNon%}XGtSa9 z99T%ZYUP>@8~P<`o4w+wvcs4VR>L3{)47&&y_QOg&je`FILkoxBSTq#zIV%Jf0-e@ zkYl~a%Kt(_>+j-)awC~chsm!&^DCYZ54Yyv32{YJQ!PF<{*Wh>Pi)Yeh0Amx@L)W4tbx>(K{*x|)r#mee+4`Z9Sl7Z;$ z;Jz5m#oNnD!`G}`zy3QIf<6f>j;ZbCP_$6FZ7Do=`hF2^CoVR5INi}0)@t{A*=TG~ zu`f}c`+mwjWWY_wFYOR>H>M-ILv=84WRPoPM);5%XebtEwqO$`$;Ex#V}na?)w>JvJBnv zmvlIYMnm62xi|pNT#ZKSN2G4e62g#ZyB>Y?^x6%#e-F(OORK7h2xA_s1o*mB>*lcc zW;M5R7KW^!{bb*c9k0u`Y{K3xd(W@i5ZMQfoB&C4NOOJM_2CVp1!8Sqdw0cca~5=& zsa^WB1@C8j&RuvAoDUG(`y*V2o9Q!Wt^x1j-k$2JGxVLEx%gN?Mff5{PW$2i3n@N4 zR7F;8TDM@&Pq&HCk}+Ufz6r0h3*@6@%Hh`z{Spm{B^oozqh+G=|Jyqg@VJUAQCHo2 zdsC~mc$2)yy9Kr}7)*u)2p9+^B!Q3wCoHy+Wl(s@BzfPwnR)XvGYRj_d`ae;e3LNA zBf(%Ju)(}>2qaF%2@o($V!&VUuVId#sdQ|w?7XSjMmd+y5h&%d~f?JKf2z z)e-I*;a2fvu*@{sq5qI{7h=*8_{zE)3FEF*aTqo7F21ycz-5&fnhxzYDsEv;2J9eW zF-vhAv~HrUk+6_?qm+7fmk>MqTc_W4ixE^< zOGKm;((HWEFo>%xpWPsQ_Azva_-k;nm`=taFuQOgM8OdCi_D0hZFqizapLNgHoW-a zuFL0L_3zAD<6khB45hHf3oRQDcgr?D1x-?h%-P67+8qY3^Ahcz0)6RLObW1cEZOf7^`RMT8 zz3+^kIN>GQypcBPHg;rSw-Skcxym4Nw1D#@A*HW{u4R{!Hwn$~_;8#=lMEfgZmcQ# zm3SiQn~+3J&N|ax;KS1aM>VFxYxy(k=Gpw6%XhSQzdFGA|+m?NUm^=4Lk#Quv z6B1&&NUJKxkoN$Vwe==PzcEV6@981yD5hHEPEIg>hj{wZXif zfv^xifg^*M03BsEE9SOgR!T-<9vf7Bhc(J{?o4P`@YdmQbf-p&D$L;r-9&~h%+sF| z?P)FV1~P_SHTV9Y?kjmp$RS3esuN65CZNXAUhLuV>z?$UKeB88+x^+`vP1Q_PvS6@g#eaQ63NpU-OXhCQonca zk+KQnICHGeW1*NMvQr($nMU3{Ntm(~%6LZ5ux&W${iWlRU*y$X{-&_F2>g`X1!Jn| zN(de-I5aeRAN^ZL-yRNVYYT6?2}CMu*QfsD)6Z|>^v2&=!hbV6`0F9SlfeuA0%jL1 zIF$k927gJRMjU1#@1@@_>O|t<_0Rt?XWfB7fJoE?Y?5YNx*^PHKFd$c74$2)bGNL3 z5mNA`mj~&>` zK~-^#GPkeFc4Cd1v1{iqYceo0=Bpsg#=+Bsz~9Q>%S7wUsTCorO9Qyt4U82A;Rwtj z7^Q?!N}uwT<0d+l#t?{QBRkm_8}{zaDnw=lh==Ret@DUs{gUHYuL09k@Zm?W!%y&% z^{HJk^Rt6@2Owh{m(~sOL?YL`>23z0x}B3azxG+gT9DS&lurs};A%h`Bx1;fabo6F z6}@M?0pYDySHIHTP(Q!OL}It_$@TC?qM;gfubMu`b;qFMGh>FG$cm$F!^zpiq3Hj- zq+j(dEk0f9S-V!K~&=8X&XLHoTTl+JRMG*Bu#Bc@Mr1PXa$Ok z$DlDimv;vY9Rg=BG#xr*gvS9Tgp_rx3f8flM8O1ecJ?_qUYh8+rXnpo%zVZv+~BGU zU+HK|&Xwc|OU7HbFnGYDHz-g4di}a}Z&E0$vnXRtz4{<w z+tcZK5+ZY2D|uO)5m4*N{~qJME}`0=e&vs^0QXs+Ko4U2nM$VR^!d0K3WXqTS%rKwg(W9RW+QOBNRmA#K2m&y-0VVa)x^?f)ojdp6l;b_AgguL0 z$+;}4z&AR)me)6~+lcVNufCHuM@2C+{CL#3aleJg5y{P( z#^N2th=iF;W;#U?)?mtNCqmaI;w8RmLS6S&EetM!-^ps*(wnm8GsA7ze?~GU6|SM& zjLFBntb9ZrF}(hdp(scKhrPBoV+$T|YKtbG4F{a>AadFS4T+j03DnMoXV_x#6)|_LZ zW3fG+3@+nn%QL2fQJr{4tou`PQ2=uz^Y#Hu7k=(dX+aJcut~`D74^yX66JlL3%JIa zHbB5T9UVsT(V5T=yzWT-UCuW^#MExp(%PJQ*ViY(&GuY=)#X1?(pkrq=RT9y^`be| z^4aPN!pyzm@XN@Ahv}yzj@ZuE*R4bAKd@wkIs~g4 zV`2lN&+SU-b20sU>OG%S(*OgEr#(91SJuAEntB-l=LcpUu=bl{meudmZ?fIp=Y^~v zU^(zZz&b49cCV#aA`uTu`$5d7e#R@RT=z9&COsig85!0;_uRhAubKOO*8FHQ5iI2$ zbka_=#S`i+pHKWNFc^QNUTYR~xmqC@X{#CI_)#aJ_tw|fA36~%(U`Z5TZjLNG2-G^ z)r@v~YqI{d{}AwEI1xWh02~BuQs&q&vZ!B;=_V>{`xqqoplD0%>++N8p4Z8;`TtHi z24WmPGPmX>Dd{P%{e!EJwS3Z&j$s~I*jG2uhS29E_T9Pq_a(iZfz)eYG=C-yq+Dl- zp8s2%zYhh54T}UEw;&NGss;-`fnPy`UDvW}-7ac>FqP490y-p%vOy3%1tFK51I!j$>GuixqQX119smkC?ydFu0I z+E3MS#y*dZopB9~-v`$=J}?7IsGrzOzc9Qb`bF8WgZ;$mO^u_bPVpRnEgGfE2iS6g zO~4=gR`cz}d-on2VA+$-eyntIu?~gqhr1YyL2`rC-%6Qm9SAHxG-}*j6Slu~^*7&O z+c}jBLv`6EKM4Dz>Qblnsln(cvQDeU0jRI0n;0e*RR_wKO;#l_c88D8`%7szcMVDWtRGz?T#Rh5f? zbE&JnUAC4}xu9!L?Sl`#oR;MS{|eKv3yKS7Yhg`lICS(s*Q{BS^OoKd0W<$=^9w_& zWUf~3krhiHO5Q|!`{KnjY}>x*kp~}qjPfV6h#P@+$DTcxaEV_9_mu9peAXxtbJy3_ z)(-SS#uI^?f8S3GFi(TpXU!AREn&VuZdP|psGNK?qgg=}%lcVOKHC5>a55SW!|;m+ z*xsqi-h#k^WSSH@Ox*mzq`Zb>FjzZvW#C0(I??Gbbd)mJO&j0on=MB!5`~54Hrvyd z0*+H;Sz?Z>#F*38=vms3vaG2PhAN-1J|!)ynyW-_INe=sZEba=n8H=hGa`{l*XC2sga}=6hCupAG^?doz-`O}*CKJWhMUfVw#PlhXCxJ4 z&pA0IM_$8mMh33CQFGm|4e_4m)BaMCa2< zV4%TqHkGRAU)!$T;Mw*XS6HY0W=AmX~1!-bWVvzU#uH-8XzOmh_161kC{)Dl%q?N9&6Lk;H%^GT4=}?>>UO2Y&8gi&BR^2e ziSBX!09*gaR_)l%7~D9D25#(Rdn)CKj!>Xjw24C>Mg*Si6HB5hw2mA(B1euKsUdns z_1i-mWK_@Qy%{|0mkQPIiPXd0b(%7mA58v}DC1GQd%cU*k36!^)SD}%!<(y58D%Z{ z)vd|uXPJyDa{f%#-BMX8Bipv=e&QlonNhKm-|B+LAR#^Vz;QpvCB6JWzxQYlxC}f! z=E*=RT(fkkF<)$FtjxSR)-~@2QpE?E*T7`{O#k}dM>E5dtAx)%rd6v})q|4;Q@nQO z>Uwd{3D-^5mdxB)vwy!mxuHRpmX_+JOP8AQI^h}=_uM1zAtU7n*7vMX4EmvDKHJQD z3oVqasHjj44GoGplDP&3-N4BdJO#siGR>d$W#1CQFDx;WrH8mTzy&2u0X1CuhfTGSsbMpbSi%T!Vcf-hv0>dH`Z6&5w6c-N{QpNA6oV;Ht>%GQ9hYksiMj>t9 zEvQ*AT1ltyvHNS^ORG!XR8>`6YjlWxZ^knVNUJ0-g#@8umYv4mey{&_0Bs-`j{uurz^}nQQGQQ zIBim$(((8AZQpm$z@AxOAHOZ&FG8y^4%5L{#;OP%sEc3DVeL!o>ZtEHl4Xwcs_w?> z8zT`bQXICzhk!THD+3R1sJWq_NEHnOpY_z)ku6W^nbz6{t`g62M%%(2q0v^jt{V*s z=Me7>EnmLe;I#k3N2=m}eu96$U1*p2Wx)h(S)(keoJISpTf8c@mqD+4s<8iIg>RghZPmXh1BX#{5r0XPmN&TU$p3ZRYFVy~B1(&su!f z;ucRh2fX(7gO5J?XiIX~ zQh4vHn?vp0StW3km6eSaj{JLJ2cPjtIZ<2o1k40c)K}&lQZXNqu#)SmtE->zY;mD& zS)XFiee8|enSXvPWFzsPh{KgvK_s6^5ppBQl&P^-pwRlf5Y7nlH481H!qOqyDZ#GR z;U8A~6lI>KOeaHR7q(!}o@usYeUAF)Fz^X%ClFQ}b%qW*mTDSSKJpJd$1rBV;~&Wu z!JB+q%!asr-4Gu`WG7ZuPF33bJUK4F?g4zdMcc4qq44wY`TU-k{OOIzk$tdI4aWy%625}Z%P*OywtJ6jSKeg|M!(bY)UrV&;RBxSu%`<=UGzD zqexh3A_PmX1O0lCB^>cvvSs+FQ7?j{X+dd6M~@!8jC@Ch&;A>qw02n~1siRtzCf2t z3H4`m^_#)@>*Q%){ME(N5yWn$ZX|eZ#;t`h$8%escc#l`0%pWW2qc@L52&44VJ$Bejs(UK+qYFX;bSdqpv=I!*W!`32z zR=L=c!DADqOnIWFvhu}TOrN^C6Ju}tOT#m?^nK12dM0CJ^q)}#Cm&zJQu!MTN}Olr zFPZ=B>Se2QnpjLdAt!RN5Z1gzB5@xL)O9y<{EI9WBhGa!c}rke;87mGar{-UZ$26F z0gs%6XnT&7j&YG^IDC#Lw8!|pjxe$Y0ed@-v*IsVqtTJ&ew)ma?Z4Y@yRFn$Q1EHS z@EVFo_(aBl>kCnUABa^VVQT zzul#^NC!bOS4)Gj_G@gveKma^Mqk+wSRU(u)uTLF5PTDX{n;&>w!DQ|D63$XUSaxo z)|w9uOTh2!uL{BPrA z>nCV^aJ*OR5IfXsbhz-%k}K_dSjfndi4)zg z4e?sEf5$k>@h^h$Vz1LrXxsm?YHMqZhC)uj^~!CZbtT02QwSR~m?}F=J0?+2F#^J< zO3V}p9CF;`$y2oU7DJRqDG=PHFB1W--k7Q`wchT z5V9TdO|lfa%KbOX?`>7hI!cmGad9}{xznZXeA5x$HxQ=oUb}X!AyOwy5dBa{%4?a~ zUt*4L_7dXhsFXXRhYv?1<06583XJwx3=mI*5jlx|yh?kW<{W8_)LNBULRZk=KO=v= zAmXyV-L~VRwYBLhH8qo|^M67G9P&M;WA4U|j*ccn&;x8J%YkAP2bAnu~Koxtp;rVqDj_p5EB5R8zp`a~!QEKx94( zky#u@bAd+Zu`Z2H)@p5~i_=D4L_d$+Q7=ELmQ z2~V%JJa13TA9DloK&kNC9|OP}aUq!C3x|J5-RWAr9!=SWg=5ef{WasY3*6opZEo82 zwh-~)jvboyX6Rs#v1hJ^3vifaete0(Z_%z;g+#GCsCB}%twNlq&O_5MPiSY#tczyd zPaQ^R>rqD!0J?sdHBeAeGFd8hjwp$Y!t=?A3NIQeiR?qu^6uMKXm3jBPcLuQUPu)- z;zaz2bk(1HK3`))V}rq}KRhfv4miGLY5OnHzP-EZ!Br=;&ohU@cF3L_({5$3Br?*I zmK`oB>Zq=%-WyZa+mALi9T0s8aOtr1{yxBg?p?tUe_}RxqS%Y*%Z`N4<&>#Ta(^R< zrUOnc=7VvwOQz%}PEk5>{2BXO&x~PLhOWHn<;=`PdWT$z?|MdsvpT`PzH_1Fv}t%NjLfY_){YyxFAC6n9{|L zf_JhAdt&N%?h}1Gs|1d&&f)p@=%p`^W;8u}CY&>+4q@l^GM-$BcfK9@|s?u2ifHQ?07wGUYUFc=;J#D!y;cnVRI822Q#nM@t595exBNd+Me~TN7Kkr zPsWz7T)NWC-R?GlX=}K&sFeo`Ex&&j@7CpnU=SLPQmrpVd-N6dUk@SfuFep$jxwe@ zCr+FAo|g9i_WSH5!1EpEMW$IY2~yB!eH@~Pnacgvie){_joCn!;gaxl1dT7TZl7;+ z^`n?kGqpJPl;B|=u&5aO&SZRS%{N31$fD5Zy@gtq&(18U zad$hW>_8LM`6x4+4aa25(e-HhVx5iAwrMRX@MPB7EjXoKP|Rr5yWmVcrFXnYRoB@u zo$Mn@b!i-m;Vs6=cyL|l+mnyzVzHI*SiUZ9n?$>({SGK7R= zaYKCFj@S$QFgvTP>RgRq0mC|r@qeX39LZYG#-$q*0d2pgl=nD0`MN`qLrlL|l-=yl zkG97*XTsX`8x+|_s}c0Yyd|OJ3#`buSa-)K zF17JvZ@cIHCSBMtjU;!BLSK>a#LsG%*1p@B)x0^L%vino+UqYu=6}o1{dVKia{TR} zz8!PpYGsD7(Or>wo)GSGV4fazUBirXrr~1vcwt-Dvg`O|w54TpmU+cyb9GbPvwp?S zVu!8dH3*zJH4{lPkh8Ucy@gml%*fsX0cnI{qG399iTM)3T=h9- zz+3fF{zrzek!;A|Y2w(48;Q%YlB1ZP4ipuQ&kcc|1|8kkcC2kj?mV4u5D?)B*2nqf zB|QCP7Gc9=)VsFr+78|PE#D_59DR;?m@83dv84j@A+*<_8QtV*`BO)UAI00FKepoP zN4Nt#0Cw>{m$!vV3g?>jl3ADOFF4O?Hrlmo*G}>ugOc}w10im_@y1BN61T!Wu45DO zlIN@#eDC^`v&l1?b$ua!7g7EqnDQK2xH$a}DPSsd zEljx=m=FQC5J-GB6rx-T^S z0)CShE9l_+aMo!!AaETx{v8G}Srd~5jhHxw*IZUJLLn;tgcNbb_7K~sEG#X$m_d!R zvoBou)oN_(*%Jf+ZLMgvrJSWa-)8LgMZ_D}zWnD8^w{a7myX3^hwV^cE3+TTw|7E2 zG6t2mgFOB2ng?b)0p7Df?B4W8u@3|@4#s)U4Jj^^W{|Go0gB&9okkl ze(YhqFd#hQkLFpn#9WyQ1o!}XFXv(?rd;E`eT`+~#%yN6UWrP*m`6sN@_{93DHle# zU)jOBoQ+uVC?<^-#wuN~SlVG-tYyv{kl5KtAH&rekkK4lUoWso69&g07kRurZV9~Vkby((b5VyvY z?WG)9ktx*qOtX(8)W0ZWYW0fR(?!hp_#X5%d|kK>w|Ga2fdN~m##9*e#IZ!Kkg z7oE~~Fveg!OHH|1bXj&X(4aglo2*^wv!~DTGm6zdz^?d zE#tRf#wNnfCc(gge(_;>17P5UdCJo)8l`7(0Rve(MDByJ0 z#o(v`VdH5WY%_%oQ>}jdp@;T*#xG3h;sT%VJWMD9+R#C_7>mAlkB+oI%UQF7iT3E4 z)%W!fHoCj^*s^7H2~Yh}2|Zi}0>)uIpYj+O5*QfJf*2AI_X~(#t}y*7l`WG}I*OwK zy%s|0*JiIH_I1ziS9UC+$sx-1Emc&=NUQ@j7 zB1_l{`dcZxM#X6Zv_hJLIeo(u6b*!@KZ@Jig8S+G0P^s)WlWWM>gjq0NKh%(l-nHOaU6Pl$8tY}+=`O8dbYm6{bfuOj(y{&D3=KHkY+UJV*lusX{?Fo^}O20sh zlJ@?jzRsLE(~pKhI;}RAb<@ z5WQ0k^l7b6>UZFj*ATa$<*`Q|$+^hc1=$6*{c(-=IXjhlc&+QxP8p|GeA#?BOdoI* z3le5x9Gf?oUr+W~5sRs)^p3%t3UC`9NA_3w%SH0#9baAYNyuh7F-ZP^H}oA;x3>2F zW%p7hD+6CtU2WryL8Cp}C4bh0KT9mC-9y-hFY_#`j7&Lq^8v4DByQi6z(EFa&d!h7 zUvGywjapQ*Xxt-9AK8-?fYd|npAN_gZO0E2S{pNf@nh2F;yKA~HkB*=6PZEcNKCk# zw5RZwN%L#w7o(CkYUr$qI*k^k0>b@^tQoo;lkfpKiTPB5 zpqdU&cl9O+9jBdmDLII8JOX5QhR!ccG4xe9np*0)WnSp3-0d5su<1hZA7%fml2{)&i zC{;FI7>_xzP(5p7ScB7Gg!x_qM^bB9U`}pXiX*jYv?c9ps>1wd9s{QU0|Q&er=Y

Fi~97hl*4N3JWj5#{7@0-EtHk5CmO^Q`bc^=gi6Kp8+1E6|jhlV9kNK zgtOwsa(7bCVU9^&hAnnX);v7Kc07)_1UCccI2A+#V9X6F8Hp|{gD`PLxYy!J%pSR_ z?DgF2kd!ChhJeM1<8d{@5^fZ|r4>%>6ye8mHT2s!B=sw)czg>C2erC?!Q863Id{3Y z*3^u!h{FI3&p!I#qx%ycY9=LOKru2%%GMbE0UUugj$Nw9Q8a|SDIr<>>0D!K1jt}% z(L9tFP9p9ZVJ~OG+4UWm+aZEGd_E~eX3r@xqnLnTH}X0sBjOYT+9B>3k#Y=2FSD9* zfSH2{&ImK!CZAQF={C7X8Pg4jMPK*=r#o_$n~Tt` z{MIeZM2@}Y%Ej}nGdX*HgaVhN2QTACRc3{Jm*pDc?4^4>l?Ys=z&0LDmhp2z8Abm|lA0lj2S_MdA$9_MDv zJH}6&);NF4luf0!-2wyl%&t0GS{f)yBqlnJ^>ucfZ?xNiS61J5UmF^S=djn`O>Ctv z!1R7e7~?~R5O$V{Qf9S;JX`PnjvT_b zAh}zCxv@JD<~cnX@J;?h%5(O!kb9j#8q2UPXYh%h3(>u;s%H+t}59 zY5cUw^|y@~vvKRzt*vOHJj2Y#j2RR0g?tx5&h7%Q4?kX8+o#rL-}dbXiJH0+Rm$zS z*1nH$_}rd7dzy?RAaF{UYG52uZ4pTB1P-IE+JVo2-{9RGljOJ9!HFmnNGeoRWE>}n z&mx9vTVBag%y*;p(QaP^BM5~`OPMq33N$Om_vH$ru>Khb*j?MUZHuSs3pNHFS-?mk z`NjQybLDu}Md8{mp#=y-hm&+VJVw(papFXC7t2T(_jTZ1d7gaJz}lb0*m<{BRsF*6 zw=XSGzQ0|tWXaF>dfwi3wYA1PrA=Go$B!@OwwHMb-Jb#1_;BbXPO{dIY7LTC$3ku4?6+)n%Wd(enWG*}dE?bEy(_{W+>jU%H zD6V?+5zT{~e8prZ)D|L+gRhEujbJ^SO~aFY#m@=Gf~B4#XCPRQlAbdcIDVIcgE?Xa zhX+fT|5pfPn@wr-|;~f4F@m$`C=pnVOOiT^!Vn#58NySzB!+u#f5-<9@3WfD*-1D{) zCcOo@#uw7w80pxbG{Uy$#U5C_bXoFLO8c?qS3|>!$HRQD*FJkVfq^y?Qrwtie1)>O zj6LpbfF+KX+5qEkjyau9tmYY1#}H+6l+vrNu3ks1&0=T~M+|*sBgd9+!W>eM6C1~{ z?U4`*j$^3`P9ywA#bR5Qu2_*E#>Ofb|96O5`t^iNyt=5Sx_M_^ouwT)!tn>EvqmRj zCioRhZHYhNyQX6Ds!s`_)~_h0#W2C}2)1 zj6?9-LVm(RaFDSpVN%)U891eNn-dProO#jt@6VibL7OE0B;#61xl4e4L%VEQNs;by zsq*QchRH3NGG&cxOWG1&mI2>{ib<2UESxl{5iOR3U|GQ#_A9}`81VBD_`eX3g}D=_ zP9?NE6NfYt0YngD-?GFfm=E;`I&TmpZMM?>#o=Om)9rUvHCkM>1)fXbydS5?IL7`l z>Zzlxxn4F}@=JyS(Ch-n=QtGZX()lps|5dfM+ZNun_+AT#YGT>^ zRfVu$WG>=ZNl&yc0SD*P*Gs8;Er66UP8Uq5oN`@8HOZe~X%Yhcs9f(&CbWF<`IVI$ zRueO2)zYQM?x?xrQ9MLyXrr2tz#P*SJ7;?5x9bB*pBqZhe_M^<%LD{29V{xkj(#V{ z8qF4{up>cFP3OT(YJZ6iPw*EMT!2vWLYH7;n(a;|+&ro$M#(5j#Y!kGFRiSUZz66NH1xLplxUMC*&1YaCScV`!BFT*Q z;Yj*_JM8AIVNp^o|82x;xps45_oNli| zz_^;|sY$NJYfi?9-TW|u~S4#1cA~)8+RbuPmYH&Kx!5d{r80WsioBc=t>pL`iqk*D`RL0 zUT2LbHy2c8G4`ce`57;LB?ws;kGsDK`t8{?bTJ#8Pm%>$GL=#&JO0GHf%)$SCn!`> zeFUncj>>F8tV0|S`-hma4$BE(bd`|~d{gz@}QjiYS&!~#kJJP?GZhwq9-xHBT z73hyBT+B7YD_h_J2l;+hC2QWog`r~N2pjD{ww}S%j2Xh_y%9K)#3du2xp0k$$vfOk zXHRxE&gja~B>_oTX6-ks&4er3o4U*vy_~YT>Xp?*45hJ=en*92>|U$qH65|6deqC& z_>O^fTu!ao)mt;c{7SjsZqENo*6g+c1M8MqulL(TA6R4AYWYbk~xvA+z25(9#F4 zC6C55RiynKA;h^YnB&Ng|vy}b>yNK4VWQAPm`v1fd?--?!Ew>Y&A^)SHGcleRr2ZN3;weml#fvnHP;@{|2F20 zwPWv&^N88;C1e&fifShoo}I*y>0sV)ACjDgtWu6}u`!-dzv75&9o1N@F+%&$E&!zJ z9>}MkKE-{$4o<%{LnERFPsU%2>lAK*jF04xNUcT~XVP0%37X4u5UNIV9m0n8gji)R zH8f>#SdJtdrx4EUL)=M-j*jL>r%h|k)R35QibW!h3E(#nI8S%pBO}g<5SjIVumJuF zp)hi~+t0T*01PmPAyuysocEh2O_&DIY(DFU90S$~z=4m;mul~S&9c1~z&V@H@wyVRlhZ5cJ&h?=t0M?r8#xpFYK{o2 z8MS>le}Y`Ap?t=5_&NOxLYIjan&)LhawySlm;e%5FB=w1eCMn(sSHVcpG82i+d71l zx*aw24I{^mYldL|sjjZ>7@7^^Y-uN*ErY?2q2Rm&BhDV5r#Ea|KBUk8=VS_JYS=I- zeGIc*^%y=`saNX&BQI3v7V1Pp`>3>Uoaa@4DWZLg*;GRUj7Hd zf=2vG*>Q6Lp}(Vf|2z9zGR7%ub#}o zlovL7V25j--*}_${5j{}kAKcLIL7_c^6_JLSJm9PAH2GlP)aa`Ov7KI0G}T&@DmSl zvMl9~kx^6cpIw5>5#E@;0VgM>+6leR_4Hmd{!nV;fNSV1U`#B0Gk=E$S;dFCSfu6M zV+{pUmMa;UjDq8OIx{G<)rT4hLmYVYPK~U&pAI|x?yE?H$DOB!INW*gh7JZKnvDW{ zC8jWuW;nJOkKH(eOI$nWCii)seiKKu?f7jN8}N{1g!30K9vSxQlG^)EcxPx3z5_j9KF(`)Z*j@tIKfXS*iiB=K~@;t&|?*r;5}kuAmh{&!nCC_Vu^TP;4@&mGy#gVl`#?or;20!o^TqNQ$YUUnfjkC=4hHr{ z&K+J5k+-06y&3-}LKo;_L=Iff@QN~QFrQ9220*GgfNwlC5Gr&#aUU>S%5`WIAARoN zwvAuz8TcnZ2&a4m@)hPWkjFqC19=Rb5eyg;OJm8T3NI9xLy)ssFvD^fVFB6>6AmYz zP9X-&@jk-DaBYwYi!U4b_P!(ahT;Rw@5n9_N@jEaAEX)|Y+6uM0{{R307*qoM6N<$ Eg3P3x_W%F@ literal 0 HcmV?d00001 diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 7cb0159c..2952e734 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -11,5 +11,17 @@ const Map> localizedValues = { 'services': {'en': 'SERVICES', 'ar': 'الخدمات'}, 'mySchedule': {'en': 'My Schedule', 'ar': 'جدولي'}, 'logout': {'en': 'Logout', 'ar': 'تسجيل خروج'}, - + 'login': {'en': 'Login', 'ar': 'تسجيل الدخول'}, + 'loginregister': {'en': 'Login / Register', 'ar': 'دخولتسجيل'}, + 'welcome': {'en': 'Welcome', 'ar': 'أهلا بك'}, + 'welcome_text': { + 'en': 'Dr. Sulaiman Al Habib Mobile Application ', + 'ar': 'الدكتور سليمان الحبيب لتطبيقات الهاتف المتحرك' + }, + 'welcome_text2': { + 'en': 'Have you visited AlHabib Medical Group before? ', + 'ar': 'الدكتور سليمان الحبيب لتطبيقات الهاتف المتحرك' + }, + 'yes': {'en': 'Yes', 'ar': 'نعم'}, + 'no': {'en': 'No', 'ar': 'لا'} }; diff --git a/lib/main.dart b/lib/main.dart index dff61ac6..e208a45a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:diplomaticquarterapp/pages/home_page.dart'; import 'package:diplomaticquarterapp/pages/landing_page.dart'; import 'package:diplomaticquarterapp/providers/project_provider.dart'; +import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; @@ -61,22 +62,18 @@ class MyApp extends StatelessWidget { splashColor: Colors.transparent, primaryColor: Colors.grey, cursorColor: Color.fromRGBO(78, 62, 253, 1.0), - iconTheme:IconThemeData( - - ) , + iconTheme: IconThemeData(), appBarTheme: AppBarTheme( - color: Color.fromRGBO(247, 248, 251, 1), - brightness: Brightness.light, + color: Colors.grey, + // brightness: Brightness.light, elevation: 0.0, actionsIconTheme: IconThemeData( color: Colors.grey[800], ), ), ), - initialRoute: '/', - routes: { - '/': (context) => LandingPage() - }, + initialRoute: HOME, + routes: routes, debugShowCheckedModeBanner: false, ), ), diff --git a/lib/pages/landing_page.dart b/lib/pages/landing_page.dart index 116abcdc..4fb12a7a 100644 --- a/lib/pages/landing_page.dart +++ b/lib/pages/landing_page.dart @@ -31,6 +31,7 @@ class _LandingPageState extends State { return Scaffold( appBar: AppBar( elevation: 0, + backgroundColor: Colors.grey, textTheme: TextTheme( headline6: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), diff --git a/lib/pages/login/welcome.dart b/lib/pages/login/welcome.dart new file mode 100644 index 00000000..fa9d7d52 --- /dev/null +++ b/lib/pages/login/welcome.dart @@ -0,0 +1,75 @@ +import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class WelcomeLogin extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: TranslationBase.of(context).welcome, + body: Padding( + padding: EdgeInsets.all(20), + child: Column( + children: [ + Expanded( + flex: 3, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset( + 'assets/images/habib-logo.png', + height: 80, + width: 80, + ), + Text( + TranslationBase.of(context).welcome, + style: TextStyle(fontSize: 30), + textAlign: TextAlign.left, + ), + Text( + TranslationBase.of(context).welcomeText, + style: TextStyle(fontSize: 24), + textAlign: TextAlign.left, + ), + Text( + TranslationBase.of(context).welcomeText2, + style: TextStyle(fontSize: 24), + textAlign: TextAlign.left, + ) + ]), + ), + Expanded( + flex: 2, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Row( + children: [ + Expanded( + child: RaisedButton( + color: Colors.red[900], + textColor: Colors.white, + child: Text(TranslationBase.of(context).yes), + onPressed: () => {}, + )) + ], + ), + Row( + children: [ + Expanded( + child: RaisedButton( + child: Text(TranslationBase.of(context).no), + onPressed: () => {}, + )) + ], + ), + ], + )) + ], + ))); + } +} diff --git a/lib/routes.dart b/lib/routes.dart new file mode 100644 index 00000000..d25f9988 --- /dev/null +++ b/lib/routes.dart @@ -0,0 +1,15 @@ +import 'package:diplomaticquarterapp/pages/landing_page.dart'; +import 'package:diplomaticquarterapp/pages/login/welcome.dart'; + +const String INIT_ROUTE = '/'; +const String ROOT = 'root'; +const String HOME = '/'; +const String LOGIN = 'login'; +const String WELCOME_LOGIN = 'welcome-login'; +var routes = { + // ROOT: (_) => RootPage(), + HOME: (_) => LandingPage(), + WELCOME_LOGIN: (_) => WelcomeLogin(), + + // LIVECARE_END_DIALOG: (_) => EndCallDialogBox() +}; diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index f9630b6d..faff53a1 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -37,8 +37,16 @@ class TranslationBase { String get replay2 => localizedValues['replay2'][locale.languageCode]; String get logout => localizedValues['logout'][locale.languageCode]; - - + String get login => localizedValues['login'][locale.languageCode]; + String get loginregister => + localizedValues['loginregister'][locale.languageCode]; + String get welcome => localizedValues['welcome'][locale.languageCode]; + String get welcomeText => + localizedValues['welcome_text'][locale.languageCode]; + String get welcomeText2 => + localizedValues['welcome_text2'][locale.languageCode]; + String get yes => localizedValues['yes'][locale.languageCode]; + String get no => localizedValues['no'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/drawer/app_drawer_widget.dart b/lib/widgets/drawer/app_drawer_widget.dart index 6474e05b..9960c59b 100644 --- a/lib/widgets/drawer/app_drawer_widget.dart +++ b/lib/widgets/drawer/app_drawer_widget.dart @@ -1,3 +1,4 @@ +import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/data_display/list/ListContainer.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; @@ -5,8 +6,6 @@ import 'package:flutter/material.dart'; import '../../config/size_config.dart'; import 'drawer_item_widget.dart'; - - class AppDrawer extends StatefulWidget { @override _AppDrawerState createState() => _AppDrawerState(); @@ -16,6 +15,7 @@ class _AppDrawerState extends State { @override Widget build(BuildContext context) { return ListContainer( + widthFactor: SizeConfig.widthMultiplier * .18, child: Container( color: Colors.white, child: Drawer( @@ -31,11 +31,11 @@ class _AppDrawerState extends State { child: InkWell( child: DrawerHeader( child: Column( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( child: Image.asset('assets/images/logo.png'), - margin: EdgeInsets.only(top: 10, bottom: 15), + margin: EdgeInsets.all(20), ), SizedBox( height: 1, @@ -44,36 +44,18 @@ class _AppDrawerState extends State { ), ), SizedBox(height: 15), - CircleAvatar( - radius: SizeConfig.imageSizeMultiplier * 12, - backgroundColor: Colors.white, - //TODO add backgroundImage: NetworkImage(''), - ), - Padding( - padding: EdgeInsets.only(top: 10), - child: Texts( - 'Patient', - color: Colors.black, - fontSize: SizeConfig.textMultiplier * 2, - )), - Texts("Director of medical records", - //TODO: Make The Dr Title Dynamic and check overflow issue. - - color: Colors.black87), - RaisedButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(18.0), - side: BorderSide(color: Colors.red), - ), - child: Texts( - TranslationBase.of(context).logout, - color: Colors.white, - ), - onPressed: () async { - Navigator.pop(context); - //TODO add await helpers.logout(); - }, - ), + // CircleAvatar( + // radius: SizeConfig.imageSizeMultiplier * 12, + // backgroundColor: Colors.white, + // //TODO add backgroundImage: NetworkImage(''), + // ), + // Padding( + // padding: EdgeInsets.only(top: 10), + // child: Texts( + // 'Patient', + // color: Colors.black, + // fontSize: SizeConfig.textMultiplier * 2, + // )), ], ), ), @@ -84,10 +66,12 @@ class _AppDrawerState extends State { ), InkWell( child: DrawerItem( - TranslationBase.of(context).settings, Icons.settings), + TranslationBase.of(context).loginregister, + Icons.lock), onTap: () { - Navigator.pop(context); - //TODO add fun + Navigator.of(context).pushNamed( + WELCOME_LOGIN, + ); }, ), ], diff --git a/lib/widgets/drawer/drawer_item_widget.dart b/lib/widgets/drawer/drawer_item_widget.dart index f7c6bf54..991d34b0 100644 --- a/lib/widgets/drawer/drawer_item_widget.dart +++ b/lib/widgets/drawer/drawer_item_widget.dart @@ -24,7 +24,7 @@ class _DrawerItemState extends State { @override Widget build(BuildContext context) { return Container( - margin: EdgeInsets.only(top: 5, bottom: 5, left: 10, right: 10), + margin: EdgeInsets.only(top: 5, bottom: 15, left: 10, right: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -33,21 +33,26 @@ class _DrawerItemState extends State { color: widget.iconColor, size: SizeConfig.imageSizeMultiplier * 5, ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Texts( - widget.title, - color: widget.textColor, - fontSize: SizeConfig.textMultiplier * 2.3, - ), - Texts( - widget.subTitle, - color: widget.textColor, - fontSize: SizeConfig.textMultiplier * 2.5, - ), - ], - ), + Padding( + padding: widget.subTitle == '' + ? EdgeInsets.only(top: 20) + : EdgeInsets.only(top: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Texts( + widget.title, + color: widget.textColor, + fontSize: SizeConfig.textMultiplier * 2.3, + ), + Texts( + widget.subTitle, + color: widget.textColor, + fontSize: SizeConfig.textMultiplier * 2.5, + ), + ], + ), + ) ], ), ); diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index 27c0a826..c6fc690b 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -1,8 +1,8 @@ import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/providers/project_provider.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import '../progress_indicator/app_loader_widget.dart'; import 'arrow_back.dart'; -import 'file:///D:/Mohammad/diplomatic_quarter_app/lib/widgets/progress_indicator/app_loader_widget.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:provider/provider.dart'; From 8dd38a8b3c0e2eee7b3f33921f094dc9ab977536 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Mon, 20 Jul 2020 09:34:55 +0300 Subject: [PATCH 2/4] no message --- assets/images/id_card_icon.png | Bin 0 -> 1924 bytes assets/images/my_file_white_icon.png | Bin 0 -> 2109 bytes lib/config/localized_values.dart | 18 ++- lib/pages/login/forgot-password.dart | 87 +++++++++++ lib/pages/login/login-type.dart | 139 ++++++++++++++++++ lib/pages/login/login.dart | 106 +++++++++++++ lib/pages/login/welcome.dart | 7 +- lib/routes.dart | 8 +- lib/uitl/translations_delegate_base.dart | 12 ++ lib/widgets/card/rounded_container.dart | 88 +++++++++++ .../input/date_picker/button_actions.dart | 2 +- lib/widgets/input/text_field.dart | 46 ++---- lib/widgets/mobile-no/mobile_no.dart | 75 ++++++++++ lib/widgets/text/app_texts_widget.dart | 74 ++++++++++ 14 files changed, 622 insertions(+), 40 deletions(-) create mode 100644 assets/images/id_card_icon.png create mode 100644 assets/images/my_file_white_icon.png create mode 100644 lib/pages/login/forgot-password.dart create mode 100644 lib/pages/login/login-type.dart create mode 100644 lib/pages/login/login.dart create mode 100644 lib/widgets/card/rounded_container.dart create mode 100644 lib/widgets/mobile-no/mobile_no.dart create mode 100644 lib/widgets/text/app_texts_widget.dart diff --git a/assets/images/id_card_icon.png b/assets/images/id_card_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9665060423d17540e312f259817dab4b88cae742 GIT binary patch literal 1924 zcmV-~2YdL5P) zd5jcA6o)?+L=Xf7BO)sbh>8k$prWE8sPVv?sEP5G2nG|0Xk1Z1JiseKqXtccjsKW< zM5ACt5fWqKg$F@lRU|?1z(rU&ycWSceM5$}YNmU-`kLu4>10#gU0YMXuIj4yURAfD zG@XFcfT2J=(5}q&Ic{hL)&fg_MZoVtbL|N{25bg)^5ltdHv;W*Jz}T5*8L`nHjfkv)X{R0qz$Q^`bsTBEc&zn9i-6bS`;2z z>ou1m##%HwONuzva6+aLyVZKFr3letgF&Y$b-@0Ha(<-NfSh#Ds)I-`^>r5W*t%S} z)M3)3eVwJ0+iR#|vVu_)7sl!C!0AB0!l)<($f&IeSX_xAI7@^Pus3i&a7Bu}6kBwT z`(U*iA#7b}IYt1>fU8sPViJqST{-~hmxA&*rxF1N0rP>qQvTbD5wp`<87s3df(j_M z)49MN36(bt{ecHESniSp?f%XOjo2}hyTEs&is+qw1hI2UEy)5w1#~@S7^TDf5tj4ow1q#a z0aif?BYq~RbRHNM8O1&aEG!`&+Tz7qvH}=hebpbHBm@-k764ZUxTm*@eRhQ9$|Ok$ zIH$tav^(%3a7YAY$}DjUDA81xl{hbhmz5>nT@oq&OhjeNBykHk&655BaGXZR4FGxo zcUz1Cr|41h5VIkApk*HUE^r3$S5expz;KJBUS3)v%6BJm3TUb%Q>*kc zz>wDJ(8DeQPH~i1F%k*zeFXXLLY(iwFAZtp_8F;*7)`WMPlunp!XT!)_kdwV>qWvK z(F*T4E~Ak+1zeu|3{4}~w<9Ruhk9g+IJ;1B_`YsP@1skJC+Um7 zmxhdsx$QQ?^*dDbnui1elBTLPrmZJkTs#l!QI1BPAJ#l1V2P1w!<`}S{}#B_VR90AG5>R+n=Yi9KZw%+RswqwO zsW}h$Ie{{!o}{Cy*XzJ$st#lhRAX{;0wIcG**PM?^&J~D4k*yVqBMoYuP#gRsCWiq|;xYKzQC==E1tVLDL%`uWfgkPTTEED;{x@{7iVNfOr700{o`#b6Ch9J9 zq!y}UMEN)9lChgYhW0PjXgAwVRdKMb5*JyN0?G^dwKC#0sh8qAojMc`Q1;ZWcc^+R zY`aB`Q>X7e4$2(41J*TB3D`knI6GO+&)2TvGoSfM%eY0o6Q;F^({zNoI7FEJC<+0)TRaBabxX_HA@Xk0=r)sx5_)k>h`cjN z6arpn={jfVJ25QHy3o`VigMZ`OR!*o8jJY~c4&AM&$WSvUPNkN$+A*?ZbrG~^$O6l*b zdTcE)$#BCQGsebNXR&6Ow$#c=mU_c~-zEaCF`PI)|87L8=%9{mFKg;7=BTcgg_SwU zFy3P2`d2&Kx0AM5RL_Z*VH!ed`nJ{1a24Cv%eJbIEvlfT96KG=F>VrXM`4AR-|q*C zke??Q`d({@9!HjFI4v5ovde;>{0pAhImXx?==>YH=|3iv>y7fSSf}&YSgPfD$-g6? zo@29WVKlCkTUXFYSI7=kOF)`Gvr|oobxeG(GS8D>Wf?^NAK)L8NzS}Lwp=U#0000< KMNUMnLSTZHjFeLV literal 0 HcmV?d00001 diff --git a/assets/images/my_file_white_icon.png b/assets/images/my_file_white_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6bd9b935925cc843dec9e738568e3292f278d984 GIT binary patch literal 2109 zcmV-D2*US?P)3(R6#m|OEk$;!pa|j;K*S&_8kPj&hD(e_qakj=HAdnB#>9yF!}W(zNnCI@BF4Cd z7$i2BXjO=aU|F<8K@(cE2#P`x3Z?D4X2^HVFx+?FoqOlaTwdRoOw-J&!+coaYz0IxvV4d7t_J-aba2T%pzH+KsxPNOma zsC`B;9l)mmwrTh#QEmwlBFJ>Zis)Sz1Gp;9M2X(+r6Rpuq0#~1ypXyticzO1d)QH^ zn&=$D1n0+WRGtogXh4yuq=Q<5kJ6V9oGVQM!B~Jz~=zA(3ceY ztaboP0Bn-3_hQ|9rE4PqTnL~CNe+@FN8-hErz!XE1@J*gyMyZ6PVN66@{1z6zL^pC zV1Bq4p;A%DDE4|jUIXwLfR+e?ski{Z9M=6ffUjfJAvE$4w#UaVb_QMq!ZQ3)M2NEr zz#9OXJ$2&ive^RYTE|k7Q{Dty%ghss39!tElGQ zB4((fnvU8>K4rs^P9+4XQsga$41-@E`K%H;WHbruP-3OtDNDc9Nd6TZg>-7Xe+VBs zYzu7~7!WjW;6NJm4GXAT4@dXi;u&Dr^CLuCB zW+QwELGA%?B|{8XDR7V4HB7mF1%UGvxiTb6e9<39sk}*XiYkd>P`%JlER*K4TAEAn zkyY|>Em2ISrxeGOGX_M-YD6(fPwDxD`Zm(xr)kzn7ouHbq%f!}!q{2M>HBD=FK90V z!rlWgP3NUJgyk9i?u+qm+MpdX#_9Gm39=DsgLeB}#Yu-P;+SMoR7J=XL_vnn>O}5F zgtrCJW#0f`hB91Hp+lGmju&zEe3y-O*d%NQQ`e?3iNl@yZ8XBB51VATzD}u^JKI)A zWK+ZBF1(%VCe(p^j>8k#$L-?aI4eC<$7?gCx~*hMY!W8>CNbf19aF|~Lxnug($@)W zWRSd7A}r5L$ZSb|Ps8^mf{R`fbk^IcX)0Dogf%iH69gx+yNbiIAts~}k*ZkHWr8ng z_8I}XszR`0f+}2odxgfLvWA7FTb#)5%7=~S6xOc{2R3td2XyppTwk$4(xg6o4}3=} z%U}ww2ph&lajn#%uK?V}P(v&=xQwHLl@eidxK_d+{5wf%x*`nJpkDm_EG}8t!Je~T zc{aB?nEc?$JgXQ`GqazpHQ}yDP#vB1ZbvAwwvusc9ds zoc_cm$qah}e6y7b&cW-hi!U#`dZMi;2Nq_9bttj%XI7as&Uiy@MU3j(yvQ|imu znpCz)nB3@$Mus%XvsqgvYSV`;WJpj7e4=hZC>3mKm>5)F&OJqiLJD1Ua>aL@twz{( z`pZ}jTU3?`Xre-xCMtw!q7**NWl}N-M#Bx0jqAs>%m{;ZCWWw|-vG>Gh9fad5_T7W zC#_Qw4Fk9wJ~2%Cu#-#FSQ8j&sv?sb_A0l_IiIMIkm1D2JW~~#By2f%|DWV)RyqI~ z&J{G7s?c*I6vR~N@4HRNWzvT^nYt&AQL-fdxj;UQrFTpc_5x$E4$GyT+yB-{vWSD;-r~I$ zo`YxvCQWiBCuxs0SZ6V08T)Nip6lYlB#XF8XtSvgG~G-7$&wbRL?%Wh4%0-1Filhl z(?o?ZO~fIr%hnEl3s85T6h)j~awrdiEr-L3#_7Hkg)sG4yMbl;PXN^OAPYWJ44o-T z2$mW}=OUsIwwwEW)GaRM1mTz80q|F`Hbp&fZ9dnM)~0Ai$Q1nHRb!M+Aga^P`={h~ zcc_l8+_c984%%O!9(-HlY7b9JkykgdR&j;i@%(!X_x8Nsje5pH$neb9iPHU@;^KqK z%E5MS-rUoThfW?(E*P(Dczs3uI8K@wu9U)MtNedPCa_zr5EfjTxn1#~9`ZzPI-jQT nPgKesVrovDc<}atunNF`qlPXy0&X&600000NkvXXu0mjfzG~J} literal 0 HcmV?d00001 diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 2952e734..1360d80e 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -23,5 +23,21 @@ const Map> localizedValues = { 'ar': 'الدكتور سليمان الحبيب لتطبيقات الهاتف المتحرك' }, 'yes': {'en': 'Yes', 'ar': 'نعم'}, - 'no': {'en': 'No', 'ar': 'لا'} + 'no': {'en': 'No', 'ar': 'لا'}, + "logintyperadio": { + "en": "Choose from below options to login to your medical file.", + "ar": "اختر من الخيارات أدناه لتسجيل الدخول إلى ملفك الطبي." + }, + "registernow": {"en": "Register Now", "ar": "تسجيل الان"}, + "nationalID": {"en": "National ID", "ar": "رقم الهوية"}, + "fileNo": {"en": "File Number", "ar": "رقم الملف"}, + "forgotFileNo": {"en": "Forgot file Number?", "ar": "نسيت رقم الملف الطبي؟"}, + "enter-national-id": { + "en": "Please enter mobile number and national ID / Iqama", + "ar": "الرجاء إدخال رقم الجوال والهوية الوطنية / الاقامة" + }, + "profile-info": { + "en": "Please enter profile information", + "ar": "الرجاء إدخال معلومات الملف الشخصي" + }, }; diff --git a/lib/pages/login/forgot-password.dart b/lib/pages/login/forgot-password.dart new file mode 100644 index 00000000..4a1069e7 --- /dev/null +++ b/lib/pages/login/forgot-password.dart @@ -0,0 +1,87 @@ +import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/widgets/input/text_field.dart'; +import 'package:diplomaticquarterapp/widgets/mobile-no/mobile_no.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class ForgotPassword extends StatelessWidget { + final String selectedType = 'Saudi Arabia'; + final TextEditingController nationalIDorFile = null; + final TextEditingController mobileNo = null; + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: TranslationBase.of(context).login, + body: SingleChildScrollView( + child: Container( + padding: EdgeInsets.only(top: 10, left: 10, right: 10), + height: SizeConfig.realScreenHeight * .8, + width: SizeConfig.realScreenWidth, + child: Column(children: [ + Expanded( + flex: 1, + child: AppText( + TranslationBase.of(context).enterNationalId, + fontSize: SizeConfig.textMultiplier * 3.5, + textAlign: TextAlign.left, + )), + Expanded( + flex: 2, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + // add Expanded to have your dropdown button fill remaining space + child: DropdownButtonHideUnderline( + child: DropdownButton( + isExpanded: true, + value: selectedType, + iconSize: 40, + elevation: 16, + // selectedItemBuilder: + // (BuildContext context) {}, + onChanged: (String newValue) => {}, + items: [ + 'Saudi Arabia', + 'Dubai', + ].map>( + (String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList()))), + ], + ), + MobileNo(controller: mobileNo), + ], + ), + ), + Expanded( + flex: 2, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Row( + children: [ + Expanded( + child: RaisedButton( + color: Colors.grey, + textColor: Colors.white, + child: Text(TranslationBase.of(context).submit), + onPressed: () => {}, + )) + ], + ), + ], + )) + ]), + ))); + } +} diff --git a/lib/pages/login/login-type.dart b/lib/pages/login/login-type.dart new file mode 100644 index 00000000..713333b4 --- /dev/null +++ b/lib/pages/login/login-type.dart @@ -0,0 +1,139 @@ +import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/widgets/card/rounded_container.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:diplomaticquarterapp/routes.dart'; + +class LoginType extends StatelessWidget { + static int loginType = 0; + + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: TranslationBase.of(context).welcome, + body: Padding( + padding: EdgeInsets.all(20), + child: Column( + children: [ + Expanded( + flex: 4, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset( + 'assets/images/habib-logo.png', + height: 80, + width: 80, + ), + AppText( + TranslationBase.of(context).logintypeRadio, + fontSize: SizeConfig.textMultiplier * 3.5, + textAlign: TextAlign.left, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + onTap: () => { + LoginType.loginType = 2, + Navigator.of(context) + .pushNamed(LOGIN_PAGE) + }, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: + EdgeInsets.fromLTRB(20, 10, 20, 10), + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/id_card_icon.png', + height: 60, + width: 70, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context) + .nationalID, + fontSize: + SizeConfig.textMultiplier * 3, + ) + ], + ), + ))), + InkWell( + onTap: () => { + LoginType.loginType = 1, + Navigator.of(context) + .pushNamed(LOGIN_PAGE) + }, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: + EdgeInsets.fromLTRB(25, 10, 25, 10), + child: Column( + children: [ + Image.asset( + 'assets/images/my_file_white_icon.png', + height: 60, + width: 70, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context).fileNo, + fontSize: + SizeConfig.textMultiplier * 3, + ) + ], + ), + ))) + ], + ), + Divider( + color: Colors.grey, + height: 2, + ), + Center( + child: AppText( + TranslationBase.of(context).forgotPassword, + fontSize: SizeConfig.textMultiplier * 3, + margin: 10, + underline: true)) + ]), + ), + Expanded( + flex: 2, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Row( + children: [ + Expanded( + child: RaisedButton( + color: Colors.grey, + textColor: Colors.white, + child: + Text(TranslationBase.of(context).registerNow), + onPressed: () => {}, + )) + ], + ), + ], + )) + ], + ))); + } +} diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart new file mode 100644 index 00000000..de649382 --- /dev/null +++ b/lib/pages/login/login.dart @@ -0,0 +1,106 @@ +import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/pages/login/login-type.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; +import 'package:diplomaticquarterapp/widgets/card/rounded_container.dart'; +import 'package:diplomaticquarterapp/widgets/input/text_field.dart'; +import 'package:diplomaticquarterapp/widgets/mobile-no/mobile_no.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class Login extends StatelessWidget { + final String _selectedType = 'Saudi Arabia'; + final TextEditingController nationalIDorFile = null; + final int loginType = LoginType.loginType; + final TextEditingController mobileNo = null; + + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: TranslationBase.of(context).login, + body: SingleChildScrollView( + child: Container( + padding: EdgeInsets.only(top: 10, left: 10, right: 10), + height: SizeConfig.realScreenHeight * .8, + width: SizeConfig.realScreenWidth, + child: Column(children: [ + Expanded( + flex: 1, + child: AppText( + TranslationBase.of(context).enterNationalId, + fontSize: SizeConfig.textMultiplier * 3.5, + textAlign: TextAlign.left, + )), + Expanded( + flex: 2, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + // add Expanded to have your dropdown button fill remaining space + child: DropdownButtonHideUnderline( + child: DropdownButton( + isExpanded: true, + value: _selectedType, + iconSize: 40, + elevation: 16, + // selectedItemBuilder: + // (BuildContext context) {}, + onChanged: (String newValue) => {}, + items: [ + 'Saudi Arabia', + 'Dubai', + ].map>( + (String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList()))), + ], + ), + MobileNo(controller: mobileNo), + Container( + child: TextFields( + controller: nationalIDorFile, + prefixIcon: Icon( + loginType == 1 + ? Icons.receipt + : Icons.chrome_reader_mode, + color: Colors.red), + padding: EdgeInsets.only( + top: 20, bottom: 20, left: 10, right: 10), + hintText: loginType == 1 + ? TranslationBase.of(context).fileNo + : TranslationBase.of(context).nationalID, + )) + ], + ), + ), + Expanded( + flex: 2, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Row( + children: [ + Expanded( + child: RaisedButton( + color: Colors.grey, + textColor: Colors.white, + child: Text(TranslationBase.of(context).login), + onPressed: () => {}, + )) + ], + ), + ], + )) + ]), + ))); + } +} diff --git a/lib/pages/login/welcome.dart b/lib/pages/login/welcome.dart index fa9d7d52..021b2bfc 100644 --- a/lib/pages/login/welcome.dart +++ b/lib/pages/login/welcome.dart @@ -4,6 +4,7 @@ import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:diplomaticquarterapp/routes.dart'; class WelcomeLogin extends StatelessWidget { @override @@ -54,7 +55,11 @@ class WelcomeLogin extends StatelessWidget { color: Colors.red[900], textColor: Colors.white, child: Text(TranslationBase.of(context).yes), - onPressed: () => {}, + onPressed: () => { + Navigator.of(context).pushNamed( + LOGIN_TYPE, + ) + }, )) ], ), diff --git a/lib/routes.dart b/lib/routes.dart index d25f9988..8e4f55ed 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -1,15 +1,19 @@ import 'package:diplomaticquarterapp/pages/landing_page.dart'; import 'package:diplomaticquarterapp/pages/login/welcome.dart'; +import 'package:diplomaticquarterapp/pages/login/login-type.dart'; +import 'package:diplomaticquarterapp/pages/login/login.dart'; const String INIT_ROUTE = '/'; const String ROOT = 'root'; const String HOME = '/'; const String LOGIN = 'login'; const String WELCOME_LOGIN = 'welcome-login'; +const String LOGIN_TYPE = 'login-type'; +const String LOGIN_PAGE = 'login-page'; var routes = { // ROOT: (_) => RootPage(), HOME: (_) => LandingPage(), WELCOME_LOGIN: (_) => WelcomeLogin(), - - // LIVECARE_END_DIALOG: (_) => EndCallDialogBox() + LOGIN_TYPE: (_) => LoginType(), + LOGIN_PAGE: (_) => Login(), }; diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index faff53a1..ca48792c 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -47,6 +47,18 @@ class TranslationBase { localizedValues['welcome_text2'][locale.languageCode]; String get yes => localizedValues['yes'][locale.languageCode]; String get no => localizedValues['no'][locale.languageCode]; + String get logintypeRadio => + localizedValues['logintyperadio'][locale.languageCode]; + String get registerNow => localizedValues['registernow'][locale.languageCode]; + String get nationalID => localizedValues['nationalID'][locale.languageCode]; + String get fileNo => localizedValues['fileNo'][locale.languageCode]; + String get forgotPassword => + localizedValues['forgotFileNo'][locale.languageCode]; + String get enterNationalId => + localizedValues['enter-national-id'][locale.languageCode]; + String get profileInfo => + localizedValues['profile-info'][locale.languageCode]; + String get submit => localizedValues['submit'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/card/rounded_container.dart b/lib/widgets/card/rounded_container.dart new file mode 100644 index 00000000..a6cb36e2 --- /dev/null +++ b/lib/widgets/card/rounded_container.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; + +// OWNER : Ibrahim albitar +// DATE : 05-04-2020 +// DESCRIPTION : Custom widget for rounded container and custom decoration + +class RoundedContainer extends StatefulWidget { + final double width; + final double height; + final double raduis; + final Color backgroundColor; + final double margin; + final double elevation; + final bool showBorder; + final Color borderColor; + final bool customCornerRaduis; + final double topLeft; + final double bottomRight; + final double topRight; + final double bottomLeft; + final Widget child; + final double borderWidth; + + RoundedContainer( + {@required this.child, + this.width, + this.height, + this.raduis = 10, + this.backgroundColor = Colors.white, + this.margin = 10, + this.elevation = 1, + this.showBorder = false, + this.borderColor = Colors.red, + this.customCornerRaduis = false, + this.topLeft = 0, + this.topRight = 0, + this.bottomRight = 0, + this.bottomLeft = 0, + this.borderWidth = 1}); + + @override + _RoundedContainerState createState() => _RoundedContainerState(); +} + +class _RoundedContainerState extends State { + @override + Widget build(BuildContext context) { + return Container( + width: widget.width, + height: widget.height, + margin: EdgeInsets.all(widget.margin), + decoration: widget.showBorder == true + ? BoxDecoration( + color: Theme.of(context).primaryColor, + border: Border.all( + color: widget.borderColor, width: widget.borderWidth), + borderRadius: widget.customCornerRaduis + ? BorderRadius.only( + topLeft: Radius.circular(widget.topLeft), + topRight: Radius.circular(widget.topRight), + bottomRight: Radius.circular(widget.bottomRight), + bottomLeft: Radius.circular(widget.bottomLeft)) + : BorderRadius.circular(widget.raduis), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + spreadRadius: 10, + blurRadius: 5, + offset: Offset(0, 5), // changes position of shadow + ), + ]) + : null, + child: Card( + margin: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: widget.customCornerRaduis + ? BorderRadius.only( + topLeft: Radius.circular(widget.topLeft), + topRight: Radius.circular(widget.topRight), + bottomRight: Radius.circular(widget.bottomRight), + bottomLeft: Radius.circular(widget.bottomLeft)) + : BorderRadius.circular(widget.raduis), + ), + color: widget.backgroundColor, + child: widget.child, + )); + } +} diff --git a/lib/widgets/input/date_picker/button_actions.dart b/lib/widgets/input/date_picker/button_actions.dart index 685d6a77..c3fbea64 100644 --- a/lib/widgets/input/date_picker/button_actions.dart +++ b/lib/widgets/input/date_picker/button_actions.dart @@ -18,7 +18,7 @@ class ButtonActions extends StatelessWidget { widthFactor: 0.6, child: Button( onTap: onPositive, - title: "Confirm", + // title: "Confirm", ), ), ); diff --git a/lib/widgets/input/text_field.dart b/lib/widgets/input/text_field.dart index 6ab268d5..5c11f699 100644 --- a/lib/widgets/input/text_field.dart +++ b/lib/widgets/input/text_field.dart @@ -80,7 +80,7 @@ class TextFields extends StatefulWidget { final bool autoFocus; final IconData suffixIcon; final Color suffixIconColor; - final IconData prefixIcon; + final Icon prefixIcon; final VoidCallback onTap; final TextEditingController controller; final TextInputType keyboardType; @@ -198,10 +198,10 @@ class _TextFieldsState extends State { decoration: widget.bare ? null : BoxDecoration(boxShadow: [ - BoxShadow( - color: Color.fromRGBO(70, 68, 167, focus ? 0.20 : 0), - offset: Offset(0.0, 13.0), - blurRadius: focus ? 34.0 : 12.0) + // BoxShadow( + // color: Color.fromRGBO(70, 68, 167, focus ? 0.20 : 0), + // offset: Offset(0.0, 13.0), + // blurRadius: focus ? 34.0 : 12.0) ]), child: TextFormField( keyboardAppearance: Theme.of(context).brightness, @@ -257,19 +257,7 @@ class _TextFieldsState extends State { ? Colors.transparent : Theme.of(context).backgroundColor, suffixIcon: _buildSuffixIcon(), - prefixIcon: widget.type != "search" - ? widget.prefixIcon != null - ? Padding( - padding: EdgeInsets.only( - left: 28.0, top: 14.0, bottom: 14.0, right: 0), - child: Text( - "\$", - style: TextStyle( - fontSize: 14, fontWeight: FontWeight.w800), - ), - ) - : null - : Icon(EvaIcons.search, size: 20.0, color: Colors.grey[500]), + prefixIcon: widget.prefixIcon, errorStyle: TextStyle( fontSize: 14.0, fontWeight: widget.fontWeight, @@ -279,35 +267,23 @@ class _TextFieldsState extends State { color: Theme.of(context) .errorColor .withOpacity(widget.bare ? 0.0 : 0.5), - width: 2.0), + width: 1.0), borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0)), focusedErrorBorder: OutlineInputBorder( borderSide: BorderSide( color: Theme.of(context) .errorColor .withOpacity(widget.bare ? 0.0 : 0.5), - width: 2.0), + width: 1.0), borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0)), focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .dividerColor - .withOpacity(widget.bare ? 0.0 : 1.0), - width: 2.0), + borderSide: BorderSide(color: Colors.grey, width: 1.0), borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0)), disabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .dividerColor - .withOpacity(widget.bare ? 0.0 : 1.0), - width: 2.0), + borderSide: BorderSide(color: Colors.grey, width: 1.0), borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0)), enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .dividerColor - .withOpacity(widget.bare ? 0.0 : 1.0), - width: 2.0), + borderSide: BorderSide(color: Colors.grey, width: 1.0), borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0), ), ), diff --git a/lib/widgets/mobile-no/mobile_no.dart b/lib/widgets/mobile-no/mobile_no.dart new file mode 100644 index 00000000..a4407e73 --- /dev/null +++ b/lib/widgets/mobile-no/mobile_no.dart @@ -0,0 +1,75 @@ +import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// OWNER : Ibrahim albitar +// DATE : 12-04-2020 +// DESCRIPTION : Customization for Texts in app + +class MobileNo extends StatefulWidget { + final bool disabled; + // final String data; + final String countryCode; + final double margin; + final double marginTop; + final double marginRight; + final double marginBottom; + final double marginLeft; + final TextEditingController controller; + MobileNo( + {this.disabled = false, + this.countryCode = '966', + this.marginTop = 0, + this.marginRight = 0, + this.marginBottom = 0, + this.controller, + this.marginLeft = 0, + this.margin = 0}); + + @override + _MobileNo createState() => _MobileNo(); +} + +class _MobileNo extends State { + @override + Widget build(BuildContext context) { + return Visibility( + child: Container( + padding: EdgeInsets.all(5), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(10)), + child: Row(children: [ + Expanded( + flex: 1, + child: Icon( + Icons.phone, + color: Colors.red, + )), + Expanded( + flex: 1, + child: Text( + widget.countryCode, + overflow: TextOverflow.clip, + )), + Expanded( + flex: 4, + child: Container( + margin: widget.margin != null + ? EdgeInsets.all(widget.margin) + : EdgeInsets.only( + top: widget.marginTop, + right: widget.marginRight, + bottom: widget.marginBottom, + left: widget.marginLeft), + child: TextField( + controller: widget.controller, + decoration: InputDecoration( + border: InputBorder.none, hintText: '5xxxxxxxx'), + ), + ), + ) + ]), + )); + } +} diff --git a/lib/widgets/text/app_texts_widget.dart b/lib/widgets/text/app_texts_widget.dart new file mode 100644 index 00000000..e3989719 --- /dev/null +++ b/lib/widgets/text/app_texts_widget.dart @@ -0,0 +1,74 @@ +import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +// OWNER : Ibrahim albitar +// DATE : 12-04-2020 +// DESCRIPTION : Customization for Texts in app + +class AppText extends StatefulWidget { + final String data; + final Color color; + final FontWeight fontWeight; + final double fontSize; + final String fontFamily; + final double margin; + final double marginTop; + final double marginRight; + final double marginBottom; + final double marginLeft; + final bool visibility; + final TextAlign textAlign; + final Color backGroundcolor; + final bool underline; + AppText(this.data, + {this.color = Colors.black, + this.fontWeight = FontWeight.normal, + this.fontSize, + this.fontFamily = 'WorkSans', + this.margin, + this.marginTop = 0, + this.marginRight = 0, + this.marginBottom = 0, + this.marginLeft = 0, + this.visibility = true, + this.textAlign, + this.underline = false, + this.backGroundcolor = Colors.white}); + + @override + _AppTextState createState() => _AppTextState(); +} + +class _AppTextState extends State { + @override + Widget build(BuildContext context) { + return Visibility( + visible: widget.visibility, + child: Container( + margin: widget.margin != null + ? EdgeInsets.all(widget.margin) + : EdgeInsets.only( + top: widget.marginTop, + right: widget.marginRight, + bottom: widget.marginBottom, + left: widget.marginLeft), + child: Text( + widget.data, + textAlign: widget.textAlign, + overflow: TextOverflow.clip, + style: TextStyle( + color: widget.color, + fontWeight: widget.fontWeight, + fontSize: widget.fontSize ?? (SizeConfig.textMultiplier * 2), + fontFamily: widget.fontFamily, + decoration: widget.underline == true + ? TextDecoration.underline + : TextDecoration.none + // backgroundColor:widget.backGroundcolor + ), + ), + ), + ); + } +} From f8d8e1c68517158276644b65dfc80ed427a37136 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Tue, 21 Jul 2020 09:09:39 +0300 Subject: [PATCH 3/4] new pages added --- android/app/build.gradle | 2 + android/app/google-services.json | 42 ++++++ android/app/src/main/AndroidManifest.xml | 4 + android/build.gradle | 1 + lib/config/localized_values.dart | 7 + lib/config/shared_pref_kay.dart | 2 +- .../model/auth/select_device_imei_res.dart | 68 +++++++++ lib/pages/landing/landing_page.dart | 8 +- lib/pages/login/forgot-password.dart | 21 ++- lib/pages/login/login-type.dart | 21 ++- lib/pages/login/login.dart | 36 +---- lib/pages/login/register.dart | 139 ++++++++++++++++++ lib/pages/login/welcome.dart | 6 +- lib/providers/auth_provider.dart | 96 ++++++++++++ lib/routes.dart | 6 + lib/uitl/translations_delegate_base.dart | 5 + lib/widgets/mobile-no/mobile_no.dart | 101 ++++++++----- pubspec.yaml | 3 +- 18 files changed, 485 insertions(+), 83 deletions(-) create mode 100644 android/app/google-services.json create mode 100644 lib/core/model/auth/select_device_imei_res.dart create mode 100644 lib/pages/login/register.dart create mode 100644 lib/providers/auth_provider.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 807f7fad..300075a5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -23,6 +23,7 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'com.google.gms.google-services' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { @@ -60,4 +61,5 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "com.google.firebase:firebase-messaging:20.1.0" } diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..f86832ad --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,42 @@ +{ + "project_info": { + "project_number": "815750722565", + "firebase_url": "https://api-project-815750722565.firebaseio.com", + "project_id": "api-project-815750722565", + "storage_bucket": "api-project-815750722565.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:815750722565:android:62281cd3e5df4063", + "android_client_info": { + "package_name": "com.cloud.diplomaticquarterapp" + } + }, + "oauth_client": [ + { + "client_id": "815750722565-3a0gc7neins0eoahdrimrfksk0sqice8.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyDUfg6AKM1-00WyzpvLImUBC46wFrq9-qw" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b88d5204..c5095d24 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -37,6 +37,10 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle index 3100ad2d..70b3637d 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/lib/config/localized_values.dart b/lib/config/localized_values.dart index cb1b7962..2527e363 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -41,4 +41,11 @@ const Map> localizedValues = { "ar": "الرجاء إدخال معلومات الملف الشخصي" }, "submit": {"en": "Submit", "ar": "ارسال"}, + "forgot-desc": { + "en": "Enter the mobile number to receive the Medical file Number via SMS", + "ar": "أدخل رقم الجوال المسجل لاستلام رقم الملف عن طريق الرسائل النصية" + }, + "dob": {"en": "Birth Date:", "ar": "تاريخ الميلاد"}, + "hijri-date": {"en": "Hijri Date", "ar": "التاريخ الهجري"}, + "gregorian-date": {"en": "Gregorian Date", "ar": "التاريخ الميلادي"}, }; diff --git a/lib/config/shared_pref_kay.dart b/lib/config/shared_pref_kay.dart index 8c03fcce..59f4f0ff 100644 --- a/lib/config/shared_pref_kay.dart +++ b/lib/config/shared_pref_kay.dart @@ -1,3 +1,3 @@ const TOKEN = 'token'; const APP_LANGUAGE = 'language'; - +const USER_PROFILE = 'user-profile'; diff --git a/lib/core/model/auth/select_device_imei_res.dart b/lib/core/model/auth/select_device_imei_res.dart new file mode 100644 index 00000000..14444279 --- /dev/null +++ b/lib/core/model/auth/select_device_imei_res.dart @@ -0,0 +1,68 @@ +class SelectDeviceIMEIRES { + bool biometricEnabled; + String createdOn; + String editedOn; + int iD; + String iMEI; + String identificationNo; + int logInType; + String mobile; + String name; + String nameN; + bool outSA; + int patientID; + int patientType; + int preferredLanguage; + + SelectDeviceIMEIRES( + {this.biometricEnabled, + this.createdOn, + this.editedOn, + this.iD, + this.iMEI, + this.identificationNo, + this.logInType, + this.mobile, + this.name, + this.nameN, + this.outSA, + this.patientID, + this.patientType, + this.preferredLanguage}); + + SelectDeviceIMEIRES.fromJson(Map json) { + biometricEnabled = json['BiometricEnabled']; + createdOn = json['CreatedOn']; + editedOn = json['EditedOn']; + iD = json['ID']; + iMEI = json['IMEI']; + identificationNo = json['IdentificationNo']; + logInType = json['LogInType']; + mobile = json['Mobile']; + name = json['Name']; + nameN = json['NameN']; + outSA = json['OutSA']; + patientID = json['PatientID']; + patientType = json['PatientType']; + preferredLanguage = json['PreferredLanguage']; + } + + Map toJson() { + final Map data = new Map(); + data['BiometricEnabled'] = this.biometricEnabled; + data['CreatedOn'] = this.createdOn; + data['EditedOn'] = this.editedOn; + data['ID'] = this.iD; + data['IMEI'] = this.iMEI; + data['IdentificationNo'] = this.identificationNo; + data['LogInType'] = this.logInType; + data['Mobile'] = this.mobile; + data['Name'] = this.name; + data['NameN'] = this.nameN; + data['OutSA'] = this.outSA; + data['PatientID'] = this.patientID; + data['PatientType'] = this.patientType; + data['PreferredLanguage'] = this.preferredLanguage; + return data; + } +} diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index ea5198ac..c7748b4c 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -4,7 +4,7 @@ import 'package:diplomaticquarterapp/widgets/bottom_navigation/bottom_nav_bar.da import 'package:diplomaticquarterapp/widgets/drawer/app_drawer_widget.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; - +import 'package:firebase_messaging/firebase_messaging.dart'; import 'home_page.dart'; class LandingPage extends StatefulWidget { @@ -15,7 +15,7 @@ class LandingPage extends StatefulWidget { class _LandingPageState extends State { int currentTab = 0; PageController pageController; - + final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); _changeCurrentTab(int tab) { setState(() { currentTab = tab; @@ -27,6 +27,10 @@ class _LandingPageState extends State { void initState() { super.initState(); pageController = PageController(keepPage: true); + _firebaseMessaging.getToken().then((String token) { + print(token); + //assert(token != null); + }); } @override diff --git a/lib/pages/login/forgot-password.dart b/lib/pages/login/forgot-password.dart index 42b951bb..c1fa7b18 100644 --- a/lib/pages/login/forgot-password.dart +++ b/lib/pages/login/forgot-password.dart @@ -7,8 +7,13 @@ import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -class ForgotPassword extends StatelessWidget { - final String selectedType = 'Saudi Arabia'; +class ForgotPassword extends StatefulWidget { + @override + _ForgotPassword createState() => _ForgotPassword(); +} + +class _ForgotPassword extends State { + String selectedType = 'Saudi Arabia'; final TextEditingController nationalIDorFile = null; final TextEditingController mobileNo = null; @override @@ -18,14 +23,14 @@ class ForgotPassword extends StatelessWidget { isShowAppBar: true, body: SingleChildScrollView( child: Container( - padding: EdgeInsets.only(top: 10, left: 10, right: 10), + padding: EdgeInsets.only(top: 10, left: 20, right: 20), height: SizeConfig.realScreenHeight * .8, width: SizeConfig.realScreenWidth, child: Column(children: [ Expanded( flex: 1, child: AppText( - TranslationBase.of(context).enterNationalId, + TranslationBase.of(context).forgotDesc, fontSize: SizeConfig.textMultiplier * 3.5, textAlign: TextAlign.left, )), @@ -45,9 +50,11 @@ class ForgotPassword extends StatelessWidget { value: selectedType, iconSize: 40, elevation: 16, - // selectedItemBuilder: - // (BuildContext context) {}, - onChanged: (String newValue) => {}, + onChanged: (String newValue) => { + setState(() { + selectedType = newValue; + }) + }, items: [ 'Saudi Arabia', 'Dubai', diff --git a/lib/pages/login/login-type.dart b/lib/pages/login/login-type.dart index bf69053e..e22ce297 100644 --- a/lib/pages/login/login-type.dart +++ b/lib/pages/login/login-type.dart @@ -108,11 +108,16 @@ class LoginType extends StatelessWidget { height: 2, ), Center( - child: AppText( - TranslationBase.of(context).forgotPassword, - fontSize: SizeConfig.textMultiplier * 3, - margin: 10, - underline: true)) + child: InkWell( + onTap: () => { + Navigator.of(context) + .pushNamed(FORGOT_PASSWORD) + }, + child: AppText( + TranslationBase.of(context).forgotPassword, + fontSize: SizeConfig.textMultiplier * 3, + margin: 10, + underline: true))) ]), ), Expanded( @@ -128,7 +133,11 @@ class LoginType extends StatelessWidget { textColor: Colors.white, child: Text(TranslationBase.of(context).registerNow), - onPressed: () => {}, + onPressed: () => { + Navigator.of(context).pushNamed( + REGISTER, + ) + }, )) ], ), diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart index 8d4c9fef..1cd6fa11 100644 --- a/lib/pages/login/login.dart +++ b/lib/pages/login/login.dart @@ -10,8 +10,12 @@ import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -class Login extends StatelessWidget { - final String _selectedType = 'Saudi Arabia'; +class Login extends StatefulWidget { + @override + _Login createState() => _Login(); +} + +class _Login extends State { final TextEditingController nationalIDorFile = null; final int loginType = LoginType.loginType; final TextEditingController mobileNo = null; @@ -23,7 +27,7 @@ class Login extends StatelessWidget { isShowAppBar: true, body: SingleChildScrollView( child: Container( - padding: EdgeInsets.only(top: 10, left: 10, right: 10), + padding: EdgeInsets.only(top: 10, left: 20, right: 20), height: SizeConfig.realScreenHeight * .8, width: SizeConfig.realScreenWidth, child: Column(children: [ @@ -39,32 +43,6 @@ class Login extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - // add Expanded to have your dropdown button fill remaining space - child: DropdownButtonHideUnderline( - child: DropdownButton( - isExpanded: true, - value: _selectedType, - iconSize: 40, - elevation: 16, - // selectedItemBuilder: - // (BuildContext context) {}, - onChanged: (String newValue) => {}, - items: [ - 'Saudi Arabia', - 'Dubai', - ].map>( - (String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList()))), - ], - ), MobileNo(controller: mobileNo), Container( child: TextFields( diff --git a/lib/pages/login/register.dart b/lib/pages/login/register.dart new file mode 100644 index 00000000..6c58ba72 --- /dev/null +++ b/lib/pages/login/register.dart @@ -0,0 +1,139 @@ +import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/pages/login/login-type.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; +import 'package:diplomaticquarterapp/widgets/card/rounded_container.dart'; +import 'package:diplomaticquarterapp/widgets/input/text_field.dart'; +import 'package:diplomaticquarterapp/widgets/mobile-no/mobile_no.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class Register extends StatefulWidget { + @override + _Register createState() => _Register(); +} + +class _Register extends State { + final TextEditingController nationalIDorFile = null; + final int loginType = LoginType.loginType; + final TextEditingController mobileNo = null; + var isHijri; + + DateTime selectedDate; + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: TranslationBase.of(context).login, + isShowAppBar: true, + body: SingleChildScrollView( + child: Container( + padding: EdgeInsets.only(top: 10, left: 20, right: 20), + height: SizeConfig.realScreenHeight * .8, + width: SizeConfig.realScreenWidth, + child: Column(children: [ + Expanded( + flex: 1, + child: AppText( + TranslationBase.of(context).enterNationalId, + fontSize: SizeConfig.textMultiplier * 3.5, + textAlign: TextAlign.left, + )), + Expanded( + flex: 4, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + MobileNo(controller: mobileNo), + Container( + child: TextFields( + controller: nationalIDorFile, + prefixIcon: + Icon(Icons.chrome_reader_mode, color: Colors.red), + padding: EdgeInsets.only( + top: 20, bottom: 20, left: 10, right: 10), + hintText: TranslationBase.of(context).nationalID, + )), + Row( + children: [ + Expanded( + child: Row( + children: [ + Radio( + value: 1, + groupValue: isHijri, + onChanged: (value) { + setState(() { + isHijri = value; + }); + }, + ), + Text(TranslationBase.of(context).hijriDate), + ], + ), + ), + Expanded( + child: Row( + children: [ + Radio( + value: 0, + groupValue: isHijri, + onChanged: (value) { + setState(() { + isHijri = value; + }); + }, + ), + Text(TranslationBase.of(context).gregorianDate), + ], + ), + ), + ], + ), + Row(children: [ + Expanded( + child: RaisedButton.icon( + onPressed: () => {_selectDate(context)}, + icon: Icon(Icons.date_range), + label: Text(selectedDate != null + ? "${selectedDate.toLocal()}".split(' ')[0] + : TranslationBase.of(context).dob))) + ]) + ], + ), + ), + Expanded( + flex: 2, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Row( + children: [ + Expanded( + child: RaisedButton( + color: Colors.grey, + textColor: Colors.white, + child: Text(TranslationBase.of(context).login), + onPressed: () => {}, + )) + ], + ), + ], + )) + ]), + ))); + } + + Future _selectDate(BuildContext context) async { + final DateTime picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2015, 8), + lastDate: DateTime(2101)); + if (picked != null && picked != selectedDate) + setState(() { + selectedDate = picked; + }); + } +} diff --git a/lib/pages/login/welcome.dart b/lib/pages/login/welcome.dart index 1dab3e1a..978ff449 100644 --- a/lib/pages/login/welcome.dart +++ b/lib/pages/login/welcome.dart @@ -69,7 +69,11 @@ class WelcomeLogin extends StatelessWidget { Expanded( child: RaisedButton( child: Text(TranslationBase.of(context).no), - onPressed: () => {}, + onPressed: () => { + Navigator.of(context).pushNamed( + REGISTER, + ) + }, )) ], ), diff --git a/lib/providers/auth_provider.dart b/lib/providers/auth_provider.dart new file mode 100644 index 00000000..09b880b9 --- /dev/null +++ b/lib/providers/auth_provider.dart @@ -0,0 +1,96 @@ +import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart'; +import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; +import 'package:flutter/cupertino.dart'; + +// SharedPreferences sharedPref = new SharedPreferences(); +enum APP_STATUS { LOADING, UNAUTHENTICATED, AUTHENTICATED } +AppSharedPreferences sharedPref = new AppSharedPreferences(); + +const String INSERT_DEVICE_IMEI = + 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; +const String SELECT_DEVICE_IMEI = + 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; + +class AuthProvider with ChangeNotifier { + bool isLogin = false; + bool isLoading = true; + AuthProvider() { + getUserAuthentication(); + } + + void getUserAuthentication() async { + Map profile = await sharedPref.getObject(USER_PROFILE); + if (profile != null) { + isLoading = false; + isLogin = true; + } else { + isLoading = false; + isLogin = false; + } + notifyListeners(); + } + + APP_STATUS get stutas { + if (isLoading) { + return APP_STATUS.LOADING; + } else { + if (this.isLogin) { + return APP_STATUS.AUTHENTICATED; + } else { + return APP_STATUS.UNAUTHENTICATED; + } + } + } + + // Future login(UserModel userInfo) async { + // try { + // dynamic localRes; + + // await BaseAppClient.post(LOGIN_URL, + // onSuccess: (dynamic response, int statusCode) { + // localRes = response; + // }, onFailure: (String error, int statusCode) { + // throw error; + // }, body: userInfo.toJson()); + + // return Future.value(localRes); + // } catch (error) { + // print(error); + // throw error; + // } + // } + + Future insertDeviceImei(imei) async { + try { + dynamic localRes; + + await new 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 selectDeviceImei(imei) async { + try { + dynamic localRes; + await new BaseAppClient().post(SELECT_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; + } + } +} diff --git a/lib/routes.dart b/lib/routes.dart index 2f25e075..8b3d1d4b 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -1,7 +1,9 @@ import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; +import 'package:diplomaticquarterapp/pages/login/forgot-password.dart'; import 'package:diplomaticquarterapp/pages/login/welcome.dart'; import 'package:diplomaticquarterapp/pages/login/login-type.dart'; import 'package:diplomaticquarterapp/pages/login/login.dart'; +import 'package:diplomaticquarterapp/pages/login/register.dart'; const String INIT_ROUTE = '/'; const String ROOT = 'root'; @@ -10,10 +12,14 @@ const String LOGIN = 'login'; const String WELCOME_LOGIN = 'welcome-login'; const String LOGIN_TYPE = 'login-type'; const String LOGIN_PAGE = 'login-page'; +const String FORGOT_PASSWORD = 'forgot-password'; +const String REGISTER = 'register'; var routes = { // ROOT: (_) => RootPage(), HOME: (_) => LandingPage(), WELCOME_LOGIN: (_) => WelcomeLogin(), LOGIN_TYPE: (_) => LoginType(), LOGIN_PAGE: (_) => Login(), + FORGOT_PASSWORD: (_) => ForgotPassword(), + REGISTER: (_) => Register() }; diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index ca48792c..8a99c420 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -59,6 +59,11 @@ class TranslationBase { String get profileInfo => localizedValues['profile-info'][locale.languageCode]; String get submit => localizedValues['submit'][locale.languageCode]; + String get forgotDesc => localizedValues['forgot-desc'][locale.languageCode]; + String get dob => localizedValues['dob'][locale.languageCode]; + String get hijriDate => localizedValues['hijri-date'][locale.languageCode]; + String get gregorianDate => + localizedValues['gregorian-date'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/mobile-no/mobile_no.dart b/lib/widgets/mobile-no/mobile_no.dart index a4407e73..a1304eff 100644 --- a/lib/widgets/mobile-no/mobile_no.dart +++ b/lib/widgets/mobile-no/mobile_no.dart @@ -31,45 +31,74 @@ class MobileNo extends StatefulWidget { } class _MobileNo extends State { + var _selectedType = 'Saudi Arabia'; + @override Widget build(BuildContext context) { return Visibility( - child: Container( - padding: EdgeInsets.all(5), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey), - borderRadius: BorderRadius.circular(10)), - child: Row(children: [ - Expanded( - flex: 1, - child: Icon( - Icons.phone, - color: Colors.red, - )), - Expanded( - flex: 1, - child: Text( - widget.countryCode, - overflow: TextOverflow.clip, - )), - Expanded( - flex: 4, - child: Container( - margin: widget.margin != null - ? EdgeInsets.all(widget.margin) - : EdgeInsets.only( - top: widget.marginTop, - right: widget.marginRight, - bottom: widget.marginBottom, - left: widget.marginLeft), - child: TextField( - controller: widget.controller, - decoration: InputDecoration( - border: InputBorder.none, hintText: '5xxxxxxxx'), + child: Column(children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + // add Expanded to have your dropdown button fill remaining space + child: Padding( + padding: EdgeInsets.all(10), + child: DropdownButtonHideUnderline( + child: DropdownButton( + isExpanded: true, + value: _selectedType, + iconSize: 40, + elevation: 16, + onChanged: (newValue) => _selectedType = newValue, + items: [ + 'Saudi Arabia', + 'Dubai', + ].map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList())))), + ], + ), + Container( + padding: EdgeInsets.all(5), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(10)), + child: Row(children: [ + Expanded( + flex: 1, + child: Icon( + Icons.phone, + color: Colors.red, + )), + Expanded( + flex: 1, + child: Text( + widget.countryCode, + overflow: TextOverflow.clip, + )), + Expanded( + flex: 4, + child: Container( + margin: widget.margin != null + ? EdgeInsets.all(widget.margin) + : EdgeInsets.only( + top: widget.marginTop, + right: widget.marginRight, + bottom: widget.marginBottom, + left: widget.marginLeft), + child: TextField( + controller: widget.controller, + decoration: InputDecoration( + border: InputBorder.none, hintText: '5xxxxxxxx'), + ), ), - ), - ) - ]), - )); + ) + ]), + ) + ])); } } diff --git a/pubspec.yaml b/pubspec.yaml index 4bb76eaa..bbea1b45 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,7 +38,8 @@ dependencies: url_launcher: ^5.5.0 shared_preferences: ^0.5.8 flutter_flexible_toast: ^0.1.4 - + firebase_messaging: ^6.0.16 + # Progress bar progress_hud_v2: ^2.0.0 percent_indicator: ^2.1.5 From 5a08cb720c406f35fb4784ae29fe93ee76d1a5bd Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Wed, 22 Jul 2020 09:47:05 +0300 Subject: [PATCH 4/4] login changes --- android/app/src/main/AndroidManifest.xml | 3 + android/settings_aar.gradle | 1 + lib/config/config.dart | 9 +- lib/config/shared_pref_kay.dart | 4 + .../check_paitent_authentication_req.dart | 76 ++++++++++ lib/core/service/client/base_app_client.dart | 3 +- lib/pages/landing/landing_page.dart | 16 ++- lib/pages/login/login-type.dart | 135 ++++++++++-------- lib/pages/login/login.dart | 98 +++++++++++-- lib/providers/auth_provider.dart | 36 ++++- lib/uitl/utils.dart | 38 +++++ lib/widgets/input/text_field.dart | 6 +- lib/widgets/mobile-no/mobile_no.dart | 45 ++++-- 13 files changed, 374 insertions(+), 96 deletions(-) create mode 100644 android/settings_aar.gradle create mode 100644 lib/core/model/auth/check_paitent_authentication_req.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c5095d24..02c26fa6 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -33,6 +33,7 @@ android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background" /> + @@ -47,5 +48,7 @@ + + diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 00000000..e7b4def4 --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/lib/config/config.dart b/lib/config/config.dart index 57695678..dd958c10 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -1,11 +1,14 @@ - const MAX_SMALL_SCREEN = 660; -const BASE_URL = 'https://uat.hmgwebservices.com/Services'; +const BASE_URL = 'https://hmgwebservices.com/Services'; const GET_PROJECT = '/Lists.svc/REST/GetProject'; - class AppGlobal { static var context; } + +const CHANNEL = 3; +const GENERAL_ID = 'Cs2020@2016\$2958'; +const IP_ADDRESS = '10.20.10.20'; +const VERSION_ID = 5.5; diff --git a/lib/config/shared_pref_kay.dart b/lib/config/shared_pref_kay.dart index 59f4f0ff..1e75a802 100644 --- a/lib/config/shared_pref_kay.dart +++ b/lib/config/shared_pref_kay.dart @@ -1,3 +1,7 @@ const TOKEN = 'token'; const APP_LANGUAGE = 'language'; const USER_PROFILE = 'user-profile'; +const PUSH_TOKEN = 'push-token'; +const REGISTER_DATA_FOR_REGISTER = 'register-data-for-register'; +const LOGIN_TOKEN_ID = 'register-data-for-register'; +const REGISTER_DATA_FOR_LOGIIN = 'register-data-for-login'; diff --git a/lib/core/model/auth/check_paitent_authentication_req.dart b/lib/core/model/auth/check_paitent_authentication_req.dart new file mode 100644 index 00000000..2846c1fc --- /dev/null +++ b/lib/core/model/auth/check_paitent_authentication_req.dart @@ -0,0 +1,76 @@ +class CheckPatientAuthenticationReq { + int patientMobileNumber; + String zipCode; + bool isRegister; + String tokenID; + int searchType; + String patientIdentificationID; + int patientID; + double versionID; + int channel; + int languageID; + String iPAdress; + String generalid; + int patientOutSA; + Null sessionID; + bool isDentalAllowedBackend; + int deviceTypeID; + + CheckPatientAuthenticationReq( + {this.patientMobileNumber, + this.zipCode, + this.isRegister, + this.tokenID, + this.searchType, + this.patientIdentificationID, + this.patientID, + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID}); + + CheckPatientAuthenticationReq.fromJson(Map json) { + patientMobileNumber = json['PatientMobileNumber']; + zipCode = json['ZipCode']; + isRegister = json['isRegister']; + tokenID = json['TokenID']; + searchType = json['SearchType']; + patientIdentificationID = json['PatientIdentificationID']; + patientID = json['PatientID']; + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + } + + Map toJson() { + final Map data = new Map(); + data['PatientMobileNumber'] = this.patientMobileNumber; + data['ZipCode'] = this.zipCode; + data['isRegister'] = this.isRegister; + data['TokenID'] = this.tokenID; + data['SearchType'] = this.searchType; + data['PatientIdentificationID'] = this.patientIdentificationID; + data['PatientID'] = this.patientID; + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['IPAdress'] = this.iPAdress; + data['generalid'] = this.generalid; + data['PatientOutSA'] = this.patientOutSA; + data['SessionID'] = this.sessionID; + data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; + data['DeviceTypeID'] = this.deviceTypeID; + return data; + } +} diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index 72c38568..57686824 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -14,7 +14,7 @@ AppSharedPreferences sharedPref = new AppSharedPreferences(); /// body: null); class BaseAppClient { - post( + post( String endPoint, { Map body, Function(dynamic response, int statusCode) onSuccess, @@ -22,7 +22,6 @@ class BaseAppClient { }) async { String url = BASE_URL + endPoint; try { - //Map profile = await sharedPref.getObj(DOCTOR_PROFILE); // String token = await sharedPref.getString(TOKEN); diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index c7748b4c..7557d1a0 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -1,4 +1,7 @@ +import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/core/model/auth/select_device_imei_res.dart'; import 'package:diplomaticquarterapp/pages/landing/replay_page.dart'; +import 'package:diplomaticquarterapp/providers/auth_provider.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/bottom_navigation/bottom_nav_bar.dart'; import 'package:diplomaticquarterapp/widgets/drawer/app_drawer_widget.dart'; @@ -16,6 +19,7 @@ class _LandingPageState extends State { int currentTab = 0; PageController pageController; final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); + final authService = new AuthProvider(); _changeCurrentTab(int tab) { setState(() { currentTab = tab; @@ -28,7 +32,11 @@ class _LandingPageState extends State { super.initState(); pageController = PageController(keepPage: true); _firebaseMessaging.getToken().then((String token) { - print(token); + sharedPref.setString(PUSH_TOKEN, token); + if (token != null) { + checkUserStatus(token); + } + //assert(token != null); }); } @@ -78,4 +86,10 @@ class _LandingPageState extends State { return TranslationBase.of(context).services; } } + + void checkUserStatus(token) { + authService + .selectDeviceImei(token) + .then((SelectDeviceIMEIRES value) => print(value)); + } } diff --git a/lib/pages/login/login-type.dart b/lib/pages/login/login-type.dart index e22ce297..c0697099 100644 --- a/lib/pages/login/login-type.dart +++ b/lib/pages/login/login-type.dart @@ -38,69 +38,82 @@ class LoginType extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - InkWell( - onTap: () => { - LoginType.loginType = 2, - Navigator.of(context) - .pushNamed(LOGIN_PAGE) - }, - child: RoundedContainer( - borderColor: Colors.grey, - showBorder: true, - child: Padding( - padding: - EdgeInsets.fromLTRB(20, 10, 20, 10), - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/id_card_icon.png', - height: 60, - width: 70, - ), - SizedBox( - height: 20, - ), - AppText( - TranslationBase.of(context) - .nationalID, - fontSize: - SizeConfig.textMultiplier * 3, - ) - ], - ), - ))), - InkWell( - onTap: () => { - LoginType.loginType = 1, - Navigator.of(context) - .pushNamed(LOGIN_PAGE) - }, - child: RoundedContainer( - borderColor: Colors.grey, - showBorder: true, - child: Padding( - padding: - EdgeInsets.fromLTRB(25, 10, 25, 10), - child: Column( - children: [ - Image.asset( - 'assets/images/my_file_white_icon.png', - height: 60, - width: 70, + Expanded( + child: InkWell( + onTap: () => { + LoginType.loginType = 1, + Navigator.of(context) + .pushNamed(LOGIN_PAGE) + }, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB( + 20, 10, 20, 10), + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/id_card_icon.png', + height: SizeConfig + .imageSizeMultiplier * + 12, + width: SizeConfig + .imageSizeMultiplier * + 15, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context) + .nationalID, + fontSize: + SizeConfig.textMultiplier * + 2, + ) + ], ), - SizedBox( - height: 20, + )))), + Expanded( + child: InkWell( + onTap: () => { + LoginType.loginType = 2, + Navigator.of(context) + .pushNamed(LOGIN_PAGE) + }, + child: RoundedContainer( + borderColor: Colors.grey, + showBorder: true, + child: Padding( + padding: EdgeInsets.fromLTRB( + 25, 10, 25, 10), + child: Column( + children: [ + Image.asset( + 'assets/images/my_file_white_icon.png', + height: SizeConfig + .imageSizeMultiplier * + 12, + width: SizeConfig + .imageSizeMultiplier * + 15, + ), + SizedBox( + height: 20, + ), + AppText( + TranslationBase.of(context) + .fileNo, + fontSize: + SizeConfig.textMultiplier * + 2, + ) + ], ), - AppText( - TranslationBase.of(context).fileNo, - fontSize: - SizeConfig.textMultiplier * 3, - ) - ], - ), - ))) + )))) ], ), Divider( diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart index 1cd6fa11..7bb61da5 100644 --- a/lib/pages/login/login.dart +++ b/lib/pages/login/login.dart @@ -1,6 +1,12 @@ +import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/core/model/auth/check_paitent_authentication_req.dart'; +import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart'; import 'package:diplomaticquarterapp/pages/login/login-type.dart'; +import 'package:diplomaticquarterapp/providers/auth_provider.dart'; +import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; import 'package:diplomaticquarterapp/widgets/card/rounded_container.dart'; import 'package:diplomaticquarterapp/widgets/input/text_field.dart'; @@ -16,10 +22,14 @@ class Login extends StatefulWidget { } class _Login extends State { - final TextEditingController nationalIDorFile = null; + final util = Utils(); + final nationalIDorFile = TextEditingController(); final int loginType = LoginType.loginType; - final TextEditingController mobileNo = null; - + String mobileNo; + String countryCode = '966'; + bool isButtonDisabled = true; + final authService = new AuthProvider(); + var sharedPref = new AppSharedPreferences(); @override Widget build(BuildContext context) { return AppScaffold( @@ -43,20 +53,24 @@ class _Login extends State { child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - MobileNo(controller: mobileNo), + MobileNo( + onNumberChange: (value) => + {mobileNo = value, validateForm()}, + onCountryChange: (value) => countryCode = value), Container( child: TextFields( controller: nationalIDorFile, + onChanged: (value) => {validateForm()}, prefixIcon: Icon( loginType == 1 - ? Icons.receipt - : Icons.chrome_reader_mode, + ? Icons.chrome_reader_mode + : Icons.receipt, color: Colors.red), padding: EdgeInsets.only( top: 20, bottom: 20, left: 10, right: 10), hintText: loginType == 1 - ? TranslationBase.of(context).fileNo - : TranslationBase.of(context).nationalID, + ? TranslationBase.of(context).nationalID + : TranslationBase.of(context).fileNo, )) ], ), @@ -70,10 +84,12 @@ class _Login extends State { children: [ Expanded( child: RaisedButton( - color: Colors.grey, + color: isButtonDisabled == true + ? Colors.grey + : Colors.grey[600], textColor: Colors.white, child: Text(TranslationBase.of(context).login), - onPressed: () => {}, + onPressed: () => {this.startLogin()}, )) ], ), @@ -82,4 +98,66 @@ class _Login extends State { ]), ))); } + + startLogin() { + if (isButtonDisabled == false) { + checkUserAuthentication(); + } + } + + void validateForm() { + if (validateIDBox(nationalIDorFile.text) == true && + mobileNo != null && + util.isSAUDIIDValid(nationalIDorFile.text) == true) { + setState(() { + isButtonDisabled = false; + }); + } else { + setState(() { + isButtonDisabled = true; + }); + } + } + + bool validateIDBox(String value) { + Pattern pattern = loginIDPattern(); //r'^\d+(?:\.\d+)?$'; + + RegExp regex = new RegExp(pattern); + return regex.hasMatch(value); + } + + String loginIDPattern() { + var length = loginType == 1 ? 10 : 7; + return "([0-9]{" + length.toString() + "})"; + } + + checkUserAuthentication() { + var request = CheckPatientAuthenticationReq(); + request.isRegister = false; + request.patientMobileNumber = int.parse(mobileNo); + request.zipCode = countryCode; + request.searchType = this.loginType; + request.deviceTypeID = this.loginType; + if (this.loginType == 1) { + request.patientIdentificationID = this.nationalIDorFile.text; + request.patientID = 0; + } else { + request.patientIdentificationID = ''; + request.patientID = int.parse(nationalIDorFile.text); + } + sharedPref.setObject(REGISTER_DATA_FOR_REGISTER, request); + authService.checkPatientAuthentication(request).then((value) => { + if (value.isSMSSent) + { + sharedPref.setString(LOGIN_TOKEN_ID, value.LogInTokenID), + sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), + } + else + { + if (value.IsAuthenticated) {this.checkActivationCode()} + } + }); + } + + checkActivationCode() {} } diff --git a/lib/providers/auth_provider.dart b/lib/providers/auth_provider.dart index 09b880b9..3590355b 100644 --- a/lib/providers/auth_provider.dart +++ b/lib/providers/auth_provider.dart @@ -1,16 +1,21 @@ +import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/core/model/auth/check_paitent_authentication_req.dart'; +import 'package:diplomaticquarterapp/core/model/auth/select_device_imei_res.dart'; import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:flutter/cupertino.dart'; // SharedPreferences sharedPref = new SharedPreferences(); enum APP_STATUS { LOADING, UNAUTHENTICATED, AUTHENTICATED } AppSharedPreferences sharedPref = new AppSharedPreferences(); -const String INSERT_DEVICE_IMEI = - 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; +const String INSERT_DEVICE_IMEI = '/Patients.svc/REST/Patient_INSERTDeviceIMEI'; const String SELECT_DEVICE_IMEI = - 'Services/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; + '/Patients.svc/REST/Patient_SELECTDeviceIMEIbyIMEI'; +const String CHECK_PATIENT_AUTH = + '/Authentication.svc/REST/CheckPatientAuthentication'; class AuthProvider with ChangeNotifier { bool isLogin = false; @@ -78,7 +83,7 @@ class AuthProvider with ChangeNotifier { } } - Future selectDeviceImei(imei) async { + Future selectDeviceImei(imei) async { try { dynamic localRes; await new BaseAppClient().post(SELECT_DEVICE_IMEI, @@ -93,4 +98,27 @@ class AuthProvider with ChangeNotifier { throw error; } } + + Future checkPatientAuthentication( + CheckPatientAuthenticationReq request) async { + request.versionID = VERSION_ID; + request.channel = CHANNEL; + request.iPAdress = IP_ADDRESS; + request.generalid = GENERAL_ID; + request.languageID = 2; + request.patientOutSA = request.zipCode == '966' ? 0 : 1; + try { + dynamic localRes; + await new BaseAppClient().post(CHECK_PATIENT_AUTH, + onSuccess: (dynamic response, int statusCode) { + localRes = response; + }, onFailure: (String error, int statusCode) { + throw error; + }, body: request.toJson()); + return Future.value(localRes); + } catch (error) { + print(error); + throw error; + } + } } diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index 1c2da2b6..ac586b7d 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -42,4 +42,42 @@ class Utils { static hideKeyboard(BuildContext context) { FocusScope.of(context).unfocus(); } + + bool isSAUDIIDValid(String id) { + if (id == null) { + return false; + } + try { + id = id.toString(); + id = id.trim(); + var returnValue = int.parse(id); + var sum = 0; + if (returnValue > 0) { + var type = int.parse(id[0]); + + if (id.length != 10) { + return false; + } + if (type != 2 && type != 1) { + return false; + } + + for (var i = 0; i < 10; i++) { + if (i % 2 == 0) { + var a = id[i]; + var x = int.parse(a) * 2; + var b = x.toString(); + if (b.length == 1) { + b = "0" + b; + } + sum += int.parse(b[0]) + int.parse(b[1]); + } else { + sum += int.parse(id[i]); + } + } + return sum % 10 == 0; + } + } catch (err) {} + return false; + } } diff --git a/lib/widgets/input/text_field.dart b/lib/widgets/input/text_field.dart index 94dfddba..5429dd39 100644 --- a/lib/widgets/input/text_field.dart +++ b/lib/widgets/input/text_field.dart @@ -46,7 +46,7 @@ class TextFields extends StatefulWidget { this.suffixIcon, this.autoFocus, this.onChanged, - this.initialValue, + // this.initialValue, this.minLines, this.maxLines, this.inputFormatters, @@ -75,7 +75,7 @@ class TextFields extends StatefulWidget { : super(key: key); final String hintText; - final String initialValue; + // final String initialValue; final String type; final bool autoFocus; final IconData suffixIcon; @@ -223,7 +223,7 @@ class _TextFieldsState extends State { minLines: widget.minLines ?? 1, maxLines: widget.maxLines ?? 1, maxLengthEnforced: widget.maxLengthEnforced, - initialValue: widget.initialValue, + // initialValue: widget.initialValue, onChanged: widget.onChanged, focusNode: _focusNode, maxLength: widget.maxLength ?? null, diff --git a/lib/widgets/mobile-no/mobile_no.dart b/lib/widgets/mobile-no/mobile_no.dart index a1304eff..2c17a669 100644 --- a/lib/widgets/mobile-no/mobile_no.dart +++ b/lib/widgets/mobile-no/mobile_no.dart @@ -9,21 +9,27 @@ import 'package:flutter/material.dart'; class MobileNo extends StatefulWidget { final bool disabled; // final String data; - final String countryCode; + final List countries = [ + new Countries(name: 'Saudi Arabia', code: '966'), + new Countries(name: 'Dubai', code: '971'), + ]; final double margin; final double marginTop; final double marginRight; final double marginBottom; final double marginLeft; final TextEditingController controller; + final Function onNumberChange; + final Function onCountryChange; MobileNo( {this.disabled = false, - this.countryCode = '966', this.marginTop = 0, this.marginRight = 0, this.marginBottom = 0, this.controller, this.marginLeft = 0, + this.onNumberChange, + this.onCountryChange, this.margin = 0}); @override @@ -31,8 +37,8 @@ class MobileNo extends StatefulWidget { } class _MobileNo extends State { - var _selectedType = 'Saudi Arabia'; - + var _selectedType = '966'; + String countryCode = '966'; @override Widget build(BuildContext context) { return Visibility( @@ -50,14 +56,18 @@ class _MobileNo extends State { value: _selectedType, iconSize: 40, elevation: 16, - onChanged: (newValue) => _selectedType = newValue, - items: [ - 'Saudi Arabia', - 'Dubai', - ].map>((String value) { + onChanged: (value) => { + widget.onCountryChange(value), + setState(() { + countryCode = value; + _selectedType = value; + }) + }, + items: widget.countries + .map>((Countries value) { return DropdownMenuItem( - value: value, - child: Text(value), + value: value.code, + child: Text(value.name), ); }).toList())))), ], @@ -77,7 +87,7 @@ class _MobileNo extends State { Expanded( flex: 1, child: Text( - widget.countryCode, + countryCode, overflow: TextOverflow.clip, )), Expanded( @@ -92,6 +102,11 @@ class _MobileNo extends State { left: widget.marginLeft), child: TextField( controller: widget.controller, + keyboardType: TextInputType.phone, + // onChanged: (value) { + // widget.controller.text = countryCode; + // }, + onChanged: (value) => widget.onNumberChange(value), decoration: InputDecoration( border: InputBorder.none, hintText: '5xxxxxxxx'), ), @@ -102,3 +117,9 @@ class _MobileNo extends State { ])); } } + +class Countries { + final String name; + final String code; + Countries({this.name, this.code}); +}