From efdbe858976857036839dbcc3e8db47413f36289 Mon Sep 17 00:00:00 2001 From: olshab Date: Thu, 12 Dec 2024 13:54:24 +0400 Subject: [PATCH] implemented shared preferences --- Makefile | 17 ++ android/app/build.gradle | 8 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 4433 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 2453 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 6391 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 13576 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 21950 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- android/settings.gradle | 4 +- assets/launcher.jpg | Bin 0 -> 17504 bytes assets/svg/ru.svg | 5 + assets/svg/us.svg | 9 + l10n.yaml | 6 + l10n/app_en.arb | 21 ++ l10n/app_ru.arb | 21 ++ lib/components/extensions/context_x.dart | 6 + .../locale/l10n/app_localizations.dart | 213 +++++++++++++++ .../locale/l10n/app_localizations_en.dart | 50 ++++ .../locale/l10n/app_localizations_ru.dart | 50 ++++ lib/components/resources.g.dart | 10 + lib/data/mappers/characters_mapper.dart | 1 + lib/domain/models/card.dart | 2 + lib/main.dart | 46 +++- lib/presentation/common/svg_objects.dart | 32 +++ lib/presentation/home_page/card.dart | 59 +++-- lib/presentation/home_page/home_page.dart | 100 +++++-- lib/presentation/like_bloc/like_bloc.dart | 39 +++ lib/presentation/like_bloc/like_events.dart | 12 + lib/presentation/like_bloc/like_state.dart | 14 + lib/presentation/like_bloc/like_state.g.dart | 56 ++++ lib/presentation/locale_bloc/locale_bloc.dart | 22 ++ .../locale_bloc/locale_events.dart | 7 + .../locale_bloc/locale_state.dart | 16 ++ .../locale_bloc/locale_state.g.dart | 58 +++++ pubspec.lock | 244 +++++++++++++++++- pubspec.yaml | 20 ++ 36 files changed, 1072 insertions(+), 78 deletions(-) create mode 100644 Makefile create mode 100644 assets/launcher.jpg create mode 100644 assets/svg/ru.svg create mode 100644 assets/svg/us.svg create mode 100644 l10n.yaml create mode 100644 l10n/app_en.arb create mode 100644 l10n/app_ru.arb create mode 100644 lib/components/extensions/context_x.dart create mode 100644 lib/components/locale/l10n/app_localizations.dart create mode 100644 lib/components/locale/l10n/app_localizations_en.dart create mode 100644 lib/components/locale/l10n/app_localizations_ru.dart create mode 100644 lib/components/resources.g.dart create mode 100644 lib/presentation/common/svg_objects.dart create mode 100644 lib/presentation/like_bloc/like_bloc.dart create mode 100644 lib/presentation/like_bloc/like_events.dart create mode 100644 lib/presentation/like_bloc/like_state.dart create mode 100644 lib/presentation/like_bloc/like_state.g.dart create mode 100644 lib/presentation/locale_bloc/locale_bloc.dart create mode 100644 lib/presentation/locale_bloc/locale_events.dart create mode 100644 lib/presentation/locale_bloc/locale_state.dart create mode 100644 lib/presentation/locale_bloc/locale_state.g.dart diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f43ff46 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +gen: + C:\Users\Oleg\AppData\Local\flutter\bin\flutter.bat pub run build_runner build --delete-conflicting-outputs + +icon: + C:\Users\Oleg\AppData\Local\flutter\bin\flutter.bat pub run flutter_launcher_icons:main + +init_res: + C:\Users\Oleg\AppData\Local\flutter\bin\dart.bat pub global activate flutter_asset_generator + +format: + C:\Users\Oleg\AppData\Local\flutter\bin\dart.bat format . --line-length 200 + +res: + C:\Users\Oleg\AppData\Local\Pub\Cache\bin\fgen.bat --output lib/components/resources.g.dart --no-watch --no-preview + +loc: + flutter gen-l10n diff --git a/android/app/build.gradle b/android/app/build.gradle index b36db2e..51f4907 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -8,15 +8,15 @@ plugins { android { namespace = "com.example.flutter_android_app" compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion + ndkVersion "25.1.8937393" compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + jvmTarget = 17 } defaultConfig { diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..fb0c9491fe7b605feaf1c2b8b802bd653ebb0aaa 100644 GIT binary patch literal 4433 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 X2@PBw>=(3p00000NkvXXu0mjfM~;&H literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..75cbaa9db78066013146d2fb521dca2ce599b933 100644 GIT binary patch literal 2453 zcmV;G32OF71dS+08U>%QL>Cm7MRxZ-&gpmWU6$pwd$*=%*jdg! zkNZ2{?P_D404u&+}UXAEHbSa<(4x~ z6_qmt5(E?buVD6Y7@)Z_pq*>bJ9nY(W}=7TF+msx@bEOE4hsJu@?Sug|BYJzpb!aQ z(Zc)LoR!3p4ihlOlfNVxKzguGJ+WPU{3;3GFb<0?6vLmG7TYC4McyXiZ3-QEjufwv z%ARCt`L_f}7)=kK`ip3Ofhd0Ce2Gsu0YIt^qEjy`pX^l2*UNXV!^9CsR1*WTbfgEm zl=ps!yAGPFu_5lb4HSx+wuH_#NXxgei~=-?1}Bw}a&f@}y)w6%s8|#VCZdoqlk%6cNM8o>f-9CBYW8)og6d+4eYR6l=aU{YQNBY+H#3S8D3HyG|}Ur`{P>=H-iM)1IJ+so+SPejTLK4m7pdXjL( z7@q84us~?yK)se;$fgzHVco?7(!&4TM2D?-($|mP6dvK+#n@y>(bHl)D6DZU*({WS z(B8Gg`(gZ}VJ)OK*3;UzF?Edv6mENkb{|QoDV|q>Gv|n&W4ON)OabI9 zDR&V(SNl8ZP%o#loL6piubm;vHJhpz$9|*Et!3^Uug zTJ#_)`l_{xNGZJHX%y-wEX@eCpB^=wP9!FGVQ}Vvc62NI;`6YT0SKZdKm97T0*g$zqs6enp?r9mw@t2NSH{ea@l(A_7&>hC&-O+2{r^6 z9edECCmB})sJkiISjDH8PzJG6mPI9`4|?%H*T^uoTv-}<0MgSH8yjPO{R|WS%cC=68|!iwTK;7<9=IZ$ zSt95&IR}^rX&Hsig8N1$0E_zCY#dvlfR~}6-sIpI+_*TlD}i&ZZPB3o=3n*=_o*+s!?5|Ne;+L&BSy}(}%8v8|rA#Ru~~_ zh?#jn5@p14?|p)*wpiDkBA70@C{U5z z=3hM5R(gse**4mbUR@NlBj zVw{@KNY-4`btwK+o-%`0|A_ZA3pGeRcSWD8{!1j_9ltZbb|%(yF>?ub78)Esb5t`V zomt3GZiQ&wo*>aIecVyJMij5X*1{-I$XW6DsEmoHYSe~8N03b1y+T` ze!?aYcceMyf5S{I#=>T|eOdj=HmKgw)mG&9A}x$kv+=x#8~jBUxLdByWE$ zF-?P+W){*ZvzT$KGG{gNHjgVQEI3fz^rI6y#ECzKu>*9BX5Q^w@?(rxOm%1d$0n?U zRbMM^-@EA!U`A z9?oM}F><4%UGLQ1T}MP>5)yks}Rpl@E0Bu0x{Z9ijyju&!A$pgH%mG!KdjSt_ej|MMnR0|^cS zc9UOiN=$>Ki~#;w_n7cF|KNE%)Tc-EE)1)}R@IR}I0n116jr^_QiK7>sD@JW)WuJU zBhMuuNKEmJQux+xT%vCd2VKao4u9ebeS=|vclovi0>fDRL zf#d8VbmjGxs*!#eZY{Fs5l5OZ2`TZLC*Bb0>9;$}z8ifo0toEMv3#rYMvYl9PI4NI zC=l-1w~eb8==EO+H>`u&9zqzMY)#w-m9DgWE7T_w0m6i)&nC;Zh=0@>Q8B(DTGtHf z06ONSZSfpSWX}t>O{+a?kuWJ?iN-q zsL|33l*W3}ciJM0 zDx-9lQb_6J&P8=ZawmOp9)$(Dm2+{uHvb{DWvgg^19K(0OKX$21q7&~)l$_a=@x%l zh&Jk;LBF&`D}PEq^EbV75AJIxMkqDogBjn(Rd$w&2+u5_b81*|EkpvF=dcARk{YMw zF`(44Iz7;>0X1K36W7o3Ko?YZR1KOxPq`sW$7vptQHXO&nWqx+8*_CM#rl5%m=@Ze T42PfG00000NkvXXu0mjfYip^3 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@UW2Q^ba(wya|^4we*OQJ z`|f`4dlJSN$P7@?GJ^o7t}y-r6xuz`mBvJ81H62aU2e3a9VpgDj4RMeK*xZ9F|0Wx zLW8+ZsE}lpqWmhFQxz$JmWDr3NP-=9UjoawiKY^D0DB4N{Dg;2_NWAe6ASWlL$=~@*p_ng* zYS!uoaSPQ!f+HEU?gp*zuszSjg88uYMp(5{ue^ms#$|36z9C4lDsx|s-EqJ?@*+IF z8QEP#5l6o@7Ni6EUt`SulL40|_y@bH`931!SfrYH37mNyo_^hefkgFkZPo+Y__+{< zp=uTSMpHggkQ6znWSvv3-o_ei+rb^r;x zTK1&_K2nesZ`{ESJcrNk)ffekiw?yyeJk%fK!D}KI07XX4};eq?k$>%r{5o_{S?r$ zed%J92ukTb`9ZA<^~PIIYi;`xaG1i0WFnZlB|`wI`j8?_j6}P56uk9B^w9JA(tpv* z76Bp7kmB6YX}Zx*g#Cwy%qe$-7e9%Eh3PQ) zXb~h;PNL;)d)rfdG>T>uRpEb`gE{-`G_7L7J?`fI-6t1YTjmUdQ3MiO1Ao_(~bfN#X9n_>OIZQhIO&q zz8ju=w=h9C=Fs(dZCD6mLTOW@d55*}5zX%UC`jVb0Jkcs>1=r-PQt+n!k!$?L&LgB zV5emVeeDrqcmGwQ#s#iJ7`7A68;{19d?R$j7lE)duLDCNh%twgp^!UGo2}O#C038C zAu<8N*<#9rl_og#KY}3#FK|TTY}-=_Eh{wnvr3Yp!S&kE6vQ8MjLTdqe~nnZh-FfZ z^Q8^sA>#^?on+8G5$KolblbO#!dkuXhM|{yXaq4QaoOJVRn6=an9d}3nYrazpZ~ql zeSx*s+Z_j;_WD5Qi4656Whf(Nm$_jby7Pau{Aokn?17-Z7$bKh-gr#s1BDq|PTm<5 zdIpx>1hj%+;TTZJhkHK*X75XPXcv!RE?A+65J_)~C232{&{a+&hd#a5d*0mexA@*y zP$19!WdL7$Q4nM*`qI1iC%9>QMj1k(rKZ~K!k3md0#SwDieGA^7XSuS>tB7P*D*C2EbppG!o+KH; z3KoXOa#4zru!@6v;Z!@2?>3$$hQ#AcAbs=W&gUlKtO)~e@jwutNbJDR^~()x1U{Vy z$RINpG0f3&pw&wRCoz^1AF19T)W%Hj_g!d9&~Z3*1&^H$afGQ`1@|-7yxU)r))O7k z9Y4ta_%j2Yeh&oM?fb$0pZXwpBn42Y>-W9JZ0fY_r{@o_3rFCk6NJXqErP1}oX5@Y zCmk8&c1n9c1eGtA<`_^m3$>%5wVwHH3FxOb#Ls>@QoZt;>wO54BjpB~8Gq~BK_^Dj z=5QG@qBL)U7O4{R&#PfmKFfQd#znJbuhYC6oZH2^&Jqwu<7W4N(75=n7Vi|4#vcb7 ztXK$THb}(h`1mdyBTkq9QjrtquJ6;zTObUAej$;56eQOp-ncc;afAZkgK8J-1UZBB zza$LVKv7`A$KiyJGiHF^=2+Xi;ev^McQ9bL>?cqS2s`1zto$0+Cy+$rv>)|7SEaN8 zx%6)I)T`l1pYAVOuA(5WJ?Me|!oWsyF6nX^q=>8VaX0p3AJ<4mDq_voD!V3?_t*NRE6n6uBo z5Cno41#+~yzhN`i8kgR)_B@MDzkz@#f)EN$%FMK5P3BF_!MuSsD@z5rQ=)3{mWW+~kJ z`Eets6qhXo7 z{y6{wM2^g4E&I}HcX%MiK6WO=A?U;mbfVjT(*HL({%MxOXE2kT0!X z4;-ik%5P2v2Co5VB`)Ag@2k=$l{i-3Kjx0Wg+ul$5A`nodU)o8!U*z;u?rnHYaMOb zftZpNX$_SN9P`X(I_*9p{J_=&?y_YVXs86`S9^vi`9-_+AZDi5D1>0qK*HSdJu`QL zUb({Saq(QBYrR_(B*^$vg9tEX0LKGf^#h}x)9eWZN zw@i@8`stkPcmGJMTr$v%a!Zm(#3`6UI`;YEgphc<)!jm9_c>%-!IaW8f```uRp-hT zPQ}e&kgP1E33zUo=gKps##Gkq!U^CcxEXZq<50Q(9RIn(*=1>)yL>?y1(!~e_@y(1 znNB7tNJiJWsjSP$JoJo>)988D)jV_zOekDLQp(=*4#zf$swPbnLn4?#?e22~UVdL{ z5a0BpS7&_fp_5e_%B^q}`T$6@?7<*0i2Uwrh>ouV$iqrV0lL!USK5&QjINv}@X8q( z-=LYR#pZx0LgVWoRIK4a0`%NYQTi#ghs39Auqts5Rc6{o;lR8{JVz-bD!}S(MbS0{ z(q}N~7&GehwiC0rJs?xD87$UC+^lfenAt^`e?sSW_*N1qtxaNf5p2h#!HP0k z(98yL!P0G3y12rIx^m3g@=e{(DM-`8u?TcbSrtH0=17R!5EZw8k<^wBw_#~TCQfgn zTfa$+i+-|!4B9bjim;2Yi82}GaF`Y>UkJtiglqK|_eX83+rDrlFlH*yasX3)mYWt- zwSEJmV3M|m~Db}{Jqj~=Gp5Gr3H#E@4W5&{!6{l!5k2`D@sEzto^ybRv^T`XLJ zZ+bL1^=<$)PU9(FL#ef7I52J=y7L9&x1ZBut$t=4#8ydY2O@-qia=LmCIqy*H;(&G z<7c}pJ)j#FZDUu?A#dr*^k|E-<%#aoTe4QHN0AaZNKvYmQw>)Bo3Y_xjmCTx(|`u^ z3CQl{rl7;Myu=Dj*IpqF#NWDFJpE7~NT`vUkCk?nqJqAhn za&ziE;MgyGodDIsV+hWzlto18X5v+_oXYeRX9udjasC=thmdl?`Z{33A&}^6dYg}f zdev#El4B_E(|VhX?N8}ze(8$mq{YyeJ7Y+j^F`;_i%3|~K7dRXVw5$G&|F#CrMA?j z)1v#1L{TPC<3+NCU>DL2M5&_db`VtI8C!wt56@S6B_*v?vuuR1dpPd$cI>eGFZHYr!yq2`PbK;bg)% zb_yr5);(#`j|BsPnO~5GFXnCP6)RxU8ujX)sVvy=+Qy=CNz+5cwP3J(g^VIG<4QVH zxT-yoW8=D+)85B)Gr`S zlzUUJ76pFn9^B&(e*qDqL7-$7fMJoFCl$-UzGp|7l4nvGL9EYxNZ2WY8PxcbX=3lk z1XGa(k6CB8u$BX$tAQ{RGe_)$ml+I6cS5yt;xPfCRkw#1{EX2t$oMV^NX;bgfD;5nMiWUmt>{eYcu0MvN1@%z*0{(}rmP8RyJ|8r^ zK8l9qMsP+0IY#4lGG-bM6%Q}|udFU5R0AMqLL{e#PGOP&9X?rkXb0z2T`eJG*NYLF zm)OZoe&h?2P<#W)tp=%Gcd+VXtYMQ>CTK(kkt{Z6q~$NH`5hA?yQr3wEdk@_1xsfk zy-bt5jRdMkKUCfxPhy})5i7Nvmb(O>JaR+PR=Am$@>$)QQB7z{w5 z)`z<@6}Ol$h?zO+6%hNpn1wGKVi%6EdfcPsi2~sAg`|9Ou&9=y!1Yo(qXFroP@1^H z>Yo>fKKRfer2tbzw22>63rk#ICR}1vuY{*J$b}q@w5BTa$pxtpur$aeTGI~Lyq)g) zerMs#{Cj^5MAF%J1PN-7?^v(L+khV-Efs*ErSrAy3OQDhT~Xc**6P;U4Q~)prZ}3| zsGA)I{li>B)ANPZ3Mv5#h@Y9#{jBHoYmvfglv^dq7=wP5?JC0s`#D_Kjz3w@D0RCT z+w)_5;{Rk)!yoA*gu;}25Og`duhLB`nQM)i0oo7v(hUHr{3|j6Enfqfo0C zz4=cu$D(;PuyUb(!{-A9wf&wON)O4no^h+L61gL`dlzFb}H3!km^d389TpEod1?+BQ5P}laD+h1Va%OQD2jlrVRVFnU?a^ z6QL{&XW!2PMZgn5l2TD{@|xJe=e0|RS=u$n3^*d4BsR13vwEmO+m58Z!SY3751ZVM zDE8jb7;4!KS;~)-F1pxJ@2F`=DszAGGYunsNISPGJo7AT z(OolCp##zU$FP=jO~W4b+GN~(bLywyv0tU#FEzESP(c}W)3!pKI<5OPMkNt27RU(} zO;K}ITQ!}IBfdp+Mgp8>%rVm=lRh!#s9s^|BjMuNDV}#WC7F~cca)@2i;UMCm=f92$4^~gkk0& z1Q$P{70vX##S=k-7lKu{MklR-Cx7o_?P9>{d9kJ_k5b)YJpK^ka;$O{6Z-MXHPnKQJjG8BTOn*#!6%M!Q!z~1sWv3oOG3HyP8+G0r;e?3yOMqL;J zMMEM8x*@>exOfn;;{DUbIBU0zAdr% zakhQEqiXd33c*c|b6Gn7(eS*7*^nF1QZT$@0%Z~+G~>az9--UTBdaH)6`vUbu^$Z) zy679>x`&3(0>eTOPLg71%DqNGt-0|lTC~M=hd%m}Th?Xp(HeRoS^0FhYV{CDx($R8 zA62Rs&xCjWx3TeIy{ExVqkgnOy1T%Rlm%8jhl_`-_VLWmsAxobWckE zFlmapl{8!w3!lc)3((Sk$(nMP$lt(JP1Xot)F;gd$_>`6(u-?j+rO)yc|#SI2}krp zJ#|~|%8}Ms3*7o$QaDw`QbuQ+q;V9FIzS?)CTrDC5@+6Y-uVIPJOwgv;K&FE zCDKMt?j$t-AHtJ92}Qy(Ef^(&pgIlMed*zv)wF6w?BoV#_mB0Sv+i%eJ=raTC%N}k z4!WryBU}MzuMN-m64oNV^x)fJP7nvfwV!1ZZcQBirE}yZE!r%j+RV>memr_rXHbgZ zw;e2CGwzSfd64OaKJGj5@w6)`{q%z1yhqurFB@kz(-SYFroE8%W^Oku6(I(~%5QO| zd?r}E4C;9Z`0NMyM?t9<2Q5M-uW=@=rtwS0sSVDFS6Ih!O`LqklE`vvT9QgvJVn)+ zrD}((P)AIiwws)=DuGeaYfgblLEBMHoHYt$xkFz<9VUYZGDFS!ie^-JRxlB^Wu70D%s^Euf)zItH?y!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..801f68859fe05c0f2920f2ead342a15c4a0c4927 100644 GIT binary patch literal 13576 zcmV+jHTTMiP)&FHO>tcNA}A=#F3Y-1a26N8B{5E4FMmt{9$1H0dsO_ncs zo$v(*LdcqL32d?-ERTTs2#K-5#5Q2rvSrzpthYvQ>oFr~-ZS0P?|Z9i>zukhni+Xo zBYC=K9JW47o*7Md*R50M)PK(T&nZhOMdrXzk`StAqW@zTen|Dt^k4dq{x|(c5hVx> zh)AnKLJS`dM!NHfUO#n?r+cjI5YHv3pQ9o}MV=`lxuq;uMyiBeCA@|p+Gxewo!a(D z?IKpws+@Xe$BBw4{fU%Qn1W>Cr&EGcp*Rbi7^AbYE*A}JwkJ>=RGR-0SRom%jusXX zfy%L5A{ahd=s%){PpY9e3ZrL9deD(sE~QJ9LnXdMQnR$??ev!_V1*Pbq%G1bhmUE& zFnDt-OIg5N;?}Y1Hdebp)h%_JI_&xm;?7h0=Xz(DnNX0G`JbMK7V4}l%%m|_1O`h3 zORTrKGO8ts5b3j-<6G3p=ls6oZeh?-83ua5BGl-k;!JA=D4>E@Q+OHZp#u3)cpJ1H zu;NTVDb;@qNqk!oE&`HH(exR1e!CWiPa+9k$6HqM#kV<&u8-8Oq{M?4Q;Baw1z~e! zrRK;q^pK(P6Uj{9;h^gU()Ehfe>@^av=p=&=`{z#2qsZbW$CZAx(F>Yty%bb3Svf~ zDg7^ci9x9PTSh?tj8P?KXTU#!@-qBFf$qp^(J#*p(6cX!m%UVVt6XrCwcr+K{&kku zpjU~*KKaelFx>CvU<$tjgQJxOmf0txClZIAk%ymjlE*w$53LD|270L&yg&%5Wv0Kz zjjxpq6$_hW!5-PBegrg*ksWo2^irR?BBvaA|8ukI4VM2e)l>WKUKVymGR^qta z_x+sPBo^OVz4m_Edc7i15V3jJvAj`ZVsZ@E_@gUk+bACOP;D(TDyW z_z_c1p^qH-=k&3sMaz2Lac|YKn`CSu1Dv9m5t*^W&%|-#Rqq5%jPJll}RZ^i>p1`0~A?L+LamEvz?rOdEm9S$clSo*ZdxdFEP-j;_|An zNz{ivZgiRH${+fv-}!_$a=GH41GdEo#eb4i)|d)>CPNtet>d7u)xZ^x-Gy zvb(%>AF$`G*SP23vWDqrSBazPy+5W$e(L7?B8c^TPA!euD8thzKxob`^+uH#Gz5uM zG07yil?WJ2(k=9;L*LII`AK&E4feGkcNg5Macjk9RR)16HRg1NXEVCR%pXYY`(d!_ zyKa8Kf`_N**ii6rF90w;`w5qg5<{X&&2Qeyw$kA7^W%9rYwVo(a^;TRMtQBTz>oiiVwaHp&&rw(nKYM zcCeH%=Hu-+Aeur+fl*896$D@2QlzHu<;>&%UTyeTbp1zoWF8MakQp8`ATYFg7{?2p z9PpxOFqGT&RqMbHT;=;L8j-&K4M8QB5H%2bbCS2MxL{E5Kfue@C{aq~Fyi~1x%nRQ z%HL*AzEJb7hh*Ib8hV@P8*0EsXCQ(+6B>pFP@0$>#z{r*j*+cj^ZH(;5J{pI2_!RT zF;@_%Kp*vOJwjK}U?mNo0)^-a0$?e9oGKqSo z+Qe~f9P&q>%s&6+c;OssoRTy20dJRqAxl-2K3jPH&r<2p>P?@J#O9!jY(~zsnK6kF z%b`4w+1&R3$#?%BkK{3$Bn3oze$xh1R68xw4PUvoLhPP<-xiXZG<=Irsbx zUwDV5EC_jH%$Tt&3Fut0hC#R*M5TfHaOcRge-R&eMIXWvf;n>{urx;oX26B(52l~_ zym$Mkwe&tML4+q)_=Z<3FouSZM#=_5g5Zhop>?ARv}k=*j%@ zVRf5uR=uCH2xeKYWL%-ZAnY!wKhl|d>a(@!;~HFWr2?unY?uFEVB-c?fnZd-p#gEC zax}m7F9|JpD}GmTUi1nsZ%kKUCMF19A&k)O6-n$(Jo%a0#L2vEbE%~T3MXb+!PJF# zGc1QmDhijt7gmB!jW(G&OG88m6Q%$jb2IMh}lX z{e`O3sX#l!5|a=xwOI{b6w~$?m!*1Zqs%OHTW2lStQbWH8-k7+CF+%m$b9bkFY)R{ ztm%eO5kRKXWo1oQU`S)qFx^+wR=M*dKl{_z&|Ynz9qAXiLrHMu&opBL!bO2z7wU6m z;}I(W7g0J#G6NbIatNk!FMoFQnTKj0_zsD-SVZr4n@t-{Pv0aW!-8@lGnrpMtffUD z+bRP{Wr-_%f*Bq`+NyJJ`cK(p4>`LpGITjt`)H~ll^aVQ9D3@r zb?^DAh%R6x5Y(FHfp&SIL(44p^51$Vf1wc7OTZd>269fs-5H||9rn79aTc?r5Pl-x ze6b*@# zA^C5LQCh=7LOVt974*E4d*P9&DyTU_G#^XGD`1$~cGGHL4s%Aw$UHz($5>!NaMq+=jVCEBRrWxr0OCPG9epy>dYyOmM;Ur%lA3(Rl%ITQ zlZeQe(V#!E_0cN7PvNmJCrGekWJIdZZJMQSUGplSdWL9GBBmAEdZ$jmW|5p^CZ)i% z4Ii}{>)!o{TQ!gN9vSU^HP`(*>+6gKNl-_HunvL|W31xxOdc_aWI^HONA0#vcHK&( zsb1o&EhR7-T0|bGOm^#6-Tqx@GV+#m)%0Oad50{T4<_U7G`kp()~dE!`6dx$`|{`aioTuf;Ny0FP=<`|G7ei71a&l&^$LBd zXFgwZ|JRh;K92MH=A)FrqI_UZl zB*`24_P7HYP8$_^^ls~VYSmy}kd(%VEByr%*+DjVg5g;wv1EeFz-n0~Se1oEFC0k3 z)Q+}U%i4p*8&gN0i{#HM$VXabrAPWK0z3)u>Sc6jM|S78t8V@iEfGU@o@!jeB-n94GFQ2+v_Sc0(ei%9W&mB6_ta-qf-7W(cS z^~)4G5Wnw`C33}+0p42hh-zBHu)3ni+~y`Sz=uwgOdo-mx?!x9QD6+cX=Brg41$CI z94xz;x87d*;4Enp^&gc@Z2yPa!Gn2j^K$xI51R}fL6 z1_>-+PSwKeCcY&zRO_H`UrhPIxMe7iNLBON@Nh_|8D>5cG!jRukzDFKE z^hS*NeTnD3Qv0E6EwB?;1UmGz^JiXkI)CUh$CkbhuCi}Apuh9n7T*C5-^&+j%d9fq!0#k>~`q(QvHdj0Q$75DJkj;VfglE6&) z6uL1=q;`MD9XbSuv|c-!BjwCYD#d|&q_hL1(u?kjQ4h91wcPj$74J|h-U~D_e`xgl z9&+YYzk4SgI_AMn%4-3GMQptmXbIyV2eC@JcfXY%(W^nhuIgQ^4V~>T*$mzp6POzY zpAuYXjjj6jIVy?n5S0}!N{5 z3`{Xk0c9HHJb?|1mfHG&i7s3}aY|_4^rG91@ddZ5g|{)8lOw0Iz59dy14KJgiJr!J z9U3uASYv#M;LHvVuBbT|El2=yx4Qj$O05ukqIz*G(Imb5%lCk#hn^$yUjmrt(VqoZ z|Blsg4Fd;dat!ohlNfTs)B7Kb6-FR7uSCG9Ek#*1EF?kbRg5=BY8Fj8jY3=i-V7K)vs2o9;7N44@P991vrr79tVyKaVTqwoHk`14a<7mWe);bj?)$nR9)`{)WE-qWuQUIb>C^1UFTz4ncpO%4_LDTh zWNi~$Hc;YRG^r3BK>Q{|bQ*6U453vj5<@b{1fGPRI?oOik^_obT=~e+MICP10J~Ne zJqZJLw9ynvHh83*k63yrWbEjNDrj5cbiF9fykIZB7YS(-lEM=Nroiig<2QTg@kpUh zK{^0J0}L=sx$_goC1xB1#>X&SSiTybD8`vmCfZBDOT$8SWYkSU2oRr+E^PVuk4Afs zvhLUX?j6Cv2}dOC=JizBi0K8KRi=zk(I9b_XZqCzJXztQLU<}XO7-5;8#bNY^CNrF zZIU>2qGg+;VOVt?B*dX7Y-wwGaTQvPa%Ynu=&D$r+N^nv0DT*as$IzMBY_TS-ea;c z>_hn{wm$LJNY=B{`!2v-o_ipAZS#)*PO zDPRFe>X_rrG~Qsw)K7a9g{|M)qfy(AwqA_>(6>{fcb^3y-@%?{ICZ%fx7 zNWJ#`_rBezF7A2qb_kAw{RiZvql?=*55~|7{N6^_61{j)k(P;rbmR~@`eW@1GTO4|4YLny99D7d_IQI=Ll&&m-2tyGzJQ z79Dn@eIBBkEK;h!vhOCD1`}5m`n0x;oM#qpH|Khsu2tt^9M$^d^!H1 zjS;6|s%as77#GejW|rw?sib1eu8*zzJ+|`B?9pd4d;cjiazI0VhTTJoj7L)LwUMyT zAaG`7`cub#8C~^2kpK@(n+y;Hu#`CRj28?DJcQ{S5*h4nXY^#Q@2I_C^OSRMC>O|skRfy1oU1?Xt+*@w+IQ4}A4EhFViBR@;-}5TgH1gY(io{F^Qrwm zjjgTkMw4<(A%@dG3EW$!?~6)7+}uD?`JURzgsl5A2siovd*qmU=3y*j9t( zdk=ew6R;jCxHwffivz2JNuIg9Ztrl1e3=4HB=-TRp2by{EIUy}VOdyJ@Xq#8vR-*LMC6;u`_Dz&~B`updu@nSyd-iJ`v6OEI!>WIm z9NZ<3{AiR``SY%^Hhi#p+3k{5GmMc3R9Mqv)2i6A>bo8qeEbjNqlc8TE0^BX`>*d1 z$@Gw_B_KnLz$lsNX8lJD(WOH3nD)?~Y(TB(q8qSX;nd|Z5RC(qCvt-%ar#0;2fP$W z4{^ggei-I|CkVk>{!Tl)bkzHIuT0Z0JFJF4#ftKf-$$MZvF&Rtv>+Ga72DSoXz?O@=xO(= zj}Yj^3JR7JC!fQ|nIil!!_y^(tFGw8M3mF z!zM<^zVD2ldNuyOzoyk|jXX-62-v~`Y6+sNKA76|4{l+AU@x=s=P_WYp4}qbXL&71 zy~`(qzN2WA=VH$;q0ioy)s#l0DYTlx7NJ|KxW>5W_fO||0at*FUej@5?f} z9NVBzxgiiXLn%Is){*6RkdYfY-!)of9*Wlz>DaRRGH0OE_ zu)<*JU5~|y5|v2zbj}IVQp*|mpQ7yO8ZKWz(q{6s6%3z*mKM<3W;R(2hZHD zUv@9tyH)|46arB{Gi2pc=PV|T2R3)&9KhRE(DBD>T0Py@ST*w>{A%{}&h+VRR@V+o zB)Q5%CwZVig&rn+#}L&)XiDUG)L(FO?VW$7+y(HPC9|U{>?ulfqrGhffb!U?U!*9U+b)0(~;a`>1S zI>}RKS$0JEc~g|GteC29B~2^&vU}qTZYIEiL>k2--u&R+9Elwhi{qpc`*MZD^^Ce^+f$xVXDJhX+7 zIVA!O->L0T;tCqU!_7ygHYR5XA0PV-BVmdZp)+#x{ULSWCo+Vx6&c}$SLo{Gk`~X8 zLiLoAmji~&Jg}4lV)M=G`DJXNarAoJl}KSDz`f)KTUL+%ZOi-~h;581J#iFCbKrCt zM_y$TuY5C-JW1(To~J~@XXZu-Y7`H07WdPp>pbFSIR_Lh#M*+`s%iafc8H?I02ds9 zaM786>?ywQd(7NeSIN}8DsI6buLYJd2WL^uXJ2AS|D<`lK0dEwa?Q5$HYW`z$|9Y zCSLlAee~xp^(8DEt$ays*c3zh7EX-g-Faj#APyK9QS}zy1Vz3jVUUtYDVG|cqyz3T zNN7={7D{vFp$cyrl2`;07UY!J1CUcgpIU&2mgc#>(av9}UEgu?eH5?Oq$Y7)(S zwwjI1EX5&4Rh+=w5EvyntGcFb13Eg$!=3Us0pVrNY{|d$s6B5PZCL3vUu8FRNUxC+ zj~L`@0y}t>tO~=&C3q_aWmqgo5A6DZ*#E=Y>?ty zU=T=*w~F{8dm1i|)-baPfOQO zDHbx;r+1~ z9%r?Y^&evkHfOgy967(O^i0Y+ivBSbc9kU}F`g!dI6IpVaoqNWfNay%6p~@IG!BBy zS*q6_IVP}WzJfX>f%r~x=o6Tug9q8r0e|;567_4m^&j?D-Yu zGPU6if%8l2SMm4${m{=o6F>L7>7ywi-&Wx!tO^@W3uU>M@EYaFF{C5P*=-k2%&s9U zPu%L}RWvN9D~(!Jw*QDLvsjxU3>hTk?+x~`OXd};ki&}AUx+?&`=`eEKwB&_ ze_%^_E8jcV`D|6sR&_a@4Bp~Eqrngra;vJ@vTEA%lv(D6Kvmw#Cx|gKhCPN%G=muz zS3*8TU}Fbc(TKa~Iw+@mQ!rP|4PlKXEu7mG36fwKA%A91Y1mE62>6O)SRNcRTaM;l zdL+_*lX9EU&9W4o*!GR05{*qlpIlZAzxD&<7cZ7M$vk10M&A*k_q3E%?Uq&Bp3*w5 za!`6iWmyk1y~>tQf@wqmw$4<~N%*nE^q@Yk{CvYIZ|drVu*}$Wr6MYQdZ(*}Mdf8h z&9RjZ#7*7N?#%A*R^9YpLszDJ~p13ei?YIxpj?-|{e=p*)Yps$2CYv#pv1vN zL6cN!nrB?bJ`>2V=E&2w0qqxxjdn^4Jlqi6idV96*oEjpyqQ{67WkMA%N3Euduz)$ zlK^hVh}K;9Af+C0oY;~(=;GUmOsQm-pX~Eu4Xl2-Vou3bGqxNEFru&1Hu%kyH(bsc zhQ(f5vw7Zfh#L=;tF(?8?lFW?{0igg@Q$szMM`Uz)~ZNjM?f85H#PslWzQ5ZPl#U_S3E=-i>zEz+ql}$rn8xBhIxkc}buegU6`#;FZZG$I%vZ;N_3|Yyuf>bKb5q>n!u~@Wa4bUm^ zK9Z=l@K$#IrEz4S8T+WPo(C1zUj2URHL9@O-)3Q?mXZtExJxKFLJmwY##@3lAI+WF zX^ozBWJSGMqK{NVcC@nBHzS9z0_W*+}VmzKwMD{5M zHAHLW)h<)FJsb_vB-x$oKjxp`Lk14zhtJqSG9q$X6Oa%fz`bMCbAvm$kQ$ZymhgL7CEWTtj-nK+7v%j2%tJ3lLBzba%Ka7T4 zmWV#8m)&N$%_cGyg4HXUK18^nXhgejTv@fMp~kIW%T~URs9elXkdf2*-UHeGPBz@l z(!(k}tUnoE!y`Oamv3C`ExEOR$?ejauXT{C%Q&^cVa)Xfr?(f09~BFAD4*HYOK&mX z7>1=@Q!iL>W8~l)Gppwi0>b7r1r?!9E2T(L9;MTX15G&;=7h0v6fq1U#tdYj9*aa} zb4#S@rU>i@0Wm{p4JGgzV~bEbs_n4i5cdYVX~S({Q^bqk^l5UZw?zwmXge#{S{4r1 z`W2*RIT~)5uBlxieBo~?Xk`$X+!URmJp=~^+_9D?&wnAg{qNQMb)McCi#PMwe8S@x zUk}s1l#Dxd3^)3s{?Hi5lEoHFz&6LVgF7C~KH%t&0ctmGN2n7rn#~d;sxa=R#3DIL zr*_hfCKb!ArOE`yeigyyU{`J-rZ+It1vVHTpIfb)D2p50ZQ<-8Koo7;n2gkVg#mn2 zL1%orhSEP{aGl$bNa0r>PrMwX)Wm z_>voA?bljfvm}n;NX~8nlrr^6u+@Ae{n3}cQ5B4s>kv%4(DHpWT0aSmcZkeJ7uB?` zlPWBjvO@KPZ|s`252TO$t0z<9Lhaj34uryik%H;!poJHe8992ICy$DwKg=^PRo_8d zH}KYt(dF;v%*CMi?9i3M)13-m@!Y{5xP7lZKLS=wTaWr{1z&9&Xr+-6F2@0)u4nzIV_VoZ(uL)-!a<#x?1)Q zLLzwU(TvYynzJ<+mjwg6$;)4|RY4!dmV_&kWSKz+LI|NhC2;0>>pn=sOBOLSLyM;Z zHcRm6@^`837vQS;%WUaC&54llAyzCv#!RqDLo*IhU5JBN&8w+Zt-`2`40H7GwXX{O zEK&oq#K%C;h;8N}3w>e281^%*!hx_hJuOwH$2j5?0l`N7RrXZ&+0R9T5p%PnK-OZp z8UN6&37fcO7Tr}9ozIHEi(Pc&(yArz7Ep6!;bqD|XnXt?1EK^@Yx2HN}<0iaXBgI{$%w0n^+&JI2 zWAxXLM29kkU?iVCvo#8|9XJaum95L4&5RsGv8YK5VF8yI2XIX~ z1dA_;Tns$|s$67{%AMQg@A_ljv> zA8REY?@{~zZ&>>QgcT{uObV6?+BIO9QMzqwm0evVBVXvFEDK52dyv63&DcB{xKftY zcvZk_EYs+{C|-EtV5E23H{(@tXWlAS*G{~7ggICs%ZcfI5h@q*j%1$5(O~Fw{`jx* zCw}P;pKwSJFdGu&G^%%o08CWQ?Q3`{VZUx@)Fx^>VjXv5hYmh|r%VtSGsGsvqgOwW z@BAlQj2beUG=bAH&KE-uu#6VdYO&xJtn?xV9Vye!jHqm1rz_IN6Nks5JRlZrT5aLY z*+mvULK7|L(KGgeA90n;Y2TApF)wC$^~`HvUbT$G6}RCQOpW-09L*<#^q@%f@N|!( zVKnA@Ozaq&Z2Q=KvE0VS&>n!bpug~G#98}(%4+DPu2iJVG~KMfS}k}7IrU7~h6Q3v zKTu8shxzbHRJO_20>eu&0q(SI9=-ZweDAlAhbHBOfL%EThR?KU=5LbJ znV3rio-GZASkK;IB0T49*GYGt=|HbA@@5n)C?q1?&lBpSxR^A~9z^F%#LGZZQ%n#F z8DYz~s=W%v<4KVq3tiD@kX?LlZO8q1gtLopz?p;+i+4@pKUHt~4}&LPh$WBVzm-?R zAnO5<%>rw=4qa1Wpo5v0Ud+tEF*h?5aLEFWgj8)nZMyI#1>sQSfWsQ2E1-gW?;)gc zqwhqOVf&EcqmR1@{&kdC|v?n6t$&=h_wll3jxPA!P{Nt z&dmRJ&iQ8ywBmZ<-s@|W^8h>;G0d5NIp=(fUe`vY!X(k)1_8Nn&K}mK%^mex1v&_7 zk*03!Zm3xcL%%RwPBZ7oJiUP3kLZTXr51fDTDL6EPv%RQ_ZC7e_g^~wPU763ytl)P zxuGMHK$GF>P@+oR?jaA*Vui+?l$L$&pa~5N4m$^Q+N7v%(Bn-??pi?`@N4vTZ)W!& znR)e!se~G0r1k3P$|q@Faqs*I^UCO|`1)PhH%{tSe^HMxG+1%X^!ee}9;L}vE!iQH z%R_TonNjVnFPgbX`c8PKu~1&j&>N&~a=9e1b)b?M^Szk?M3N@`$BOu@#fcmZ^Htw~ z`+43@<%Eb$sa3XFE1qHpeGDR{zE*`pB$;BR=P<6a5nTq3=Hw*Rv~D@`4Yh*TaP5o2C@fRrT!^G@l+T>h4{r05u}yO?m4eYc|AJKTTO&sTAe;TN6M~@HI+i)FgU# z4ZZnfD1FvnWCeWii6Sgqhh*^9s|l~LmT-ml7M2(|;>2orEGcP(_>2K~WYKqABUU+R zFy#*gGO;;xB@eCL!RFi&)auhum_%AQgM+@J&Aj7TYws>^qhg?TQMypD8a4do*lzQl z$?&dKANp4ZnB&xzjetXOCGW_X|eyuK=LVJC^H7BxM4o27p4y!RKQ(6e3A_vBd1@_NuDw1 z*fmX|z7HiW7eB~6;gvBqHFJ$?<7;;^U%rvEiGY&%&oK2jv4IRI10%8gv7y0J;S;;j z)|f!EO9<7XDBOSK|DQuO;IFQC)fip+U0?!=+k)i!^$Yz)e3I)6>i4CUZJh)1!4;iV z_q{}oipxet6CF2GvUl?iNiBNE*T+8nSNPHqioGwmI2H=Rc%ugv{1REhAT5_MZ;JJN z$2IFUlJ{PCbxZ;G3feN#6`{u1rWdkrK4Ulo4$(~ESe)}>cCBuh0NN+q2{o@|ba*VX z=>@HR70#8WfD4;!!q6QL3LqF{)UGt{e>t^hXT&=1FvdR5*5m@9hDd{RyxYcI-#3~z zVVe`B5J8DzQrFtaCQRuhDEDLUR;|t77+vqA_BJ6dV=CMS}QV z?wZ~CM11LXl`X`v=e60oIwrls$oP3k@zO@kg&XAhUD*$Q6tagAmL*(D3f}^m+LG0lXjk)ZeKL|Pxsa+=%s%TV^b0LPP3QWIxE02|6n7@(L! zPUqtltDcqM`JEF)o8I9u?G=U+BLJk<^_Fck(LDP8^RdxWB?X_(hG4{YDYvy4S@*-( z(nkmgVu2+8wCMuVOjrOOh8Kq4>4Tad0q#=Nk#z@2BJ;S2l4s9jE16JU(Gdkr{CKd8#*Gu zvI{VW2=*4fUmkvgvp189HANMv7h#P|x+q=+hg8bADZFlnx#S_}Sn zZ>Pz5clV|ZiPg`rn&qlNcsWCb$QCI`!u~g)i6x+s6<&~7`vbdq-S8h?svP;)VVc7B z3IM7yAI3S0gQBaV>k`dorY@|EUc=XXE3s@Vr7@}~2@^Pu0EsD)1$ zPUn@wl|Sa8Mpa_<_nejo#t#3MfAp^Iq=Jd?tlkn8$4^f!{$gasSHiXJ0In86e^<(> zsO(H3im<{0@beXaf?tiAPQLLMPRG`v1HTFN{Y9r1aRq|Mb-X?i>>Vp?A%eYTJbalK zDFaPtluYs-4TS7%5w%2SGA(&~?Zch9-alGL zUndt1>&^%q1B!?&nId?VPw_VH(gHI^p$z*RON+TxZD!||ipBSNpW#%dj|GU5CJa7R z?_*_Aqj|I5+#^0YH2U}5{F8lQH|sD1`Ne|xe&*$HzzI~u&`{MLIQ@Po|E(#(Lk^QkQfoT;^*v%y^)%8ABmX zk~3@5O&dck_rx03FdmcW%A)~#RV(pfT;hb$zDZaWW41!XLXV7NgjF>Yq?Qr6feCGJf*$ zSTw^8E4;*Pdm!Gmje&L`<33PJr#_6U#D24-P1t3SWWdM@j%MzfwV`F(BCQX~&yJ7v z{#BkmBnFO~xlu-KR5bIioz%C2qRQY0-g|&lR6I*W-mA`nlJ`O0wi1qzD3I@?7+9dx zhFl87Rp9hhNU2%WkkyOy#+8u;t1Iifq+a7aVKAV$NU(Bz+;%dmwY_9nyEy6lqWng15}omrb$zjZ~KLS0RH;z<>G69LXmr5D zIK>v$y2}JdaHUP-ZrxJ7d0k@RT3UItq)`QQXKG=WN0dv#h%b7ea^d|RA<>25_U3Tg zb~iVW9XMkR9Fqe_$!BNCa366-ICZ$Ie1`xup}MLZl{P42FoqJG1^`zC1S&kLi{x5? z#6N1YIE&OdRSTF`MI}3oWV;!uM-9pGYJ{SRpQL4j3@e|6abI>ylHmM-;>X*Fm@zlj zST7py#KXvzBIAw@Si|RXBfT_r&Q4u)()~O;s97VzPID(m?TpgkmyA2ykXl6OVPQla zvw}zJwCFq%Yml+IG%+ty*~q~vTF1>0tyPc#blIg3rMB_lD@-Tw`s2UbavKr?N?4=- O0000{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372eebdb28e45604e46eeda8dd24651419bc0..4457d18825b38d79f2b2c940f1f97d37e54b623b 100644 GIT binary patch literal 21950 zcmV(uKJ?DHm-*<1fWYmPmb1(13 ze3vDsdmU*#3o z`h~T*o;5tv%|*sCpD`slr%R(NqH6$dHDex#xl43EEN2pCZzj1^u~f^qkffIT0$L%< zE&X;2&vEf-w~#s9BOY&?wX{8)TYymL8U!U)y4;w#+?YJ8OP9TwD{SV9sFyj|EYmq* zh1DEPBqXQLbj-$q_)WM^j+l;kRE3)RgZJ=*mPx}M0|?7i)opybA96jmuvQk=s-BxO zz3W)l&EVz1D{z+LR!Db2BEIIBO}GGVkkQKFX5fXLmkOL*Do_|ixV#R+X))S zHv;)7f?%{hdd`dnRbX@ih`(jXMUGS!2OC0Rh}kWR%-j`O9-oKsoZOyOVDl)6x z2RP0nrg2y6B$9iaNS`@z+Hus845XP86mDPL=8?MKAgu!Ag+Q2z>V?0n9Dh1Z_^pa}xK?Bd#Oy;U0hx$dM9^;}>D1#+Sy*j`ozJv=j6PM@`7V(-})b4#gWP zAS;+K33D(d+@%CLm~sM-mkz^eS(lkfk%86sc{jhVxaDmuyTPz5@uK?}LpLPwW>^Qx zpAKap$uzN!1nYJ&WV#Nelam3yQ6UgW$;8K9>)zSv!XPmIsw-G=iaP^Pj;76 zUe@ukV<|bbI~;m?X5Uxsip_HEuEK_Uq3;gi=NVc~PBR+iK3sI(c68nq6S=c)n4YeU z4#I^!jq`ie)CG@Kve0l+grONWmr=*;oasQ-Z-aw&(Y7PyW*#71a|75WR zjNF7Qgm#o;Qb?>{Zi$(kdIuaAH6wjihya1Sp?S%y7IaFdhrMXcVpt z+u>i%ypRp@t5R$3mYW~St$!VO-JAqi$5A^nkY$M&08$%TkbXkX%gF=no)flGyZDRB zzW?q|9rtW4kM;zq9<*9wTSCTGk&Q(K<8wX{i+!?0u0Zk+^b`2?hDdx3?w6Q-)2x%n zuYXq}tdd8G{|BVwVit=pz|MURN3j%1Udqjs?1{7CsUME{E4({CRJiR!BEN<98CqqL1O^=kcvFISI#ORs->aqAo8+SeJcUx3F!8zD$1k_bf>wETAr z)C5^N&CYan_9+V$c;Q6-^e-Bxc01wU6-_c{_}a*64?_lxfOb2UO_8&yoSJh7Kvv)PAP`<+|fe&UC{#Ez9?qr}G%vx$Kvy@`dQS*ML|griM88&!`( z3eK%Z%h`ueRnM|RUzs}kqx{?dFt_m$BOQAQk;Ec2<7zGsi0&TaOKE5?wFJV*3uO!N zk63_EZqYC!D`%z;ew&^6QK2@hxYh1VicSsiFBF9Wlm&7WY**t{i5YH% zA9$=+58ESuGj;mu?3+KH+4=!xCF8#1ABizEMQ-fU(ULL{%xY?9C`X`GGy#K;mJfcb zuYAnu^t#MSYXqha(2};4!lZQ9QeIeFDt+1Z3 z&aO0OHX-mDCgFHRpoJ~1)BM~y`dQ8*jYfbh=<)E-HzvU#pjSt&&Z| ziG-x?QZNzOWL3C3V3G%2GiPdhK3geW%)jZ6LXq<=kINn7ay90TrE_8ztyE+Y8AxI2 zs6vw&OSIy$EMURV)bn4p$G@94CA*Zy-v7T8NS%Uu~HWR6eW-?{GzS`-^o=-F?SG#t7BvJz@EIk2Wix?SNL=&*dlgr&%Rp8Hwpq@jH8GX(-}8RZU?zY*+d4)MKAa zzvYkRP49MgHi|3k16eRyFa~n0O;Il&^ANSc$)A3zuYAz4d&F|U7w- zo%syrcX7idA>W3fP!e>?MotE&UaLgz`5pT#8F5NNi-<{qNdO&4(N!Co`pIY0Z-?AX4>6WnsBdbK zfhf=Aw5gMY?ph;mWgxtCaBAjff8IO&qLEU}LKMXJ(@`m{xTDB=8iQDxXWb9MG={I7 zZg4he+bd#2^;UDuv+iNqKqPswdZzODr@V)i+VGHYTW<^|nj|(oMqGL=eOHSNq%iQH z;_hOgR9`AQKlSs^rzek?xTt_FX<5^PQPPE~0Bj_r5!Sb5$20&+a}T5I*a_cx_l5Q2 z;5m~tr!SZG{D*<}^+WeA5SUFOd>`q=0pqPOL(3{m5~NCmF$HI>)rO{bf6BZ3oX-Ny z{ge$N;j;ueptH!C4ndR@LsD%U72n{WSo=;Vy7TzQ?S$`Hxk5W%ufcDMQ)U#hHTz=ZIvpc3JlL%d>1J~Kfo~X|AcJ%Mi^6_630TVVs|Bh!iVJ9Bb zhO5?Cp+yEFGXN0X0&3CmZ>LUwpCEIbtPdP-gAW|~Km?Rw zvA~i+jALS%3a`ExJpFI-x{SG)7-EO)9uS?;YwT`@aOT{tNrEavIGEb1yRtkdc*t3X z>L@*~QmnTx)3YnHcm@%yu&OJD zm2qE1X9|Q{KE(n8pjjfaF~%0=ndo*o^9`bD+5P{uv2vTg@e#~k#&}s6(M#Gqn%To9 z87K~HCL+c8U&tVhbCqZQGH)h;`MfjX4XzPFDPkN;+l<%0nFOpi*8zY}34$`jek9H= z9h2BRYOrCQyn4&i%Any_v)zhEKGY+p?JT}nV5e4uApnym{61HGRg1 zpz`Ejh`+ze8@Lyf_A$DWAQVt&3d^A>1|o5S-ARIi$>_I3we)xYC3AJ370v@Rq2#Iq z(OwZf2om6*7||~9dJ3yN0(8Vlia42KSUtZk^ZMVf zO$~)tj>Gs#PXxZLJB!sR_lT#Q%WSDa(-|BR2;*#7!yI*)NtwFi=|bc5)RUj<|G;1I z>^kx=F>A@2Zcl7d0wsYdN~=re*!IM?`SI@yf&J>>q&^x+ERH^Uo!mWRh6;7`;cr-LMbfk9X zIdkzqJ{-;2s^cPMB9d5&0+K>3DPA-zj?7C0sDET(~t+*zh*DdwWo*5c-^a?|@kmmA}!W`>Uk<3}?i z`~C8{7~&Hfbe2`?r%kmcx}4XH?Pgrtqu;KtyW6|@A?NUmS3nm025M4;B^@G8jLUFr zde0Y%!H5yy8!)1vY-D2WgU%y+-9lkpy=U8l0^*h!r=ntX#JPNo(|4g6e#rw)^=!5jR8#*0;+1@nt?B@6x@W)6?YtN9g|ZMl*=1Is1!1p5@?ZNp{-r9 zZJsZ~RrUyiMTqjSsE*wD5|6V+VIxm<&#F6uC{HAeiS;4Z6*+OyS*Rjbd+mpar9p}z zXS6*D8$T#0)v#b*7~w5*+qgWj`!D*-XN_1^;XAkX&gmo=2K^mp&NL|W zkR)~Ig)kF{dWMX}g>%DgcI{oi<_if#gz;c}Fcp<=TvcuwYW3YrWEr3HMHA1B%yR_C ztdE~ir6GpLI-=rC+isyU173kmmiB(Nd*$7b*~pqh`DjuCxt$8jFMY3XY_Fxz22Wsh zmx*Ta130Pyv|1Zo+cir;vRYVut@LFvN2UQ;o`C!Q9({h}T|4g^VO zr;m+4^Vj|F{FD{h1yf;&)`7^h0b+)Y&0HJfcyK?u_n-A|dLWn{3&#el zqesG#qhk8J)QuDmB@3HG#7!nn3YGcjF)rqjWOd$? z8Mu|$F?r7`CkKI(-s-}$vzIOiYP#(hNZKHjSsxndQ$Gkczd3!&dzu-(&=dm+(9`?> zSH5zpstUfX7@k>PP|MkE;s~|ubddD>H{Q=uYf=L%(<^qeosWR6nc6s;9I9S9WJX?6 z6DLG%%&DLoK1nLft~;BFdHq`$8Zq+{rjATw1jbKeSIiB|Dhjuxy4O<=sFd+_T^pie zP;|`<^U>pIS0K=8+!F!qrotM^_iPaHR1rq5?)zG1-90R|`ZvC7UIwyp?#roa3EF~) zrVg;dA1k+Vh8vz@BIHd6nihjJ%XoYS;ZATnbYsnPn+k-7A>E|`#tCtK1UmEzwBdd@dN9W(<2*qOwb72LAMP#{Q+#!iD^4B` z&OE8M|DGqb0Vz>0$0z4k_kCUliZgF+nVhF5gr1ms`in(9PHPfiYRD?ams0|H7V9A~ z5+gkX{utOY&x;_Q_~ka!=W12Y+CH=XL9WZ;)P?ZUAwK$YGTnbp3aZmb{&vNt2f<%G+f1Y8b<2K@1foD0$5DH>a_sy0;pY`1?RstnQT{Hs0jMAh zuu#yFn3TCScg}-95eESYkBAU3SernDXkvh(SJM0vh=MCpGokdjKK{L&MWl^5DCVRb*3T|$ z+!@F>=Co-uER$WaZ5{@~p*l3LXZF;@MR$S*Ye<%1G8N|gMSf>t!+X0}-HD%hV>32+~q> zt0WbG((b8qq__Ecl27bndqi{Qn}>xEJG zG+vD~q3K@7vjaE2hHgU4`qL;;(Sc@mF2jz7GYct}?aY_7vQ)2f!+k{@I|%gH8D}9V zAszQ1!o0xQF9HWW32)%Gxu_4!`d3t}j(FBs(lLG7)8)lplUGlIaDox?9829%0p+5p z`jPLXAKDJQNI}|p`swFmAZ|3lfpAkUz4)yht1(1ScPgD@trU$SSY8WIyS=xX;7gge zax3%Z@t(M)p|(6Jzh&1T-{KfCNn?!M;K)IgXMFz1tHQo2S=_M8y!+GDv9o;mu$nk! zbUB5GN*GYZ)wi>F5*aSKj&T84;>TlHse0vTn$;I|K^BM*Hy7<_3{#Q(a5s4RCvew4 z5dHTOoZLM7J`V$F=iF)=IZxx%Pg0{V3d}P(*CN*HOAA8$Ye<3&r1Fg8B*6x5r(%-p zV|Vem!C23Vq(~}ptmiOr$v~QGpJKCk@i!2SB2=P#yDV8d{Aobs{O-cMpK7Q$1iiP3ldLp^ zvj?$CB+hFXMpH7Ex1g*UijQJu=JdqAZ*;%)PhdVwp?Mex3(QSJpMJc{HX0%;LAP5k z9S*$|PRFvY=<3z~^YKjY&Gij$>b+@Kc3@|ux-dJ=u|9#AUl8OiUr3BMG&DWR!N&sx z=ivh^(ZY2M#?Kz;W(_BStn{%1i;`+INH1!Cv?Pw^rt%?}Ir(F_=Oa+qdgE*6VW1GK zKY5am95O8Z%95*gA*==x*p{!XS*b7Sk*oRfeT{?p>Fi3~ztLZHdtu$(y6+C|C9Vd_Q(!d@WkSF&+&1WqC? z$@9DMkRzHE_8zob+Aps7i+vv(w^WM6B9)l9asM(UD-(@F7bm7)>VMZ4!0&FdhbAP1 zEJ_7p?>7EZjElvS!b|)z3>Tp_kcgf6*b*V+lQnZJUS#>A+`iS@{(;7o{pI~%%Ut|L z8p7J)dD#N+Ddgj(aExTe;bKzV=l1AVJ@v5AjX4u74U_^}67jrJUe z>+EqFS+vYb4qXJG7Ir35JglGC&F=jtOs%*!ACXbGeYUj@yPN9c$NcF*&W#37&?oRt z(AM)1mE0Jf%|(;Z_$l6ZTT>H{lK`5b=n>7vqsJ^(DrgtCI5(MGHk@HaWsB~^3t|7R z!rM33*4|%z=F5ff6p-Kpu*s>t7Vum~!gP%#AJ$r(s$85pyQgRC2b0S~7y*O^%C2HOog_wDVjym@uP8Ps=sN_qEn;_}kUh8cJoK+?t9OWJKW|K( zs_;Gj}5XT*u}DX(-fNgLriedb() z<-CQ~iBnC21YJ>u?*8q(xn6H_8scukK)XGE`RnPyAC-8D4{QzBy{>rkTe1T?7%$Mu zq9bN44nv!(PNiHeWvy?JcX7EszfLn@Y6aCH=|tI|zx@x&ecQsvKG9n}SN9OhXW7k9 zGJ(hta&9k$axxae%Rd(@-Fo666oE{G&&6^TYQrx{Gf&$}ClVx`m5TN4l$mbUT$fY4 zXK?|Z)YH-EnG{qCYz9Uq(qjjr7yqW3?XLCSo>_ZaZtX7JyG8ijgV{>ES}yn0flMIXfNmP)nb*ScE7zqeppd)aEyFf-6ziTEC-F zJ~l`bH#<~oy@CX`KidY+cHbN$-!vzH$alkx1MtS!NgryG1yubU*Lq@bug+3R7~f9G znQ?vM<>=%$hKoCLcYU~f$HS3aDdN)lmZ0A-LB=!b9UrVsoz;iF>Wr|3f&*VDGJ>b0 zv1nqD=Qm+#p@^HM$ce9B+9zw{uQq4hHbmt;+;(kHUF&}vHDKbjnPj#x^0Ks%=DtWw zmjt^wA2keDnx_!j1GEqIfvI2Co*tYSd@Ogzht#ps?XR@hnqJWsur8)xl@Fp++-xmUfu@;t*gSK=D<#8eWvV*)A*! z7`UBX-4pk)N@VROUCBixEP?}WCXPY% zjLq*9fS|R;dGL+#i)mX)ATpQr5*Lb`ml=44?t#s-ZN^P4J|xjXUKx6chn41mW)u7^ zWB?6%y1x4};(=23wtpD%yayDFY=VO@eoLYf%SVMTZ+UYxve$#~T9jb9+gSrRG)+yQ}LqLJfSTY;phyS)sz*2w80ogT1#n`F{t(yVKZd2tSn6HgVP(R30A z5rYVHf|C~lec`3C=l+{lTq|yR4`GF-)F~b#KSCSUK(|7g`C?$F;Bf&IZ#J<_9l7D;S=qRn^hP)J zzIeJefh;H3n_5EXjUK36+MC+&Udebf@-Mc^V@{zyS7lb;sYecC5*Az2WjpW?HNJ^- zG#pM3rTbUJh|eWGeL04jm+VznpSK4EBI8^zMv&GtkcKtGLzKsW`jz7usADbNe0>P> zy-hmTgrde2L}DxrI^dbKE>9l%L1z7%8SiT5V`5}smf){ZxoqzyCQ<-(iYUfd*2|n8 z6WCrNQ?^_mKbP*iQz6?|FQs*(;jwfSwtuh5yo5O!Fa}*O8%J*q&t{zj!Uxn%)7*Ut zoy~L6kBFsx2oct5_z<^sCW=j2Q#|QTBOyk3@`WCP z?&F&K(o#wO@|r8!SD2|Q?M_JLVj4Y7S}&L_sp=@g z##;?s_kzbeX+7QF* zQ=&#+S0wuXBFRi;^q2=xJpQcZ<*<&I5#%Ce*Y5(}6k6r{*E4-aSUcCeZxeyvC0?Fgdlz$FSaK>j3D>5q840!M>ai3@ zTbjju*%B97{5Bh@-u~O(g*l^EZ5KX_lYtCi=~-NOBbPgw!KhCM5MHto%#0`&RakY{ z38VCN; z1pP0Z3!rI0wpd@27bg?JRF777CL4PjpeTh##kFUDteP^rlYc1H3v-rQhY?`S zx}b1xa$Sd#UDf zCcUxv)_*Qnzn)#^2mWTFtUYO6gYNQ$z40uE*6wAID6!-*R&IltQB^Nr$e`t5ajrOq zi8|5-qBar?{|jMc&nBjdt$j|N7g1fQe8l zNMB{Ua_Mf~wMM79seKHCnK(oto}^^m!Ikr1Gu?O>cm`;4A`7PuJ(^)GC+7W#JZR#OoC8i?Zci4UJsN`a+%SZW>X z#))74d~bin7-l{TLO?$FjV}f|$LP2ax`O-r|FZWbV0KpLd1w2VyU)F|YNSC(XkXC| zGD6tIV2n)?7T0d$x~XeBko0Ms)b5g}t`q0U(0^3!{sEA$|yYG+7P z#)LB+(CUlTpM07f{+7^T$Q&Q!I6H9-AYL1#7}h?!K}?3yhLQ zYb7i4%OL;)qn3tP3RP_!y|4O{&*mo%a~1(yONTLaAXM$h^T2{`H6nK{2;3ws97-To zpQzo}HwWX?l{)r%H$WDxf$uBb_bDQ^c>92~0c5fzOE~D-S8lF<=KV zwHf3~sz;_Y&PNj(L6;uBS30`cc=6HZqhH`JKA1PDB*U>PtVgpBBQ~{$V%aWUp~6uG zCV(a}4m4>o^IaBe_ac*82Rv7@Q(&0z(i9W^aAxDiTRZ!3^Tb2N-le2(t@g{>DN^de zdV&`d)J}^L+l98D!I9qc6K82U&=!edQbkXwus(c1oqlBM#EZ1}a2xqrPC%V+)ozC(dl@-@3Z?PsBipXm#r~-8O@N-fjR$=m)aRkgOMV;)T z&H4V%)t~#y$o>DhyZO9`;>gWX&{^tmL+LqO08qr@zR+%7*GH}3Ikj?EmthnXQO5h% z;uM%}2|B&9;Wnbe@n6& z7}s%?wk0e~;z?sNyx&u`n($x@BY}P;-_L-(nUEGv$|Hdn53AE-wDzxfZ?q*^7(;~c5-UJ-jsu7JG zg%~+C6bkB0G|n}S1P}eu_`z=%w%+cqyiK{~m^vJuVp>K9Y&1uzD8!^N zj!Q|z!C37qJ$EFgg0&=lUeOp9f)o)BlVb8f^tXqnpZu=B^ZnTs?;zB}x|$?u3Q;W` zd5aG<>0ZwbAFIYw^4YHuitQNO%+lP*!WxpdV&_z4x`oIO0eZ%)8>TLoB#hb7L8?J1 zSw)g$O3U{U>b4G!IOXe@^DZ1coKcfF1s10Kt~&QJvf*iEww#!1PuH@e_n!U1Nfu1z z*4`fTJQ9k(vZ1en@TDXUM?WzKasHYQjhuMA(tIu=E?274MjW7FhxFQ;TRN8xhBu;PS=ASy1d602{GpZsh>Gu2^jC5>7l3CDxE z`fQKLmlxF%z3WzuvE5hsiU!)RT7uRtFcdrS;3h%~b_(oOmD2@jhGz~M2VyYD%y953 z#dk?z_dnP>Ae;xmnwYtn_+0hj&rJq#VfRPO^`!Xu&6xNCMXRh7FPzK7FJ67eAq$I6Z0{usK*v)_JqgXlSR^Eq9LZ@k zH!cMVZIY3|G3OUApriv$UGq!jqw(sK zf8KTD22FFVk>u0>N%TUqy8Bk{Z9erEo}9MXe+QYinnMt|DOM1fig|bZpg7=;{|x`V z{oM@77?AWNtb^uaL=4<F@n8Qm$nsKTyj&64py{E5(XNSOTvZ)C`e6UIbt-8ONmQGAWy3}X zs@#iGSX`8yc&;->QO_F(c>_ECs6=sqvMkKJIpw8N2~Gpc=HKQp8m@r5DvGEV`n@!q za%G)C)MgxtC4dSL!;4)dn>r%~cMz6M^TM=+S=aMc?tw54Yu>6{pK3Rs-Nk0RhxiOR$uFWJ11zoCuEllj z5z?@kWqU8$Y%3;5HXBZ@Z)fF}f2*d(gOLN()BD-!C)~y;^4OU$0eHP*nr|%G*0u4r z)DTK(Ywiqowm3NTxF7*c26AlcP|oJcTcBVt6*@x#;&hXxIBsK%;?QAh3^?7r;|Tyq zw|NR~xdX9%Ci4=gxNC9_ud>*zWC72#NVrk2LBofZ(!p+Td2ZTFSia5zCl%;fMcVZE7ww`K>f)4M|w zH{dN78KmApm}#0#sO4woO=7AVj2=yO@})3PCSWcnvGJj%0L*Jt95V3`RQzpqGc8n@ zC8$NFL+z%iK@Hit7F-mps9N@3up>)baBJ$@9thkvF2vtJdgFPR>uHH)%HA|tEs?URk`x5 zAvCvR%Pa<4BQj$UJGsUkZEJ$?H;M89DO`x!N<8$P)YuVM*5>iD1#CiQW0Nimnq60y zy4T=JmB|lIR}#cA4LB0a9?a__l&U$GrY?~QP*%Zha$o}!Ws0iJm@0R#Y|yMrg0>ew zDRbrG-7>craOM~l;HVnq33W)KXpGw=Qio|w&Qm>SJGTvsBp5y@$h_f40RyC^Id~Wi zYov#-y-g>r413K8l1vxPBupIflrwc!w>u%e*su)8BI2^aEr5^Gu&kjFpX*<7j^!L_ z`4!sfL;)%Jn{HJs<7g!*!bY(}ikUX**uw>LODT`N0t&);XZMY>E(;m%5$lV^2xr1Sj8RuOr~GL;oO?2rm*rUJ1` zZbnAf4dj>r%T)KLlHCTugUs1`XAAz*_58OAf+ zz-*E6SY~DS4IgFxl2&)iQqHG+8Zjh;O|9JNlRtDx9cE@atdK~N=!jOX;)S&cyVQwh zs!2@T6}!SS4*;%X0go|c9Rv;~DLK~-$x80EA0VPc0M^d5o!XkGeh?s8@Ho`G(zEj; zWb1o_v18H5v-ML?%5#U=)X7XZ5gHEyY9Bz1E2b2Ugc3|!=pc%(fN%nIF)v3(QfyRM0e0}R$^w}%h(IRiV$ z#=DpbSp8Hu{A@gSur_*vj~~&Kr(6|qB_r?`iI8XDpwKv5XFdizwK=m$PKi>uWOH%# zZQhl8v{M3Yjkz-1V^v%PlSlcBPnvT!o?#g37=z82^6b)`Cb}>W2Wly>O(Tk!=a$9g zWpsFCA>Ce@X9Seo($PVKac}k8De(mIpCaj!n#YTwpd1Lj1w5HxBF6*5TFlFMUKQ54 z`E~lLUn=X+?1dy4ZHzrLIr5AV8eL~Q* z;Lg`>0$>yhbwo_&+FxF>3ehtf1nnV*2kg##?LZ1ausorl#}kNH^t3&1ph)IHkYp|@ zuQLT_@$#O*n*nwR%r^l824|DRN*t{NjARqk~_&Ap*i|g@C%sgkuxm z_;;kThV`%FgIn`GtCd?u1nzuo2BgSY|YkIzuldGoO9pi5@bGvQvlU)CqR1(%S{^7 zp||0jKgTzM3DRQXhg@3t{*tZo@G~HK087d?m=?4iA#_6nr)iLjC-w2KM#sK6;gncu zDH+)4^{;jM*T=;{AxautpKCi`0&lgn5rZvG%)FzWZ04;2DtzRz)6@ilI$u9H_Uyw2 z6#|=i+i^7rj)e3E3mbqz)S^*Z-P5}yfxX#TUTj7u&mJZYSKJsq_cfPHO7I@uT4xJ- z*@#@lg$!IYu@?=ikx@OmFFqhfS&kL@Xn6x0SRyAZjlYJALNCMl{1V-^tvHI^Qw1G&flIVW`)W z8`?4K59O#Yh@}gx^eX{6 zMqa6B)h&v7EFsPZ-%2JCXadMJ;cQ84y0h`)qdw3^mevVFRpU1j z33(7|0!|$Vv|uhRtEcnfWc1we_}JG?z|d{xRS*1GJax=& zpnPH1fkx?d9PWe(VT1`YowOkcPA)5(H=E^a&RMf>da9WXrq9JwlH2@Q*$R7yo4qTn zcukN0=+l|8Cpa?I6U45oRzIb!SI8{>PQff*rnKfJv*TQFN${LOwVB~{;xE{cxYrvD zUGE=!J_g0-MF0kZ%Dh3~oerf&U#Hy9G- znh&5`tS81F`K);MZ%p1`qJPZ%WW+DX7~5wd^Kx-DV7{-aXS%i&7j2{Td|8g-Slle0 zVN&Swiak?L|7A`!B6u^}o=(2pT7(2MEQK^SIe+(68aWkk@Y(XPVJ`$G%+1%vwSAu( zKXB3M>Ud|d~7VJQ*LGskGF-~cKZC_M∨lZ4 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 Vv+zK)jR61v002ovPDHLkV1mFDbn5^B literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6..afa1e8e 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index b9e43bd..b5e1b3f 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false + id "com.android.application" version "8.3.2" apply false + id "org.jetbrains.kotlin.android" version "2.0.20" apply false } include ":app" diff --git a/assets/launcher.jpg b/assets/launcher.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9db76a73ba22e4408964e3b03889f3b3e1821130 GIT binary patch literal 17504 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 literal 0 HcmV?d00001 diff --git a/assets/svg/ru.svg b/assets/svg/ru.svg new file mode 100644 index 0000000..cf24301 --- /dev/null +++ b/assets/svg/ru.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/svg/us.svg b/assets/svg/us.svg new file mode 100644 index 0000000..9cfd0c9 --- /dev/null +++ b/assets/svg/us.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..8bda731 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,6 @@ +arb-dir: l10n +template-arb-file: app_ru.arb +output-localization: app_locale.dart +output-dir: lib/components/locale/l10n +output-class: AppLocale +synthetic-package: false \ No newline at end of file diff --git a/l10n/app_en.arb b/l10n/app_en.arb new file mode 100644 index 0000000..3167b3d --- /dev/null +++ b/l10n/app_en.arb @@ -0,0 +1,21 @@ +{ + "@@locale": "en", + + "appBarTitle": "Crypto Exchange", + + "search": "Search", + "liked": "You liked", + "unliked": "Like removed from", + "errorOccurred": "Error occurred", + "noErrorMsg": "No message provided", + "retry": "Retry", + "unknown": "Unknown", + + "apiYear": "Year", + "apiType": "Type", + "apiRating": "Rating", + "apiDesc": "", + "apiNoDesc": "No description provided", + + "arbEnding": "t" +} \ No newline at end of file diff --git a/l10n/app_ru.arb b/l10n/app_ru.arb new file mode 100644 index 0000000..ede8c3f --- /dev/null +++ b/l10n/app_ru.arb @@ -0,0 +1,21 @@ +{ + "@@locale": "ru", + + "appBarTitle": "Криптобиржа", + + "search": "Поиск", + "liked": "Вы добавили в избранное", + "unliked": "Вы удалили из избранного", + "errorOccured": "Произошла ошибка", + "noErrorMsg": "Нет сообщения", + "retry": "Повторить", + "unknown": "Неизвестно", + + "apiYear": "Год", + "apiType": "Тип", + "apiRating": "Рейтинг", + "apiDesc": "(Описание доступно только на английском языке)", + "apiNoDesc": "Нет описания", + + "arbEnding": "t" +} \ No newline at end of file diff --git a/lib/components/extensions/context_x.dart b/lib/components/extensions/context_x.dart new file mode 100644 index 0000000..f4204a9 --- /dev/null +++ b/lib/components/extensions/context_x.dart @@ -0,0 +1,6 @@ +import 'package:flutter/cupertino.dart'; +import '../locale/l10n/app_localizations.dart'; + +extension LocalContextX on BuildContext { + AppLocale get locale => AppLocale.of(this)!; +} diff --git a/lib/components/locale/l10n/app_localizations.dart b/lib/components/locale/l10n/app_localizations.dart new file mode 100644 index 0000000..030d71e --- /dev/null +++ b/lib/components/locale/l10n/app_localizations.dart @@ -0,0 +1,213 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'app_localizations_en.dart'; +import 'app_localizations_ru.dart'; + +// ignore_for_file: type=lint + +/// Callers can lookup localized strings with an instance of AppLocale +/// returned by `AppLocale.of(context)`. +/// +/// Applications need to include `AppLocale.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'l10n/app_localizations.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: AppLocale.localizationsDelegates, +/// supportedLocales: AppLocale.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the AppLocale.supportedLocales +/// property. +abstract class AppLocale { + AppLocale(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static AppLocale? of(BuildContext context) { + return Localizations.of(context, AppLocale); + } + + static const LocalizationsDelegate delegate = _AppLocaleDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// Additional delegates can be added by appending to this list in + /// MaterialApp. This list does not have to be used at all if a custom list + /// of delegates is preferred or required. + static const List> localizationsDelegates = >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [ + Locale('en'), + Locale('ru') + ]; + + /// No description provided for @appBarTitle. + /// + /// In ru, this message translates to: + /// **'Криптобиржа'** + String get appBarTitle; + + /// No description provided for @search. + /// + /// In ru, this message translates to: + /// **'Поиск'** + String get search; + + /// No description provided for @liked. + /// + /// In ru, this message translates to: + /// **'Вы добавили в избранное'** + String get liked; + + /// No description provided for @unliked. + /// + /// In ru, this message translates to: + /// **'Вы удалили из избранного'** + String get unliked; + + /// No description provided for @errorOccured. + /// + /// In ru, this message translates to: + /// **'Произошла ошибка'** + String get errorOccured; + + /// No description provided for @noErrorMsg. + /// + /// In ru, this message translates to: + /// **'Нет сообщения'** + String get noErrorMsg; + + /// No description provided for @retry. + /// + /// In ru, this message translates to: + /// **'Повторить'** + String get retry; + + /// No description provided for @unknown. + /// + /// In ru, this message translates to: + /// **'Неизвестно'** + String get unknown; + + /// No description provided for @apiYear. + /// + /// In ru, this message translates to: + /// **'Год'** + String get apiYear; + + /// No description provided for @apiType. + /// + /// In ru, this message translates to: + /// **'Тип'** + String get apiType; + + /// No description provided for @apiRating. + /// + /// In ru, this message translates to: + /// **'Рейтинг'** + String get apiRating; + + /// No description provided for @apiDesc. + /// + /// In ru, this message translates to: + /// **'(Описание доступно только на английском языке)'** + String get apiDesc; + + /// No description provided for @apiNoDesc. + /// + /// In ru, this message translates to: + /// **'Нет описания'** + String get apiNoDesc; + + /// No description provided for @arbEnding. + /// + /// In ru, this message translates to: + /// **'t'** + String get arbEnding; +} + +class _AppLocaleDelegate extends LocalizationsDelegate { + const _AppLocaleDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture(lookupAppLocale(locale)); + } + + @override + bool isSupported(Locale locale) => ['en', 'ru'].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocaleDelegate old) => false; +} + +AppLocale lookupAppLocale(Locale locale) { + + + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'en': return AppLocaleEn(); + case 'ru': return AppLocaleRu(); + } + + throw FlutterError( + 'AppLocale.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.' + ); +} diff --git a/lib/components/locale/l10n/app_localizations_en.dart b/lib/components/locale/l10n/app_localizations_en.dart new file mode 100644 index 0000000..4d7f100 --- /dev/null +++ b/lib/components/locale/l10n/app_localizations_en.dart @@ -0,0 +1,50 @@ +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for English (`en`). +class AppLocaleEn extends AppLocale { + AppLocaleEn([String locale = 'en']) : super(locale); + + @override + String get appBarTitle => 'Crypto Exchange'; + + @override + String get search => 'Search'; + + @override + String get liked => 'You liked'; + + @override + String get unliked => 'Like removed from'; + + @override + String get errorOccured => 'Произошла ошибка'; + + @override + String get noErrorMsg => 'No message provided'; + + @override + String get retry => 'Retry'; + + @override + String get unknown => 'Unknown'; + + @override + String get apiYear => 'Year'; + + @override + String get apiType => 'Type'; + + @override + String get apiRating => 'Rating'; + + @override + String get apiDesc => ''; + + @override + String get apiNoDesc => 'No description provided'; + + @override + String get arbEnding => 't'; +} diff --git a/lib/components/locale/l10n/app_localizations_ru.dart b/lib/components/locale/l10n/app_localizations_ru.dart new file mode 100644 index 0000000..d3f54e9 --- /dev/null +++ b/lib/components/locale/l10n/app_localizations_ru.dart @@ -0,0 +1,50 @@ +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Russian (`ru`). +class AppLocaleRu extends AppLocale { + AppLocaleRu([String locale = 'ru']) : super(locale); + + @override + String get appBarTitle => 'Криптобиржа'; + + @override + String get search => 'Поиск'; + + @override + String get liked => 'Вы добавили в избранное'; + + @override + String get unliked => 'Вы удалили из избранного'; + + @override + String get errorOccured => 'Произошла ошибка'; + + @override + String get noErrorMsg => 'Нет сообщения'; + + @override + String get retry => 'Повторить'; + + @override + String get unknown => 'Неизвестно'; + + @override + String get apiYear => 'Год'; + + @override + String get apiType => 'Тип'; + + @override + String get apiRating => 'Рейтинг'; + + @override + String get apiDesc => '(Описание доступно только на английском языке)'; + + @override + String get apiNoDesc => 'Нет описания'; + + @override + String get arbEnding => 't'; +} diff --git a/lib/components/resources.g.dart b/lib/components/resources.g.dart new file mode 100644 index 0000000..915a8d9 --- /dev/null +++ b/lib/components/resources.g.dart @@ -0,0 +1,10 @@ +/// Generate by [asset_generator](https://github.com/fluttercandies/flutter_asset_generator) library. +/// PLEASE DO NOT EDIT MANUALLY. +// ignore_for_file: constant_identifier_names +class R { + const R._(); + + static const String ASSETS_SVG_RU_SVG = 'assets/svg/ru.svg'; + + static const String ASSETS_SVG_US_SVG = 'assets/svg/us.svg'; +} diff --git a/lib/data/mappers/characters_mapper.dart b/lib/data/mappers/characters_mapper.dart index a5fed1e..e6c28bb 100644 --- a/lib/data/mappers/characters_mapper.dart +++ b/lib/data/mappers/characters_mapper.dart @@ -17,6 +17,7 @@ extension CharacterDataDtoToModel on CharacterDataDto { title: attributes?.name ?? 'UNKNOWN', imageUrl: attributes?.image ?? _imagePlaceholder, description: _makeDescriptionText(attributes?.born, attributes?.died), + id: id, ); } diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart index 1132fd0..e7a9b62 100644 --- a/lib/domain/models/card.dart +++ b/lib/domain/models/card.dart @@ -5,11 +5,13 @@ class CardData { final String description; final IconData icon; final String? imageUrl; + final String? id; CardData({ required this.title, required this.description, this.icon = Icons.adb, this.imageUrl, + this.id, }); } diff --git a/lib/main.dart b/lib/main.dart index eb214ab..a91fc51 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,16 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_android_app/presentation/home_page/bloc/bloc.dart'; import 'package:flutter_android_app/presentation/home_page/home_page.dart'; +import 'package:flutter_android_app/presentation/like_bloc/like_bloc.dart'; +import 'package:flutter_android_app/presentation/locale_bloc/locale_bloc.dart'; +import 'package:flutter_android_app/presentation/locale_bloc/locale_state.dart'; import 'package:flutter_android_app/repositories/potter_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'components/locale/l10n/app_localizations.dart'; + void main() { runApp(const MyApp()); } @@ -13,19 +20,32 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.green), - useMaterial3: true, - ), - home: RepositoryProvider( - lazy: true, - create: (_) => PotterRepository(), - child: BlocProvider( - lazy: false, - create: (context) => HomeBloc(context.read()), - child: const MyHomePage(title: 'Harry Potter characters'), + return BlocProvider( + lazy: false, + create: (context) => LikeBloc(), + child: BlocProvider( + lazy: false, + create: (context) => LocaleBloc(Locale(Platform.localeName)), + child: BlocBuilder( + builder: (context, state) => MaterialApp( + title: 'Flutter Demo', + locale: state.currentLocale, + localizationsDelegates: AppLocale.localizationsDelegates, + supportedLocales: AppLocale.supportedLocales, + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.green), + useMaterial3: true, + ), + home: RepositoryProvider( + lazy: true, + create: (_) => PotterRepository(), + child: BlocProvider( + lazy: false, + create: (context) => HomeBloc(context.read()), + child: const MyHomePage(title: 'Harry Potter characters'), + ), + ), + ), ), ), ); diff --git a/lib/presentation/common/svg_objects.dart b/lib/presentation/common/svg_objects.dart new file mode 100644 index 0000000..1c3292c --- /dev/null +++ b/lib/presentation/common/svg_objects.dart @@ -0,0 +1,32 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../components/resources.g.dart'; + +abstract class SvgObjects { + static void init() { + final pics = [R.ASSETS_SVG_RU_SVG, R.ASSETS_SVG_US_SVG]; + for (final String p in pics) { + final loader = SvgAssetLoader(p); + svg.cache.putIfAbsent(loader.cacheKey(null), () => loader.loadBytes(null)); + } + } +} + +class SvgRu extends StatelessWidget { + const SvgRu({super.key}); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset(R.ASSETS_SVG_RU_SVG); + } +} + +class SvgUs extends StatelessWidget { + const SvgUs({super.key}); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset(R.ASSETS_SVG_US_SVG); + } +} diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart index 5edb47d..f148566 100644 --- a/lib/presentation/home_page/card.dart +++ b/lib/presentation/home_page/card.dart @@ -1,49 +1,53 @@ part of 'home_page.dart'; -typedef OnLikeCallback = void Function(String title, bool isLiked)?; +typedef OnLikeCallback = void Function(String? id, String title, bool isLiked)?; -class _Card extends StatefulWidget { +class _Card extends StatelessWidget { + final AppLocale locale; final String title; final String description; final IconData icon; final String? imageUrl; final OnLikeCallback onLike; final VoidCallback? onTap; + final String? id; + final bool isLiked; const _Card({ super.key, + required this.locale, required this.title, required this.description, this.icon = Icons.hail, this.imageUrl, this.onLike, this.onTap, + this.id, + this.isLiked = false, }); factory _Card.fromData( + AppLocale locale, CardData data, { - final OnLikeCallback onLike, + OnLikeCallback onLike, VoidCallback? onTap, + bool isLiked = false, }) => _Card( + locale: locale, title: data.title, description: data.description, icon: data.icon, imageUrl: data.imageUrl, onLike: onLike, onTap: onTap, + isLiked: isLiked, + id: data.id, ); - @override - State<_Card> createState() => _CardState(); -} - -class _CardState extends State<_Card> { - bool isLiked = false; - @override Widget build(BuildContext context) { return GestureDetector( - onTap: widget.onTap, + onTap: onTap, child: Container( margin: const EdgeInsets.fromLTRB(20, 8, 20, 8), constraints: const BoxConstraints(minHeight: 140), @@ -73,7 +77,7 @@ class _CardState extends State<_Card> { height: double.infinity, width: 100, child: Image.network( - widget.imageUrl ?? '', + imageUrl ?? '', fit: BoxFit.cover, errorBuilder: (_, __, ___) => const Placeholder(), ), @@ -86,12 +90,12 @@ class _CardState extends State<_Card> { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.title, + title, style: Theme.of(context).textTheme.headlineLarge, ), Text( - widget.description, - style: Theme.of(context).textTheme.bodyLarge), + description, + style: Theme.of(context).textTheme.bodyLarge), ], ), ), @@ -101,24 +105,19 @@ class _CardState extends State<_Card> { child: Padding( padding: const EdgeInsets.fromLTRB(8, 0, 16, 16), child: GestureDetector( - onTap: () { - setState(() { - isLiked = !isLiked; - }); - widget.onLike?.call(widget.title, isLiked); - }, + onTap: () => onLike?.call(id, title, isLiked), child: AnimatedSwitcher( duration: const Duration(milliseconds: 100), child: isLiked - ? const Icon( - Icons.favorite, - color: Colors.redAccent, - key: ValueKey(0), - ) - : const Icon( - Icons.favorite_border, - key: ValueKey(1), - ), + ? const Icon( + Icons.favorite, + color: Colors.redAccent, + key: ValueKey(0), + ) + : const Icon( + Icons.favorite_border, + key: ValueKey(1), + ), ), ), ), diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart index b824c11..7be7b96 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -1,13 +1,23 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_android_app/components/extensions/context_x.dart'; +import 'package:flutter_android_app/components/locale/l10n/app_localizations.dart'; import 'package:flutter_android_app/components/utils/debounce.dart'; import 'package:flutter_android_app/domain/models/card.dart'; import 'package:flutter_android_app/presentation/details_page/details_page.dart'; import 'package:flutter_android_app/presentation/home_page/bloc/bloc.dart'; import 'package:flutter_android_app/presentation/home_page/bloc/events.dart'; import 'package:flutter_android_app/presentation/home_page/bloc/state.dart'; +import 'package:flutter_android_app/presentation/like_bloc/like_bloc.dart'; +import 'package:flutter_android_app/presentation/like_bloc/like_state.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import '../common/svg_objects.dart'; +import '../like_bloc/like_events.dart'; +import '../locale_bloc/locale_bloc.dart'; +import '../locale_bloc/locale_events.dart'; +import '../locale_bloc/locale_state.dart'; + part 'card.dart'; class MyHomePage extends StatefulWidget { @@ -45,8 +55,11 @@ class _BodyState extends State { @override void initState() { + SvgObjects.init(); + WidgetsBinding.instance.addPostFrameCallback((_) { context.read().add(const HomeLoadDataEvent()); + context.read().add(const LoadLikesEvent()); }); scrollController.addListener(_onNextPageListener); @@ -60,14 +73,36 @@ class _BodyState extends State { padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), child: Column( children: [ - Padding( - padding: const EdgeInsets.all(12), - child: CupertinoSearchTextField( - controller: searchController, - onChanged: (search) { - Debounce.run(() => context.read().add(HomeLoadDataEvent(search: search))); - }, - ), + Row( + children: [ + Expanded( + flex: 4, + child: Padding( + padding: const EdgeInsets.all(12), + child: CupertinoSearchTextField( + controller: searchController, + onChanged: (search) { + Debounce.run(() => context.read().add(HomeLoadDataEvent(search: search))); + }, + ), + ), + ), + GestureDetector( + onTap: () => context.read().add(const ChangeLocaleEvent()), + child: SizedBox.square( + dimension: 50, + child: Padding( + padding: const EdgeInsets.only(right: 12), + child: BlocBuilder( + builder: (context, state) { + return state.currentLocale.languageCode == 'ru' + ? const SvgRu() + : const SvgUs(); + }), + ), + ), + ), + ], ), BlocBuilder( builder: (context, state) => state.error != null @@ -77,25 +112,29 @@ class _BodyState extends State { ) : state.isLoading ? const CircularProgressIndicator() - : Expanded( - child: RefreshIndicator( - onRefresh: _onRefresh, - child: ListView.builder( - controller: scrollController, - padding: EdgeInsets.zero, - itemCount: state.data?.data?.length ?? 0, - itemBuilder: (context, index) { - final data = state.data?.data?[index]; - return data != null - ? _Card.fromData( - data, - onLike: (title, isLiked) => _showSnackBar(context, title, isLiked), - onTap: () => _navToDetails(context, data), - ) - : const SizedBox.shrink(); - }, + : BlocBuilder( + builder: (context, likeState) => Expanded( + child: RefreshIndicator( + onRefresh: _onRefresh, + child: ListView.builder( + controller: scrollController, + padding: EdgeInsets.zero, + itemCount: state.data?.data?.length ?? 0, + itemBuilder: (context, index) { + final data = state.data?.data?[index]; + return data != null + ? _Card.fromData( + context.locale, + data, + isLiked: likeState.likedIds?.contains(data.id) == true, + onLike: _onLike, + onTap: () => _navToDetails(context, data), + ) + : const SizedBox.shrink(); + }, + ), + ), ), - ), ) ), BlocBuilder( @@ -120,7 +159,7 @@ class _BodyState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( - 'Card $title ${isLiked ? 'liked' : 'disliked'}', + '$title ${isLiked ? context.locale.liked : context.locale.unliked}', style: Theme.of(context).textTheme.bodyLarge ), backgroundColor: Colors.deepPurple.shade200, @@ -149,4 +188,11 @@ class _BodyState extends State { } } } + + void _onLike(String? id, String title, bool isLiked) { + if (id != null) { + context.read().add(ChangeLikeEvent(id)); + _showSnackBar(context, title, !isLiked); + } + } } diff --git a/lib/presentation/like_bloc/like_bloc.dart b/lib/presentation/like_bloc/like_bloc.dart new file mode 100644 index 0000000..7f982f8 --- /dev/null +++ b/lib/presentation/like_bloc/like_bloc.dart @@ -0,0 +1,39 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'like_events.dart'; +import 'like_state.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +const String _likedPrefsKey = 'liked'; + +class LikeBloc extends Bloc { + LikeBloc() : super(const LikeState(likedIds: [])) { + on(_onChangeLike); + on(_onLoadLikes); + } + + Future _onLoadLikes( + LoadLikesEvent event, Emitter emit + ) async { + final prefs = await SharedPreferences.getInstance(); + final data = prefs.getStringList(_likedPrefsKey); + + emit(state.copyWith(likedIds: data)); + } + + Future _onChangeLike( + ChangeLikeEvent event, Emitter emit + ) async { + final updatedList = List.from(state.likedIds ?? []); + + if (updatedList.contains(event.id)) { + updatedList.remove(event.id); + } else { + updatedList.add(event.id); + } + + final prefs = await SharedPreferences.getInstance(); + prefs.setStringList(_likedPrefsKey, updatedList); + + emit(state.copyWith(likedIds: updatedList)); + } +} diff --git a/lib/presentation/like_bloc/like_events.dart b/lib/presentation/like_bloc/like_events.dart new file mode 100644 index 0000000..938bce0 --- /dev/null +++ b/lib/presentation/like_bloc/like_events.dart @@ -0,0 +1,12 @@ +abstract class LikeEvent { + const LikeEvent(); +} + +class LoadLikesEvent extends LikeEvent { + const LoadLikesEvent(); +} + +class ChangeLikeEvent extends LikeEvent { + final String id; + const ChangeLikeEvent(this.id); +} diff --git a/lib/presentation/like_bloc/like_state.dart b/lib/presentation/like_bloc/like_state.dart new file mode 100644 index 0000000..bb9d50a --- /dev/null +++ b/lib/presentation/like_bloc/like_state.dart @@ -0,0 +1,14 @@ +import 'package:copy_with_extension/copy_with_extension.dart'; +import 'package:equatable/equatable.dart'; + +part 'like_state.g.dart'; + +@CopyWith() +class LikeState extends Equatable { + final List? likedIds; + + const LikeState({this.likedIds}); + + @override + List get props => [likedIds]; +} diff --git a/lib/presentation/like_bloc/like_state.g.dart b/lib/presentation/like_bloc/like_state.g.dart new file mode 100644 index 0000000..0888cf2 --- /dev/null +++ b/lib/presentation/like_bloc/like_state.g.dart @@ -0,0 +1,56 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'like_state.dart'; + +// ************************************************************************** +// CopyWithGenerator +// ************************************************************************** + +abstract class _$LikeStateCWProxy { + LikeState likedIds(List? likedIds); + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LikeState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// LikeState(...).copyWith(id: 12, name: "My name") + /// ```` + LikeState call({ + List? likedIds, + }); +} + +/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfLikeState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfLikeState.copyWith.fieldName(...)` +class _$LikeStateCWProxyImpl implements _$LikeStateCWProxy { + const _$LikeStateCWProxyImpl(this._value); + + final LikeState _value; + + @override + LikeState likedIds(List? likedIds) => this(likedIds: likedIds); + + @override + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LikeState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// LikeState(...).copyWith(id: 12, name: "My name") + /// ```` + LikeState call({ + Object? likedIds = const $CopyWithPlaceholder(), + }) { + return LikeState( + likedIds: likedIds == const $CopyWithPlaceholder() + ? _value.likedIds + // ignore: cast_nullable_to_non_nullable + : likedIds as List?, + ); + } +} + +extension $LikeStateCopyWith on LikeState { + /// Returns a callable class that can be used as follows: `instanceOfLikeState.copyWith(...)` or like so:`instanceOfLikeState.copyWith.fieldName(...)`. + // ignore: library_private_types_in_public_api + _$LikeStateCWProxy get copyWith => _$LikeStateCWProxyImpl(this); +} diff --git a/lib/presentation/locale_bloc/locale_bloc.dart b/lib/presentation/locale_bloc/locale_bloc.dart new file mode 100644 index 0000000..03e22b1 --- /dev/null +++ b/lib/presentation/locale_bloc/locale_bloc.dart @@ -0,0 +1,22 @@ +import 'dart:ui'; + +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../components/locale/l10n/app_localizations.dart'; + +import 'locale_events.dart'; +import 'locale_state.dart'; + +class LocaleBloc extends Bloc { + LocaleBloc(Locale defaultLocale) : super(LocaleState(currentLocale: defaultLocale)) { + on(_onChangeLocale); + } + + Future _onChangeLocale( + ChangeLocaleEvent event, + Emitter emit + ) async { + final toChange = AppLocale.supportedLocales.firstWhere( + (loc) => loc.languageCode != state.currentLocale.languageCode); + emit(state.copyWith(currentLocale: toChange)); + } +} diff --git a/lib/presentation/locale_bloc/locale_events.dart b/lib/presentation/locale_bloc/locale_events.dart new file mode 100644 index 0000000..c08cd1b --- /dev/null +++ b/lib/presentation/locale_bloc/locale_events.dart @@ -0,0 +1,7 @@ +abstract class LocaleEvent { + const LocaleEvent(); +} + +class ChangeLocaleEvent extends LocaleEvent { + const ChangeLocaleEvent(); +} diff --git a/lib/presentation/locale_bloc/locale_state.dart b/lib/presentation/locale_bloc/locale_state.dart new file mode 100644 index 0000000..80dd1b2 --- /dev/null +++ b/lib/presentation/locale_bloc/locale_state.dart @@ -0,0 +1,16 @@ +import 'dart:ui'; + +import 'package:copy_with_extension/copy_with_extension.dart'; +import 'package:equatable/equatable.dart'; + +part 'locale_state.g.dart'; + +@CopyWith() +class LocaleState extends Equatable { + final Locale currentLocale; + + const LocaleState({required this.currentLocale}); + + @override + List get props => [currentLocale]; +} diff --git a/lib/presentation/locale_bloc/locale_state.g.dart b/lib/presentation/locale_bloc/locale_state.g.dart new file mode 100644 index 0000000..e374db6 --- /dev/null +++ b/lib/presentation/locale_bloc/locale_state.g.dart @@ -0,0 +1,58 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'locale_state.dart'; + +// ************************************************************************** +// CopyWithGenerator +// ************************************************************************** + +abstract class _$LocaleStateCWProxy { + LocaleState currentLocale(Locale currentLocale); + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LocaleState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// LocaleState(...).copyWith(id: 12, name: "My name") + /// ```` + LocaleState call({ + Locale? currentLocale, + }); +} + +/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfLocaleState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfLocaleState.copyWith.fieldName(...)` +class _$LocaleStateCWProxyImpl implements _$LocaleStateCWProxy { + const _$LocaleStateCWProxyImpl(this._value); + + final LocaleState _value; + + @override + LocaleState currentLocale(Locale currentLocale) => + this(currentLocale: currentLocale); + + @override + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LocaleState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// LocaleState(...).copyWith(id: 12, name: "My name") + /// ```` + LocaleState call({ + Object? currentLocale = const $CopyWithPlaceholder(), + }) { + return LocaleState( + currentLocale: + currentLocale == const $CopyWithPlaceholder() || currentLocale == null + ? _value.currentLocale + // ignore: cast_nullable_to_non_nullable + : currentLocale as Locale, + ); + } +} + +extension $LocaleStateCopyWith on LocaleState { + /// Returns a callable class that can be used as follows: `instanceOfLocaleState.copyWith(...)` or like so:`instanceOfLocaleState.copyWith.fieldName(...)`. + // ignore: library_private_types_in_public_api + _$LocaleStateCWProxy get copyWith => _$LocaleStateCWProxyImpl(this); +} diff --git a/pubspec.lock b/pubspec.lock index 07d63cc..75818df 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -22,6 +22,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.7.0" + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" args: dependency: transitive description: @@ -134,6 +142,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" clock: dependency: transitive description: @@ -166,6 +182,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + copy_with_extension: + dependency: "direct main" + description: + name: copy_with_extension + sha256: fbcf890b0c34aedf0894f91a11a579994b61b4e04080204656b582708b5b1125 + url: "https://pub.dev" + source: hosted + version: "5.0.4" + copy_with_extension_gen: + dependency: "direct main" + description: + name: copy_with_extension_gen + sha256: "51cd11094096d40824c8da629ca7f16f3b7cea5fc44132b679617483d43346b0" + url: "https://pub.dev" + source: hosted + version: "5.0.4" crypto: dependency: transitive description: @@ -222,6 +254,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" file: dependency: transitive description: @@ -251,6 +291,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.6" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "31cd0885738e87c72d6f055564d37fabcdacee743b396b78c7636c169cac64f5" + url: "https://pub.dev" + source: hosted + version: "0.14.2" flutter_lints: dependency: "direct dev" description: @@ -259,11 +307,29 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + flutter_localizations: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_svg: + dependency: "direct dev" + description: + name: flutter_svg + sha256: "54900a1a1243f3c4a5506d853a2b5c2dbc38d5f27e52a52618a8054401431123" + url: "https://pub.dev" + source: hosted + version: "2.0.16" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" frontend_server_client: dependency: transitive description: @@ -288,6 +354,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + http: + dependency: transitive + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -304,6 +378,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d + url: "https://pub.dev" + source: hosted + version: "4.3.0" + intl: + dependency: "direct dev" + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" io: dependency: transitive description: @@ -440,6 +530,62 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" pool: dependency: transitive description: @@ -480,6 +626,62 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "7f172d1b06de5da47b6264c2692ee2ead20bbbc246690427cdb4fc301cd0c549" + url: "https://pub.dev" + source: hosted + version: "2.3.4" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" shelf: dependency: transitive description: @@ -589,6 +791,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "27d5fefe86fb9aace4a9f8375b56b3c292b64d8c04510df230f849850d912cb7" + url: "https://pub.dev" + source: hosted + version: "1.1.15" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb" + url: "https://pub.dev" + source: hosted + version: "1.1.12" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" + url: "https://pub.dev" + source: hosted + version: "1.1.16" vector_math: dependency: transitive description: @@ -637,6 +863,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" yaml: dependency: transitive description: @@ -647,4 +889,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.5.2 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index e226e6d..b889f3b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,9 @@ dependencies: pretty_dio_logger: ^1.4.0 flutter_bloc: ^8.1.6 equatable: ^2.0.7 + copy_with_extension: ^5.0.4 + copy_with_extension_gen: ^5.0.4 + shared_preferences: ^2.3.2 dev_dependencies: flutter_test: @@ -53,14 +56,31 @@ dev_dependencies: # rules and activating additional ones. flutter_lints: ^4.0.0 + flutter_launcher_icons: ^0.14.1 + flutter_svg: ^2.0.10+1 + + flutter_localizations: + sdk: flutter + intl: ^0.19.0 + build_runner: ^2.4.13 json_serializable: ^6.8.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec +flutter_icons: + android: "ic_launcher" + ios: false + image_path: "assets/launcher.jpg" + min_sdk_android: 25 + # The following section is specific to Flutter packages. flutter: + generate: true + + assets: + - assets/svg/ # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in