From eace1767f09775ed09a6b3b4923e2d1f299ad851 Mon Sep 17 00:00:00 2001 From: Juan Gilsanz Polo Date: Tue, 27 Sep 2022 15:43:52 +0200 Subject: [PATCH] Added theme modal --- assets/icon/icon1024-white-center.png | Bin 0 -> 27185 bytes lib/l10n/app_en.arb | 8 +- lib/l10n/app_es.arb | 8 +- lib/main.dart | 3 +- lib/providers/app_config_provider.dart | 58 +++++++ lib/screens/settings/appbar.dart | 20 ++- lib/screens/settings/custom_list_tile.dart | 78 +++++++++ lib/screens/settings/custom_radio.dart | 55 +++++++ lib/screens/settings/section_label.dart | 29 ++++ lib/screens/settings/settings.dart | 52 +++++- lib/screens/settings/theme_modal.dart | 180 +++++++++++++++++++++ lib/services/database.dart | 16 +- pubspec.yaml | 1 + 13 files changed, 495 insertions(+), 13 deletions(-) create mode 100755 assets/icon/icon1024-white-center.png create mode 100644 lib/screens/settings/custom_list_tile.dart create mode 100644 lib/screens/settings/custom_radio.dart create mode 100644 lib/screens/settings/section_label.dart create mode 100644 lib/screens/settings/theme_modal.dart diff --git a/assets/icon/icon1024-white-center.png b/assets/icon/icon1024-white-center.png new file mode 100755 index 0000000000000000000000000000000000000000..a7917e9bfc384652f1a199c86eb92ac11ea3046e GIT binary patch literal 27185 zcmeGDhgVbC_XdpLfXFBcIu=9-I5G|@s31KwJEKTZdJiHX9fSyk7KgFYbWlO6g3?0o zEf7UPsUn2l1ZklJgb-TDyRY+^-|zc3yz8B{vebL;IcJ|;p8f27&OFl7(cHQH;C2K- zc3%GT!gU1M0)O3t{IV7P2*yf=Ajl!)@`bYozVR~yer2gXXNNefm$F*+e?++!T>bOh zIWC#Me?PQKeAnN5O~Z|jAAJ7T(Z?SjCz}+TU2~zCb=?@)e%$P$2ltjEQZ}FOYfZPl zJ#M&L>W#~9e7|k$2@dW*yYuGDvG~Qn7hTg8w`GKGCoC$rmM1ZO_|3hA_5Z*B{$H*E z6EVpY?xqymp?PeII6@ulHc-nX1~8RrA(^)1+PMu*Zic!E+m)$FQ_1u(EOqzLLAo8p zR5=ecHDgrbGV(M(1>w2Cr2CSW<{7h$PNCGV7)%(6Lbo}>l}k=gRs{r`NX-c0l5=KHNg|CEy(y2 zE(95G&!?%7gY)kWEpGD((q-`=BxQ7!RWB!kA2Sa#v~Hsvxm}e&Wo9LCNY>#eEv+?teDxe~A}^%q76=_FYcQLYh|Q^LM6m%~zOgTC1Gh zR>U5a)V_V0u1F4+#eGuu4bmTR%BI0UkQ}W%)O1y~FKG3R5d`f1iu`U*SbE|6cRI!p1y7+!ry!(KJakQ~RB>(C2 zEjcHhiLMBVkP2pFvL2>}&v9$=zC0`7M06FE!To|r;b5k$TnYIEdbNZ16QL4Vf;a-3 z%libo&I{TkFxQ;ACJ%YxjhXl9FHxbA0bi+WD<$Ba*(o7SPqS&9Tf|v}B#*99T%57? zh^~p+XuR!8yEAK#9~;4IqZ*%e$+j}3cz8eInSW33^4iLSWC@{*ho8^nBlBJ2H9aIK zM@fBvYCQA|n2vX@oBj{Is_pFlFMhO-+PN}_2LdvA;C09+b6XB#Z{Afanv&nlYCDVI z6VU}Yfo=px!q;Ju#^E>gg48Y%q+0-0hlaI@rNOKy_U5A*H)3C~v zpaLtOQ_1X7VDlrSz*n$`z{L^z7>z!8NXw;o%4dG$=K`qp7+FRd))X-EW}8-Kl9muR z;(rkYWx4t@`)G@oc)!U81TxLFYs8UZEBJnR5POaCb}c$3#3Qo0Y|6*`1L#${5#2+p zPS(i`QCZwCtSK4o8uEH1Y`X9Y%;m#qN}Xs)Qpf$`Kf6T#kvfD$<{e?g{7X@5)c=%t z*XPPohXzI=DoCa&AZ;b_62XShJ$Y!Rv^G;wo_!KSQUPrYCsn;75{g~Dcky?Z&<(X~ z^pQiLZG&tB4Figt*XUtW*R_OAy>`X{FZ6Eo1> zi=KBhhEc01_HP0UW|VpQR41wxPc93p%3h7|o8>lM<5m zt;KC^AW0S6%ta2?ZXDmOEllN&;D0YIkaf}>w;#bff|^YJ(9ImYhLu&~9mTeLOQ||~ z@FU&Q=tLh2GZnx8;js}FLhe$;3L|;*=(-{9xk1X2cSmJiU2zK4fvDHJ!`J(JQt1+8 zu^gkV4mNkP<*?!!FN=30d`-XeQj>d)*hFS?N{F;#bve&2K)$YamfM}T>p0Zyogm9wW-=N!WM-}kGKiN@_R zJP6-ec%JNQKrkgh+(?D(A#24&oIqmyQJLNe8oFmk9Kim4uds5edo3AUY4{9SC&tIx zn5_fgw`+fAM5^tKGpbeY*WhD`f$q#9GOg{bi7%Pf7#pFC#Av}x<84mub)5CB6Zq8t zYv$sy1SIA>`nY*HwLQPa&3o62&c)b>cPQ{ttMve{bR*JFHtg&<&>Aj*iBUm6y{B0q z<19MheU-TMJK}{(t*S(>s3Oi!9-4O)wXp2;4&$O;1t^l9ZXpkv4!C>oD&wt}$EHk# z!}eL1V1U$m0X>{%lM+G=RLYt%VSh#UlL$79F&r{r6H#yL*6PbNHav9zR5=#`sx&RU z&Yqyx*eBlDbjh^p_1=-YqlF9cv9aNyO7&c4-)3TAHq06*!LJd*WBwS3YX9*aO*j*@ z%;o&ulr|j~;ffs4L6=ubCHgbpw4KF=tCdf6tJ{O^(Y^L^$0eq0euC!-ss#Y%CcGpY z@RTs`JMDFo&(Ozec~d6F-WcgHkmy>X1?5EAr9xG8LPld0C?2m27CG>(r(F49dQ_aL3q@6e3WANfG zWGhPw-g{S!%&BxM+L9=SM0g7ZrC^OLP1L~BG1sikDEU(qE@T?jB@vfHbYQN$Q^t2D zbS+sagAI}W(I6l5HW7TObMlb1M2i!#Rn-@L5rw{(p9Dbs0Q+f)H?izp66GSvqbpvYtm9Xjo^1Tl3v0 zo>F55hIk=)hv0=sI*o2e3)SSk%fqB-Gi1gNBD@zs*t^}=D5-0`u*ADS*Y+bA08I=& z2-MbXT^Z+QuzU}U_|HnmP6Z!Wj2ZwLB2Pn|nO>j?Hq;uwrp-``?B0S;LI)T-7&0<- zgt1#*bU11=-W8%VRf7w43r-kD8=#@41;9U&%K9CdLDQW7^k3j}zk%q6*xseYD$p=8 z9s=s1EWD>br=sfF;OlTZR-Zy4ew{o- z4f4Crj7VjjMmA7V!|CTHH9Yr%GF_s5csKpr)5<5aJ`b%KbX zR`h;dvf{L$Ujt_4#T${MjWkTMA&OjpO+1JlTqlPVBGN!c@T(#QluY6~7_{rut%KYp zup4R}*g`707E&zAWp*&b=-S%0T!_{=m`gQ+3|UAK_lxu%U^o483P|1-&_&}n$UO8g zP}0lW_U+vsYY>-N8axPfM5S~pii0MrrZ?+~;kzS+KuJt+K@%5i3race25dPM&3TSZ z2>vV>dw*9=Mi99dvYE7CiDI~rwFc;D8g!KBYm^Bt80Qeky>4H;R-P)eg~S8eHjx6* z%M?UcC>At6rTgfYJUx&o)K-((OD_jw@qH`Twrz+2ZI}pe2fmwE2}<3B9iLOKsYrJW z!{A$B-SMHzkb;!Kt3#)};_70ewoV|!2>PP$JQ%I@Aa;w%tt6UUr>Zx2({d8%E{Gip zklziPe(T}V9^*9#o1PJaO$SuGBH9u@!4lV%-&Eu|?%=|=fV+;j@{z4`OTb;F-ezmt ze&IubWC(pxe}$Ps)9qh%AYC(xtxFdB?7Kx;5jL@Cx<$Iw$hWQHAQ3m;j)U%|l%{PT&S~stRVz?!6KrX5SctBHPnvpv>0``s95TSW1 zQ}yAS;T({va7-EUJLG*tX_pGQOFrBYY5E1WJ+qQS7bHW@M6&Ll(6;UML7fSpKzh)L zIg}}u4hV=b(UR1*?bDSHCm=hZE;um#icX`|Ko-Sg18v()e7=AV8?VBcmT$DU%v0bk zcrs1U*z^Ds=x=Qfg-!ary09{X67RD;rHC#4hmzs(b>ZnHt338ye_0* z0Ke{)4RrFmFnM6M0VjX$r7E}Z@LZNc_|u^wIeV@=9ni(JgBSA$T?67onzuTQXxiSr zjf#T=lNFgjbI!~~<&RJ;b)4x}hJ_Dd40rH?>0uF|ADHS_j4FuYTgrcFSkf>*AF^jHncP3-7N3M?R zXD!4#Cz&~vdk1u%N8)!pXj>Bi%JNG?5GCoM>uj@P0{oMwq!>6&3?DTJB$`QjPOr}t zt66LXR{uOzhNUSx$2B7e2CeQhV>>ZXz>|6{C?Ec=rHZRt6GROxBu|-j!6td5m~7%fyLm+)e+qLTPa@1ycqTo3wsM zhv3L0freLhfZw%Epeme(X;^c7nW32}fbqkkSel%X1~3GYDF9rVgS924q!$#4upAwj z6{-2cq)OmFW&T5!>~qBcp2%|VcxwJSs?wN?utud>c2LEdF0El$3Yn>dt!<>m)p;Xx z;CL$%yoNQVfwiDakv#YGpcF?JULd>FG!ZLGIq@fay$q(wm58AsBLxQS*hV`-vxS-Q z&1xkTWsX_ACQjQCd{4qPOCvS3i0f=lt6P%=u@3<2lafu^j**Jo6I&PH;E&PLf+vz) z_qe3QSpJw7Ko?Ce&F$EkSEahZgED6POJ4;!M7|lLF(4 z7K(qnwm{cpY{(*6_rS|y#}6#>NwYwvsy;JH!P*NjzljOzmMzlU?B_WrHXdtldDz7_;e0@_Q+yA_%guR@-8+WUQfKt8+;ktFDoqFL);+JAPK% z>w7JHvmX+wiMy@~?xSZb>`gia^4P6dSxjd*JlEw^5YHDo!xAx`VCN)L1Zt^Vk#md-`AKzRz0dQSu!lc$DxEBPT@6EiDp2$%s@;aGPAcC}a?64jAGt zE*mPLNz@RpM0@4Bf`EQg1E3b-9q}S-kx~9Yy6E#iOs9&#i}mRZda@G>9r61eV|VA+ z5X|yRE~HzmHQUO37A=2XG)1H;ub`x55s2Fi8Td@D5i07DVlzsXqt4cDXAsFf+epJ0 z?I|Fyo~J6WPF!!`_6N+F37@688~@}>9)i}^Y@>FIogTR$X`pg4QHyyB=0WB<1&!U^ zVhb^IkTc5^S-JnV6cCTx7T4H925>FuN*JN0Tv$1>b1f-Pt0`Xc*Et(G)7|99^9+K;FhXi*3@UwAtnC?T) z1?)jgjI9kRIgWF@FP?EBFS^=jeVJ(hR*1{PG=*liCIoEQYlJlBeFea68MIBkkE?Xt z>4ExRojyYS;di0^1BVKhCjBOAVmVm!2lC<}Ow<^a>0?m8qXoi)a22RiF(&W#y})=A z4Jqo191QYDWo+kGlm~Vn*p8U+4_UEqqsbJ(r@FYBiEp440y7QxWl6@`XZiy&w6h>8 zi>|YyQ{_Y07%6FY4-*S0bd844?uN8rb-Ckg9-uWo@F;?p!9tx^fz~Pb9E&eS_m#l9 z_}OC!e&PS;e$vq`U5$r0qrJH&-Dxx)vZ8Zfy52suCj`0478(#LH2)*NG-1G0^N&1 zU^kUAvaO8Jf)9}@qNU2$Ly3n$dGC0;6LXQq+6ju1ijJ1cJ{z!tc>Re%79ITC9erD& zOhZhrv^txGx_aSWH0#t?|I806Hc= z)B0jNaa6#I1B|=0w={8dA11u;JwX&|JSi0(B+Tv{#P?kRRs2>MEt2*DT>86yw5qzJ z_bwA77&vNLevBW<3*gTgd=e*G3$250-=VgpbdAW57@)ZIqP2(Mky2b{v=OJ=4CF@e zZ=R>hw*@yRZczwR6m|)7g>9pIMWoMHXE=rzfpeK`1y>CQRwKjM?0Q( zFD3)oT@0kP8k3>gLZtqpr568mCqBp;yl%xrQziwSN$M3Nd(&V2=3QU2YKiA8*jqAKQ0f4p$5$4Z8dkC-57hhg$I~Se; zzaGB_16mZ}LR+mpw+(O+iSl-dC9s^vkGv@)(I7 zMK4tBJ@{jkVHGm3QM7R+nkz``<%iI+F2;ID@E{veg>ip8Myohvn3V9fs6@pdx<~sU z_Egap!V>DHSua!KI(>BkPwkl=;NC^nypjh)(^dS#+_tWlua~bqG=Q9_JAhVK+zw6zfA^S zEMi2-Al9Ml?pO>_xr!$Ie1ir*90`8X2f?~LOjU1WWvnP-ZlO2yk_+luTrplMDe!U~_N ztJkuf)_)GEf|RJ3{hQ5iu(b=4a1fM4hJzFs5|pKo{hRe^+%H+YJV>ZL>U1OMCSuG_ znT;?CDNI9<{){)cP*IVM~)n{C)6Kpl` zb(wYoTjgiYo9*Vfo_b=o_qLuS?FF={+y{x#xq+X?L*^FOgEu;L2giootC-_%<)bBY z={c2SQ3Jl~Cjx(zn6G`vRwRtNmU_3tZ{X+O6@A)gOYgwnnG5C`Jv7CkFU6((-SVaV zU*Oj*5C7IK9jdsWyO(-@tsfX@25r6W(p~Np1V5+-9d5!5s4vN_F_jk4PxPo4_5M@S zt&b+tcZaZ4Vu=m>k`vKO^myPt&}L&k*FO(`mT23ijp?4+HurcmBfwNDbc)8dMjT@TzVawOp=5cFfz(r;0sVr;pOe@2)qE4w|jG42XU zLpYvi8BFZAd@44l5r?M2RhNOH^3hVU&TT6EjFs63J{!xmIJb2hEXCE>pC4BwUOG4P zFk3~lK3=F#!F4Vsgnud~WZCUgHGO=#^2hk}`WK1ZS#<4vidOBsZdIuQ{k{Z7%{RKb z$Ef_kOcod377IKt(383R&J#E5e6WkD>FnRw2P{%T zrHak^Zfp%Z&oQNDbY7=B$XC-<#n=18y*nQgcp5Tz#R4Na&6@6O7Z^1Quud&4aJVjG zuP-Oum^nDD(YfwkR$)Hpu^*E+&hJ>UwA4c*^E%uOOhxdbl)SYCCp*~o=B)DM6P+GE z0||y|fj+-_ChtuDK*$}@0Z@ZG;Und?L(jE7{<(BlUeP}@8i%xQ~LZ>!8**9&GY2rN%@ zS+ylut=}E=Vb@pG@&-}ATN~FKSYNkPRO0KG&79I12On!07H z|Bd!2OiQl1983+Z;=-A;+CHXgXzgW-EoTmk2CcCDCliF(4@8OansgccJFbJBwvkoN z$2@4wT`Y&6k}hs;&h$#IMUgq~#)BJ=?jF0l6HO8H&$OYPEnGfY7-|--a*aYyN13Wm zLrV&7{ox*!iTNn_GYaQ7@iayJow~}6>6R81dI$Oo-l(jp*=*Qc$z(Af7}w-#RMW+X ztxPd&%&u+(JutS`V=oL#%?s^Cnv&CuYD`zl1onRc=xV_&m9?mkd{Ccg*~xKBnk#&z zGw62{bz(jp--5Eoo<8b?*dE$~E@Sht46Z2y3*kFM}${fzqC+S0iL*lpuq&yvlF8`sj7S5z3{ z9?WJ%@1FWW*?nAM>y@a7ZI#%v+;)W-LSttN8tE+99OXe$um)_Wb}#+A%K6TVCF+b% zyv)B-bf^2pb*BIWBO|u(P0eSk;5gl~D)1w(QNxXWrk*pVk|V1sLvuI!aw?gr@3!5g zEQM=FmIfIyKfg0Ixv?F&gsUQIGof=zT3;q5XfCg6CUx$K^z)by@w{$sWTdJ2*IO^Z z*YzKJM0=u>=0BkcXLBBW;DrE(;LiS3>Ca#qM?~=US31ZI9Gah^(LxII-dH$O#QM4M z+9E^V#vN!MY;N#{HaWrT12=J`EscpT!mS!BVBhPXTT@UP^nHLbCeD}>$R*~+ZF@hn zHbm3Ul)S|I(q|5n$JmRkpT&4kb#hN;=>XR$Ba4@c_V0;M&Xy1jG)waN9)j~-ENOd6 zV$VM^cc+g?a!N`Az7JR~ee>}dYfb`XmyubD&yiqx+$U9iWJV<#$!lxL4l12m3dV00 zfmltv-E^MVoA|)HWw*es_Q!4q#s}WTl`@Oe9G2kcy^i%+dSFZ`9pZekzVqz?r$ExJ z%HCTQzjkQmAG)kMCnS_;JJ#-tK; z>sq0+#urB5d@$?2z~)6pIe4a4bL192JH1PWlQeYZ-gBK;DB~QqquAQ_dQHs`y8`HA5o+lE zWRjb}*^xWhp8Z8@9ni z&N(aXgY&OB1NH9Zp5DKk{86LFj-z+BogKd`i!3J?ehbn=W}YWNNdmp@yLNeYcEu7R zUS`&J`fL5)x1|-^MUh=e+&+!7rGz%k!2x%R1&N>bYs8A4_(gblCyj@;6RwKjc&OE0 z+mLA+AErM|85mx&%Ho&Nis2Q_rKNSXte>I9Ya(r~ki85TFm=pd^eaksoHvJ(mgxc; zxtk+qk*6LIyn~n}biU(?6L{@^_c?5pU;zCJf(O5eiKfdyPc)V@e^P1lX<%oL?WKCm zi!Yq=xmwB^H>YrDg_`6IAR8IM9ZGl4lrUxp$J^S&EJMeT=TlnU@j)I=X{iM02C~5rHtDMrw z{1aT>f{SYAcMhs0IJSg41LLpGuXVvR)uF%7j9d&YIZ!+lzi;WL3+Oxt5o!z65l zoj)p*|1!IE3ZoJ!g5|~6WaYTf9sOG-(I2JDx+iyINMpv3!AY{5_WaA^P>E5lOGU@B z1h0clL{HHyuLEMxp1&wg3x#6Pk7ZgJG3Bg7^lnv}`{rs5sh^)3Te$$qK3j70jdj4# z7&~cNT@}aQR4GQ@v{a_l2_fq(LdZ;HHtm$5HJk=Ck+mfy12@|Q=A6amV_F6R8zz;I zX{UAii$ns)i`WT*evPE0Mc1$j2G^d}+-X14t#Qh!LXm2$Xn7Fv*Tzt*dkrb6Q>npJ z_1^r7V!nvr3)VhA$`gugSum6ET>n6t_uQO5acHO5v|VtpW9}xEL%-iQV}ln9v?F-8 zH)C>zSYq|2$-@o4sl8{Uki~Ux09r*QZqD;F?#AAOMQR zDW$Q6z<2o$Maj-QWx8n4?30KeKrudu5yGiVBDSim0p1+I@{Pay41J7Mn%K^k_hI^o zhc&qBrDEW0F}#t3fwzZz8%F&hmqkQyNk@Zgp|FSkuwv}E%|8FZwlT5w^|pL`C)SXX zy;hK_b?2MgF=#kiTe4Xq5*|q?oLDWrYGquj)D^|TDT3-|x;{GLa!w>WP-D5&-Ea$) z(g(NL)+*@xY*VDkE;D5kkaO$%CAj8jewqorrHN~+Y9o2;kr7;Zd7{PZ--Dc4i)+?h z8$&@G?t{I38WrBrxZ1&9I7A^>Fu6ktr9<{20Tnd3jG+iklES&2k*lR@8+m&!)gvYc zBb8=0*}W41+9)Yg;S?l^VtMUpSC~ne>u^tHKtX}O@MilY()27OHiuQZ`hbF86p+5Z zAh_HBMfuaRMW{@g(eHW@7>N%9N1aJMR(c@}fVP{KgaI1=q$ASU`rT}7Qf z^c~v~TuQ}E3x@}a$kw#Z4FR|nmA@C-ocWI2P;UysUBiD0gQ8=(@P2BPso3BycuKv! z(h*pb2+79wDDt9R(V*s~%3n~C7bvGYo*Mpatpz}0q0YSeB`N1;m5bDwxc2VZs83bn zg2VefRR!Z3y+E}8j8Lzx2x$BN-3&LbWMEMnlpm4NLKm@bFgDJ0?Ul_N-iw4X(&@=` zw6%yJvQvDq%R4mTCf3?@M5=_>Ale8$vV*d`$Sbokc6pc7Q6B2Z+6-I+==iz+au26= z(Ge*7^VDIcscmpAR1Jl;$`qALn$RJvvo=M}zM)z?$oFo_BZX?u~ysSdiOpSlDzX!1on ziv*RS6TFniOcZ4Ss+g{?P2I%2nR z@1@7h_QCIPozaGI4DJGS8RTZ%fwJYQ+wDEaNxy+uvUiNYBxGq`SofQMX0&k}m}>J; zoE|3328I`uJLdingS&*)#}NBIC#EcoWh@C7JkTpD(D785wFGbY2Gb zr$i3X|1dzr4+PuTtJOFPcmeo8kCf^H+|Y};1mgLRA2cAz!0PRZR&YH-w>In=bWrzX zYLU^7$XtT69;Qxu^L>*_X~i2y_u3us_JwR_Be@-Y+b7{harE9odV6!@Uiti!R7$f@ zO31wKUZil;6Z&ln;8One$I=m7Sl>-#sHlFm3U1DUgtgHIg5x-$7)izcJB$C*p4Zqs z+(7Xcg*&fdtZ*9HEA48GN|y@HKKw7ErMl z-jh3qHC;syZX_H%pS>UKvqwvgA@I^~h?6O(Q787omVnN^UCXduxvRio&>OD95@4a1G)%HKh z|7E-lv!Cjf3GG=-*g}5Xi3@iteWtOcER?2el+h^^)>W~TU{@UFBif^^srpKj zp&Ir0fDjEOJnQ_b>Q(vRlC}o;muOx%=G2pucC$4}st> zn(h@7!ky5YD0E0#DOclsZ=D`)?o*Kd79czK{`&d?oaAzZu{W*Cw+vG^@Pw7gT~sCG zfe|wUxIz1a9o(<%&iNKJ1MR!qI8Lnk=gmholyuD+wr0ir`QY-i+a{7=*S+7g{iT$b#v5s$u)ShZ(a4I1@y<(QZ?3hj()cKfqTap8Vs!O zG3;6u<6J%d`tQNF;*=u~b8>Pdb4>JhU(9@!pXK`TN1+rw$MvG+HEFJ`hY$X8k&BD( z;h&RlSeJhNdO7L$sGIhuU*2|@W3zV~bZq(OGlk{PP-~qS{ieY+Q6(y{aI?jKPFZpB zWatUj4et=ltMzIT(buFV^MTH1ILx0e?^25w65A9%j5?3sSwGMfzxKL2t<~*fR;Fc6 z3jYi6W0X#C9Se-wna_nvx+1*_y0r_37v|PPKOy&3erCHOqy=( zboCnGfiW@BY3N%1g9mr}zl}h?IyV$w@~@U9Y<)uQA75LUFN^b`XD_AA`P~ZOykYIj z&nzjPP)Rw~6^rBk(>=HQwr(B&X~es=?>aB?+}6 zy>6$v%!ln-bg+8iJCK1JbdFs&yi+#Fb;|1;o#b>A_RH2sm)4FGync4SR8Rk| zXzi6|ouLhZ?&-Xhmdg|SGme{ExZjQLIYl@l52EUFIxuI((%o6l4fLj8xVSwO2&ed^ z1#?pz7(p^Ohu^kU<~TfUDEP?S?<>T*iE30dcVp}3jpvLv_hXH+;y4xQq0YLMhxn&U zec-$L|MOk&8WNmeMK}*SxL{PGuzze^VQx@T5Yk$vps0qgiUjx0-Ewc77}WvJeB*PK#nqm=Hys*u$nAbQI5zPQ82lUEWj zd)w$GsVl=}aW^h&)#`{j=MGlZX>*?pwIT$~^a_=qi}pc~Q!G?L-*uDcgyL{Wy2$Fe z-;9dfuEOBUGVYtx$tQ#S>MnZzS)&%J_rg`uOz~2+-k%8=1O9*aoS24c)vi49?Ky3e zp|)QIBgD*}p~h+zTkP~*$J7gsnV3%C_%;$8uJam*bDv>d4S#qqL!8u*-xQkhik{85 z^++I6_#mG`_KAiCtD4rQ3*n=!#~SiI5_mT2k{`zWgG)Xrgj6shP;1Qpf*6!)3~jVJ zT3J3Do$YfdJ#c#X>*Q29C)qQB$7+1J14C;_x-!5bKfI-l#Taa@dHENe*54y47+Lf7 zmLf-uP9M3C5v)I3xpb;wq5C~yzwc%L3p*}juVsV7mEsP&U4c>e-zI9`%j|$*(P11y zlarZgk*$?qQ{Ra7vcGFvME(ApLaNsN3m-B&cGDV=Jg=Z#yFdDA?b4&|FWx)x(&kmb zX27C`-Dp8Fb}@Wi6l<+EhrOsG8a#&M`|!d)mys5cZoie3P^f-bJsQXLr@QNV>Mgp9 zRszN)tt7`Hz~yW9MartiD~71dP3qgWl$@Mf^*2LPTS`p&s*gdq4Nlx>R68(m6Y2I7 zKRoiHWA_osOMSQj{ujbml5Z8U1 z@li(_*;_wxc;qvTHRChue4~R{eN1xS)Rf=L>IMa~?UKiExu>E12ll#O^_tFOk zea#Lo?lYd=7e4Tc-!P!>I+XD7gw-~#=TgR#k6W)&$dig3PQj4#Xk&dfCB6Q;dwKP_ z)bNNCEHiAzd8fOWSH1_uM-p~>y2HqDp16(s+m9ROeA$;28=$Fbq*0k(ujUcG=~+t( zRbyG-fHh57mp&-xk6DEt22s1lAC^fU-V{Gvm9h1-y-lct!Rueg`0oAFzrlhn)*SS> zJOhr9EE*mBeQo>8!eb@<`j!XG=kkyK%6(>G-{Fz_50&H(2MO+8EmA&HF7<=^xIuit z>s`h=V%L^XN6p2uB39A@BaW|mu4=;CLaW`k1qeU8;Q?7>b+!kMkAV!N$j-Af$_nNa6<4+g4d(I_7NR<~8P=;H$m3fjLk4HB4<)cYKD%uWc@95Xc$qSE z{U6&x*BmnP(H23DCiBE~Uds9M9LIfnie4UB*Bq+({CoF<TKC|KyH+}4krx3{5w3w-V6#>(K9Pmr@Qn?Bc~B$?@L9a^M3t#^DkGv^=rJCS$V*y(6#XI zG7;nTz8pg+m3V?F#b%!&} z6|)}~JZV|HSBMdecyG7(iiy`p)Od5VspUde ztL?gX^x2FELv5wwfcFPstvdlFk<&-dEWkFd;GIT)bZpb}nzL5U{;tT;oGr25==b96 zdq>#&Y6YY_BHiqs^C}%)pU8<O|EcR$xT43Ir34FaT=Fl0(1EBbuy>)gA-@0~OO?ao(=~MI}S1>X{ z<%Rac;@P;zK^p{Y+=#>})&1w;sk=z9PQds1F8?hzB~&Zjf=t~ueWrR;+(cKNb{9J& z{ge0rJGvT7`YQcX>`NL{qrc>5n>}maJKR|Ly3p47Tyk|4T|v=)Pz=y!e@JVYG)gNz zx0*U%Qj`ii8|5as+8li015F}HP-4at|GBj`!jrw_=uY>OTt}Zy#2Gyw+j>9SdA8xB z?nHQ4aL`(sjQ2u%LH|Zg{|Ym7G=5@hy}t9rb7mFI&Aaw}*^QCBTPJEcR)UoArm~g1 zuIC%7Gcgv`l8Nqs6x^@=K;7>5XvSm5>U!KGO{3PwrK(=q7Al-ax29(P>}-p14ww9c zKh)e>Bs%MLEb7VXxP?wwO{}K=t|#-D*wIzLZqN3E(ZafzD<8zcMdea$Y*0kWkUec1 zsHtTESmS$(*3@wC0XS6ycEp<=2| zhEj0#>Zz`-YWDYz#nG|>fuoJ(-JUsd$lKA~2-N8Z8;m2l{u0 zEPSGyX2>3I0Md)O28nmJ_N)UR}B^nN|(d49?Eh!Wr1?)xhf`u3T!N}ymvSi=tq-d8G=_{b%vu^Mb0EP~smy68N)<=s1%Ho7N zg=Qx+p`qyH4pOVD#Ei zJnHP|+3yu=l-Ba;&2-C(N0m)d%5?{q_9VJPJ~gG+HSDwco29_KvUeDHy#OSDGk zfFxyE5`C8I=5tWQj=B{S=U*w)#JapL%iZ-eCBgJ(t`(kbg`N|CRMy=8?=C>WqYT+A zZlIiiTNZwR%&guc_Y+s2PL7syGKX>7^oWotP9GS^lO~+ApY5r%?q66to9~`9a6QeX z9egf*DlUoUs=e^eQ}N?JFYXs4vK-Q^cWKU4=$f`(W|ix3Jxly4i-Oc+usY$AJ+^vU zU1laL@={GAML*5O@Z`|Gr1$`T0MKaM+etKl?~OiyjRk*s>i*bE0QWX);>~)+cE3}| zmZRKYBOw$P0ky6>-0Xenj}?V5KT1zN3C`l$MKgOvkbWLWB${= zitA}JML(JJNd{c^o*6iWQUYQZQ)=3;M>!`F8M6Vfj&kT)#gzUUusj+3C{lDmH$%3> z@oH`IO6yC3H!a=AniFO{S3lU;)vV@*R+KFl@r~pK`A0LWW>mX0Nk33DdlXq_6d{%v zU{%E?jp~DyEgS!+3lB}yPG~!Uj{dx2E#dclY$!6wt7`gHRAZ3Uoe0f0NJBk@?;i>G zsv^sc9*PnOXoQb|JG{~9NhMEg%4`~Fs1WM-d-`d+QHp-`vWKkC_~3*3Ql0evdX?@H zht8Hrol}>2j`E>uRV%l5qi?Y)0H~1JV1|r53Gz?X>B$5Vn3S|u8AB^NO=!5|INk8E z{*S@f@8iM$r%KAoxReu$jE(AEA)O{V%~o}6t7^I%$a?tAVdrBtB2zn|z%Z^7H}d#V zZ8D^ILW86eOtWv#gOBN3hDNOf2{J2Te3ExQeWR71_jeHpU8FZZyN zj-ol>F?)6at;`F6J-EqybckQ+x6kE0ezFIRKg4bqD?^+v z+iezc>(z>~Ji8t*cCxL7;s4Cr029llcwXG7FRIjc*a)$BEvYWQ8gbLzBbcqOS*IAG zA@Lb*Fm|0M{XnC-=hK>U#-8rSS^_GP)gCi_XcUT*9X`^$#IzF@1OXd^rP@Nbv!)8o zcL;enE@geub;}F15WqAvCdDFl3b0a^oAZ@~cSaV34VBTV^E$eKDnQO~b5`oggiGJ~ z?ybD-5P1M{sSMI znwDjRE=&tbs03H*J(Ns~e8_9u{AZ`fn2dX9a1W#SbBnI$Mn=$`y~$5-+=ukR*|!}) zjvF&X)kaGltafWMO04P6vKz)KM@FL_)c@1G(@uj0^$o*Zrg&yzvruu)-#dU==JUIX z#>Y|IFM2_M16%6kq#lpAEO!XG)D8yT3GZt?xOaW2=L8yjliec5S4H+~mv;gN#I(=PEGF%M6XFFuhsckXSCavr~=iMChH zj04yB)z25Q;kK&BU9*7~cBqdgr-wFdgfFHO_(tLiMIoJ5%TIGgItA+?Q|Ery%2iVt ztYXMq7CtK4r9qMd{XA05U%uDfPkV|BF|+_sRq-FcyH|sZA4qs(IaLvhl!_XqOtv8@0AtwY^T!nzo7I zB&f~pps#6sKj%ruF>~72p50;z-p*N$?t@dd11N3p*{BcIEB2};_SbyWnDsKC?|7VE zEGZZnJ=}gAaS;O#Ja-}iD^oBiP)oZ3l+$*_R4g>)&Quc4jtoT}%B}h`B8`XsR|4$M z&-8B@@XNYsTYS@bxVDAmnk zzjbVoZs}&v&`BZv-HIGuMuEe|kFe0|4tiWUK8Pcbg5W{F_^PkME3?-dIsJqP#A z(zA0=^G(aEEuyAslDHoU8M4UfW&mT%oVCme0@r}Y>Nod?sNp+=%ncu&3$UxB$avO< z=B}^?YHphaEUq?`tp?ZMm8f%w+>GuJdiHQytg(`NcnMZNs;qkJxJei<))ppZJ24zQ8XMtQ^(H$Eci$3UQRfx zxD%q`F}s_1UQ;XJ=6m;)@V;SkeILaSTligpY5!DQYedc|wYlly7{2ljb>cUwnu!)jdThZ@~-_9?}6@#%>Vf~iB6V6^{#A^EoD z)!!CF$ng+>^m9@!ro#G)C$&JD*>;E0GIrM4ee26>XcBVQ;NZiulJ+FU-}e9h!!jf4 z@ZpgG-UN{(ReF-XgWfq97JBc5Gn9S1K$ge1BZvMmEKc$1I~C+VzOOA!GZ&niFdaI2 zEb%HLhCa8MPqRxzxo5} z{B%fU_y{`0YXT_Mo}+)A5?L=PTgofE?qKkSB^uzg12+<$A$yd&OP17d13}WIZH4!v zunW)r5=$ZmZA@?0zimlB`d@AOG7lIhbgANT+@xs0OM{qmdq-N{200t?5oyeaaa*nS zOU!xd(Vsp3!g@Qg>BFEY61LlUOniNG?O}uO#1_OHF!A`8hhtGGh3BeM5)ukEbE{=G zvd(%ApJeN&{mx=X4GBsxHIxWj?Y@|Ps)r9j!}C6jQ|I}0}-g3FI3-O z$)rc&j=V%^?MaOdRO~3Us(~5|+0D@(KZgulUyq15wOwvnW39-&8Tu|2CFEr@#jphY-Li= zr&vF5vY7i9VU6zXfI~c$H1{^A7R|_&w3Vhd_sa>_6pWJstm5tvD$Ko&eJ;NTY2Jm=1)y=ggG9%|)fZxPTv4Ty3HUVG+7b1(){=)BHzE|I$>H>53{ zfldDG=8juENYgp?a+IYcoufX+4O12Fmi$B0%fX+%11Wh2@&3)tRJGT~vFnv3aXG@q zAy6)&n~>CT>|*KvskbupkEVd(UVKbJwYweFuG_W73f~*ed@$qP!1bB^r8Pl%Gc7q_H za{dATp9yEVa`chstsof>TE%Rjp@(5_|5pXkcl;^@J46uxjLi=Yb^LU|)Zg9TRZ5)ApslemEqf{wwFVGT z<+q&Q7T8gPu*L-iLP`Dn+da?=%u4|E8ooK!b+9%%LO0>;quDmHdw)>pDizHG3Lx(}_y8qx z=#DVYS$lYpT>AZstrv`cOTvYm_C<356mRbIuo@YBZtX~=L_!=cNN)AOwq#9BYJISG9*vc+)s%#;mD2EN{ zgb3Rjq>N-F5i&W4rlA=Op7*7F{)z8*`@#LX=DP3uI(?4s_h+WG+e*yR!^ivPR=be2 zD9ES}N~f%RxVClTa8;RQs-IIWj%IjV+K#@}atl`E8-o>XdtdN5Ue!bivh<~G)eZR} z-JXwW^L%#5G~V$2dFdOkp)`dwxTltaS6)-JtV`sHn&yWqm+jX{w zbU(azHB$fM_JR;0>)a{`|0^r9mW}DBAKB1cUNQrHqxB9<@p{^dkh>P{8FJ#@pWa~GT2@PKx6z;-CF}iZaJezH+lHqYz( zMBCTiwhDtzh7AvFNH&nBm&zYt}gGhbnev(DfE!oGfi&V~|(NC$vsLn=Zr zcNzUlFw03UFf}yG{c;_x(uOl*Os9q(O)XYr)|A~+^h-7@V#Uy|nc37%ERq!D#L3|{ zBBEDBne%N|bBZotVtvMK2HWh-9%XvDhvUv9@)%MrP8_Hi5ob=( zh5;vd|Ea)^v%Wpaqp#g-qqJpsrswQSliBjJC!7i)6;ec6#V0&R)8gujb$!HV1@>iV zS5`&`)ca06{a;|N&X8rfeiMqtDbhW zdBZ1i&1xt3ekFX-mP_hVI4WBg$dH^?)}ccPPN4f2&TtyYk(M7jyX;9rY3qX=bJ6iK z6#|A-JDRD;0}eIQS_@9l7>O2j{H>r%q@+7%lq37&L(AG$;(2)q%(GK}JCFAcJY{oOlAZxBs*S^Toa@(r@McrTg+QVk>Y|^%}XtezQaxtD?VLH2YAc;&;K}&zNM>QMt2#?MHV86rD9=D zmd{}32ke}N+{LBapEV}Rx*^Z%o4fiY(3pS$MPqTSdc$&O)$;rsQ>CgGa!14_cPl-1 zR3v=^niSBYX0ZTfnc^jsfFtXq6O;k;PWb zB@m8L9N(gEZpvoSLH3Hg*8B^U%Ws$peQ^IqwUu|B0U=s=JR4J4Hb<;#2~M{HD4KKf zY3Gl#oigo$O-_d72*+NI7cY@oPA7x>MC<|M0}N}hiKnA*`%73mh`Z|%imJ-!?=q6L z+=x7ls`da(SKv8$1wvy{hKyy$z$jbzE@B*qE1Z()xmhKbP2?hneVX^ofhOeEz>iCX9K}%_X=?P zx+U)}xc0dRSFLk@zo0FC!j?Q4N}j~bmO0;G+7KXNX3rf2GcW3gcyEHJNgPFR(0`E9 z!*xOlUs(|xA8{QK=0jMBM*|Td^`9DX%)YPY)Qo%+H!4L8JMcE^Yk*sTZ(mZ~rJ?Of zVjk&H*CvCS2dDBWj}W}~L_)KpV%znJ-#M~nzGJPQjLIF8TWAM~&ndojNImM}CHH{H zCH7A)xp$S{lR@N6rJTcC{Y@QOS2Ddg`P%8$w8uArH!&;O=xsq7+?Q^VW!T+O)Q!ityUb|Bxzaiyb8hSngR1B0DcxWG+r zvx5^zp4EXi_Q19iXCcK3s%5IK^m0TA%W?L{NK0<1n^7zTSq>g6MfK!pj__mJhrD-! z%UkMzgN55z%PlJm*n>46Ct`Uk)5|L=+WLvsyC)|z?Na(40XIp#;u$%Hm{N`6{D9$2 zwH`1`1CCV~WNN1L1>&kvZ#hM&Dw8fjd$lZMKty(|;fe3$A|BdM+6)bG&v00&DeZ;qnlyp*SR{!VM`Gt~cf!XpM$-;W>+a0eyOA0=8Xnur8JDw~HnGOf zfyhfI-#BT0YVj8=uLBoeubN+Z;++K zkku&%9Rt{E(LBhRbZ?I9BJQ^{Qt%~bgf>K}%n0zkZJuW!BT+Iq>m=!zRud{Xo9uF3 z1Z6)*dy2BxCGQwQ7faABLOAYGkLzDGMwB#iHRD}N?)MZHoEc2b)NEID1TaY2P`=Mu zI7j=)ei_3P-=*9l9Rx9icpof+4cslDU(>r4a5vb$U3cS4&pYXC* zCk$zr%-Oq4U&oCfwDZ6u`^?rlY6ty5({qxR0l14g{w(9S5XJ}L&2J`H%Z0F-o0vx< zj>Cn{q;)`fQ*Buv%8Pch#lmr?~LKxw(6nvXHqBY*hNi+3C~ z`@E2K4wDA^?>#Ryr#SP;4Q}Au0uH{6iK{D6_L;rwD6w{BaY}hv*&2`lDbQuX2^@q+ zG7&{O)9B#rT_58g@ww+1+UDo|wtll2oV!*aV_0d27=ka)Gwm|O{M3_ydCPS*|43!* zBkS1@GRrxh>E)Q;{v7kT*S}a_mb6JqYe%KHoVh)p3f{TKL}^kGQhC_4ze4z2t=k+? zKWD3bD43SEIG>=Fyi=R8)v7wE16Zy(xK~%naAWVAqy5#lt#67ESebss(+9_S1Ts(+ zTiN(Bl3&>><=(7)+gj-+SoIE3o;C{s#2sr|@O>P4j7~k2`>dI>BIrci^Q(^4pB)CN zxzW9mFYMAO<9%?NRcXX$6z6RbiEpAWbJo;m%j^9(UA!Ykxk3k*KOi|a)Q*KB6wG6; z=K=lIP|2D`5iMq434R-Sd;jW>+@c4HQ6bmgR7e0pJ=4%s;cn%oq}Y})5~LB(D}+?U z#L_5AnXvVFfVSo;`0pbH5q7k^OAJBT zUeOIvjw?N8RqQ@I0_h<@8|5FbvThzZ^^Ux;rcArHv!WYnqrA=A7LY^>3u8ey%i5a0 zoGkmmKdr8cu~R`RQ1}wFz2T8}_DbH{!*{m-4d7ar*ij{e05chx7=NPn;$B zI7Bs#O$!dE<697WK36u>R-PrV-#D&%TE*dhp;D{f*l$8^UpLuC78Jhh&p5;^L(6;u zBOEnhS{yV^)+G81GWzMjS#YKqM=|ZU^AS=D-AzRXlq&;1V7giO)1N(<)n2;$4!Kpx4aRv>S>b5G|2nZz^Rq1m@r>gMyQ0#r(p*G@inP#3uZN z3u#U}V7x91H>LbQ3PJ_Zqq_*Q;MJ<#2y zh*BkdQ9$J$RNC;TuXhR%4O~(e-WVG|GS~5L)TaFRiq?r4y5+T?{p z{(~}*!<2H^Oj~jAT0B23^HGl*)TK`f zN9EQyJnfO7s-I)Evp^me5JsQveSSJ(({a@R-=%dtw!k) zd&haM8$ZkK9u<5S8gCqO9V*%#Il2oe&);?LKqT|ENrgxfGPTomrZmA!yD2KS4BNXa z1u^~2i{`B68&5Y*+a_xh6QWeb15NJqo{k;6re1HRs({T>_Lpv7Z>(f-y~5OON>?G^ zwtjsN*;l~nF#`rq=x`WfwG}_*qR{OCy{LxOA-*FzJAM%c$|z{Z(-Mo{foMzpQ@E?;2uD1VSAg1U}r_H^U@*z zuQI$;nMtV=rp&DeQCZ0xhD}kZom57zBZoeN>I5_%EElup6iZ!3U)n3MtD6UmIsD|y zRd0$HOgCT5v@y+T|8s&$d3XAI;0iIIoTkG*!O~OP0t9K^T&;<(tsm%Xy^tg(P5kcf zGIDpJlo*vs%!jxEC5w;Hxkrwq`cJeme)1?TtZTp4hA`j+CK_d8bt$B z*GeDXb3Gwy=w-<@WB)of&?M~!t0IdxuPH!t3}c+=9%eErbO zASz}itYK9QSbtB)VUL!Ao+g+gfIV?10%;VgkvAg;u}4Q1pnC3}$k4W0{4!n6s> z0gpHX+YaYSg7kkM`*%zJpGiqoIKE8+cJaV^A1d}TE%@$HYX#^Ai?6vttA;Y(eb-{T z=@73=ZF`RPOUvo@S*3q&kBifVMulsu{nPf>^}*|;hcY=d+il|1{lkv_68NC`@!Ejn zv2t$I@-<&18RmUIV8}NLAO1|uMCN?|<5*~qg#z*nR&VG!qcxkYG^rSs7s?&lnJeIp zHkHngzIYk>dB3Y!vMxp!znUGMw_bTt&*!_?^O*6m(9kt@=CGX_lPg5$LL>e|#hCh; zmDiAmEj%quT9S0ds#%zOppx=3Yck9RiHfUjlUopYS7k+o7N{yu#_8hctL~rOq`W>X zG>4;PYmL!7yiF2iB(-nP2SDwC?>~&@b-Mjrg>vP6*Di+Env}cdbc@YK=`U)1lO>!-zOP&3L)oWvO7fB=c{QP%)+n>1LN!-(6omR)nS5F- z8F;yYMtwf1AX&H2f%)5Y8ObZk9hsqVOC(1xIAN#%{r7)u2V6f-(HIuIvhhatF|xL; Mrq(7on-8A*FWju!t^fc4 literal 0 HcmV?d00001 diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 93898a1..930685c 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -55,5 +55,11 @@ "topQueriedDomains": "Top queried domains", "viewMore": "View more", "topClients": "Top clients", - "topBlockedDomains": "Top blocked domains" + "topBlockedDomains": "Top blocked domains", + "appSettings": "App settings", + "theme": "Theme", + "light": "Light", + "dark": "Dark", + "systemDefined": "System defined", + "close": "Close" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 3bd5bf1..fa946be 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -55,5 +55,11 @@ "topQueriedDomains": "Top dominios solicitados", "viewMore": "Ver más", "topClients": "Top clientes recurrentes", - "topBlockedDomains": "Top dominios bloqueados" + "topBlockedDomains": "Top dominios bloqueados", + "appSettings": "Ajustes de la app", + "theme": "Tema", + "light": "Claro", + "dark": "Oscuro", + "systemDefined": "Definido por el sistema", + "close": "Cerrar" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 39dc802..031f7c3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,7 +28,7 @@ void main() async { final dbData = await loadDb(); serversProvider.setDbInstance(dbData['dbInstance']); - appConfigProvider.setDbInstance(dbData['dbInstance']); + appConfigProvider.saveFromDb(dbData['dbInstance'], dbData['appConfig']); serversProvider.saveFromDb(dbData['servers']); PackageInfo appInfo = await PackageInfo.fromPlatform(); @@ -75,6 +75,7 @@ class Main extends StatelessWidget { darkTheme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt! >= 31 ? darkTheme(darkDynamic) : darkThemeOldVersions(), + themeMode: appConfigProvider.selectedTheme, debugShowCheckedModeBanner: false, localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, diff --git a/lib/providers/app_config_provider.dart b/lib/providers/app_config_provider.dart index 1f96839..2700ef1 100644 --- a/lib/providers/app_config_provider.dart +++ b/lib/providers/app_config_provider.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/scheduler.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:sqflite/sqlite_api.dart'; @@ -10,6 +11,8 @@ class AppConfigProvider with ChangeNotifier { AndroidDeviceInfo? _androidDeviceInfo; IosDeviceInfo? _iosDeviceInfo; + int _selectedTheme = 0; + PackageInfo? get getAppInfo { return _appInfo; } @@ -22,6 +25,29 @@ class AppConfigProvider with ChangeNotifier { return _iosDeviceInfo; } + ThemeMode get selectedTheme { + switch (_selectedTheme) { + case 0: + return SchedulerBinding.instance.window.platformBrightness == Brightness.light + ? ThemeMode.light + : ThemeMode.dark; + + case 1: + return ThemeMode.light; + + case 2: + return ThemeMode.dark; + + default: + return ThemeMode.light; + } + } + + int get selectedThemeNumber { + return _selectedTheme; + } + + void setDbInstance(Database db) { _dbInstance = db; } @@ -37,4 +63,36 @@ class AppConfigProvider with ChangeNotifier { void setIosInfo(IosDeviceInfo deviceInfo) { _iosDeviceInfo = deviceInfo; } + + Future setSelectedTheme(int value) async { + final updated = await _updateThemeDb(value); + if (updated == true) { + _selectedTheme = value; + notifyListeners(); + return true; + } + else { + return false; + } + } + + Future _updateThemeDb(int value) async { + try { + return await _dbInstance!.transaction((txn) async { + await txn.rawUpdate( + 'UPDATE appConfig SET theme = $value', + ); + return true; + }); + } catch (e) { + return false; + } + } + + void saveFromDb(Database dbInstance, Map dbData) { + _selectedTheme = dbData['theme']; + + _dbInstance = dbInstance; + notifyListeners(); + } } \ No newline at end of file diff --git a/lib/screens/settings/appbar.dart b/lib/screens/settings/appbar.dart index 5d91161..7d53c37 100644 --- a/lib/screens/settings/appbar.dart +++ b/lib/screens/settings/appbar.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class SettingsAppBar extends StatelessWidget with PreferredSizeWidget { const SettingsAppBar({Key? key}) : super(key: key); @@ -7,7 +6,24 @@ class SettingsAppBar extends StatelessWidget with PreferredSizeWidget { @override Widget build(BuildContext context) { return AppBar( - title: Text(AppLocalizations.of(context)!.settings), + toolbarHeight: 50, + centerTitle: true, + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/icon/icon1024-white-center.png', + width: 60, + ), + const SizedBox(width: 20), + const Text( + "AdGuard Home Manager", + style: TextStyle( + fontSize: 20 + ), + ) + ], + ), ); } diff --git a/lib/screens/settings/custom_list_tile.dart b/lib/screens/settings/custom_list_tile.dart new file mode 100644 index 0000000..f97cf67 --- /dev/null +++ b/lib/screens/settings/custom_list_tile.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; + +class CustomListTile extends StatelessWidget { + final IconData? leadingIcon; + final String label; + final String? description; + final Color? color; + final void Function()? onTap; + final Widget? trailing; + final EdgeInsets? padding; + + const CustomListTile({ + Key? key, + this.leadingIcon, + required this.label, + this.description, + this.color, + this.onTap, + this.trailing, + this.padding + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: onTap, + child: Container( + padding: padding ?? const EdgeInsets.symmetric( + vertical: 10, + horizontal: 25 + ), + width: double.maxFinite, + child: Row( + children: [ + if (leadingIcon != null) Row( + children: [ + Icon( + leadingIcon, + color: color, + ), + const SizedBox(width: 20), + ], + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: TextStyle( + fontSize: 16, + color: color + ), + ), + if (description != null) Column( + children: [ + const SizedBox(height: 5), + Text( + description!, + style: TextStyle( + color: color ?? Colors.grey + ), + ) + ], + ) + ], + ), + ), + if (trailing != null) trailing! + ], + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/settings/custom_radio.dart b/lib/screens/settings/custom_radio.dart new file mode 100644 index 0000000..868f407 --- /dev/null +++ b/lib/screens/settings/custom_radio.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; + +class CustomRadio extends StatelessWidget { + final int value; + final int groupValue; + final Function(int)? onChange; + final Color backgroundColor; + + const CustomRadio({ + Key? key, + required this.value, + required this.groupValue, + this.onChange, + required this.backgroundColor, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + Container( + width: 20, + height: 20, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(40), + color: value == groupValue + ? Theme.of(context).primaryColor + : Theme.of(context).brightness == Brightness.dark + ? const Color.fromRGBO(184, 184, 184, 1) + : const Color.fromRGBO(104, 104, 104, 1) + ), + ), + Container( + width: 16, + height: 16, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(35), + color: backgroundColor + ), + ), + Container( + width: 12, + height: 12, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: value == groupValue + ? Theme.of(context).primaryColor + : backgroundColor + ), + ), + ], + ); + } +} \ No newline at end of file diff --git a/lib/screens/settings/section_label.dart b/lib/screens/settings/section_label.dart new file mode 100644 index 0000000..ea31a1a --- /dev/null +++ b/lib/screens/settings/section_label.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +class SectionLabel extends StatelessWidget { + final String label; + + const SectionLabel({ + Key? key, + required this.label + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(25), + child: Text( + label, + style: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 16 + ), + ), + ), + ], + ); + } +} \ No newline at end of file diff --git a/lib/screens/settings/settings.dart b/lib/screens/settings/settings.dart index 0168162..17422aa 100644 --- a/lib/screens/settings/settings.dart +++ b/lib/screens/settings/settings.dart @@ -1,10 +1,60 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'package:adguard_home_manager/screens/settings/theme_modal.dart'; +import 'package:adguard_home_manager/screens/settings/custom_list_tile.dart'; +import 'package:adguard_home_manager/screens/settings/section_label.dart'; + +import 'package:adguard_home_manager/providers/app_config_provider.dart'; class Settings extends StatelessWidget { const Settings({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return Container(); + final appConfigProvider = Provider.of(context); + + final statusBarHeight = MediaQuery.of(context).viewInsets.top; + + String getThemeString() { + switch (appConfigProvider.selectedThemeNumber) { + case 0: + return AppLocalizations.of(context)!.systemDefined; + + case 1: + return AppLocalizations.of(context)!.light; + + case 2: + return AppLocalizations.of(context)!.dark; + + default: + return ""; + } + } + + void openThemeModal() { + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) => ThemeModal( + statusBarHeight: statusBarHeight, + selectedTheme: appConfigProvider.selectedThemeNumber, + ), + backgroundColor: Colors.transparent, + ); + } + + return ListView( + children: [ + SectionLabel(label: AppLocalizations.of(context)!.appSettings), + CustomListTile( + leadingIcon: Icons.light_mode_rounded, + label: AppLocalizations.of(context)!.theme, + description: getThemeString(), + onTap: openThemeModal, + ), + ], + ); } } \ No newline at end of file diff --git a/lib/screens/settings/theme_modal.dart b/lib/screens/settings/theme_modal.dart new file mode 100644 index 0000000..b984eb1 --- /dev/null +++ b/lib/screens/settings/theme_modal.dart @@ -0,0 +1,180 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'package:adguard_home_manager/screens/settings/custom_radio.dart'; + +import 'package:adguard_home_manager/providers/app_config_provider.dart'; + + +class ThemeModal extends StatefulWidget { + final double statusBarHeight; + final int selectedTheme; + + const ThemeModal({ + Key? key, + required this.statusBarHeight, + required this.selectedTheme, + }) : super(key: key); + + @override + State createState() => _ThemeModalState(); +} + +class _ThemeModalState extends State { + int _selectedItem = 0; + + @override + void initState() { + _selectedItem = widget.selectedTheme; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final appConfigProvider = Provider.of(context); + + final mediaQuery = MediaQuery.of(context); + + return Container( + height: mediaQuery.orientation == Orientation.landscape + ? mediaQuery.size.height - (widget.statusBarHeight) + : Platform.isIOS ? 408 : 388, + decoration: BoxDecoration( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30) + ), + color: Theme.of(context).dialogBackgroundColor, + ), + child: Column( + children: [ + SizedBox( + height: 300, + child: Column( + children: [ + const Padding( + padding: EdgeInsets.only(top: 24), + child: Icon( + Icons.light_mode_rounded, + size: 26, + ), + ), + Padding( + padding: const EdgeInsets.only( + top: 24, + bottom: 24 + ), + child: Text( + AppLocalizations.of(context)!.theme, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 24 + ), + ), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + setState(() => _selectedItem = 0); + appConfigProvider.setSelectedTheme(0); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: ListTile( + leading: const Icon(Icons.phone_android_rounded), + title: Text( + AppLocalizations.of(context)!.systemDefined, + style: const TextStyle( + fontWeight: FontWeight.normal + ), + ), + trailing: CustomRadio( + value: 0, + groupValue: _selectedItem, + backgroundColor: Theme.of(context).dialogBackgroundColor, + ), + ), + ), + ), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + setState(() => _selectedItem = 1); + appConfigProvider.setSelectedTheme(1); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: ListTile( + leading: const Icon(Icons.light_mode_rounded), + title: Text( + AppLocalizations.of(context)!.light, + style: const TextStyle( + fontWeight: FontWeight.normal + ), + ), + trailing: CustomRadio( + value: 1, + groupValue: _selectedItem, + backgroundColor: Theme.of(context).dialogBackgroundColor, + ), + ), + ), + ), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + setState(() => _selectedItem = 2); + appConfigProvider.setSelectedTheme(2); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: ListTile( + leading: const Icon(Icons.dark_mode_rounded), + title: Text( + AppLocalizations.of(context)!.dark, + style: const TextStyle( + fontWeight: FontWeight.normal + ), + ), + trailing: CustomRadio( + value: 2, + groupValue: _selectedItem, + backgroundColor: Theme.of(context).dialogBackgroundColor, + ), + ), + ), + ), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.all(20), + child: Padding( + padding: EdgeInsets.only( + bottom: Platform.isIOS ? 20 : 0 + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(AppLocalizations.of(context)!.close) + ) + ], + ), + ), + ) + ], + ) + ); + } +} \ No newline at end of file diff --git a/lib/services/database.dart b/lib/services/database.dart index 3085c75..49b84b1 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -2,13 +2,15 @@ import 'package:sqflite/sqflite.dart'; Future> loadDb() async { List>? servers; - // List>? appConfig; + List>? appConfig; Database db = await openDatabase( 'adguard_home_manager.db', version: 1, onCreate: (Database db, int version) async { await db.execute("CREATE TABLE servers (id TEXT PRIMARY KEY, name TEXT, connectionMethod TEXT, domain TEXT, path TEXT, port INTEGER, user TEXT, password TEXT, defaultServer INTEGER, authToken TEXT)"); + await db.execute("CREATE TABLE appConfig (theme NUMERIC)"); + await db.execute("INSERT INTO appConfig (theme) VALUES (0)"); }, onUpgrade: (Database db, int oldVersion, int newVersion) async { @@ -19,17 +21,17 @@ Future> loadDb() async { 'SELECT * FROM servers', ); }); - // await db.transaction((txn) async{ - // appConfig = await txn.rawQuery( - // 'SELECT * FROM appConfig', - // ); - // }); + await db.transaction((txn) async{ + appConfig = await txn.rawQuery( + 'SELECT * FROM appConfig', + ); + }); } ); return { "servers": servers, - // "appConfig": appConfig![0], + "appConfig": appConfig![0], "dbInstance": db, }; } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 915cb45..9e61ebc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -92,6 +92,7 @@ flutter: - assets/icon/icon-android-adap.png - assets/icon/icon-android.png - assets/icon/icon-splash.png + - assets/icon/icon1024-white-center.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware