diff --git a/assets/images/add_background.png b/assets/images/add_background.png new file mode 100644 index 0000000000000000000000000000000000000000..eff2d70b434489bc56206978b4b1a070d1e22c3e GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fjKx9jP7LeL$-D$|d_7$pLo5W7 z6ArNaZ*)@d5lmR*VJ>&p`Fw)gg8U9%{|Qlx7|%8_&E|FsX5AJbDPg#$&~bB!;TIk? tRr85coHNBlrYu>0F~rgH1#jA3hC5DN;`|fVcLEJ&@O1TaS?83{1ON~QEB62Z literal 0 HcmV?d00001 diff --git a/assets/images/cup.png b/assets/images/cup.png new file mode 100644 index 0000000000000000000000000000000000000000..16de29305bfbee906780e1ae115761a3a5c63624 GIT binary patch literal 15870 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 ATPu>5X8sEFdY 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 literal 0 HcmV?d00001 diff --git a/assets/images/icon_diamond.png b/assets/images/icon_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..c1104f368739e92994ef6f1a7cf52c5567d2144f GIT binary patch literal 883 zcmV-(1C0EMP)U2uuuMt59tZr~weppj{t7^{gOE-GkZpqQA>nuv*@ z1`3L*%cWw>>-kQ(aYlJ)n%bf{`B-UDeck^}Y8!hR@0vQ=(7lN)*+u zrV+qVfS zGxvDUY)@o9X=T@YeKI%EFhr(Oz)FB&M?p#h&KM>ecOP&$ZUk`y_iYo$t| zPCe~m=Ucr;OHppC49ti`(@HZkNiRzcL4(NWISLaDPoIS7lV8RrQXwE5gMt^LT(w|w z_Cd=o{T<84&D}|(hv`i&Hve8gA;&OF9j+5md5WW4hl1>YKY#eE>to^ z91kJa+ZS4w_xc~F`Om^_KWJ{M$9)^JPdf8O8iY%-Nq#nz?2^l%V+q3*m={CoHK?e4 zZtcd-1D`}At1SzU{Pkv~F54W*8u|6>#K^~Nc$$KnhKe3ABVrBmPW4US4f!2U5e0!zx93}R@KtC@z521k<{f1cVfwBt2>N164)S|`qMHhcq{2aF-SyqKZEnhWJ7mf$J>>vzdm@w_h-s-OO+FuVg!tk$= z1!sO*WL4}-ixk>v$`QkI%GLbWh`y;Nk97Uw$@qnLpj*TDtoNc>b8G#1DiHtx002ov JPDHLkV1jDrk%j;O literal 0 HcmV?d00001 diff --git a/assets/images/icon_flash.png b/assets/images/icon_flash.png new file mode 100644 index 0000000000000000000000000000000000000000..9ca0a4e82245ecd8a67bb5aadfa7b6a6797cf6db GIT binary patch literal 747 zcmVWpvE{D6-_K4mRhiOR>&`4*Mdl_D6C;yJAMI6O`)BIjj^(W#Hg4U zSi&mbVRo0d$f6vrWAK^G7xg zpgB#hHGmBeC8$^-O6}SX$T*K@Irsu{2Bp|YYH;X-z8y&?hTh~7O{3BQ@eg<$9u~;S zrNlW&K(TPz?*+L}e7<>qJ2T$z@iM%2eJVt<(z5{9DOdv|V68*|1tS8Gilm}fBwYh5 zIp4fmvD_P@$3m#)7-fgSu@vb@I?0*{A1!jLbx;(7_J)DOUtX;Fg&loH0SS5RZ-E*I zV2eOqS&>pn3OEdyg1f|FOL(Yx_w`V0l zv-^F+o>D`p5HulD);Ui;mvLRpG_Keqw>CsI)yGsHkOtcunLy=FljON;>0XE1 zEzgoJw$QCVkmv3AI;iH|B34dnJ3iT=aMQAF1agxY8{83}cENsi=3l@m5NVo3pxO@x z1-BVN4IFHh>?xFSCQ`}cC3_5!_K>v%Fev03Wa9mjQ%vS?PNX2a*G!sr(><9886BAV zqVp2x0y-d0tPyO9a*^LQv}{kKi2uYfCw0%~rjgN!S2Eq0!3B|m=*sW}UwJrhUzWeJ dC}i$V;YjlZ&io7b=#2W?N1wv6Z#K?u8k7(b5O zdxr6c_a|JQ8pU#(2-RZ7=yU+%S6Nq_Nsa!9-*ZbAM>(Xkn%vt9T1jT0s?{15W~x-E zW>L+3#k4Uyo3a#z?2m>lr*aq?gVhb7{UJj0?Z731B)agz8FUu z-$CckY;X>aqI{V1Ho&=}9t{tC1aHLPBJ=;LunTFnIoCDSFaJG?Zx6qUov$=Obv}-- zPo4ndS%m^KD0^Z%EII2C>^g?&!0!m_NJ0`J&ZC~+uI^%d9ElJD^HX@ZvK+5f*W$>b zci>+Tfm936Ov0vZ+wj-mIn4M%$aknnF-H*%|1UD3MB)ZnIp+uVcXpuicprrEDiqh$ zp{mpgtHp|!-+dkD$EVTJ)r~9jVH|sU3))_)fJNSkKYd4VX&?il2u%Rf#}o@cYo-~p z{eJkadXY6Wg!7+$jIpz4aBg!2DsxqwZf(Yy9nZrY330s$Hb)t9*Ua*40Rsp~f@t^! zF6POGa+sD6<8J>Xq<>;qzjh6pd%nX9t*7wYFr z0w%KoA}%?@8_5!RkDHMyf|9;e zU7o#XSzgkRjA0iM`h^t0H^4As{sp4!#==xLeBLjh%PR8odApbk{ZqhX=QU(3-PnOd zlQhDfUN*opOnzV~0z}t!to z821&p?Q!VmYD67xV(W7|u(`GbFZQf}PBYwu#u8*-A8Wy#B2hA)mOZEKij{KH(kUn1 zMpj8CRWZ?*yC0SLYqz7VaMD?f%=% Z{|}8`lv<-{JoW$p002ovPDHLkV1mHE^#}j} literal 0 HcmV?d00001 diff --git a/assets/images/mic.png b/assets/images/mic.png new file mode 100644 index 0000000000000000000000000000000000000000..ca96910a7d97d200bc0767be4376ec5fb143960c GIT binary patch literal 3498 zcmV;b4OQ}qP)@@dbuN}v^d?)saB|FnsSLnP$ zbA&{*!1m`FT`se&#*yjRX1CjGtQK=kNpZ2u<0&Gu**y7hNg^gr7K=sf^SLWFi*^61 z<+;D7IUp_4Ae$Aj?8(Yr@SHO%+XX@nhn=b_$|)nmHsif$%mn%2%uH+J>SgYq(k!8y z^pnrNu+nC8yjoaP;5C~q;ur{5KUfvlyE8#0&c7PW$jJEKn&tVwq**{0>8GA;^jd7@ zQyz~;^e%v&{lv(FA(@JSVPIUnYTWywOMMZ@%!a!+>XGX#%lZiKT zY=fqOP$)!^NQ4wcaRh_G7ibnp`CesN+2_h}#UufM?4pGWL&P-A!p=M$+hIli9S>>2$^&&&$oB z(a}-5dbORpy042*e2;6aB*&4Cz7>VCvYg`Dk3Kp}ot<5l@9h5OLww>88AY1a(2$v# zIqmqhYhColoBxa>YO~o0CNGN{=vlm&+-`T=JQ5eQa!$IyyS(F28=j?arg6OO^{e;~-mG^9kOn#XbD;BqAKMaZ2nOeuzw|V*ufo@kQ79au zwl+T+ot8vW+36N0`c;0Hahk?!|H9{X2(pmJ)wVX?{6gPaWM@zB^@2r?Ag) zRKL2885o|7 zSH<^Lt7@xWZ@uZ*Qe7}ib0xi@zS{rcho=X4*JZU@se&bvX}42%cQ-XRH^+!pR;&=3 zcDwUqQi+mF{`k!e4^x@fOMU(Qbgiq)VvU5B^WhfKfs_u@GvD5KYVl%^&^2)5#tpFn z>(X%>pGi0ek-f%>V&mPhQ9tjF&T*oOrgCGReN3}9Z2bWD2jAE5DW;?y}iAH zFi3uK(*`k3M@e?mIUb->H4Xn`CeqE#AJCbz=UDsM^x%V4x+j^Gq$LbS9_iv@_S`s9 zp(QMZk-#Xu`r1)pEmTa^^pY~~jL)vDsKBhtGweP3;Db{Qq!TIS0jDV=)7rk+A(1{Z# zG0FH+@zEFDDa12llr%_rOH0MX@b}l>Oehhp*#j_{UKEO zqwl7qql>h5FfL!dJSvg4c!_8y5m*#VZNhf`Ty1#%8s#O&_JczJBQ2 zd#t_Pm1;2RP9bOqTjiaFI^6w8oKKy0nZuMT><5RI37AYlCAn zULCkjXBHI{Eabp@)0#d=F1} z^Bu7qNO7@;ii!%vKJp|OCqsjS-e3QOj3KRrs6{)#T+ALnguwR?fBaLdXQAcV>gt51 zPdrCKq6VZD(SXV03dfB1NDp+AKJ=?b|I@qo`Pt@rF__?@Vi+TmNoM*I0X91kKp4+q z_Jd>;=?Sz10|BpnBCX)}cZeTay{Z=3BAP8YJ;o-lPxv5;4xc(@E-wyIH#PPZ9$zWX zj-2+T*#bF~j*bpOkO7R0j2%gJPg*^#m?mdN0EB_T!66#p&6S;{`&lFGZww3!@V$d# zY(W34Hs7ut8;$MhLqBiy1%g4gB7te=Iy$cr2-bR+motG=}&ls%8bHL)jG$tE>kQg?$9{Zo(TI(krFj1N~ z)9mxFsNDopJ1sdmHa0F|!!S=2c>N%Ze6-fIX@SP&vWLgm|KyhXM$(D2Nekj9eZHkD z*CixAJ|0b)BQ%rcWZ&?y0Zu~tY&QGLPi|SA(oz^s8bA!`blMxNw#+?tdqynPpaRlh>)=zA zaI4ed@IC*n&(Dge7IP-81xj|Gs$0D?FE798_U+qrZ#e4Roxa#t<~!8rCxejQZ8$}vGfd;Nf#Ia#v8h0Lf*mX}8uzWoeBnOn`NID<>Akyl_y-eYm7-8!^892F z3^jQ-Zr%1tlH362A9a)vM=&VrBU*?=LdVG<80wk=2M@pf_@9Gd~(Un%e#bBU6^|qg-!U={_6otgWKhG#iW=V`@{>WBwVgh8svVICwi=3X#KQX{Bg0;<-tL)tE&JF5D=RDa z@_R+84O`3R+SE1hIgy?qSi`{wmw}~+`KB7q&UvR^heYGWix;Ndk63ZVit?$42iTss zplT*l1hXX?;-|Tg22m!tlc(TqoFqccI%SNfmo%0zBl8pvM?`3bEm}b0Mkvb5oKZV6 zQv;*~WWB7!Jrq%P>LEHC(nteiQK7aF3gXDHBJ+w*#t~UoUSje-N=7;=0eMd(qBPPh zk&ZkP5m$jA7=BB%s45+l<;Z?*&&v~pyp-gM-rY>m+fPT9A{j2Mk3O& zH&3=V#Lf#j@Ifi6+j#|KfP8i`sBeSoFd-g2%wz^6=G+;(~ zmvseOE$Y>f3kvl)IXThQNIQqJw&Rdc-!_vy+4s#j<(tuC4yq z(2dqi+oqD$Ez~9)1R`w+#uLT-`9zuh#VPCreK}{6^`{+r0VpEI#DKNl|e`)WoZH?N4 zNsVOFfma)Nz7jzI89Zz10GFldW%jaQ4V+ol7rv5Oe?@{iSUL$D^u8$F}&r=$kFT2d1Mt>h>1$_Wejc;C{Z>NFkv Y2M&foRI_OqkN^Mx07*qoM6N<$f?oEr`v3p{ literal 0 HcmV?d00001 diff --git a/assets/images/mic_blur.png b/assets/images/mic_blur.png new file mode 100644 index 0000000000000000000000000000000000000000..cd6367e40b83ffa79fd93acff3e3615f20313409 GIT binary patch literal 1906 zcmV-&2aWiNP)fW!;<2&a&MPSb1y@%c1U3&li zeFEFt(C+of`T4ou-rjcQeL{%8X)n0}kUZMm73-~!!^UDYYPXjwomMA6Ai{`CamfG% z&nH`3TlOaKE5O}umtH_C3FGRmMkQY9EOk1q)3S_|;6{>;@ZZ%Qh#-=c>fitdBS@}2a8DD2L`;Pg9 z&`?%7MA8RLh)+3ZchIGp)+W|kOAlUVDvSDqK``i#rqk)@^x69AWN&xZ&$amCq9veh z7pY|*s$4BPqk}BVKyVI8H33RnV6A1-@uW7MW=m1X8tV6ddWBo7Qw6C(gOwO+E^vP|@-Z|FSc(bpjuL{_GT>-2#u^A> zhG7J?nxO!$qK&Ju!Uwo@`Ytei`{a3V(?}^MnE44~C3s01f*~l4q`;VfFbEL1Mk`6B zB0|=TgpRu2)49M~Tl+4xeCmiFB2@0Z^F>iWt~4n8FGIr6bIwIcgUBe;?2o6F&0cRl zaJReT1En%d#lTsY8SA`3Fz*}~V<1ga$nq4l)!?+1s>o}``O24HW^67nTIpc|3N0OY z;-~m;XTe~YLb65j)i+2lvsGd|*kPB>+@Tw>8$gvFN(2%6PftlQn44-ByHoGzxo`~V!NKm;CH0LvfTh86s_78W21Lx`f-CDp1;qJ|AZ z>vwi`{9NF2flA5LI&v;J9m+u1Dpp;!T1Bv6wgwsERi5Woy9*)7#X_xma@$zZf^nRG92Zn%d(J!b$!v4u@-wlarNV?UUEX zsiFtW7@g(Wns?Aa4;-cBR4{RZTz)14c&eB!heFLojOzDCs zrT-eWqQ}4e<(A~6`&I4XQJoK_z=aR7+GOq5NX%;GP^-uc&YT>-C^MR2gfW1Rt z>x{LtaiOrCYF$y&LOv-4_Wgl(vBIp!ri|FuIcvNz1@;f)*AKV-djpr8&W01EoEbU; zV+`mBFh`w@szpUN3S!7+X6Y z7d#h1ASabus|6|+%mXLi#hQVU12pu-!GY-1@A8ZOY21H3TANJ9Kb}l7j*R`=y`|-^ z%-Y?lV1pt$IkEfu`>qVz+k7T(0n%RYFk;n8RS{^Q&ee&tRc%bIKe${TUJgIf){t6K zf8M^;{-#>1_c`-J6oKK`n^AF;O&-89`uQYWW-oeMN5(>*!n+1Ga zf+-3aYylr7Hb54|;0N7>MO_BsY~oO~poZT1ddqW+~N_$tbE zJ)jG#q~(pjkIJ;}fV5__ACw-^S*$oplaLat+7XkOIw>OV8uPSVo<|K?q$&@84{s7%GfO63>9iTST(f0hT!ELb)`}?PNT% zRyki55C3!XncEyJjFO@_7D2ceO1;d5jAiLR#fHfU=99i*4(cC(_NE*G(9qNy3@*-h z(>zOGC}Uns(Gp`~35`LfR`d1QM@dyJ)~4Up{vVhzuwr;yd*Ua+u8Jv{rXmRyPx^t5o6I(Cdnc)pz0}! z7%=I;N`e%@kH!fmM;FF8+M@6N0{iNjO^2`A2@D@?Y?v#RS2p&aBnh`lMKFmXUzjKm z5b!YIE=y@3;%}2o0^qjL;wH)07*qoM6N<$f-RSo-T(jq literal 0 HcmV?d00001 diff --git a/assets/images/shia_mind_group.png b/assets/images/shia_mind_group.png new file mode 100644 index 0000000000000000000000000000000000000000..b47c20e94ac5d81edb2552230a3279b5409c9771 GIT binary patch literal 19431 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/icon_awards.svg b/assets/svg/icon_awards.svg new file mode 100644 index 0000000..67901d2 --- /dev/null +++ b/assets/svg/icon_awards.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/icon_clock.svg b/assets/svg/icon_clock.svg new file mode 100644 index 0000000..f657f87 --- /dev/null +++ b/assets/svg/icon_clock.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/svg/icon_home.svg b/assets/svg/icon_home.svg new file mode 100644 index 0000000..a88c424 --- /dev/null +++ b/assets/svg/icon_home.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/icon_plus.svg b/assets/svg/icon_plus.svg new file mode 100644 index 0000000..9c6b2b4 --- /dev/null +++ b/assets/svg/icon_plus.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/svg/icon_setting.svg b/assets/svg/icon_setting.svg new file mode 100644 index 0000000..dfc6c52 --- /dev/null +++ b/assets/svg/icon_setting.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/svg/icon_share.svg b/assets/svg/icon_share.svg new file mode 100644 index 0000000..43b2c59 --- /dev/null +++ b/assets/svg/icon_share.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/svg/icon_shop.svg b/assets/svg/icon_shop.svg new file mode 100644 index 0000000..57c2ab6 --- /dev/null +++ b/assets/svg/icon_shop.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/medal.svg b/assets/svg/medal.svg new file mode 100644 index 0000000..8b4a41a --- /dev/null +++ b/assets/svg/medal.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/common_ui/resources/my_assets.dart b/lib/common_ui/resources/my_assets.dart index 09d8c1c..6edec51 100644 --- a/lib/common_ui/resources/my_assets.dart +++ b/lib/common_ui/resources/my_assets.dart @@ -7,9 +7,28 @@ class MyAssets { static const String sample = 'assets/images/sample.png'; static const String shiaMind = 'assets/images/shia_mind.png'; static const String question = 'assets/images/question.png'; + static const String iconProfile = 'assets/images/icon_profile.png'; + static const String iconDiamond = 'assets/images/icon_diamond.png'; + static const String iconFlash = 'assets/images/icon_flash.png'; + static const String iconCrown = 'assets/images/icon_crown.png'; + static const String shiaMindGroup = 'assets/images/shia_mind_group.png'; + static const String cup = 'assets/images/cup.png'; + static const String addBackground = 'assets/images/add_background.png'; + static const String mic = 'assets/images/mic.png'; + static const String micBLur = 'assets/images/mic_blur.png'; /// ----- Svg ----- static const String sampleSvg = 'assets/svg/sample.svg'; + static const String iconHome = 'assets/svg/icon_home.svg'; + static const String iconShop = 'assets/svg/icon_shop.svg'; + static const String iconAwards = 'assets/svg/icon_awards.svg'; + static const String iconPlus = 'assets/svg/icon_plus.svg'; + static const String iconSetting = 'assets/svg/icon_setting.svg'; + static const String iconShare = 'assets/svg/icon_share.svg'; + static const String iconClock = 'assets/svg/icon_clock.svg'; + static const String medal = 'assets/svg/medal.svg'; + static const String friendBattle = 'assets/svg/friend_battle.svg'; + /// ----- Audios ----- static const String sampleAudio = 'assets/audios/sample.mp3'; @@ -21,5 +40,10 @@ class MyAssets { static const List images = [ shiaMind, question, + iconProfile, + iconDiamond, + iconFlash, + iconCrown, + shiaMindGroup, ]; } diff --git a/lib/common_ui/resources/my_colors.dart b/lib/common_ui/resources/my_colors.dart index 5af3ddc..087ce37 100644 --- a/lib/common_ui/resources/my_colors.dart +++ b/lib/common_ui/resources/my_colors.dart @@ -8,5 +8,5 @@ class MyColors { static const Color white = Colors.white; static const Color black = Colors.black; static const Color transparent = Colors.transparent; - static const Color introBackgroundColor = Color(0xFF160C30); + static const Color backgroundColor = Color(0xFF160C30); } diff --git a/lib/common_ui/theme/my_theme.dart b/lib/common_ui/theme/my_theme.dart index 9ba99f4..7ee5201 100644 --- a/lib/common_ui/theme/my_theme.dart +++ b/lib/common_ui/theme/my_theme.dart @@ -5,7 +5,7 @@ import 'package:get/get.dart'; enum ColorsName { primaryColor, noColor, - introBackgroundColor, + backgroundColor, } class MyTheme { @@ -20,13 +20,13 @@ class MyTheme { static Map get lightColors => { ColorsName.primaryColor: MyColors.white, ColorsName.noColor: MyColors.transparent, - ColorsName.introBackgroundColor: MyColors.introBackgroundColor, + ColorsName.backgroundColor: MyColors.backgroundColor, }; static Map get darkColors => { ColorsName.primaryColor: MyColors.white, ColorsName.noColor: MyColors.transparent, - ColorsName.introBackgroundColor: MyColors.introBackgroundColor, + ColorsName.backgroundColor: MyColors.backgroundColor, }; } @@ -36,5 +36,5 @@ extension ThemeExtension on BuildContext { Color get primaryColor => customColors[ColorsName.primaryColor]!; Color get noColor => customColors[ColorsName.noColor]!; - Color get introBackgroundColor => customColors[ColorsName.introBackgroundColor]!; + Color get backgroundColor => customColors[ColorsName.backgroundColor]!; } diff --git a/lib/core/params/awards_params.dart b/lib/core/params/awards_params.dart new file mode 100644 index 0000000..63bc3a0 --- /dev/null +++ b/lib/core/params/awards_params.dart @@ -0,0 +1,13 @@ +class AwardsParams { + int? id; + + AwardsParams({this.id}); + + AwardsParams copyWith({ + int? id, + }) { + return AwardsParams( + id: id ?? this.id, + ); + } +} diff --git a/lib/core/params/home_params.dart b/lib/core/params/home_params.dart new file mode 100644 index 0000000..22518f3 --- /dev/null +++ b/lib/core/params/home_params.dart @@ -0,0 +1,13 @@ +class HomeParams { + int? id; + + HomeParams({this.id}); + + HomeParams copyWith({ + int? id, + }) { + return HomeParams( + id: id ?? this.id, + ); + } +} diff --git a/lib/core/params/master_params.dart b/lib/core/params/master_params.dart new file mode 100644 index 0000000..62509d2 --- /dev/null +++ b/lib/core/params/master_params.dart @@ -0,0 +1,13 @@ +class MasterParams { + int? id; + + MasterParams({this.id}); + + MasterParams copyWith({ + int? id, + }) { + return MasterParams( + id: id ?? this.id, + ); + } +} diff --git a/lib/core/params/profile_params.dart b/lib/core/params/profile_params.dart new file mode 100644 index 0000000..9c62c23 --- /dev/null +++ b/lib/core/params/profile_params.dart @@ -0,0 +1,13 @@ +class ProfileParams { + int? id; + + ProfileParams({this.id}); + + ProfileParams copyWith({ + int? id, + }) { + return ProfileParams( + id: id ?? this.id, + ); + } +} diff --git a/lib/core/params/shop_params.dart b/lib/core/params/shop_params.dart new file mode 100644 index 0000000..6d3537b --- /dev/null +++ b/lib/core/params/shop_params.dart @@ -0,0 +1,13 @@ +class ShopParams { + int? id; + + ShopParams({this.id}); + + ShopParams copyWith({ + int? id, + }) { + return ShopParams( + id: id ?? this.id, + ); + } +} diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index 4fece1a..272cf33 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -1,8 +1,18 @@ +import 'package:shia_game_flutter/features/awards/presentation/binding/awards_binding.dart'; +import 'package:shia_game_flutter/features/awards/presentation/ui/awards_page.dart'; +import 'package:shia_game_flutter/features/home/presentation/binding/home_binding.dart'; +import 'package:shia_game_flutter/features/home/presentation/pages/home_page.dart'; import 'package:shia_game_flutter/features/intro/presentation/binding/intro_binding.dart'; import 'package:shia_game_flutter/features/intro/presentation/ui/intro_page.dart'; +import 'package:shia_game_flutter/features/master/presentation/binding/master_binding.dart'; +import 'package:shia_game_flutter/features/master/presentation/ui/master_page.dart'; +import 'package:shia_game_flutter/features/profile/presentation/binding/profile_binding.dart'; +import 'package:shia_game_flutter/features/profile/presentation/ui/profile_page.dart'; import 'package:shia_game_flutter/features/sample/presentation/binding/sample_binding.dart'; import 'package:shia_game_flutter/features/sample/presentation/ui/sample_page.dart'; import 'package:get/get.dart'; +import 'package:shia_game_flutter/features/shop/presentation/binding/shop_binding.dart'; +import 'package:shia_game_flutter/features/shop/presentation/ui/shop_page.dart'; class Routes { static const Routes _i = Routes._internal(); @@ -11,6 +21,11 @@ class Routes { static const String samplePage = '/sample_page'; static const String introPage = '/intro_page'; + static const String masterPage = '/'; + static const String homePage = '/home_page'; + static const String shopPage = '/shop_page'; + static const String awardsPage = '/awards_page'; + static const String profilePage = '/profile_page'; } List get appPages => [ @@ -24,4 +39,35 @@ List get appPages => [ page: () => const IntroPage(), binding: IntroBinding(), ), + GetPage( + name: Routes.masterPage, + page: () => const MasterPage(), + binding: MasterBinding(), + children: [ + GetPage( + name: Routes.homePage, + page: () => const HomePage(), + binding: HomeBinding(), + transition: Transition.fadeIn, + ), + GetPage( + name: Routes.shopPage, + page: () => const ShopPage(), + binding: ShopBinding(), + transition: Transition.fadeIn, + ), + GetPage( + name: Routes.awardsPage, + page: () => const AwardsPage(), + binding: AwardsBinding(), + transition: Transition.fadeIn, + ), + GetPage( + name: Routes.profilePage, + page: () => const ProfilePage(), + binding: ProfileBinding(), + transition: Transition.fadeIn, + ), + ], + ), ]; diff --git a/lib/core/widgets/app_bar/master_app_bar.dart b/lib/core/widgets/app_bar/master_app_bar.dart new file mode 100644 index 0000000..483fdcb --- /dev/null +++ b/lib/core/widgets/app_bar/master_app_bar.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/styles/app_bar_action.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/styles/app_bar_add_widget.dart'; + +class MasterAppBar extends StatelessWidget implements PreferredSizeWidget { + const MasterAppBar({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return AppBar( + backgroundColor: context.backgroundColor, + titleSpacing: MySpaces.s30, + title: Row( + children: [ + AppBarAddWidget( + onTap: () {}, + icon: MyAssets.iconDiamond, + number: 999, + gradientColors: [ + Color(0XFF52C3ED), + Color(0XFF4F16A0), + ], + ), + MySpaces.s6.gapWidth, + AppBarAddWidget( + onTap: () {}, + icon: MyAssets.iconFlash, + number: 54, + gradientColors: [ + Color(0XFFEFB345), + Color(0XFF4F16A0), + ], + ), + Spacer(), + AppBarAction( + icon: MyAssets.iconShare, + onTap: () {}, + ), + MySpaces.s12.gapWidth, + AppBarAction( + icon: MyAssets.iconSetting, + onTap: () {}, + ), + ], + ), + ); + } + + @override + Size get preferredSize => Size.fromHeight(kToolbarHeight); +} diff --git a/lib/core/widgets/app_bar/styles/app_bar_action.dart b/lib/core/widgets/app_bar/styles/app_bar_action.dart new file mode 100644 index 0000000..77c0b59 --- /dev/null +++ b/lib/core/widgets/app_bar/styles/app_bar_action.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; + +class AppBarAction extends StatelessWidget { + const AppBarAction({super.key, this.icon, this.onTap}); + + final String? icon; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + borderRadius: BorderRadius.all(Radius.circular(100)), + child: Ink( + width: MySpaces.s32, + height: MySpaces.s32, + padding: EdgeInsets.all(MySpaces.s6), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + width: 1, + color: Color(0XFF6D2ADA), + strokeAlign: BorderSide.strokeAlignInside, + ), + gradient: LinearGradient( + begin: AlignmentDirectional.topStart, + end: AlignmentDirectional.bottomEnd, + colors: [Color(0XFF823FEB), Color(0XFF4F09BF)], + ), + ), + child: MyImage(asset: icon ?? ''), + ), + ); + } +} \ No newline at end of file diff --git a/lib/core/widgets/app_bar/styles/app_bar_add_widget.dart b/lib/core/widgets/app_bar/styles/app_bar_add_widget.dart new file mode 100644 index 0000000..092de31 --- /dev/null +++ b/lib/core/widgets/app_bar/styles/app_bar_add_widget.dart @@ -0,0 +1,77 @@ + +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; + +class AppBarAddWidget extends StatelessWidget { + const AppBarAddWidget({ + super.key, + this.icon, + this.number, + this.onTap, + this.gradientColors, + }); + + final String? icon; + final int? number; + final VoidCallback? onTap; + final List? gradientColors; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + borderRadius: BorderRadius.all(Radius.circular(100)), + child: Ink( + width: 96, + height: 32, + padding: EdgeInsets.all(1), + decoration: ShapeDecoration( + shape: StadiumBorder(), + gradient: LinearGradient( + begin: AlignmentDirectional.topStart, + end: AlignmentDirectional.bottomEnd, + colors: gradientColors ?? [], + ), + ), + child: Ink( + padding: EdgeInsetsDirectional.only( + start: MySpaces.s8, + end: MySpaces.s4, + ), + decoration: ShapeDecoration( + shape: StadiumBorder(), + color: context.backgroundColor, + ), + child: Row( + children: [ + MyImage(asset: icon ?? ''), + Expanded( + child: Text( + '$number', + maxLines: 1, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: Lexend.bold.copyWith(fontSize: 12), + ), + ), + Container( + width: 23, + height: 23, + padding: EdgeInsets.all(MySpaces.s6), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0XFF4F09BF), + ), + child: MyImage(asset: MyAssets.iconPlus), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/core/widgets/bottom_nav_bar/bottom_nav_bar.dart b/lib/core/widgets/bottom_nav_bar/bottom_nav_bar.dart new file mode 100644 index 0000000..307782f --- /dev/null +++ b/lib/core/widgets/bottom_nav_bar/bottom_nav_bar.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart'; +import 'package:get/get_state_manager/src/simple/get_view.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/widgets/bottom_nav_bar/styles/bottom_nav_bar_item.dart'; +import 'package:shia_game_flutter/core/widgets/bottom_nav_bar/styles/bottom_nav_bar_profile_item.dart'; +import 'package:shia_game_flutter/features/master/presentation/controller/master_controller.dart'; + +class BottomNavBar extends GetView { + const BottomNavBar({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + clipBehavior: Clip.none, + padding: EdgeInsets.symmetric( + horizontal: MySpaces.s30 + ), + decoration: BoxDecoration( + gradient: RadialGradient( + radius: 2.5, + colors: [Color(0XFF4F09BF), Color(0XFF250459)], + ), + ), + child: Obx( + () => BottomNavigationBar( + onTap: (int index) => controller.onChangeBottomNavBar(index), + currentIndex: controller.selectedIndex.value, + backgroundColor: Colors.transparent, + elevation: 0, + type: BottomNavigationBarType.fixed, + unselectedFontSize: 8, + selectedFontSize: 8, + unselectedLabelStyle: Lexend.bold, + selectedLabelStyle: Lexend.bold, + showSelectedLabels: false, + showUnselectedLabels: false, + items: List.generate( + controller.bottomNavList.length, + (index) => index == 3 + ? _bottomNavBarProfileItem(index) + : _bottomNavBarItem(index), + ), + ), + ), + ); + } + + BottomNavigationBarItem _bottomNavBarItem(int index) { + return BottomNavigationBarItem( + icon: Opacity( + opacity: 0.7, + child: BottomNavBarItem( + bottomNavEntity: controller.bottomNavList[index], + ), + ), + activeIcon: BottomNavBarItem( + bottomNavEntity: controller.bottomNavList[index], + ), + label: controller.bottomNavList[index].title, + tooltip: controller.bottomNavList[index].title, + ); + } + + BottomNavigationBarItem _bottomNavBarProfileItem(int index) { + return BottomNavigationBarItem( + icon: Opacity( + opacity: 0.7, + child: BottomNavBarProfileItem( + bottomNavEntity: controller.bottomNavList[index], + ), + ), + activeIcon: BottomNavBarProfileItem( + bottomNavEntity: controller.bottomNavList[index], + ), + label: controller.bottomNavList[index].title, + tooltip: controller.bottomNavList[index].title, + ); + } +} diff --git a/lib/core/widgets/bottom_nav_bar/styles/bottom_nav_bar_item.dart b/lib/core/widgets/bottom_nav_bar/styles/bottom_nav_bar_item.dart new file mode 100644 index 0000000..5ffb738 --- /dev/null +++ b/lib/core/widgets/bottom_nav_bar/styles/bottom_nav_bar_item.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; +import 'package:shia_game_flutter/features/master/domain/entity/bottom_nav_entity.dart'; + +class BottomNavBarItem extends StatelessWidget { + const BottomNavBarItem({super.key, required this.bottomNavEntity}); + + final BottomNavEntity bottomNavEntity; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + MyImage(asset: bottomNavEntity.icon ?? ''), + MySpaces.s4.gapHeight, + Text( + bottomNavEntity.title ?? '', + style: Lexend.bold.copyWith(fontSize: MySpaces.s8), + ), + ], + ); + } +} diff --git a/lib/core/widgets/bottom_nav_bar/styles/bottom_nav_bar_profile_item.dart b/lib/core/widgets/bottom_nav_bar/styles/bottom_nav_bar_profile_item.dart new file mode 100644 index 0000000..fe3f58f --- /dev/null +++ b/lib/core/widgets/bottom_nav_bar/styles/bottom_nav_bar_profile_item.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; +import 'package:shia_game_flutter/features/master/domain/entity/bottom_nav_entity.dart'; + +class BottomNavBarProfileItem extends StatelessWidget { + const BottomNavBarProfileItem({super.key, required this.bottomNavEntity}); + + final BottomNavEntity bottomNavEntity; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + height: 26, + width: 26, + padding: EdgeInsets.all(3), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + width: 1, + color: Color(0XFFF4EEFF), + ) + ), + child: MyImage(asset: bottomNavEntity.icon ?? ''), + ), + MySpaces.s4.gapHeight, + Text( + bottomNavEntity.title ?? '', + style: Lexend.bold.copyWith(fontSize: MySpaces.s8), + ), + ], + ); + } +} diff --git a/lib/core/widgets/container/gradient_container.dart b/lib/core/widgets/container/gradient_container.dart new file mode 100644 index 0000000..f7a41d8 --- /dev/null +++ b/lib/core/widgets/container/gradient_container.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; + +class GradientContainer extends StatelessWidget { + const GradientContainer({ + super.key, + this.width, + this.height, + this.margin, + this.padding, + this.shapeBorder, + this.boxShape, + this.borderGradient, + this.borderRadius, + this.boxShadow, + this.color, + this.child, + this.image, + this.gradient, + this.borderColor, + }); + + final double? width; + final double? height; + final EdgeInsetsGeometry? margin; + final EdgeInsetsGeometry? padding; + final ShapeBorder? shapeBorder; + final BoxShape? boxShape; + final Gradient? borderGradient; + final Gradient? gradient; + final BorderRadiusGeometry? borderRadius; + final List? boxShadow; + final Color? color; + final Color? borderColor; + final Widget? child; + final DecorationImage? image; + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(1), + width: width, + height: height, + margin: margin, + decoration: shapeBorder == null + ? BoxDecoration( + shape: boxShape ?? BoxShape.rectangle, + gradient: borderGradient, + borderRadius: borderRadius, + boxShadow: boxShadow, + color: borderColor, + ) + : ShapeDecoration( + shape: shapeBorder!, + gradient: borderGradient, + shadows: boxShadow, + color: borderColor, + ), + child: Container( + padding: padding, + decoration: shapeBorder == null + ? BoxDecoration( + shape: boxShape ?? BoxShape.rectangle, + gradient: gradient, + borderRadius: borderRadius, + color: color, + image: image, + ) + : ShapeDecoration( + shape: shapeBorder!, + gradient: gradient, + color: color, + image: image, + ), + child: child, + ), + ); + } +} diff --git a/lib/features/awards/data/datasource/awards_datasource.dart b/lib/features/awards/data/datasource/awards_datasource.dart new file mode 100644 index 0000000..33ebc37 --- /dev/null +++ b/lib/features/awards/data/datasource/awards_datasource.dart @@ -0,0 +1,28 @@ +import 'package:shia_game_flutter/core/constants/my_api.dart'; +import 'package:shia_game_flutter/core/network/http_request.dart'; +import 'package:shia_game_flutter/core/params/awards_params.dart'; +import 'package:shia_game_flutter/core/response/base_response.dart'; +import 'package:shia_game_flutter/features/awards/data/model/awards_model.dart'; +import 'package:shia_game_flutter/features/awards/domain/entity/awards_entity.dart'; + +abstract class IAwardsDatasource { + Future getData({required AwardsParams params}); +} + +class AwardsDatasourceImpl implements IAwardsDatasource { + final IHttpRequest httpRequest; + + const AwardsDatasourceImpl(this.httpRequest); + + @override + Future getData({required AwardsParams params}) async { + final response = await httpRequest.get( + path: MyApi.baseUrl, + ); + + return BaseResponse.getData( + response?['data'], + (json) => AwardsModel.fromJson(json), + ); + } +} diff --git a/lib/features/awards/data/model/awards_model.dart b/lib/features/awards/data/model/awards_model.dart new file mode 100644 index 0000000..5002ffc --- /dev/null +++ b/lib/features/awards/data/model/awards_model.dart @@ -0,0 +1,13 @@ +import 'package:shia_game_flutter/features/awards/domain/entity/awards_entity.dart'; + +class AwardsModel extends AwardsEntity { + const AwardsModel({ + super.id, + }); + + factory AwardsModel.fromJson(Map json) { + return AwardsModel( + id: json['id'], + ); + } +} diff --git a/lib/features/awards/data/repository_impl/awards_repository_impl.dart b/lib/features/awards/data/repository_impl/awards_repository_impl.dart new file mode 100644 index 0000000..91f3ab9 --- /dev/null +++ b/lib/features/awards/data/repository_impl/awards_repository_impl.dart @@ -0,0 +1,29 @@ +import 'package:flutter/foundation.dart'; +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/awards_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/awards/data/datasource/awards_datasource.dart'; +import 'package:shia_game_flutter/features/awards/domain/entity/awards_entity.dart'; +import 'package:shia_game_flutter/features/awards/domain/repository/awards_repository.dart'; + +class AwardsRepositoryImpl implements IAwardsRepository { + final IAwardsDatasource datasource; + + const AwardsRepositoryImpl(this.datasource); + + @override + Future> getData({required AwardsParams params}) async { + try { + final AwardsEntity response = await datasource.getData(params: params); + return DataState.success(response); + } on MyException catch (e) { + return DataState.error(e); + } catch (e) { + if (kDebugMode) { + rethrow; + } else { + return DataState.error(MyException(errorMessage: '$e')); + } + } + } +} diff --git a/lib/features/awards/domain/entity/awards_entity.dart b/lib/features/awards/domain/entity/awards_entity.dart new file mode 100644 index 0000000..edfb882 --- /dev/null +++ b/lib/features/awards/domain/entity/awards_entity.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + +class AwardsEntity extends Equatable { + final int? id; + + const AwardsEntity({ + this.id, + }); + + @override + List get props => [ + id, + ]; +} diff --git a/lib/features/awards/domain/repository/awards_repository.dart b/lib/features/awards/domain/repository/awards_repository.dart new file mode 100644 index 0000000..4a603d1 --- /dev/null +++ b/lib/features/awards/domain/repository/awards_repository.dart @@ -0,0 +1,8 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/awards_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/awards/domain/entity/awards_entity.dart'; + +abstract class IAwardsRepository { + Future> getData({required AwardsParams params}); +} diff --git a/lib/features/awards/domain/usecases/get_awards_usecase.dart b/lib/features/awards/domain/usecases/get_awards_usecase.dart new file mode 100644 index 0000000..16fdae5 --- /dev/null +++ b/lib/features/awards/domain/usecases/get_awards_usecase.dart @@ -0,0 +1,19 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/awards_params.dart'; +import 'package:shia_game_flutter/core/usecase/usecase.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/awards/domain/entity/awards_entity.dart'; +import 'package:shia_game_flutter/features/awards/domain/repository/awards_repository.dart'; + +class GetAwardsUseCase implements UseCase { + final IAwardsRepository repository; + + const GetAwardsUseCase(this.repository); + + @override + Future> call(AwardsParams params) { + return repository.getData(params: params); + } +} + + diff --git a/lib/features/awards/presentation/binding/awards_binding.dart b/lib/features/awards/presentation/binding/awards_binding.dart new file mode 100644 index 0000000..5609f9c --- /dev/null +++ b/lib/features/awards/presentation/binding/awards_binding.dart @@ -0,0 +1,20 @@ +import 'package:shia_game_flutter/features/awards/presentation/controller/awards_controller.dart'; +import 'package:get/get.dart'; + +class AwardsBinding extends Bindings { + @override + void dependencies() { + Get.put(AwardsController(Get.find()), permanent: true); + } + + Future deleteBindings() async { + await Future.wait([ + Get.delete(), + ]); + } + + Future refreshBinding() async { + await deleteBindings(); + dependencies(); + } +} diff --git a/lib/features/awards/presentation/controller/awards_controller.dart b/lib/features/awards/presentation/controller/awards_controller.dart new file mode 100644 index 0000000..e1b0bb4 --- /dev/null +++ b/lib/features/awards/presentation/controller/awards_controller.dart @@ -0,0 +1,54 @@ +import 'package:flutter/cupertino.dart'; +import 'package:shia_game_flutter/core/params/awards_params.dart'; +import 'package:shia_game_flutter/core/status/base_status.dart'; +import 'package:shia_game_flutter/features/awards/domain/entity/awards_entity.dart'; +import 'package:shia_game_flutter/features/awards/domain/usecases/get_awards_usecase.dart'; +import 'package:get/get.dart'; + +class AwardsController extends GetxController with StateMixin { + /// ----- Constructor ----- + AwardsController(this.getAwardsUseCase); + + @override + void onInit() { + super.onInit(); + change('', status: RxStatus.success()); + } + + @override + void onClose() { + textEditingController.dispose(); + super.onClose(); + } + + /// ----- UseCases ----- + final GetAwardsUseCase getAwardsUseCase; + + /// ----- Variables ----- + final Rx awardsParams = Rx(AwardsParams()); + final Rx awardsEntity = Rx(const AwardsEntity()); + + /// ------ Controllers ------ + final TextEditingController textEditingController = TextEditingController(); + + /// ------ Statuses ------ + final Rx getAwardsStatus = Rx(const BaseInit()); + + /// ------ Functions ------ + + /// ------ Api Calls ------ + Future getAwards() async { + change('', status: RxStatus.loading()); + await getAwardsUseCase(awardsParams.value).then( + (value) => value.fold( + (data) { + awardsEntity.value = data; + change('', status: RxStatus.success()); + }, + (error) { + change('', status: RxStatus.error(error.errorMessage)); + }, + ), + ); + } +} diff --git a/lib/features/awards/presentation/ui/awards_page.dart b/lib/features/awards/presentation/ui/awards_page.dart new file mode 100644 index 0000000..f7d27b5 --- /dev/null +++ b/lib/features/awards/presentation/ui/awards_page.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/features/awards/presentation/controller/awards_controller.dart'; +import 'package:get/get.dart'; + +class AwardsPage extends GetView { + const AwardsPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center( + child: Text('Awards Page'), + ); + } +} diff --git a/lib/features/home/data/datasource/home_datasource.dart b/lib/features/home/data/datasource/home_datasource.dart new file mode 100644 index 0000000..5cb70c4 --- /dev/null +++ b/lib/features/home/data/datasource/home_datasource.dart @@ -0,0 +1,28 @@ +import 'package:shia_game_flutter/core/constants/my_api.dart'; +import 'package:shia_game_flutter/core/network/http_request.dart'; +import 'package:shia_game_flutter/core/params/home_params.dart'; +import 'package:shia_game_flutter/core/response/base_response.dart'; +import 'package:shia_game_flutter/features/home/data/model/home_model.dart'; +import 'package:shia_game_flutter/features/home/domain/entity/home_entity.dart'; + +abstract class IHomeDatasource { + Future getData({required HomeParams params}); +} + +class HomeDatasourceImpl implements IHomeDatasource { + final IHttpRequest httpRequest; + + const HomeDatasourceImpl(this.httpRequest); + + @override + Future getData({required HomeParams params}) async { + final response = await httpRequest.get( + path: MyApi.baseUrl, + ); + + return BaseResponse.getData( + response?['data'], + (json) => HomeModel.fromJson(json), + ); + } +} diff --git a/lib/features/home/data/model/home_model.dart b/lib/features/home/data/model/home_model.dart new file mode 100644 index 0000000..b1d2b84 --- /dev/null +++ b/lib/features/home/data/model/home_model.dart @@ -0,0 +1,13 @@ +import 'package:shia_game_flutter/features/home/domain/entity/home_entity.dart'; + +class HomeModel extends HomeEntity { + const HomeModel({ + super.id, + }); + + factory HomeModel.fromJson(Map json) { + return HomeModel( + id: json['id'], + ); + } +} diff --git a/lib/features/home/data/repository_impl/home_repository_impl.dart b/lib/features/home/data/repository_impl/home_repository_impl.dart new file mode 100644 index 0000000..203d244 --- /dev/null +++ b/lib/features/home/data/repository_impl/home_repository_impl.dart @@ -0,0 +1,29 @@ +import 'package:flutter/foundation.dart'; +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/home_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/home/data/datasource/home_datasource.dart'; +import 'package:shia_game_flutter/features/home/domain/entity/home_entity.dart'; +import 'package:shia_game_flutter/features/home/domain/repository/home_repository.dart'; + +class HomeRepositoryImpl implements IHomeRepository { + final IHomeDatasource datasource; + + const HomeRepositoryImpl(this.datasource); + + @override + Future> getData({required HomeParams params}) async { + try { + final HomeEntity response = await datasource.getData(params: params); + return DataState.success(response); + } on MyException catch (e) { + return DataState.error(e); + } catch (e) { + if (kDebugMode) { + rethrow; + } else { + return DataState.error(MyException(errorMessage: '$e')); + } + } + } +} diff --git a/lib/features/home/domain/entity/home_entity.dart b/lib/features/home/domain/entity/home_entity.dart new file mode 100644 index 0000000..582723c --- /dev/null +++ b/lib/features/home/domain/entity/home_entity.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + +class HomeEntity extends Equatable { + final int? id; + + const HomeEntity({ + this.id, + }); + + @override + List get props => [ + id, + ]; +} diff --git a/lib/features/home/domain/repository/home_repository.dart b/lib/features/home/domain/repository/home_repository.dart new file mode 100644 index 0000000..71709c3 --- /dev/null +++ b/lib/features/home/domain/repository/home_repository.dart @@ -0,0 +1,8 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/home_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/home/domain/entity/home_entity.dart'; + +abstract class IHomeRepository { + Future> getData({required HomeParams params}); +} diff --git a/lib/features/home/domain/usecases/get_home_usecase.dart b/lib/features/home/domain/usecases/get_home_usecase.dart new file mode 100644 index 0000000..dc2ad83 --- /dev/null +++ b/lib/features/home/domain/usecases/get_home_usecase.dart @@ -0,0 +1,17 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/home_params.dart'; +import 'package:shia_game_flutter/core/usecase/usecase.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/home/domain/entity/home_entity.dart'; +import 'package:shia_game_flutter/features/home/domain/repository/home_repository.dart'; + +class GetHomeUseCase implements UseCase { + final IHomeRepository repository; + + const GetHomeUseCase(this.repository); + + @override + Future> call(HomeParams params) { + return repository.getData(params: params); + } +} diff --git a/lib/features/home/presentation/binding/home_binding.dart b/lib/features/home/presentation/binding/home_binding.dart new file mode 100644 index 0000000..51d91de --- /dev/null +++ b/lib/features/home/presentation/binding/home_binding.dart @@ -0,0 +1,9 @@ +import 'package:shia_game_flutter/features/home/presentation/controller/home_controller.dart'; +import 'package:get/get.dart'; + +class HomeBinding extends Bindings { + @override + void dependencies() { + Get.put(HomeController(Get.find()), permanent: true); + } +} diff --git a/lib/features/home/presentation/controller/home_controller.dart b/lib/features/home/presentation/controller/home_controller.dart new file mode 100644 index 0000000..ce21b15 --- /dev/null +++ b/lib/features/home/presentation/controller/home_controller.dart @@ -0,0 +1,54 @@ +import 'package:flutter/cupertino.dart'; +import 'package:get/get.dart'; +import 'package:shia_game_flutter/core/params/home_params.dart'; +import 'package:shia_game_flutter/core/status/base_status.dart'; +import 'package:shia_game_flutter/features/home/domain/entity/home_entity.dart'; +import 'package:shia_game_flutter/features/home/domain/usecases/get_home_usecase.dart'; + +class HomeController extends GetxController with StateMixin { + /// ----- Constructor ----- + HomeController(this.getHomeUseCase); + + @override + void onInit() { + super.onInit(); + change('', status: RxStatus.success()); + } + + @override + void onClose() { + textEditingController.dispose(); + super.onClose(); + } + + /// ----- UseCases ----- + final GetHomeUseCase getHomeUseCase; + + /// ----- Variables ----- + final Rx homeParams = Rx(HomeParams()); + final Rx homeEntity = Rx(const HomeEntity()); + + /// ------ Controllers ------ + final TextEditingController textEditingController = TextEditingController(); + + /// ------ Statuses ------ + final Rx getHomeStatus = Rx(const BaseInit()); + + /// ------ Functions ------ + + /// ------ Api Calls ------ + Future getHome() async { + change('', status: RxStatus.loading()); + await getHomeUseCase(homeParams.value).then( + (value) => value.fold( + (data) { + homeEntity.value = data; + change('', status: RxStatus.success()); + }, + (error) { + change('', status: RxStatus.error(error.errorMessage)); + }, + ), + ); + } +} diff --git a/lib/features/home/presentation/pages/home_page.dart b/lib/features/home/presentation/pages/home_page.dart new file mode 100644 index 0000000..fc404e1 --- /dev/null +++ b/lib/features/home/presentation/pages/home_page.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart' hide BoxShadow, BoxDecoration; +import 'package:get/get.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; +import 'package:shia_game_flutter/features/home/presentation/controller/home_controller.dart'; +import 'package:shia_game_flutter/features/home/presentation/pages/widgets/home_battle_cast.dart'; +import 'package:shia_game_flutter/features/home/presentation/pages/widgets/home_battle_league.dart'; +import 'package:shia_game_flutter/features/home/presentation/pages/widgets/home_custom_widget.dart'; +import 'package:shia_game_flutter/features/home/presentation/pages/widgets/home_membership.dart'; + +class HomePage extends GetView { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: MySpaces.s32), + child: Column( + children: [ + MySpaces.s28.gapHeight, + MyImage(asset: MyAssets.shiaMindGroup), + MySpaces.s40.gapHeight, + HomeMembership(), + HomeBattleLeague(), + MySpaces.s20.gapHeight, + _customWidgets(), + MySpaces.s20.gapHeight, + HomeBattleCast(), + ], + ), + ); + } + + Widget _customWidgets() { + return Row( + spacing: MySpaces.s22, + children: [ + Expanded( + child: HomeCustomWidget( + type: CustomWidgetType.customLeague, + firstText: 'ongoing:', + secondText: + 'Saba Center League - Imam Hassan ministry London school', + ), + ), + Expanded( + child: HomeCustomWidget( + type: CustomWidgetType.friendBattle, + firstText: 'online:', + secondText: 'No one\'s online', + ), + ), + ], + ); + } +} diff --git a/lib/features/home/presentation/pages/widgets/home_battle_cast.dart b/lib/features/home/presentation/pages/widgets/home_battle_cast.dart new file mode 100644 index 0000000..2cd7d8f --- /dev/null +++ b/lib/features/home/presentation/pages/widgets/home_battle_cast.dart @@ -0,0 +1,136 @@ +import 'package:flutter/material.dart' hide BoxDecoration, BoxShadow; +import 'package:flutter_inset_box_shadow_update/flutter_inset_box_shadow_update.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/container/gradient_container.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; + +class HomeBattleCast extends StatelessWidget { + const HomeBattleCast({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + clipBehavior: Clip.none, + children: [ + GradientContainer( + height: 120, + borderRadius: BorderRadiusDirectional.all(Radius.circular(MySpaces.s20)), + borderGradient: LinearGradient( + begin: AlignmentDirectional.topCenter, + end: AlignmentDirectional.bottomCenter, + colors: [Color(0XFF567EFF), Color(0XFF304DB8)], + ), + gradient: RadialGradient( + radius: 1, + center: Alignment(-0.5, -1), + colors: [Color(0XFF104CBA).withValues(alpha: 0.2), Color(0XFF104CBA)], + ), + padding: EdgeInsets.all(MySpaces.s10), + image: DecorationImage( + image: AssetImage(MyAssets.addBackground), + repeat: ImageRepeat.repeat, + colorFilter: ColorFilter.mode( + Colors.black.withValues(alpha: 0.02), + BlendMode.srcIn, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ShaderMask( + blendMode: BlendMode.modulate, + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFFFFFFFF), Color(0XFFE4E3FF)], + ).createShader(bounds), + child: Text( + 'Battle Cast', + style: Lexend.extraBold.copyWith( + fontSize: 22, + shadows: [ + BoxShadow( + color: Color(0xFF3C38C4), + blurRadius: 0.52, + offset: Offset(0, 1.04), + spreadRadius: 0, + ), + ], + ), + ), + ), + MySpaces.s10.gapHeight, + Container( + padding: EdgeInsets.all(5), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8)), + color: Color(0XFF203689), + boxShadow: [ + BoxShadow( + color: Color(0XFF000000).withValues(alpha: 0.3), + blurRadius: 3, + offset: Offset(0, 2), + inset: true, + ), + ], + ), + child: Text( + 'Sheikh.Sadra VS Ali Masoudi (online) - Sheikh.Sadra number tow VS Ali Masoudi tabar (tomorrow)', + maxLines: 1, + style: Lexend.semiBold.copyWith( + fontSize: 8, + color: Color(0XFFB6B3FF), + ), + ), + ), + ], + ), + ), + PositionedDirectional( + start: -1, + top: -MySpaces.s4, + child: GradientContainer( + color: Color(0XFFCC9B22), + padding: EdgeInsets.symmetric( + vertical: MySpaces.s2, + horizontal: MySpaces.s8, + ), + borderRadius: BorderRadiusDirectional.only( + topStart: Radius.circular(6), + topEnd: Radius.circular(6), + bottomStart: Radius.circular(0), + bottomEnd: Radius.circular(6), + ), + child: Text( + '2 New', + style: Lexend.extraBold.copyWith( + fontSize: 11, + ), + ), + ), + ), + PositionedDirectional( + end: MySpaces.s20, + top: -MySpaces.s10, + child: Row( + children: [ + MyImage( + asset: MyAssets.mic, + ), + MyImage( + asset: MyAssets.micBLur, + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/features/home/presentation/pages/widgets/home_battle_league.dart b/lib/features/home/presentation/pages/widgets/home_battle_league.dart new file mode 100644 index 0000000..aac63c7 --- /dev/null +++ b/lib/features/home/presentation/pages/widgets/home_battle_league.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/utils/screen_size.dart'; +import 'package:shia_game_flutter/core/widgets/container/gradient_container.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; + +class HomeBattleLeague extends StatelessWidget { + const HomeBattleLeague({super.key}); + + @override + Widget build(BuildContext context) { + return Stack( + alignment: AlignmentDirectional.bottomEnd, + children: [ + GradientContainer( + width: context.widthScreen, + height: 120, + padding: EdgeInsets.symmetric( + horizontal: MySpaces.s12, + vertical: MySpaces.s16, + ), + borderGradient: LinearGradient( + begin: AlignmentDirectional.centerStart, + end: AlignmentDirectional.centerEnd, + colors: [Color(0XFF3A0A85), Color(0XFF6C2ECD)], + ), + gradient: LinearGradient( + begin: AlignmentDirectional.centerStart, + end: AlignmentDirectional.centerEnd, + colors: [Color(0XFF3A0D83), Color(0XFF4F09BF)], + ), + borderRadius: BorderRadius.all(Radius.circular(20)), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ShaderMask( + blendMode: BlendMode.modulate, + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFFFFFFFF), Color(0XFFCAA8FF)], + ).createShader(bounds), + child: Text( + 'Battle League', + style: Lexend.extraBold.copyWith( + fontSize: 22, + shadows: [ + BoxShadow( + color: Color(0xFF3E1381), + blurRadius: 0.84, + offset: Offset(0, 1.69), + spreadRadius: 0, + ), + ], + ), + ), + ), + Text( + 'The faster you answer, the winner', + style: Lexend.medium.copyWith( + fontSize: 10, + color: Color(0XFFA183D2), + ), + ), + ], + ), + ), + MyImage(asset: MyAssets.cup), + ], + ); + } +} diff --git a/lib/features/home/presentation/pages/widgets/home_custom_widget.dart b/lib/features/home/presentation/pages/widgets/home_custom_widget.dart new file mode 100644 index 0000000..dc8853e --- /dev/null +++ b/lib/features/home/presentation/pages/widgets/home_custom_widget.dart @@ -0,0 +1,191 @@ +import 'package:flutter/material.dart' hide BoxDecoration, BoxShadow; +import 'package:flutter_inset_box_shadow_update/flutter_inset_box_shadow_update.dart'; +import 'package:get/get.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/utils/my_localization.dart'; +import 'package:shia_game_flutter/core/utils/screen_size.dart'; +import 'package:shia_game_flutter/core/widgets/container/gradient_container.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; + +enum CustomWidgetType { + customLeague, + friendBattle; + + static Map get borderGradient => { + CustomWidgetType.customLeague: LinearGradient( + begin: AlignmentDirectional.topCenter, + end: AlignmentDirectional.bottomCenter, + colors: [Color(0XFF4BAD42), Color(0XFF147743)], + ), + CustomWidgetType.friendBattle: LinearGradient( + begin: AlignmentDirectional.topCenter, + end: AlignmentDirectional.bottomCenter, + colors: [Color(0XFFED9851), Color(0XFFC77041)], + ), + }; + + static Map get gradient => { + CustomWidgetType.customLeague: RadialGradient( + radius: 0.7, + center: Alignment(-0.6, -0.8), + colors: [Color(0XFF58AE23), Color(0XFF066A36)], + ), + CustomWidgetType.friendBattle: RadialGradient( + radius: 0.7, + center: Alignment(-0.6, -0.8), + colors: [Color(0XFFE99E53), Color(0XFFBC673A)], + ), + }; + + static Map get image => { + CustomWidgetType.customLeague: MyAssets.medal, + CustomWidgetType.friendBattle: MyAssets.friendBattle, + }; + + static Map get containerColor => { + CustomWidgetType.customLeague: Color(0XFF05542B), + CustomWidgetType.friendBattle: Color(0XFFA45A31), + }; + + static Map get firstTextColor => { + CustomWidgetType.customLeague: Color(0XFF4FDF94), + CustomWidgetType.friendBattle: Color(0XFFE3DFD5), + }; + + static Map get secondTextColor => { + CustomWidgetType.customLeague: Color(0XFF85C9A6), + CustomWidgetType.friendBattle: Color(0XFFDFBC9D), + }; + + static Map get title => { + CustomWidgetType.customLeague: ShaderMask( + blendMode: BlendMode.modulate, + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFFFFFFFF), Color(0XFFFFFFFF), Color(0XFFBEF8DA)], + ).createShader(bounds), + child: Text( + Get.context?.translate.custom_league ?? '', + style: Lexend.extraBold.copyWith( + fontSize: 14, + shadows: [ + BoxShadow( + color: Color(0xFF07592F), + blurRadius: 0.52, + offset: Offset(0, 1.04), + spreadRadius: 0, + ), + ], + ), + ), + ), + CustomWidgetType.friendBattle: ShaderMask( + blendMode: BlendMode.modulate, + shaderCallback: (bounds) => LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFFFFFFFF), Color(0XFFFFFFFF), Color(0XFFFFB994)], + ).createShader(bounds), + child: Text( + Get.context?.translate.friends_battle ?? '', + style: Lexend.extraBold.copyWith( + fontSize: 14, + shadows: [ + BoxShadow( + color: Color(0xFFAA5B31), + blurRadius: 0.52, + offset: Offset(0, 1.04), + spreadRadius: 0, + ), + ], + ), + ), + ), + }; +} + +class HomeCustomWidget extends StatelessWidget { + const HomeCustomWidget({ + super.key, + this.type = CustomWidgetType.customLeague, + this.firstText, + this.secondText, + }); + + final CustomWidgetType type; + final String? firstText; + final String? secondText; + + @override + Widget build(BuildContext context) { + return GradientContainer( + height: 130, + borderRadius: BorderRadius.all(Radius.circular(20)), + borderGradient: CustomWidgetType.borderGradient[type], + gradient: CustomWidgetType.gradient[type], + image: DecorationImage( + image: AssetImage(MyAssets.addBackground), + repeat: ImageRepeat.repeat, + colorFilter: ColorFilter.mode( + Colors.black.withValues(alpha: 0.02), + BlendMode.srcIn, + ), + ), + padding: EdgeInsets.all(MySpaces.s10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: AlignmentDirectional.centerEnd, + child: MyImage(asset: CustomWidgetType.image[type] ?? '',), + ), + Spacer(), + CustomWidgetType.title[type] ?? SizedBox.shrink(), + MySpaces.s10.gapHeight, + Container( + padding: EdgeInsets.all(5), + width: context.widthScreen, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8)), + color: CustomWidgetType.containerColor[type], + boxShadow: [ + BoxShadow( + color: Color(0XFF000000).withValues(alpha: 0.3), + blurRadius: 3, + offset: Offset(0, 2), + inset: true, + ), + ], + ), + child: Text.rich( + maxLines: 1, + overflow: TextOverflow.ellipsis, + TextSpan( + children: [ + TextSpan( + text: firstText, + style: Lexend.semiBold.copyWith( + fontSize: 8, + color: CustomWidgetType.firstTextColor[type], + ), + ), + TextSpan( + text: ' $secondText', + style: Lexend.semiBold.copyWith( + fontSize: 8, + color: CustomWidgetType.secondTextColor[type], + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/features/home/presentation/pages/widgets/home_membership.dart b/lib/features/home/presentation/pages/widgets/home_membership.dart new file mode 100644 index 0000000..a575d0a --- /dev/null +++ b/lib/features/home/presentation/pages/widgets/home_membership.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/utils/my_localization.dart'; +import 'package:shia_game_flutter/core/utils/screen_size.dart'; +import 'package:shia_game_flutter/core/widgets/container/gradient_container.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; + +class HomeMembership extends StatelessWidget { + const HomeMembership({super.key}); + + @override + Widget build(BuildContext context) { + return GradientContainer( + width: context.widthScreen, + color: context.backgroundColor, + borderGradient: LinearGradient( + begin: AlignmentDirectional.topStart, + end: AlignmentDirectional.bottomEnd, + colors: [ + Color(0XFFDE8B4D).withValues(alpha: 0.3), + Color(0XFFDE8B4D).withValues(alpha: 0.05), + ], + ), + borderRadius: BorderRadius.all(Radius.circular(MySpaces.s20)), + boxShadow: [ + BoxShadow( + color: Color(0x3F000000), + blurRadius: 17, + offset: Offset(0, 4), + spreadRadius: 20, + ), + ], + padding: EdgeInsets.symmetric(horizontal: MySpaces.s16, vertical: 13), + child: Row( + children: [ + MyImage(asset: MyAssets.iconCrown), + MySpaces.s8.gapWidth, + Text( + context.translate.pro_membership, + style: Lexend.semiBold.copyWith( + fontSize: 12, + color: Color(0XFFFCC230), + ), + ), + Spacer(), + MyImage(asset: MyAssets.iconClock), + MySpaces.s6.gapWidth, + Text('125d 4h', style: Lexend.semiBold.copyWith(fontSize: 12)), + ], + ), + ); + } +} diff --git a/lib/features/intro/presentation/ui/intro_page.dart b/lib/features/intro/presentation/ui/intro_page.dart index c965cea..175925c 100644 --- a/lib/features/intro/presentation/ui/intro_page.dart +++ b/lib/features/intro/presentation/ui/intro_page.dart @@ -16,7 +16,7 @@ class IntroPage extends GetView { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: context.introBackgroundColor, + backgroundColor: context.backgroundColor, body: SafeArea( child: SizedBox.expand( child: Stack( diff --git a/lib/features/master/data/datasource/master_datasource.dart b/lib/features/master/data/datasource/master_datasource.dart new file mode 100644 index 0000000..b7d83ac --- /dev/null +++ b/lib/features/master/data/datasource/master_datasource.dart @@ -0,0 +1,28 @@ +import 'package:shia_game_flutter/core/constants/my_api.dart'; +import 'package:shia_game_flutter/core/network/http_request.dart'; +import 'package:shia_game_flutter/core/params/master_params.dart'; +import 'package:shia_game_flutter/core/response/base_response.dart'; +import 'package:shia_game_flutter/features/master/data/model/master_model.dart'; +import 'package:shia_game_flutter/features/master/domain/entity/master_entity.dart'; + +abstract class IMasterDatasource { + Future getData({required MasterParams params}); +} + +class MasterDatasourceImpl implements IMasterDatasource { + final IHttpRequest httpRequest; + + const MasterDatasourceImpl(this.httpRequest); + + @override + Future getData({required MasterParams params}) async { + final response = await httpRequest.get( + path: MyApi.baseUrl, + ); + + return BaseResponse.getData( + response?['data'], + (json) => MasterModel.fromJson(json), + ); + } +} diff --git a/lib/features/master/data/model/master_model.dart b/lib/features/master/data/model/master_model.dart new file mode 100644 index 0000000..9fe433e --- /dev/null +++ b/lib/features/master/data/model/master_model.dart @@ -0,0 +1,13 @@ +import 'package:shia_game_flutter/features/master/domain/entity/master_entity.dart'; + +class MasterModel extends MasterEntity { + const MasterModel({ + super.id, + }); + + factory MasterModel.fromJson(Map json) { + return MasterModel( + id: json['id'], + ); + } +} diff --git a/lib/features/master/data/repository_impl/master_repository_impl.dart b/lib/features/master/data/repository_impl/master_repository_impl.dart new file mode 100644 index 0000000..059428f --- /dev/null +++ b/lib/features/master/data/repository_impl/master_repository_impl.dart @@ -0,0 +1,29 @@ +import 'package:flutter/foundation.dart'; +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/master_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/master/data/datasource/master_datasource.dart'; +import 'package:shia_game_flutter/features/master/domain/entity/master_entity.dart'; +import 'package:shia_game_flutter/features/master/domain/repository/master_repository.dart'; + +class MasterRepositoryImpl implements IMasterRepository { + final IMasterDatasource datasource; + + const MasterRepositoryImpl(this.datasource); + + @override + Future> getData({required MasterParams params}) async { + try { + final MasterEntity response = await datasource.getData(params: params); + return DataState.success(response); + } on MyException catch (e) { + return DataState.error(e); + } catch (e) { + if (kDebugMode) { + rethrow; + } else { + return DataState.error(MyException(errorMessage: '$e')); + } + } + } +} diff --git a/lib/features/master/domain/entity/bottom_nav_entity.dart b/lib/features/master/domain/entity/bottom_nav_entity.dart new file mode 100644 index 0000000..76f20b7 --- /dev/null +++ b/lib/features/master/domain/entity/bottom_nav_entity.dart @@ -0,0 +1,12 @@ +import 'package:equatable/equatable.dart'; + +class BottomNavEntity extends Equatable { + final String? icon; + final String? title; + final String? route; + + const BottomNavEntity({this.icon, this.title, this.route}); + + @override + List get props => [icon, title, route]; +} diff --git a/lib/features/master/domain/entity/master_entity.dart b/lib/features/master/domain/entity/master_entity.dart new file mode 100644 index 0000000..b4e7f6b --- /dev/null +++ b/lib/features/master/domain/entity/master_entity.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + +class MasterEntity extends Equatable { + final int? id; + + const MasterEntity({ + this.id, + }); + + @override + List get props => [ + id, + ]; +} diff --git a/lib/features/master/domain/repository/master_repository.dart b/lib/features/master/domain/repository/master_repository.dart new file mode 100644 index 0000000..ab66cae --- /dev/null +++ b/lib/features/master/domain/repository/master_repository.dart @@ -0,0 +1,8 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/master_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/master/domain/entity/master_entity.dart'; + +abstract class IMasterRepository { + Future> getData({required MasterParams params}); +} diff --git a/lib/features/master/domain/usecases/get_master_usecase.dart b/lib/features/master/domain/usecases/get_master_usecase.dart new file mode 100644 index 0000000..601780d --- /dev/null +++ b/lib/features/master/domain/usecases/get_master_usecase.dart @@ -0,0 +1,19 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/master_params.dart'; +import 'package:shia_game_flutter/core/usecase/usecase.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/master/domain/entity/master_entity.dart'; +import 'package:shia_game_flutter/features/master/domain/repository/master_repository.dart'; + +class GetMasterUseCase implements UseCase { + final IMasterRepository repository; + + const GetMasterUseCase(this.repository); + + @override + Future> call(MasterParams params) { + return repository.getData(params: params); + } +} + + diff --git a/lib/features/master/presentation/binding/master_binding.dart b/lib/features/master/presentation/binding/master_binding.dart new file mode 100644 index 0000000..53c1ba8 --- /dev/null +++ b/lib/features/master/presentation/binding/master_binding.dart @@ -0,0 +1,20 @@ +import 'package:shia_game_flutter/features/master/presentation/controller/master_controller.dart'; +import 'package:get/get.dart'; + +class MasterBinding extends Bindings { + @override + void dependencies() { + Get.put(MasterController(Get.find())); + } + + Future deleteBindings() async { + await Future.wait([ + Get.delete(), + ]); + } + + Future refreshBinding() async { + await deleteBindings(); + dependencies(); + } +} diff --git a/lib/features/master/presentation/controller/master_controller.dart b/lib/features/master/presentation/controller/master_controller.dart new file mode 100644 index 0000000..ba31280 --- /dev/null +++ b/lib/features/master/presentation/controller/master_controller.dart @@ -0,0 +1,85 @@ +import 'package:flutter/cupertino.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/core/params/master_params.dart'; +import 'package:shia_game_flutter/core/routers/my_routes.dart'; +import 'package:shia_game_flutter/core/status/base_status.dart'; +import 'package:shia_game_flutter/core/utils/my_localization.dart'; +import 'package:shia_game_flutter/features/master/domain/entity/bottom_nav_entity.dart'; +import 'package:shia_game_flutter/features/master/domain/entity/master_entity.dart'; +import 'package:shia_game_flutter/features/master/domain/usecases/get_master_usecase.dart'; +import 'package:get/get.dart'; + +class MasterController extends GetxController with StateMixin { + /// ----- Constructor ----- + MasterController(this.getMasterUseCase); + + @override + void onInit() { + super.onInit(); + change('', status: RxStatus.success()); + } + + @override + void onClose() { + textEditingController.dispose(); + super.onClose(); + } + + /// ----- UseCases ----- + final GetMasterUseCase getMasterUseCase; + + /// ----- Variables ----- + final Rx masterParams = Rx(MasterParams()); + final Rx masterEntity = Rx(const MasterEntity()); + final List bottomNavList = [ + BottomNavEntity( + icon: MyAssets.iconHome, + title: Get.context?.translate.home, + route: Routes.homePage, + ), + BottomNavEntity( + icon: MyAssets.iconShop, + title: Get.context?.translate.shop, + route: Routes.shopPage, + ), + BottomNavEntity( + icon: MyAssets.iconAwards, + title: Get.context?.translate.awards, + route: Routes.awardsPage, + ), + BottomNavEntity( + icon: MyAssets.iconProfile, + title: Get.context?.translate.profile, + route: Routes.profilePage, + ), + ]; + final Rx selectedIndex = Rx(0); + + /// ------ Controllers ------ + final TextEditingController textEditingController = TextEditingController(); + + /// ------ Statuses ------ + final Rx getMasterStatus = Rx(const BaseInit()); + + /// ------ Functions ------ + void onChangeBottomNavBar(int index) { + selectedIndex.value = index; + Get.rootDelegate.toNamed(bottomNavList[index].route ?? ''); + } + + /// ------ Api Calls ------ + Future getMaster() async { + change('', status: RxStatus.loading()); + await getMasterUseCase(masterParams.value).then( + (value) => value.fold( + (data) { + masterEntity.value = data; + change('', status: RxStatus.success()); + }, + (error) { + change('', status: RxStatus.error(error.errorMessage)); + }, + ), + ); + } +} diff --git a/lib/features/master/presentation/ui/master_page.dart b/lib/features/master/presentation/ui/master_page.dart new file mode 100644 index 0000000..4866d68 --- /dev/null +++ b/lib/features/master/presentation/ui/master_page.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; +import 'package:shia_game_flutter/core/routers/my_routes.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/master_app_bar.dart'; +import 'package:shia_game_flutter/core/widgets/bottom_nav_bar/bottom_nav_bar.dart'; +import 'package:shia_game_flutter/features/master/presentation/controller/master_controller.dart'; +import 'package:get/get.dart'; + +class MasterPage extends GetView { + const MasterPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: context.backgroundColor, + appBar: MasterAppBar(), + bottomNavigationBar: BottomNavBar(), + body: GetRouterOutlet( + initialRoute: Routes.homePage, + anchorRoute: Routes.masterPage, + delegate: Get.rootDelegate, + ), + ); + } +} diff --git a/lib/features/profile/data/datasource/profile_datasource.dart b/lib/features/profile/data/datasource/profile_datasource.dart new file mode 100644 index 0000000..00cab8f --- /dev/null +++ b/lib/features/profile/data/datasource/profile_datasource.dart @@ -0,0 +1,28 @@ +import 'package:shia_game_flutter/core/constants/my_api.dart'; +import 'package:shia_game_flutter/core/network/http_request.dart'; +import 'package:shia_game_flutter/core/params/profile_params.dart'; +import 'package:shia_game_flutter/core/response/base_response.dart'; +import 'package:shia_game_flutter/features/profile/data/model/profile_model.dart'; +import 'package:shia_game_flutter/features/profile/domain/entity/profile_entity.dart'; + +abstract class IProfileDatasource { + Future getData({required ProfileParams params}); +} + +class ProfileDatasourceImpl implements IProfileDatasource { + final IHttpRequest httpRequest; + + const ProfileDatasourceImpl(this.httpRequest); + + @override + Future getData({required ProfileParams params}) async { + final response = await httpRequest.get( + path: MyApi.baseUrl, + ); + + return BaseResponse.getData( + response?['data'], + (json) => ProfileModel.fromJson(json), + ); + } +} diff --git a/lib/features/profile/data/model/profile_model.dart b/lib/features/profile/data/model/profile_model.dart new file mode 100644 index 0000000..cc17c4b --- /dev/null +++ b/lib/features/profile/data/model/profile_model.dart @@ -0,0 +1,13 @@ +import 'package:shia_game_flutter/features/profile/domain/entity/profile_entity.dart'; + +class ProfileModel extends ProfileEntity { + const ProfileModel({ + super.id, + }); + + factory ProfileModel.fromJson(Map json) { + return ProfileModel( + id: json['id'], + ); + } +} diff --git a/lib/features/profile/data/repository_impl/profile_repository_impl.dart b/lib/features/profile/data/repository_impl/profile_repository_impl.dart new file mode 100644 index 0000000..bdbcaa1 --- /dev/null +++ b/lib/features/profile/data/repository_impl/profile_repository_impl.dart @@ -0,0 +1,29 @@ +import 'package:flutter/foundation.dart'; +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/profile_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/profile/data/datasource/profile_datasource.dart'; +import 'package:shia_game_flutter/features/profile/domain/entity/profile_entity.dart'; +import 'package:shia_game_flutter/features/profile/domain/repository/profile_repository.dart'; + +class ProfileRepositoryImpl implements IProfileRepository { + final IProfileDatasource datasource; + + const ProfileRepositoryImpl(this.datasource); + + @override + Future> getData({required ProfileParams params}) async { + try { + final ProfileEntity response = await datasource.getData(params: params); + return DataState.success(response); + } on MyException catch (e) { + return DataState.error(e); + } catch (e) { + if (kDebugMode) { + rethrow; + } else { + return DataState.error(MyException(errorMessage: '$e')); + } + } + } +} diff --git a/lib/features/profile/domain/entity/profile_entity.dart b/lib/features/profile/domain/entity/profile_entity.dart new file mode 100644 index 0000000..3d7155b --- /dev/null +++ b/lib/features/profile/domain/entity/profile_entity.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + +class ProfileEntity extends Equatable { + final int? id; + + const ProfileEntity({ + this.id, + }); + + @override + List get props => [ + id, + ]; +} diff --git a/lib/features/profile/domain/repository/profile_repository.dart b/lib/features/profile/domain/repository/profile_repository.dart new file mode 100644 index 0000000..75a2c82 --- /dev/null +++ b/lib/features/profile/domain/repository/profile_repository.dart @@ -0,0 +1,8 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/profile_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/profile/domain/entity/profile_entity.dart'; + +abstract class IProfileRepository { + Future> getData({required ProfileParams params}); +} diff --git a/lib/features/profile/domain/usecases/get_profile_usecase.dart b/lib/features/profile/domain/usecases/get_profile_usecase.dart new file mode 100644 index 0000000..cb7422a --- /dev/null +++ b/lib/features/profile/domain/usecases/get_profile_usecase.dart @@ -0,0 +1,19 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/profile_params.dart'; +import 'package:shia_game_flutter/core/usecase/usecase.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/profile/domain/entity/profile_entity.dart'; +import 'package:shia_game_flutter/features/profile/domain/repository/profile_repository.dart'; + +class GetProfileUseCase implements UseCase { + final IProfileRepository repository; + + const GetProfileUseCase(this.repository); + + @override + Future> call(ProfileParams params) { + return repository.getData(params: params); + } +} + + diff --git a/lib/features/profile/presentation/binding/profile_binding.dart b/lib/features/profile/presentation/binding/profile_binding.dart new file mode 100644 index 0000000..e10d983 --- /dev/null +++ b/lib/features/profile/presentation/binding/profile_binding.dart @@ -0,0 +1,20 @@ +import 'package:shia_game_flutter/features/profile/presentation/controller/profile_controller.dart'; +import 'package:get/get.dart'; + +class ProfileBinding extends Bindings { + @override + void dependencies() { + Get.put(ProfileController(Get.find()), permanent: true); + } + + Future deleteBindings() async { + await Future.wait([ + Get.delete(), + ]); + } + + Future refreshBinding() async { + await deleteBindings(); + dependencies(); + } +} diff --git a/lib/features/profile/presentation/controller/profile_controller.dart b/lib/features/profile/presentation/controller/profile_controller.dart new file mode 100644 index 0000000..c66df30 --- /dev/null +++ b/lib/features/profile/presentation/controller/profile_controller.dart @@ -0,0 +1,54 @@ +import 'package:flutter/cupertino.dart'; +import 'package:shia_game_flutter/core/params/profile_params.dart'; +import 'package:shia_game_flutter/core/status/base_status.dart'; +import 'package:shia_game_flutter/features/profile/domain/entity/profile_entity.dart'; +import 'package:shia_game_flutter/features/profile/domain/usecases/get_profile_usecase.dart'; +import 'package:get/get.dart'; + +class ProfileController extends GetxController with StateMixin { + /// ----- Constructor ----- + ProfileController(this.getProfileUseCase); + + @override + void onInit() { + super.onInit(); + change('', status: RxStatus.success()); + } + + @override + void onClose() { + textEditingController.dispose(); + super.onClose(); + } + + /// ----- UseCases ----- + final GetProfileUseCase getProfileUseCase; + + /// ----- Variables ----- + final Rx profileParams = Rx(ProfileParams()); + final Rx profileEntity = Rx(const ProfileEntity()); + + /// ------ Controllers ------ + final TextEditingController textEditingController = TextEditingController(); + + /// ------ Statuses ------ + final Rx getProfileStatus = Rx(const BaseInit()); + + /// ------ Functions ------ + + /// ------ Api Calls ------ + Future getProfile() async { + change('', status: RxStatus.loading()); + await getProfileUseCase(profileParams.value).then( + (value) => value.fold( + (data) { + profileEntity.value = data; + change('', status: RxStatus.success()); + }, + (error) { + change('', status: RxStatus.error(error.errorMessage)); + }, + ), + ); + } +} diff --git a/lib/features/profile/presentation/ui/profile_page.dart b/lib/features/profile/presentation/ui/profile_page.dart new file mode 100644 index 0000000..8a4a3a3 --- /dev/null +++ b/lib/features/profile/presentation/ui/profile_page.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/features/profile/presentation/controller/profile_controller.dart'; +import 'package:get/get.dart'; + +class ProfilePage extends GetView { + const ProfilePage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center( + child: Text('Profile Page'), + ); + } +} diff --git a/lib/features/shop/data/datasource/shop_datasource.dart b/lib/features/shop/data/datasource/shop_datasource.dart new file mode 100644 index 0000000..b0898d6 --- /dev/null +++ b/lib/features/shop/data/datasource/shop_datasource.dart @@ -0,0 +1,28 @@ +import 'package:shia_game_flutter/core/constants/my_api.dart'; +import 'package:shia_game_flutter/core/network/http_request.dart'; +import 'package:shia_game_flutter/core/params/shop_params.dart'; +import 'package:shia_game_flutter/core/response/base_response.dart'; +import 'package:shia_game_flutter/features/shop/data/model/shop_model.dart'; +import 'package:shia_game_flutter/features/shop/domain/entity/shop_entity.dart'; + +abstract class IShopDatasource { + Future getData({required ShopParams params}); +} + +class ShopDatasourceImpl implements IShopDatasource { + final IHttpRequest httpRequest; + + const ShopDatasourceImpl(this.httpRequest); + + @override + Future getData({required ShopParams params}) async { + final response = await httpRequest.get( + path: MyApi.baseUrl, + ); + + return BaseResponse.getData( + response?['data'], + (json) => ShopModel.fromJson(json), + ); + } +} diff --git a/lib/features/shop/data/model/shop_model.dart b/lib/features/shop/data/model/shop_model.dart new file mode 100644 index 0000000..3f3a933 --- /dev/null +++ b/lib/features/shop/data/model/shop_model.dart @@ -0,0 +1,13 @@ +import 'package:shia_game_flutter/features/shop/domain/entity/shop_entity.dart'; + +class ShopModel extends ShopEntity { + const ShopModel({ + super.id, + }); + + factory ShopModel.fromJson(Map json) { + return ShopModel( + id: json['id'], + ); + } +} diff --git a/lib/features/shop/data/repository_impl/shop_repository_impl.dart b/lib/features/shop/data/repository_impl/shop_repository_impl.dart new file mode 100644 index 0000000..b8d6734 --- /dev/null +++ b/lib/features/shop/data/repository_impl/shop_repository_impl.dart @@ -0,0 +1,29 @@ +import 'package:flutter/foundation.dart'; +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/shop_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/shop/data/datasource/shop_datasource.dart'; +import 'package:shia_game_flutter/features/shop/domain/entity/shop_entity.dart'; +import 'package:shia_game_flutter/features/shop/domain/repository/shop_repository.dart'; + +class ShopRepositoryImpl implements IShopRepository { + final IShopDatasource datasource; + + const ShopRepositoryImpl(this.datasource); + + @override + Future> getData({required ShopParams params}) async { + try { + final ShopEntity response = await datasource.getData(params: params); + return DataState.success(response); + } on MyException catch (e) { + return DataState.error(e); + } catch (e) { + if (kDebugMode) { + rethrow; + } else { + return DataState.error(MyException(errorMessage: '$e')); + } + } + } +} diff --git a/lib/features/shop/domain/entity/shop_entity.dart b/lib/features/shop/domain/entity/shop_entity.dart new file mode 100644 index 0000000..1e453aa --- /dev/null +++ b/lib/features/shop/domain/entity/shop_entity.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + +class ShopEntity extends Equatable { + final int? id; + + const ShopEntity({ + this.id, + }); + + @override + List get props => [ + id, + ]; +} diff --git a/lib/features/shop/domain/repository/shop_repository.dart b/lib/features/shop/domain/repository/shop_repository.dart new file mode 100644 index 0000000..68bfb7c --- /dev/null +++ b/lib/features/shop/domain/repository/shop_repository.dart @@ -0,0 +1,8 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/shop_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/shop/domain/entity/shop_entity.dart'; + +abstract class IShopRepository { + Future> getData({required ShopParams params}); +} diff --git a/lib/features/shop/domain/usecases/get_shop_usecase.dart b/lib/features/shop/domain/usecases/get_shop_usecase.dart new file mode 100644 index 0000000..7fb6399 --- /dev/null +++ b/lib/features/shop/domain/usecases/get_shop_usecase.dart @@ -0,0 +1,19 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/shop_params.dart'; +import 'package:shia_game_flutter/core/usecase/usecase.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/shop/domain/entity/shop_entity.dart'; +import 'package:shia_game_flutter/features/shop/domain/repository/shop_repository.dart'; + +class GetShopUseCase implements UseCase { + final IShopRepository repository; + + const GetShopUseCase(this.repository); + + @override + Future> call(ShopParams params) { + return repository.getData(params: params); + } +} + + diff --git a/lib/features/shop/presentation/binding/shop_binding.dart b/lib/features/shop/presentation/binding/shop_binding.dart new file mode 100644 index 0000000..8044122 --- /dev/null +++ b/lib/features/shop/presentation/binding/shop_binding.dart @@ -0,0 +1,20 @@ +import 'package:shia_game_flutter/features/shop/presentation/controller/shop_controller.dart'; +import 'package:get/get.dart'; + +class ShopBinding extends Bindings { + @override + void dependencies() { + Get.put(ShopController(Get.find()), permanent: true); + } + + Future deleteBindings() async { + await Future.wait([ + Get.delete(), + ]); + } + + Future refreshBinding() async { + await deleteBindings(); + dependencies(); + } +} diff --git a/lib/features/shop/presentation/controller/shop_controller.dart b/lib/features/shop/presentation/controller/shop_controller.dart new file mode 100644 index 0000000..7098604 --- /dev/null +++ b/lib/features/shop/presentation/controller/shop_controller.dart @@ -0,0 +1,54 @@ +import 'package:flutter/cupertino.dart'; +import 'package:shia_game_flutter/core/params/shop_params.dart'; +import 'package:shia_game_flutter/core/status/base_status.dart'; +import 'package:shia_game_flutter/features/shop/domain/entity/shop_entity.dart'; +import 'package:shia_game_flutter/features/shop/domain/usecases/get_shop_usecase.dart'; +import 'package:get/get.dart'; + +class ShopController extends GetxController with StateMixin { + /// ----- Constructor ----- + ShopController(this.getShopUseCase); + + @override + void onInit() { + super.onInit(); + change('', status: RxStatus.success()); + } + + @override + void onClose() { + textEditingController.dispose(); + super.onClose(); + } + + /// ----- UseCases ----- + final GetShopUseCase getShopUseCase; + + /// ----- Variables ----- + final Rx shopParams = Rx(ShopParams()); + final Rx shopEntity = Rx(const ShopEntity()); + + /// ------ Controllers ------ + final TextEditingController textEditingController = TextEditingController(); + + /// ------ Statuses ------ + final Rx getShopStatus = Rx(const BaseInit()); + + /// ------ Functions ------ + + /// ------ Api Calls ------ + Future getShop() async { + change('', status: RxStatus.loading()); + await getShopUseCase(shopParams.value).then( + (value) => value.fold( + (data) { + shopEntity.value = data; + change('', status: RxStatus.success()); + }, + (error) { + change('', status: RxStatus.error(error.errorMessage)); + }, + ), + ); + } +} diff --git a/lib/features/shop/presentation/ui/shop_page.dart b/lib/features/shop/presentation/ui/shop_page.dart new file mode 100644 index 0000000..a1f6f85 --- /dev/null +++ b/lib/features/shop/presentation/ui/shop_page.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/features/shop/presentation/controller/shop_controller.dart'; +import 'package:get/get.dart'; + +class ShopPage extends GetView { + const ShopPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center( + child: Text('Shop Page'), + ); + } +} diff --git a/lib/init_bindings.dart b/lib/init_bindings.dart index c1b1d7b..0d703b9 100644 --- a/lib/init_bindings.dart +++ b/lib/init_bindings.dart @@ -1,14 +1,34 @@ import 'package:get/get.dart'; import 'package:shia_game_flutter/core/network/http_request.dart'; import 'package:shia_game_flutter/core/network/http_request_impl.dart'; +import 'package:shia_game_flutter/features/awards/data/datasource/awards_datasource.dart'; +import 'package:shia_game_flutter/features/awards/data/repository_impl/awards_repository_impl.dart'; +import 'package:shia_game_flutter/features/awards/domain/repository/awards_repository.dart'; +import 'package:shia_game_flutter/features/awards/domain/usecases/get_awards_usecase.dart'; +import 'package:shia_game_flutter/features/home/data/datasource/home_datasource.dart'; +import 'package:shia_game_flutter/features/home/data/repository_impl/home_repository_impl.dart'; +import 'package:shia_game_flutter/features/home/domain/repository/home_repository.dart'; +import 'package:shia_game_flutter/features/home/domain/usecases/get_home_usecase.dart'; import 'package:shia_game_flutter/features/intro/data/datasource/intro_datasource.dart'; import 'package:shia_game_flutter/features/intro/data/repository_impl/intro_repository_impl.dart'; import 'package:shia_game_flutter/features/intro/domain/repository/intro_repository.dart'; import 'package:shia_game_flutter/features/intro/domain/usecases/get_intro_usecase.dart'; +import 'package:shia_game_flutter/features/master/data/datasource/master_datasource.dart'; +import 'package:shia_game_flutter/features/master/data/repository_impl/master_repository_impl.dart'; +import 'package:shia_game_flutter/features/master/domain/repository/master_repository.dart'; +import 'package:shia_game_flutter/features/master/domain/usecases/get_master_usecase.dart'; +import 'package:shia_game_flutter/features/profile/data/datasource/profile_datasource.dart'; +import 'package:shia_game_flutter/features/profile/data/repository_impl/profile_repository_impl.dart'; +import 'package:shia_game_flutter/features/profile/domain/repository/profile_repository.dart'; +import 'package:shia_game_flutter/features/profile/domain/usecases/get_profile_usecase.dart'; import 'package:shia_game_flutter/features/sample/data/datasource/sample_datasource.dart'; import 'package:shia_game_flutter/features/sample/data/repository_impl/sample_repository_impl.dart'; import 'package:shia_game_flutter/features/sample/domain/repository/sample_repository.dart'; import 'package:shia_game_flutter/features/sample/domain/usecases/get_sample_usecase.dart'; +import 'package:shia_game_flutter/features/shop/data/datasource/shop_datasource.dart'; +import 'package:shia_game_flutter/features/shop/data/repository_impl/shop_repository_impl.dart'; +import 'package:shia_game_flutter/features/shop/domain/repository/shop_repository.dart'; +import 'package:shia_game_flutter/features/shop/domain/usecases/get_shop_usecase.dart'; void initBindings() { /// ----- Classes ----- @@ -23,4 +43,29 @@ void initBindings() { Get.lazyPut(() => IntroDatasourceImpl(Get.find())); Get.lazyPut(() => IntroRepositoryImpl(Get.find())); Get.lazyPut(() => GetIntroUseCase(Get.find())); + + /// ----- Master Feature ----- + Get.lazyPut(() => MasterDatasourceImpl(Get.find())); + Get.lazyPut(() => MasterRepositoryImpl(Get.find())); + Get.lazyPut(() => GetMasterUseCase(Get.find())); + + /// ----- Home Feature ----- + Get.lazyPut(() => HomeDatasourceImpl(Get.find()), fenix: true); + Get.lazyPut(() => HomeRepositoryImpl(Get.find()), fenix: true); + Get.lazyPut(() => GetHomeUseCase(Get.find()), fenix: true); + + /// ----- Shop Feature ----- + Get.lazyPut(() => ShopDatasourceImpl(Get.find()), fenix: true); + Get.lazyPut(() => ShopRepositoryImpl(Get.find()), fenix: true); + Get.lazyPut(() => GetShopUseCase(Get.find()), fenix: true); + + /// ----- Awards Feature ----- + Get.lazyPut(() => AwardsDatasourceImpl(Get.find()), fenix: true); + Get.lazyPut(() => AwardsRepositoryImpl(Get.find()), fenix: true); + Get.lazyPut(() => GetAwardsUseCase(Get.find()), fenix: true); + + /// ----- Profile Feature ----- + Get.lazyPut(() => ProfileDatasourceImpl(Get.find()), fenix: true); + Get.lazyPut(() => ProfileRepositoryImpl(Get.find()), fenix: true); + Get.lazyPut(() => GetProfileUseCase(Get.find()), fenix: true); } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ee262a0..886f871 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1,4 +1,11 @@ { "@@locale": "en", - "loading": "Loading..." + "loading": "Loading...", + "home": "Home", + "shop": "Shop", + "awards": "Awards", + "profile": "Profile", + "pro_membership": "Pro Membership", + "custom_league": "Custom League", + "friends_battle": "Friends Battle" } \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index f7b95b7..c19bb98 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -99,6 +99,48 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Loading...'** String get loading; + + /// No description provided for @home. + /// + /// In en, this message translates to: + /// **'Home'** + String get home; + + /// No description provided for @shop. + /// + /// In en, this message translates to: + /// **'Shop'** + String get shop; + + /// No description provided for @awards. + /// + /// In en, this message translates to: + /// **'Awards'** + String get awards; + + /// No description provided for @profile. + /// + /// In en, this message translates to: + /// **'Profile'** + String get profile; + + /// No description provided for @pro_membership. + /// + /// In en, this message translates to: + /// **'Pro Membership'** + String get pro_membership; + + /// No description provided for @custom_league. + /// + /// In en, this message translates to: + /// **'Custom League'** + String get custom_league; + + /// No description provided for @friends_battle. + /// + /// In en, this message translates to: + /// **'Friends Battle'** + String get friends_battle; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 3bb6aa4..ba4430c 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -10,4 +10,25 @@ class AppLocalizationsEn extends AppLocalizations { @override String get loading => 'Loading...'; + + @override + String get home => 'Home'; + + @override + String get shop => 'Shop'; + + @override + String get awards => 'Awards'; + + @override + String get profile => 'Profile'; + + @override + String get pro_membership => 'Pro Membership'; + + @override + String get custom_league => 'Custom League'; + + @override + String get friends_battle => 'Friends Battle'; } diff --git a/lib/main.dart b/lib/main.dart index dedefa7..98bea17 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -31,7 +31,7 @@ class MainApp extends StatelessWidget { fallbackLocale: const Locale('en', 'US'), supportedLocales: const [Locale('en', 'US')], getPages: appPages, - initialRoute: Routes.introPage, + initialRoute: Routes.masterPage, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, diff --git a/pubspec.lock b/pubspec.lock index 108f0fa..fc3519b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -102,6 +102,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_inset_box_shadow_update: + dependency: "direct main" + description: + name: flutter_inset_box_shadow_update + sha256: "91c912d01c049e761d0b7e9d81061acc62677f33bdde4e854257f1b10d8f0821" + url: "https://pub.dev" + source: hosted + version: "0.0.1" flutter_lints: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index f19b4db..a55a011 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: equatable: ^2.0.7 flutter: sdk: flutter + flutter_inset_box_shadow_update: ^0.0.1 flutter_localizations: sdk: flutter get: ^4.7.2