From 4c5ec4364dcfdc6c5c8e9b82bfbab44581b8f735 Mon Sep 17 00:00:00 2001 From: kicap Date: Sat, 15 Jul 2023 05:08:31 +0800 Subject: [PATCH] added splashscreen, login and add hp number pages --- .env | 6 + android/build.gradle | 2 +- assets/logo.png | Bin 0 -> 28077 bytes lib/app/app.dart | 35 ++ lib/app/app.locator.dart | 35 ++ lib/app/app.logger.dart | 159 +++++++++ lib/app/app.router.dart | 244 +++++++++++++ lib/app/core/custom_base_view_model.dart | 16 + lib/app/mycd | 3 + lib/app/themes/app_colors.dart | 30 ++ lib/app/themes/app_text.dart | 44 +++ lib/app/themes/app_theme.dart | 124 +++++++ lib/main.dart | 130 ++----- lib/services/http_services.dart | 35 ++ lib/services/my_easyloading.dart | 39 +++ lib/services/other_function.dart | 18 + .../input_informasi_diri_view.dart | 31 ++ .../input_informasi_diri_view_model.dart | 5 + .../masukan_no_hp/masukan_no_hp_view.dart | 96 ++++++ .../masukan_no_hp_view_model.dart | 26 ++ .../verifikasi_no_hp_view.dart | 31 ++ .../verifikasi_no_hp_view_model.dart | 5 + lib/ui/views/login_user/login_user_view.dart | 104 ++++++ .../login_user/login_user_view_model.dart | 36 ++ .../splash_screen/splash_screen_view.dart | 67 ++++ .../splash_screen_view_model.dart | 10 + lib/ui/widgets/my_button.dart | 34 ++ lib/ui/widgets/my_textformfield.dart | 91 +++++ pubspec.lock | 320 ++++++++++++++++++ pubspec.yaml | 9 +- 30 files changed, 1674 insertions(+), 111 deletions(-) create mode 100644 .env create mode 100644 assets/logo.png create mode 100644 lib/app/app.dart create mode 100644 lib/app/app.locator.dart create mode 100644 lib/app/app.logger.dart create mode 100644 lib/app/app.router.dart create mode 100755 lib/app/core/custom_base_view_model.dart create mode 100755 lib/app/mycd create mode 100755 lib/app/themes/app_colors.dart create mode 100644 lib/app/themes/app_text.dart create mode 100755 lib/app/themes/app_theme.dart create mode 100644 lib/services/http_services.dart create mode 100644 lib/services/my_easyloading.dart create mode 100644 lib/services/other_function.dart create mode 100644 lib/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart create mode 100644 lib/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view_model.dart create mode 100644 lib/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart create mode 100644 lib/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view_model.dart create mode 100644 lib/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view.dart create mode 100644 lib/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view_model.dart create mode 100644 lib/ui/views/login_user/login_user_view.dart create mode 100644 lib/ui/views/login_user/login_user_view_model.dart create mode 100644 lib/ui/views/splash_screen/splash_screen_view.dart create mode 100644 lib/ui/views/splash_screen/splash_screen_view_model.dart create mode 100644 lib/ui/widgets/my_button.dart create mode 100644 lib/ui/widgets/my_textformfield.dart diff --git a/.env b/.env new file mode 100644 index 0000000..c89c34d --- /dev/null +++ b/.env @@ -0,0 +1,6 @@ +# url = 'https://panti-asuhan.s-keytech.com/' +# api_url = 'https://panti-asuhan.s-keytech.com/api/' +# # url = 'http://172.29.85.181/panti_asuhan2/' +# # api_url = 'http://172.29.85.181/panti_asuhan2/api/' +url = 'http://20.20.20.25/panti_asuhan2/' +api_url = 'http://20.20.20.25/panti_asuhan2/api/' \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index f7eb7f6..713d7f6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:7.2.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bb50e392c09b4724af1668a98b49b8b7757dd0a8 GIT binary patch literal 28077 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μlOic7bfE%mmB_qK7{93$$i1+ZU20iN*VT}y5vMgn0R&R zbgZvMQ03k3vW1Z6(w{j)l|pG+Tx}EKm>j;?%Z|h4A3S|8eNi~u(^Cv*Fl1eLCh?(= z-%rg3D2@XemaRm}a?^;AuyBR8=j;Rc*=f;D@7~VN+9ez#`DCl~s-o`2Ti;=m71b6~ zsdt${Sa=TmUGY?PBK7BOy2EH4#imC0K^6+k_+11siN;pLi0v~RW)l4>!@+~)w*Qc6 z0b5m+5ml_+7mrv9_|>CmP;ZD-KwO0|K!f_}w$4uWG;IIwXkN7@p$MRZ?OF`yE8qi^ z#%CeB+edj%KCv)D*XCB-Q2XW2?IeE*@aNjK=NWz)3a^m9;wX6ngE;yZ&!ADJl;EEi z3lIU=v(i$_2t1<<;kw@1%`*jjvHga}^K}D<^~hlD7pwD1iGm|M?QeKQF`rn~GSaA0 zb9)$!GGclUlVn;IIAtI8qn2aeo#Tf|l)+g*z3KucG>$N~gI# zzM#8A6~Dr}L#udHB&C609YoQm)uj^hfyhx42XWKjiXRq6EW%*8k(Gxq#7F&`ju zlb@Nx^r-%1t-Kg^*%fuZ$)cIe-rz^wiT)^KFpm=v$+Tkl@m$hF>Cs>9LZTNRk;`K! z>C4CW2lY9!(VC-Dv#LAlTA!Zswp>|t-ZEH>$=XdL2WgYg??^B13_z@d3B%8XPXMN` zHJ~7R0HIZH6uC22W7r=%lD0^m({f;x-H{Yoab?OBaoI`($3E>IIlJq5>B{WTa=n$= za=3!_e|_$td>G3f>)S(ve7pObc)EpZM@|~aUe~@;XK=j98~6fMM+RkRFpUw)@>yv) zvwM?E6n&y+(D7Y~0rnMnx5a9@qe%wg3Sehuq{kuKkFGFUo|>w$duieG3;z+oY&|^K zo9|c&j~-5--jPokY(SjNyj*}X$)@?0$T~7r-FHp5-$bg2d3BXu>2i?mb#fZvto{52 zu|OLKoFrPjB)O^h+FJ<|x7gpkB0Ez4H&V*ZLDBiowBj)Y8`UV%)_91V8v9-yvR@|q zF~3_Q@CM(stoEtCuUXz-cx5YeBnWcze8s(DPTLc)g8rCLRSik z>`Exgwx5h${gJ4?S~cyXGb-QM&+k9N4n#tV^97gF#TrLXK|#S2jT|)XWkmp0rmzcv z`mT%x?D|n$NA*(FjT5&Tfe5cf%cr-EK~Fv{|Cu9l5ekLIe8qE>Br4T!4;?L}M@jH_ z0jP%&>Qs;qt~{bc5{6pYcN_@ZdYl;yp^C@&Y{nDCP*Mzc@6 zuQ<~GsC3QDu&$kYXmXbJlonPw)*61rRn_uo)XpFO_%EU?KRJ3ZxdVz1%0#GD-kkC={ z#jr9X(2oezi)vrLG(W#E+#fuv8#?N?8{soj^EG#G_0!l%lIHKvG?1E!ymNb`TMZtH?AYKlSuQbIYgPflgwYg4>?3Z1R~A;L<6-0^l~~LAP-&t zc4gLgStLr2gD9T37lYGS?k;f_*-G0Vw1QlWoVL2J<1)C5 zm(PVqGTAxbuuf6^)u?0>=tuT{EJ$}T_Od5{sg44pjwZyx*?OT?hvT}+tN&eRhwer7CIsC5KwoS|XC(d>|T{e1#|UnuSobEzEh8vAnvH}(2VZLJ`!W9p=dnB+bCOa+zbV$Zi4dVz*0j_@eaxH6SJ@OqaS;Ue#*BJ#LaQz&8JQej-VbGK4Sy6DXPq|? z+*1`x2}Zf+QK--=B&pau4Z%eL(vv*aA;-$TmLs&9T8t?M4WSaTe8xJ-fOl4Xd}Kf5 zgSm8&0)z?H#w|tUt@O_Q1&Elo4#RJ7bIitq3*njQ4r36Y>-*`3$i5hejc^xq18)Zq$Gu>U+^67y=*BaCN_J_d)mbYnQOKt;n zrasH(y&>USDXjM=`-hhOBldvg=#Gg-*pX3*c=JSW6+rj40GOBNS^6n( z&|PPFT!`Hs_{`Scj7|Gix1%HvR~L|`!=!Q2A;eMPuG4ylRwF-aDZw1cuW!-t``3p7 z2yr6-k#M$XiG<(p64rqS)T=sg9Dp>^y~!Cl#@)O$01j+AqNEs<3@4 za`@^R5jY5lI@XP4P1D3U{v$f1^99gS;*IA#^p~Ii?Rvdgy>_$fVm*J7-1Yex)YAj7 z@sT|D-E5_d>$hrGiMH53R(TBTUkkhUMF;14+rsPd@97LWV&FHw&~vpA5$UV@X@E3m zPy-%#-g#9R2)>W-C}qYQWyn()EeaFA9+xvT zxtp^A6z=!}FHi<~tg@s7w|=MB_0mu#I;gnsX--G>Ayot>oPA*Y@a&;byyy* zW3HJscM}5u+bo0j+ho-&(b)R2H&N@c;;}3$h`*#cH-Zc|M`1006;L4i3Fcm0pQV<_ zNrYiHm0ea3(=L6_x>551h@9JaXd54~b})TeKo3xDN3KyFX)G#Z>p+Bj(`Pl3eIaS; zJFbw`(aa*ix29z$3syZ%= z&0+Jy_B6|(wV~kHH`Ip`0~(p+)LQQ=zjB{er~N6Ck;L3oWBNNrIC6BQ4-0$ju>(_v`G9k6|s}P~oFC#nd&1~qwrjrXy zV5RLZlY6XH?Qb9xRsgK0UWClekRbn^8o}FhNaPc#sTlzk_%C?iu|+t(*1wj5u+IL_ z{MSNPtrGpey&*q=uw3plZ9{wh=3yoGC?uxHr``p-o=0Bm9qU3Pgu*`IFYL;^)=<8q z&I2`O++T8;Jth9M&+1*2ez+jEOY&(-u+;?F1oP7GWMvjnb7XFj@HB{e>hm#;t8_#H4z|UBtvg zh5Thl<8c8&RUr?=?CWv%$bWk~R{IN$04jR@-?6q;l<6|a zX(q=@c_=Yfh?f8O;AtNtP?KBD3!}H{{(2lu2@1lp@`IH)c<2gA>8_qlQfTjNuNuH_ z^hVz@mx9Oh6`0=-X#||;S^4Frxqo;?RfdK5XTD$bwM*S;X zeWq_ku_7JY=UfsnnQ&i%(vU$08A-)=(`{{vO|kzjx75S(tES~EM+t_pVI{Mx!ZmT> zopgxkMoKVH4B8S$UOxxkKm0q*wH=P9^9G!uy{}1GHMRi45RHfJ7*27x&Vpj&5kSGg z0x$~J(%t^KB+*c5*d)YnGPC+eZEZYzBoV0nVCePrY4fd^+UTeZ*PIwovENOX#>i)6 zWLyJuRSmKbdw3%`&AhSne1E@Ug;0_*%fiA!O}yo3hLE7J@Smj#$_7Q)H@w}~oy?B_ z0@j9;3zP<^FX3w8e%SaOFVPWzwb<-ZeO~(_si{dz;_htHak0rO$3uU)&_hb)!=gp+ z{7ZR&FNXy8gvPvLV`k1cgA8j`>c7a(^RR#jUp*x%sakcI)mikPz4p z_<3qV(bUuZz&15EKS_up`r_UqZ?ed~a=PMk+(j7hk`jw}O?0cwr~NzpW|t7S%o*#T zjW6fk$bW@YwS;~b_o?wcwxXt?2`0=>a6K6;KFLJhX3WCxl>;v7Ei^fkDaF0H#>DiI zjTxe`>5@?4vBE~(s~rNf{m(utey9^bR2s#hQ}lBFI2;#%!`Dj+Vi!>DqA0P0pJ3p# z4(%y`oyk8}_(sSFcqvF>5Ej4BRC`VeEn<{%;zQUgfhj#&)--sOh_ZGG$_Z_rt7?scOjRTzJ`ydDD*Jv4&NI*{{9Mde^_ zDSDeeKiZ{-MGK^653orc$Cbo!^l}5wB@BNI{MOWJT{J#-p)>XvfL%pzq3ynfsVKna4nK1{7;g?95K z#TO{LqW7CmGG&BC%!QdIV@=%IwhkG_+FUZZ0vGo;Oy{ zXK9cn)pRHjcG|}LBJLZ%x997`xQr2z&SL^baJqyWzi3Vf&!pxLTjtEBFe>$yq_1SR zQD@d58DI<4SiR-OFnrk~$3H1sU~X0C|Tt(T4FRs0d|jJd>YLW$OEXRMuM zS<2PvvOuX0sP2kTko?L^`6nGF0%e7(m(9!GDrT=SJI)gN)y6C1OSE^`xBf4pY>mS8 zLaOd_Sz+<%-(*cIgkZv~WYI=UzNy#@pDzu;?5U(rk5m}PYcvGaFPNKY}6Q@ukOc~>_QFt?Tz5?$1@R@G0x!!$q zA3!{#fB^OKk(@GJPXPrn1YVhi2u9jmy-R-+YqDZ1T^d2<5k~u;EpE``0@+=D#KSoTN^IlBl;uJkZJ_)T)fIa|ugX_BLTn(luiYy|fJc5_JE|c$iK4`aMw0`*Mk8p>b}yT{&|g`I<54OL3-2 zMu5j+q&Q&zx1P&K?^D_7VW0zEWh+?}<+Eo%OYP>fuMJ4wQvq4#BjnYV$Xq8_1V|a9 zi?huU%a==tHsqc2{Z93LBoeb4TH#h7>TJWaPg<08^s*fG02fd;Z0sa)=`lu4pB@9(gH@K)cII%F7R{{Yn=0sByC3wURyt?%l0OXqCO(7T zpSz^J@!~|Hkqkr%#{rjXohT7CIz>j{0tqjG`6wM$|1rs#K;nnV(h9(CJXdbFL_(|- zkDobUF?P&qrp$dQ(O@bUiKPau<@pm52Hl?IepqO*r!!kN^U&MG9wbRGFIx-CCazy^waKZ!+?l|Z^C^Mbr1`%E)vxYM)N4j|f#W2{ zs+OTYG512ED5K6#EDSe)lv)n&pZJ}P56rbXy^fEWYp@r9Fa!whM&tv~g(er-Pp5h1 zCdcJ|z{IP`d2z_h2dUDcz1oSMt#O!kKj=i$>sJ_lIdw<mskEa>H6HmU0860?T{9 zzh8tTS`R?LAmH)?^*zc9<4Aq|pHl(-r;pr#!>8@=%zg!Q&kgwUvB}-pf|cX%E`f0X zbqDp)OWkaLkr7t+UN5|&P`k9oN8^cxbYu1@ujmsA@LAFPB zC~JeNCngP$dScd5(-kVuqjoISCm+i0@S9&o4ncYdBkv@TrDW`|)C9{W=#nWUB`R0K zWTw;8it-vd0h&&_gGaWi;DGUjAPaN;JQs(m1IOm{QiQ{rzE_|yq{@sS)Bh{;dv;r+ zYArIG*8IpW;stqY@P#s&31>1%NJTh;GPpcc^F}^Z9ts`RKb0=4=FM1>G-`5e-Kp%ue&ebK-{D($*hx9B|!{bU&(9KN;HFP^1xpsPobkb%?R zq~{UhW}x+D#6wcAUo@7lcZ!eQs<;9CBQSVe?@QbF}-IIuN# z>orRoUqOW;t#ko)k2TkfG3Sd^s%JUVaO<*N*5|N~eIFcuGnGa@dd%XJ$TIX^m}baR zUtj=|deE9M?7Q0ndSR#jV=kh>v>aK! z88*YnYz`eLOc-tY7xR2i=V`I!zP6-0F>vh&^92&BuewksL%DCyf1SlW3&z&Spd=+b z?y%eY>UR5YKzd9uGsIc!XjPMt%Z7u`2k@hv;B{UhVA}>p(NP zJB zx!KOJn6Qr@D?e2JDBG^?kD2>3)MvdUeiTM|5|jup_ZEz_R|<14^NMH#HxhO^h}|keJHk@OXn(s!ZJw+`U` zN>7@=kNA~9obFKTZh6iL8mp>nS)92k zv-qKT3v4R9AESK^kz1CZ`7I_wD@VR;w}=T2Sa{xe_)R% zIE-Tu-}!RWE{@2SaglhS82!j3K0a=R6`Dp68^yi&<*C8S6NwpRK14?09ly3dCga=FjywliBG>ft4Od znaFc`9rdwO*`S5UhnjHzsqigC1?=j+wMpBz>RD;}lV7mQiWPoK&r=i=rwAo+by@lY z7roI)iJ(k@cYNQxu>O^kShVTtfp&5n>;)}yL@j&k{NpZK_j8?MR_IcimdW>w zkp8)2sl+?{5RK`yyKnVTVm+}^8g&kk2&u>z;s%q%03g|Ha^bRQa@W)wk)jFRqnnwT zX&OSGVdR(94=;3jQeHs~#d@AH{Gei)G#JcwGE#(;jV%j0Y=l=MJJ(`m3Z7q>QYHWo z79gZCC$ce|%WG&L#^Yn`{x)iUr!M=vQOGBD-v6;^_h|>!k7+LL11HWjgw)Ny4DlVw z5fsc9@NC3i9dCpP3ku0&c-EYW<;si_^CS{71w=K8W*04FgL8T!D@d0DV`vt=Jvx-G zWGU+e;yCxA-Y!(){(DVR*Yn|Gt(1lneQ$phNZ55#_B*Ugd0%);u5K(L61(JE;neL zh5GU)Sz1cWR0l4MW=Nt+s}8dJr?wq?8|WJl`>VQ|V}lPb;!5@~^+b;aDQ!|;+>OtH zDs$lIY;m6{=u}uRF!q74vu~>eWXp}v$Lm6stZ}mAN^#Ktcj!H1WEWH8$kbBMM!P0< z_^U)w-D7mpe3XbhtL(csOgh)cX-%OB$)jH#G&}!mCHo*#*lFht053yS3WwZqb>vlL zdZ(~`rk?7^(rfpw;5W&MbE*4P{TCuPg2YRJ*m1l}-Y6R#Xi2FD$1}rtKA8@CtBx0u*z5AjnS(d_@mFPjKxgMVpYpJR5LN8jAIA`h4 zg6Y)&8@&b8q+?*7;hD<%!y2dEEwceN@r(O|s)GWB4a09iPhrd#9`4Vvge>fZ7mp%| zwS(Jg3k$F2LBP4*>b73v=CRjPBSilIuzH>s^V&&z($)qoDs$zMZHM2QsE^?@?&`B- z*w^Ae&smzA(7p=8Tkl_Lwc3odgw_&3fEi)vnf*johDIJY=ZwpH%36|$ch1u8&q=3K zh;d}T=MK|Q?@6muitO}nzSe)fTkbeVL--kRZgrs-cU~$0Tp=ELBpGmoF0?qzdg6KE z{&6u|@CfCcW}UNcV-MbtYHCIIVphpRG3b8mO85Ex`yJ4%y4%B5J^0 zuw&Ex4f)2$7a6)Qz+9Y>d+Ydv1n<<79So%t{fRV$wrQW~%S?NPv%>8iqNPRbC+27X zlxmvzm4{C+CE;f}@uq{cfZJN1v$He7l2q_x`(y{KT;mZb;Ax?C&Lj0-gSqp`gB2PY z)ZSrSM*b1!z|P`@E&<(?r6I50jk`RMSOD(nJ|h`o>)F~IwJR;#iX*sMiDs1PJ30qM zgWJK%NFEuSF54Db$Ht_2952jb8>cOg{Ehq8NuhZeBjtAWRuO1yPrxF-g7=~RA6wA)2&|KH31snu>~B%RRH z+xtLo{5>Q8csMa#Nvx%qT$pj-i&stk!ElC&>Np0G9h%E!pUW|S!fJEc+J3ALlSKrZ zfTLMOscwSOL~o3?C%-bt2fDE*XDfl-I)%=RKDMBh_MRd`ziVO%#yq0QQ;(}5LJp5q$A7S9uP|cToKDY2c?(qo{(ODcg3|uyg9xy+lL}! zBP`0TihOYiizSEzo|SH0VXMV{8_V16@PONM^C$&BrNi&8HlYy<@(&xj1wa{yw@Y^ zMm1n`(=yvgdIu+mUN$@1Hl;i(CHUz%y}{UOS9nvwAVK^zFJK&UAx&7-f+~%nnMDms z1%AC9zot$1Slh1m-dnnR{f7cb}}X*Jz6o{~DK>fVU~ULrjd@LfqU0NdHg! z!9B|02Kb;IJtCfNQ5bMY_33v{P0}webva7Ii?mlC^?(I?0=bcdHZG#-0e4|f-!?7Gg~>8X6U!hg4t}q zDm(^OVJ4Q;7SSoLmbh7^z3?hDUxc6JLXZQ%$sR;#bCN#rKOHFYCCwyt#Qld-Q-%f$`xQ?+CbfVL6rn4i z4DmxWsnDzMruBH)cpmZIx(uAgmr+|q{T2X=O)3Djqqq6L4JiJnA4co~(9~eD7JOMQ zu~kU#QAa7zT}Yo;*kq8Yxk+owRdPxBkf})Ld!T9urU&SU0hjjHox~c}=XpI14eyD# zeR{x_!evCVztrKQ3{{%#D?R0H)Uy2I!Jk(>{->Rw*HS?tBHGa)Rf=n;3P6L;7PXj^ zDmvE37B6R@jy*tAk7p0qvV4ce0h~Z=Sm#sYWk6oIDo*~AFRd_b&0ubMj4K$T(&M7k zBq#|(?JStz7K3)0B58-t1jRN=_5eCBBh<^gr!ZJQ`_^2D36TA@hSIZ?u4TP9~?SIRW8j;EM5IsXe6YojWj=J6ruOB zJ%~76d?VggTvVEs@dmD&{FqWeL2p4fsEX6|HWuVKR$K&CC9#*8uGARs>AQF#?BoZI&YV)y z6B7*{n?uPhU6j~BC!TNaYqyUJ#9N`UJbDR}-zO9G#I)p#s3R7#JeYdrbGxLiaAU&D zv>(FgYJpif9F7KMf^KknqL{eSv0Ma+Ej`^GQaE?u$ALma)ZSfze|~% zGSra;ItYpXk}Ta}AX&}cvg*N#i6Ni?Xd~V$0q7$q5=q+MF#|*!UrD!ODv~C(Hr?GF zGj7(u%L|aPM*YSnrYbID`a+)DC&v`VgZ`(%`4*2o;$3r@cj?aaFHZ56QJ35Pkj-t; zCXN1(e}kc+vI7~=!~LqumQlY8;Kx$B4h8kaBr6w!-Y0Acs+mj((yeFF>}KVx)dM%?-K+I?cZ>|PdHv_1C3qR zM$#3e5$`l=>Ct>H;D zKdb0O$4b11P$tsEF{SmXjD_p6oa|JV8KX=aCw*qZe(AErlJ(LsnfHnkXMr-ROlujd z&xQy8FZ_wIV;EwUqFivOGCP3AWGtQvhMv}zo;Gj5KqDDXn+N=S`~uv3BHSQBU69xt zkkA_e{?~kbZ}|9dKk)4Te+D?YSliqB{htT;Nv3E41K9uH89eQsY&<+Iom~I_V+8+q V66XERRA9`5_X_IrRk9y~{vTnFT*d$Z literal 0 HcmV?d00001 diff --git a/lib/app/app.dart b/lib/app/app.dart new file mode 100644 index 0000000..58ebbbd --- /dev/null +++ b/lib/app/app.dart @@ -0,0 +1,35 @@ +import 'package:stacked_services/stacked_services.dart'; +import 'package:stacked/stacked_annotations.dart'; + +import '../services/http_services.dart'; +import '../services/my_easyloading.dart'; +import '../ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart'; +import '../ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart'; +import '../ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view.dart'; +import '../ui/views/login_user/login_user_view.dart'; +import '../ui/views/splash_screen/splash_screen_view.dart'; + +@StackedApp( + routes: [ + MaterialRoute(page: SplashScreenView, initial: true), + MaterialRoute(page: LoginUserView), + MaterialRoute(page: MasukanNoHpView), + MaterialRoute(page: VerifikasiNoHpView), + MaterialRoute(page: InputInformasiDiriView), + ], + // dialogs: [ + // StackedDialog(classType: AddSiswaDialogView), + // ], + dependencies: [ + LazySingleton(classType: NavigationService), + LazySingleton(classType: DialogService), + LazySingleton(classType: SnackbarService), + LazySingleton(classType: BottomSheetService), + // + + LazySingleton(classType: MyEasyLoading), + LazySingleton(classType: MyHttpServices), + ], + logger: StackedLogger(), +) +class App {} diff --git a/lib/app/app.locator.dart b/lib/app/app.locator.dart new file mode 100644 index 0000000..57e7a42 --- /dev/null +++ b/lib/app/app.locator.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// StackedLocatorGenerator +// ************************************************************************** + +// ignore_for_file: public_member_api_docs, implementation_imports, depend_on_referenced_packages + +import 'package:stacked_services/src/bottom_sheet/bottom_sheet_service.dart'; +import 'package:stacked_services/src/dialog/dialog_service.dart'; +import 'package:stacked_services/src/navigation/navigation_service.dart'; +import 'package:stacked_services/src/snackbar/snackbar_service.dart'; +import 'package:stacked_shared/stacked_shared.dart'; + +import '../services/http_services.dart'; +import '../services/my_easyloading.dart'; + +final locator = StackedLocator.instance; + +Future setupLocator({ + String? environment, + EnvironmentFilter? environmentFilter, +}) async { +// Register environments + locator.registerEnvironment( + environment: environment, environmentFilter: environmentFilter); + +// Register dependencies + locator.registerLazySingleton(() => NavigationService()); + locator.registerLazySingleton(() => DialogService()); + locator.registerLazySingleton(() => SnackbarService()); + locator.registerLazySingleton(() => BottomSheetService()); + locator.registerLazySingleton(() => MyEasyLoading()); + locator.registerLazySingleton(() => MyHttpServices()); +} diff --git a/lib/app/app.logger.dart b/lib/app/app.logger.dart new file mode 100644 index 0000000..26ab3f9 --- /dev/null +++ b/lib/app/app.logger.dart @@ -0,0 +1,159 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// StackedLoggerGenerator +// ************************************************************************** + +// ignore_for_file: avoid_print, depend_on_referenced_packages + +/// Maybe this should be generated for the user as well? +/// +/// import 'package:customer_app/services/stackdriver/stackdriver_service.dart'; +import 'package:flutter/foundation.dart'; +import 'package:logger/logger.dart'; + +class SimpleLogPrinter extends LogPrinter { + final String className; + final bool printCallingFunctionName; + final bool printCallStack; + final List exludeLogsFromClasses; + final String? showOnlyClass; + + SimpleLogPrinter( + this.className, { + this.printCallingFunctionName = true, + this.printCallStack = false, + this.exludeLogsFromClasses = const [], + this.showOnlyClass, + }); + + @override + List log(LogEvent event) { + var color = PrettyPrinter.levelColors[event.level]; + var emoji = PrettyPrinter.levelEmojis[event.level]; + var methodName = _getMethodName(); + + var methodNameSection = + printCallingFunctionName && methodName != null ? ' | $methodName' : ''; + var stackLog = event.stackTrace.toString(); + var output = + '$emoji $className$methodNameSection - ${event.message}${event.error != null ? '\nERROR: ${event.error}\n' : ''}${printCallStack ? '\nSTACKTRACE:\n$stackLog' : ''}'; + + if (exludeLogsFromClasses + .any((excludeClass) => className == excludeClass) || + (showOnlyClass != null && className != showOnlyClass)) return []; + + final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk + List result = []; + + for (var line in output.split('\n')) { + result.addAll(pattern.allMatches(line).map((match) { + if (kReleaseMode) { + return match.group(0)!; + } else { + return color!(match.group(0)!); + } + })); + } + + return result; + } + + String? _getMethodName() { + try { + final currentStack = StackTrace.current; + final formattedStacktrace = _formatStackTrace(currentStack, 3); + if (kIsWeb) { + final classNameParts = _splitClassNameWords(className); + return _findMostMatchedTrace(formattedStacktrace!, classNameParts) + .split(' ') + .last; + } else { + final realFirstLine = formattedStacktrace + ?.firstWhere((line) => line.contains(className), orElse: () => ""); + + final methodName = realFirstLine?.replaceAll('$className.', ''); + return methodName; + } + } catch (e) { + // There's no deliberate function call from our code so we return null; + return null; + } + } + + List _splitClassNameWords(String className) { + return className + .split(RegExp(r'(?=[A-Z])')) + .map((e) => e.toLowerCase()) + .toList(); + } + + /// When the faulty word exists in the begging this method will not be very usefull + String _findMostMatchedTrace( + List stackTraces, List keyWords) { + String match = stackTraces.firstWhere( + (trace) => _doesTraceContainsAllKeywords(trace, keyWords), + orElse: () => ''); + if (match.isEmpty) { + match = _findMostMatchedTrace( + stackTraces, keyWords.sublist(0, keyWords.length - 1)); + } + return match; + } + + bool _doesTraceContainsAllKeywords(String stackTrace, List keywords) { + final formattedKeywordsAsRegex = RegExp(keywords.join('.*')); + return stackTrace.contains(formattedKeywordsAsRegex); + } +} + +final stackTraceRegex = RegExp(r'#[0-9]+[\s]+(.+) \(([^\s]+)\)'); + +List? _formatStackTrace(StackTrace stackTrace, int methodCount) { + var lines = stackTrace.toString().split('\n'); + + var formatted = []; + var count = 0; + for (var line in lines) { + var match = stackTraceRegex.matchAsPrefix(line); + if (match != null) { + if (match.group(2)!.startsWith('package:logger')) { + continue; + } + var newLine = ("${match.group(1)}"); + formatted.add(newLine.replaceAll('', '()')); + if (++count == methodCount) { + break; + } + } else { + formatted.add(line); + } + } + + if (formatted.isEmpty) { + return null; + } else { + return formatted; + } +} + +Logger getLogger( + String className, { + bool printCallingFunctionName = true, + bool printCallstack = false, + List exludeLogsFromClasses = const [], + String? showOnlyClass, +}) { + return Logger( + printer: SimpleLogPrinter( + className, + printCallingFunctionName: printCallingFunctionName, + printCallStack: printCallstack, + showOnlyClass: showOnlyClass, + exludeLogsFromClasses: exludeLogsFromClasses, + ), + output: MultiOutput([ + if (!kReleaseMode) ConsoleOutput(), + ]), + ); +} diff --git a/lib/app/app.router.dart b/lib/app/app.router.dart new file mode 100644 index 0000000..cb37ba6 --- /dev/null +++ b/lib/app/app.router.dart @@ -0,0 +1,244 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// StackedNavigatorGenerator +// ************************************************************************** + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:flutter/material.dart' as _i7; +import 'package:flutter/material.dart'; +import 'package:reza_app/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart' + as _i6; +import 'package:reza_app/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart' + as _i4; +import 'package:reza_app/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view.dart' + as _i5; +import 'package:reza_app/ui/views/login_user/login_user_view.dart' as _i3; +import 'package:reza_app/ui/views/splash_screen/splash_screen_view.dart' as _i2; +import 'package:stacked/stacked.dart' as _i1; +import 'package:stacked_services/stacked_services.dart' as _i8; + +class Routes { + static const splashScreenView = '/'; + + static const loginUserView = '/login-user-view'; + + static const masukanNoHpView = '/masukan-no-hp-view'; + + static const verifikasiNoHpView = '/verifikasi-no-hp-view'; + + static const inputInformasiDiriView = '/input-informasi-diri-view'; + + static const all = { + splashScreenView, + loginUserView, + masukanNoHpView, + verifikasiNoHpView, + inputInformasiDiriView, + }; +} + +class StackedRouter extends _i1.RouterBase { + final _routes = <_i1.RouteDef>[ + _i1.RouteDef( + Routes.splashScreenView, + page: _i2.SplashScreenView, + ), + _i1.RouteDef( + Routes.loginUserView, + page: _i3.LoginUserView, + ), + _i1.RouteDef( + Routes.masukanNoHpView, + page: _i4.MasukanNoHpView, + ), + _i1.RouteDef( + Routes.verifikasiNoHpView, + page: _i5.VerifikasiNoHpView, + ), + _i1.RouteDef( + Routes.inputInformasiDiriView, + page: _i6.InputInformasiDiriView, + ), + ]; + + final _pagesMap = { + _i2.SplashScreenView: (data) { + return _i7.MaterialPageRoute( + builder: (context) => const _i2.SplashScreenView(), + settings: data, + ); + }, + _i3.LoginUserView: (data) { + return _i7.MaterialPageRoute( + builder: (context) => const _i3.LoginUserView(), + settings: data, + ); + }, + _i4.MasukanNoHpView: (data) { + return _i7.MaterialPageRoute( + builder: (context) => const _i4.MasukanNoHpView(), + settings: data, + ); + }, + _i5.VerifikasiNoHpView: (data) { + return _i7.MaterialPageRoute( + builder: (context) => const _i5.VerifikasiNoHpView(), + settings: data, + ); + }, + _i6.InputInformasiDiriView: (data) { + return _i7.MaterialPageRoute( + builder: (context) => const _i6.InputInformasiDiriView(), + settings: data, + ); + }, + }; + + @override + List<_i1.RouteDef> get routes => _routes; + @override + Map get pagesMap => _pagesMap; +} + +extension NavigatorStateExtension on _i8.NavigationService { + Future navigateToSplashScreenView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return navigateTo(Routes.splashScreenView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future navigateToLoginUserView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return navigateTo(Routes.loginUserView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future navigateToMasukanNoHpView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return navigateTo(Routes.masukanNoHpView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future navigateToVerifikasiNoHpView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return navigateTo(Routes.verifikasiNoHpView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future navigateToInputInformasiDiriView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return navigateTo(Routes.inputInformasiDiriView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithSplashScreenView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return replaceWith(Routes.splashScreenView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithLoginUserView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return replaceWith(Routes.loginUserView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithMasukanNoHpView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return replaceWith(Routes.masukanNoHpView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithVerifikasiNoHpView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return replaceWith(Routes.verifikasiNoHpView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithInputInformasiDiriView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return replaceWith(Routes.inputInformasiDiriView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } +} diff --git a/lib/app/core/custom_base_view_model.dart b/lib/app/core/custom_base_view_model.dart new file mode 100755 index 0000000..e4a5e69 --- /dev/null +++ b/lib/app/core/custom_base_view_model.dart @@ -0,0 +1,16 @@ +import 'package:stacked/stacked.dart'; +import 'package:stacked_services/stacked_services.dart'; + +import '../app.locator.dart'; + +class CustomBaseViewModel extends BaseViewModel { + final dialogService = locator(); + final navigationService = locator(); + final bottomSheetService = locator(); + final snackbarService = locator(); + bool backPressed = true; + + void back() { + navigationService.back(); + } +} diff --git a/lib/app/mycd b/lib/app/mycd new file mode 100755 index 0000000..66f5995 --- /dev/null +++ b/lib/app/mycd @@ -0,0 +1,3 @@ +#!/bin/bash + +ffmpeg -i "rtsp://admin:admin123@192.168.2.109/cam/realmonitor?channel=1&subtype=1" -acodec copy -vcodec copy abcd.mp4 -y diff --git a/lib/app/themes/app_colors.dart b/lib/app/themes/app_colors.dart new file mode 100755 index 0000000..b863713 --- /dev/null +++ b/lib/app/themes/app_colors.dart @@ -0,0 +1,30 @@ +import 'dart:ui'; + +const Color mainColor = Color.fromARGB(255, 37, 88, 241); +const Color secondaryColor = Color(0xFFB72025); +const Color dangerColor = Color(0xFFFF4B68); +const Color warningColor = Color(0xFFFBFFA3); +const Color lightColor = Color(0xFFF4FAFE); +const Color lightGreyColor = Color(0xFFFCFCFC); +const Color stockColor = Color(0xFFEEF3F6); + +const Color backgroundColor = Color(0xFFE5E5E5); +const Color backgroundColor3 = Color(0xFFF6F7F8); + +const Color orangeColor = Color.fromARGB(255, 250, 145, 84); +const Color blueColor = Color(0xFF026AA2); +const Color greenColor = Color(0xFF2ABB52); +const Color redColor = Color(0xFFED1717); +const Color greyBlueColor = Color(0xFF363F72); + +const Color fontColor = Color(0xFF101828); +const Color fontSecondaryColor = Color(0xFF667085); +const Color fontParagraphColor = Color(0xFFB2B2B2); +const Color fontGrey = Color(0xFF1C1C1C); + +const Color mainGrey = Color(0xFF8991A4); +const Color secondaryGrey = Color(0xFFD0D5DD); +const Color thirdGrey = Color(0xFFF2F4F7); +const Color fourthGrey = Color(0xFF5C5C5C); +const Color fifthGrey = Color(0xFFEBEBEB); +const Color sixthGrey = Color(0xFF151515); diff --git a/lib/app/themes/app_text.dart b/lib/app/themes/app_text.dart new file mode 100644 index 0000000..092d154 --- /dev/null +++ b/lib/app/themes/app_text.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +import 'app_colors.dart'; + +const regularTextStyle = TextStyle( + fontFamily: 'Arial', + fontSize: 14, + fontWeight: FontWeight.w400, + color: fontColor); + +const italicTextStyle = TextStyle( + fontFamily: 'Arial', + fontSize: 14, + color: fontColor, + fontStyle: FontStyle.italic, +); + +const mediumTextStyle = TextStyle( + fontFamily: 'Arial', + fontSize: 14, + fontWeight: FontWeight.w500, + color: fontColor, +); + +const semiBoldTextStyle = TextStyle( + fontFamily: 'Arial', + fontSize: 14, + fontWeight: FontWeight.w600, + color: fontColor, +); + +const boldTextStyle = TextStyle( + fontFamily: 'Arial', + fontSize: 14, + fontWeight: FontWeight.w700, + color: fontColor, +); + +const extraBoldTextStyle = TextStyle( + fontFamily: 'Arial', + fontSize: 14, + fontWeight: FontWeight.w800, + color: fontColor, +); diff --git a/lib/app/themes/app_theme.dart b/lib/app/themes/app_theme.dart new file mode 100755 index 0000000..eefa661 --- /dev/null +++ b/lib/app/themes/app_theme.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; + +import 'app_colors.dart'; +import 'app_text.dart'; + +ThemeData appTheme = ThemeData( + useMaterial3: true, + primaryColor: mainColor, + scaffoldBackgroundColor: Colors.white, + canvasColor: Colors.white, + fontFamily: 'Poppins', + appBarTheme: AppBarTheme( + elevation: 0, + titleTextStyle: boldTextStyle.copyWith(fontSize: 16, color: fontGrey), + centerTitle: true, + ), + textTheme: TextTheme( + displayLarge: regularTextStyle.copyWith(fontSize: 32), + displayMedium: regularTextStyle.copyWith(fontSize: 20), + displaySmall: regularTextStyle.copyWith(fontSize: 18), + ), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: mainColor, + foregroundColor: Colors.white, + disabledBackgroundColor: mainColor.withOpacity(.3), + minimumSize: const Size(double.maxFinite, 58), + textStyle: boldTextStyle, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + shadowColor: Colors.transparent, + elevation: 0, + ), + ), + outlinedButtonTheme: OutlinedButtonThemeData( + style: OutlinedButton.styleFrom( + textStyle: boldTextStyle, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + side: const BorderSide( + color: mainColor, + width: 1, + ), + foregroundColor: mainColor, + // disabledForegroundColor: mainColor.withOpacity(.3), + minimumSize: const Size(double.maxFinite, 58), + ), + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: mainColor, + disabledForegroundColor: mainColor.withOpacity(.3), + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + textStyle: semiBoldTextStyle, + shadowColor: Colors.transparent, + ), + ), + iconTheme: const IconThemeData( + color: mainColor, + ), + listTileTheme: ListTileThemeData( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + checkboxTheme: CheckboxThemeData( + fillColor: MaterialStateProperty.all(mainColor), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + side: const BorderSide( + color: secondaryGrey, + width: 1, + ), + ), + radioTheme: RadioThemeData( + fillColor: MaterialStateProperty.all(mainColor), + ), + tabBarTheme: TabBarTheme( + labelColor: mainColor, + unselectedLabelColor: secondaryGrey, + labelStyle: boldTextStyle.copyWith(fontSize: 16), + unselectedLabelStyle: mediumTextStyle.copyWith(fontSize: 16), + ), + chipTheme: ChipThemeData( + backgroundColor: Colors.white, + disabledColor: Colors.white, + selectedColor: Colors.white, + secondarySelectedColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + side: const BorderSide(color: fifthGrey), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + labelStyle: regularTextStyle.copyWith(fontSize: 12, color: fontGrey), + secondaryLabelStyle: + regularTextStyle.copyWith(fontSize: 12, color: secondaryColor), + deleteIconColor: fontGrey, + showCheckmark: false, + ), + popupMenuTheme: PopupMenuThemeData( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: const BorderSide( + color: fifthGrey, + width: 1, + ), + ), + ), + colorScheme: const ColorScheme.light( + primary: mainColor, + secondary: secondaryColor, + onPrimary: Colors.white, + onSecondary: Colors.white, + error: dangerColor, + onError: dangerColor, + background: backgroundColor, + ).copyWith(background: Colors.white), +); diff --git a/lib/main.dart b/lib/main.dart index dda5554..3c48071 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:stacked_services/stacked_services.dart'; -void main() { +import 'app/app.locator.dart'; +import 'app/app.router.dart'; +import 'app/themes/app_theme.dart'; + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + await dotenv.load(fileName: ".env"); + await setupAllLocator(); runApp(const MyApp()); } @@ -11,115 +21,19 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a blue toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), - useMaterial3: true, - ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), + title: 'Panti Asuhan Aisyiyah Abadi', + theme: appTheme, + debugShowCheckedModeBanner: false, + navigatorKey: StackedService.navigatorKey, + onGenerateRoute: StackedRouter().onGenerateRoute, + builder: EasyLoading.init(), ); } } -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // TRY THIS: Try changing the color here to a specific color (to - // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar - // change color while the other colors stay the same. - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. - ); - } +Future setupAllLocator() async { + await setupLocator(); + // setupDialogUi(); + // setupBottomsheetUi(); + // setupSnackbarUi(); } diff --git a/lib/services/http_services.dart b/lib/services/http_services.dart new file mode 100644 index 0000000..f2e4da5 --- /dev/null +++ b/lib/services/http_services.dart @@ -0,0 +1,35 @@ +import 'package:dio/dio.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +import '../app/app.logger.dart'; + +class MyHttpServices { + final log = getLogger('MyHttpServices'); + final _options = BaseOptions( + baseUrl: dotenv.env['api_url']!, + connectTimeout: const Duration(seconds: 120), + receiveTimeout: const Duration(seconds: 120), + ); + + late Dio _dio; + + MyHttpServices() { + _dio = Dio(_options); + } + + Future get(String path) async { + try { + return await _dio.get(path); + } on DioException { + rethrow; + } + } + + Future postWithFormData(String path, FormData formData) async { + try { + return await _dio.post(path, data: formData); + } on DioException { + rethrow; + } + } +} diff --git a/lib/services/my_easyloading.dart b/lib/services/my_easyloading.dart new file mode 100644 index 0000000..46cb062 --- /dev/null +++ b/lib/services/my_easyloading.dart @@ -0,0 +1,39 @@ +import 'package:flutter_easyloading/flutter_easyloading.dart'; + +class MyEasyLoading { + showLoading() { + EasyLoading.show( + status: 'loading...', + maskType: EasyLoadingMaskType.black, + dismissOnTap: false, + ); + } + + dismissLoading() { + EasyLoading.dismiss(); + } + + customLoading(String message) { + EasyLoading.show( + status: message, + maskType: EasyLoadingMaskType.black, + dismissOnTap: false, + ); + } + + showSuccess(String message) { + EasyLoading.showSuccess(message); + } + + showError(String message) { + EasyLoading.showError(message); + } + + showInfo(String message) { + EasyLoading.showInfo(message); + } + + showProgress(double progress, String status) { + EasyLoading.showProgress(progress, status: status); + } +} diff --git a/lib/services/other_function.dart b/lib/services/other_function.dart new file mode 100644 index 0000000..f58ea3e --- /dev/null +++ b/lib/services/other_function.dart @@ -0,0 +1,18 @@ +import 'package:intl/intl.dart'; + +class OtherFunction { + int umur(String tanggalLahir) { + // change tanggalLahir to DateTime + DateTime date = DateTime.parse(tanggalLahir); + // get current date + DateTime now = DateTime.now(); + // get difference in year + int year = now.year - date.year; + return year; + } + + String commaFormat(int number) { + final formatter = NumberFormat('#,###'); + return formatter.format(number); + } +} diff --git a/lib/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart b/lib/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart new file mode 100644 index 0000000..1a7050d --- /dev/null +++ b/lib/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; + +import './input_informasi_diri_view_model.dart'; + +class InputInformasiDiriView extends StatelessWidget { + const InputInformasiDiriView({super.key}); + + @override + Widget build(BuildContext context) { + return ViewModelBuilder.reactive( + viewModelBuilder: () => InputInformasiDiriViewModel(), + onViewModelReady: (InputInformasiDiriViewModel model) async { + await model.init(); + }, + builder: ( + BuildContext context, + InputInformasiDiriViewModel model, + Widget? child, + ) { + return const Scaffold( + body: Center( + child: Text( + 'InputInformasiDiriView', + ), + ), + ); + }, + ); + } +} diff --git a/lib/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view_model.dart b/lib/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view_model.dart new file mode 100644 index 0000000..e8e97b6 --- /dev/null +++ b/lib/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view_model.dart @@ -0,0 +1,5 @@ +import 'package:reza_app/app/core/custom_base_view_model.dart'; + +class InputInformasiDiriViewModel extends CustomBaseViewModel { + Future init() async {} +} diff --git a/lib/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart b/lib/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart new file mode 100644 index 0000000..a9db29c --- /dev/null +++ b/lib/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; +import 'package:validatorless/validatorless.dart'; + +import '../../../../app/themes/app_colors.dart'; +import '../../../widgets/my_button.dart'; +import '../../../widgets/my_textformfield.dart'; +import './masukan_no_hp_view_model.dart'; + +class MasukanNoHpView extends StatelessWidget { + const MasukanNoHpView({super.key}); + + @override + Widget build(BuildContext context) { + return ViewModelBuilder.reactive( + viewModelBuilder: () => MasukanNoHpViewModel(), + onViewModelReady: (MasukanNoHpViewModel model) async { + await model.init(); + }, + builder: ( + BuildContext context, + MasukanNoHpViewModel model, + Widget? child, + ) { + return Scaffold( + appBar: AppBar( + title: const Text('PENDAFTARAN USER BARU', + style: TextStyle( + color: lightColor, + )), + backgroundColor: mainColor, + iconTheme: const IconThemeData( + color: + Colors.white), // Set the color of the back button to white + ), + body: WillPopScope( + onWillPop: () async { + return model.backPressed; + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25), + child: Center( + child: Form( + key: model.formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/logo.png', + width: 100, + height: 100, + ), + const SizedBox(height: 15), + const Text( + 'Masukkan Nomor HP', + ), + const SizedBox(height: 16), + MyTextFormField( + maxLength: 13, + hintText: 'No. HP', + keyboardType: TextInputType.phone, + controller: model.noHpController, + validator: + Validatorless.required('No. HP tidak boleh kosong'), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.5, + child: MyButton( + text: 'Selanjutnya', + onPressed: () { + // if noHpController length is less than 9, return + if (model.noHpController.text.length < 9) { + model.snackbarService.showSnackbar( + message: 'No. HP tidak boleh kurang dari 9'); + return; + } + + if (!model.formKey.currentState!.validate()) { + return; + } + model.log.i('Selanjutnya button pressed'); + model.selanjutnya(); + }, + ), + ), + ], + ), + ), + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view_model.dart b/lib/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view_model.dart new file mode 100644 index 0000000..2fa3089 --- /dev/null +++ b/lib/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view_model.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import '../../../../app/app.locator.dart'; +import '../../../../app/app.router.dart'; + +import '../../../../app/app.logger.dart'; +import '../../../../app/core/custom_base_view_model.dart'; +import '../../../../services/my_easyloading.dart'; + +class MasukanNoHpViewModel extends CustomBaseViewModel { + final log = getLogger('MasukanNoHpViewModel'); + final _easyloading = locator(); + + TextEditingController noHpController = TextEditingController(); + GlobalKey formKey = GlobalKey(); + Future init() async {} + + selanjutnya() async { + _easyloading.customLoading("Menghantar Kode OTP \nke WhatsApp Anda"); + backPressed = false; + await Future.delayed(const Duration(seconds: 3)); + backPressed = true; + notifyListeners(); + _easyloading.dismissLoading(); + await navigationService.navigateToVerifikasiNoHpView(); + } +} diff --git a/lib/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view.dart b/lib/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view.dart new file mode 100644 index 0000000..3883915 --- /dev/null +++ b/lib/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; + +import './verifikasi_no_hp_view_model.dart'; + +class VerifikasiNoHpView extends StatelessWidget { + const VerifikasiNoHpView({super.key}); + + @override + Widget build(BuildContext context) { + return ViewModelBuilder.reactive( + viewModelBuilder: () => VerifikasiNoHpViewModel(), + onViewModelReady: (VerifikasiNoHpViewModel model) async { + await model.init(); + }, + builder: ( + BuildContext context, + VerifikasiNoHpViewModel model, + Widget? child, + ) { + return const Scaffold( + body: Center( + child: Text( + 'VerifikasiNoHpView', + ), + ), + ); + }, + ); + } +} diff --git a/lib/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view_model.dart b/lib/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view_model.dart new file mode 100644 index 0000000..2a8bed8 --- /dev/null +++ b/lib/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view_model.dart @@ -0,0 +1,5 @@ +import 'package:reza_app/app/core/custom_base_view_model.dart'; + +class VerifikasiNoHpViewModel extends CustomBaseViewModel { + Future init() async {} +} diff --git a/lib/ui/views/login_user/login_user_view.dart b/lib/ui/views/login_user/login_user_view.dart new file mode 100644 index 0000000..3e6ba2e --- /dev/null +++ b/lib/ui/views/login_user/login_user_view.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; + +import '../../widgets/my_button.dart'; +import '../../widgets/my_textformfield.dart'; +import './login_user_view_model.dart'; + +class LoginUserView extends StatelessWidget { + const LoginUserView({super.key}); + + @override + Widget build(BuildContext context) { + return ViewModelBuilder.reactive( + viewModelBuilder: () => LoginUserViewModel(), + onViewModelReady: (LoginUserViewModel model) async { + await model.init(); + }, + builder: ( + BuildContext context, + LoginUserViewModel model, + Widget? child, + ) { + return Scaffold( + body: WillPopScope( + onWillPop: () async { + return model.backPressed; + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25), + child: Center( + child: SingleChildScrollView( + child: Form( + key: model.formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/logo.png', + width: 200, + height: 200, + ), + const SizedBox(height: 16), + const Text( + 'Halaman Login', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + MyTextFormField( + maxLength: 13, + hintText: 'No. HP', + keyboardType: TextInputType.phone, + controller: model.noHpController, + ), + const SizedBox(height: 16), + MyTextFormField( + hintText: 'Password', + obscureText: model.showPassword, + controller: model.passwordController, + suffixIcon: IconButton( + onPressed: () { + model.showPassword = !model.showPassword; + model.notifyListeners(); + }, + icon: Icon( + model.showPassword + ? Icons.visibility_off + : Icons.visibility, + ), + ), + ), + const SizedBox(height: 16), + MyButton( + text: 'Login', + onPressed: () { + model.log.i('Login button pressed'); + model.login(); + }, + ), + TextButton( + onPressed: () { + model.daftar(); + }, + child: const Text( + 'Belum punya akun? Daftar disini', + style: TextStyle( + fontSize: 16, + ), + ), + ), + ], + ), + ), + ), + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/ui/views/login_user/login_user_view_model.dart b/lib/ui/views/login_user/login_user_view_model.dart new file mode 100644 index 0000000..f356cd3 --- /dev/null +++ b/lib/ui/views/login_user/login_user_view_model.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import '../../../app/app.router.dart'; + +import '../../../app/app.locator.dart'; +import '../../../app/app.logger.dart'; +import '../../../app/core/custom_base_view_model.dart'; +import '../../../services/my_easyloading.dart'; + +class LoginUserViewModel extends CustomBaseViewModel { + final log = getLogger('LoginUserViewModel'); + final easyloading = locator(); + + TextEditingController noHpController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + GlobalKey formKey = GlobalKey(); + + bool showPassword = true; + + Future init() async {} + + login() async { + setBusy(true); + backPressed = false; + easyloading.showLoading(); + await Future.delayed(const Duration(seconds: 5)); + easyloading.dismissLoading(); + setBusy(false); + backPressed = true; + notifyListeners(); + // await navigationService.navigateToHomeView(); + } + + daftar() async { + await navigationService.navigateToMasukanNoHpView(); + } +} diff --git a/lib/ui/views/splash_screen/splash_screen_view.dart b/lib/ui/views/splash_screen/splash_screen_view.dart new file mode 100644 index 0000000..f27b608 --- /dev/null +++ b/lib/ui/views/splash_screen/splash_screen_view.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; + +import './splash_screen_view_model.dart'; + +class SplashScreenView extends StatelessWidget { + const SplashScreenView({super.key}); + + @override + Widget build(BuildContext context) { + return ViewModelBuilder.reactive( + viewModelBuilder: () => SplashScreenViewModel(), + onViewModelReady: (SplashScreenViewModel model) async { + await model.init(); + }, + builder: ( + BuildContext context, + SplashScreenViewModel model, + Widget? child, + ) { + return Scaffold( + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Expanded( + flex: 1, + child: SizedBox( + height: 20, + ), + ), + Expanded( + flex: 2, + child: Column( + children: [ + Center( + child: Image.asset( + 'assets/logo.png', + width: 200, + height: 200, + ), + ), + const Text( + 'Reza Table Reservation \n& Food Order', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + const SizedBox(height: 20), + const Text( + 'Alamat jalan jendral sudirman', + style: TextStyle( + fontSize: 16, + ), + ), + const SizedBox(height: 20), + ], + ), + ); + }, + ); + } +} diff --git a/lib/ui/views/splash_screen/splash_screen_view_model.dart b/lib/ui/views/splash_screen/splash_screen_view_model.dart new file mode 100644 index 0000000..6938079 --- /dev/null +++ b/lib/ui/views/splash_screen/splash_screen_view_model.dart @@ -0,0 +1,10 @@ +import 'package:reza_app/app/app.router.dart'; +import 'package:reza_app/app/core/custom_base_view_model.dart'; + +class SplashScreenViewModel extends CustomBaseViewModel { + Future init() async { + // after 2 second, navigate to login page + await Future.delayed(const Duration(seconds: 2)); + await navigationService.navigateToLoginUserView(); + } +} diff --git a/lib/ui/widgets/my_button.dart b/lib/ui/widgets/my_button.dart new file mode 100644 index 0000000..13fb767 --- /dev/null +++ b/lib/ui/widgets/my_button.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; + +import '../../app/themes/app_colors.dart'; + +class MyButton extends StatelessWidget { + const MyButton({ + Key? key, + required this.text, + this.onPressed, + }) : super(key: key); + + final String text; + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context) { + return ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: mainColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + ), + onPressed: onPressed, + child: Text( + text, + style: const TextStyle( + color: backgroundColor, + fontSize: 18, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/my_textformfield.dart b/lib/ui/widgets/my_textformfield.dart new file mode 100644 index 0000000..fe069bb --- /dev/null +++ b/lib/ui/widgets/my_textformfield.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; + +import '../../app/themes/app_colors.dart'; + +class MyTextFormField extends StatelessWidget { + const MyTextFormField({ + Key? key, + this.labelText, + this.hintText, + this.obscureText, + this.validator, + this.suffixIcon, + this.prefixIcon, + this.focusNode, + this.controller, + this.maxLines = 1, + this.onEditingComplete, + this.readOnly = false, + this.onTap, + this.keyboardType = TextInputType.text, + this.initialValue, + this.enabled = true, + this.maxLength, + }) : super(key: key); + + final String? labelText; + final String? hintText; + final bool? obscureText; + final FormFieldValidator? validator; + final Widget? suffixIcon; + final Widget? prefixIcon; + final FocusNode? focusNode; + final TextEditingController? controller; + final int maxLines; + final VoidCallback? onEditingComplete; + final bool readOnly; + final VoidCallback? onTap; + final TextInputType keyboardType; + final String? initialValue; + final bool enabled; + final int? maxLength; + + @override + Widget build(BuildContext context) { + return TextFormField( + maxLength: maxLength, + enabled: enabled, + initialValue: initialValue, + onEditingComplete: onEditingComplete, + maxLines: maxLines, + controller: controller, + focusNode: focusNode, + obscureText: obscureText ?? false, + readOnly: readOnly, + onTap: onTap, + keyboardType: keyboardType, + decoration: InputDecoration( + prefixIcon: prefixIcon, + suffixIcon: suffixIcon, + enabledBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(25)), + borderSide: BorderSide( + color: mainColor, + ), + ), + focusedBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(25)), + borderSide: BorderSide( + color: mainColor, + ), + ), + focusedErrorBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(25)), + borderSide: BorderSide( + color: dangerColor, + ), + ), + errorBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(25)), + borderSide: BorderSide( + color: dangerColor, + ), + ), + labelText: labelText, + hintText: hintText, + labelStyle: const TextStyle(color: fontColor), + ), + validator: validator, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 3832970..b5bed82 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,22 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" args: dependency: transitive description: @@ -25,6 +41,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + url: "https://pub.dev" + source: hosted + version: "2.4.6" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" + url: "https://pub.dev" + source: hosted + version: "7.2.10" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" + url: "https://pub.dev" + source: hosted + version: "8.6.1" characters: dependency: transitive description: @@ -33,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" clock: dependency: transitive description: @@ -41,6 +129,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" + url: "https://pub.dev" + source: hosted + version: "4.5.0" collection: dependency: transitive description: @@ -49,6 +145,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.2" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" cross_file: dependency: transitive description: @@ -73,6 +177,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + url: "https://pub.dev" + source: hosted + version: "2.3.2" dio: dependency: "direct main" description: @@ -97,6 +209,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" file_selector_linux: dependency: transitive description: @@ -129,6 +249,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.3" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter: dependency: "direct main" description: flutter @@ -192,6 +320,22 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" get: dependency: transitive description: @@ -208,6 +352,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.6.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" google_fonts: dependency: "direct main" description: @@ -216,6 +368,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.0" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" http: dependency: transitive description: @@ -224,6 +384,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" http_parser: dependency: transitive description: @@ -304,6 +472,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.18.1" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" js: dependency: transitive description: @@ -312,6 +488,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" lints: dependency: transitive description: @@ -344,6 +528,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + logger: + dependency: transitive + description: + name: logger + sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" matcher: dependency: transitive description: @@ -384,6 +584,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + otp_text_field: + dependency: "direct main" + description: + name: otp_text_field + sha256: "340b1ed135e1abe9fac0aaebe1c4e48147d95a3e29ecb03ae45ad63a7c28d65d" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -472,6 +688,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" provider: dependency: transitive description: @@ -480,11 +704,59 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.5" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + url: "https://pub.dev" + source: hosted + version: "1.4.0" source_span: dependency: transitive description: @@ -509,6 +781,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" + stacked_generator: + dependency: "direct dev" + description: + name: stacked_generator + sha256: "52a06816caec8272b2111e247ec4484031b89858099b72073663b8e45282fb1e" + url: "https://pub.dev" + source: hosted + version: "1.4.0" stacked_services: dependency: "direct main" description: @@ -533,6 +813,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: @@ -565,6 +853,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.0" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" typed_data: dependency: transitive description: @@ -621,6 +917,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" win32: dependency: transitive description: @@ -645,6 +957,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.3.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.1.0-163.1.beta <4.0.0" flutter: ">=3.7.0-0" diff --git a/pubspec.yaml b/pubspec.yaml index 7b7d543..5f8149e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,7 @@ dependencies: # flutter_holo_date_picker: ^1.1.0 validatorless: ^1.2.3 intl: + otp_text_field: ^1.1.3 dev_dependencies: flutter_test: @@ -61,6 +62,9 @@ dev_dependencies: # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^2.0.0 + build_runner: + stacked_generator: + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec @@ -74,8 +78,9 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg + assets: + - .env + - assets/logo.png # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see