From b4f785bbad706030f8889619d4cadde57022fdc1 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Wed, 27 Mar 2024 15:12:58 +0500 Subject: [PATCH 001/112] Add intl and flutter_localizations --- lib/app.dart | 12 +++++++++++- pubspec.lock | 5 +++++ pubspec.yaml | 7 +++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index dcdceaf9..f1aaed46 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -24,6 +24,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get_storage/get_storage.dart'; import 'package:receive_intent/receive_intent.dart' as intent_handler; +import 'package:flutter_localizations/flutter_localizations.dart'; class App extends StatefulWidget { const App({super.key}); @@ -98,7 +99,6 @@ class _AppState extends State { _appearanceSettings = appSettings.getGroup("Appearance"); _colorSettings = _appearanceSettings.getGroup("Colors"); _styleSettings = _appearanceSettings.getGroup("Style"); - } refreshTheme() { @@ -190,6 +190,16 @@ class _AppState extends State { : ThemeMode.dark, initialRoute: Routes.rootRoute, navigatorObservers: [routeObserver], + locale: const Locale('es'), + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [ + Locale('en'), // English + Locale('es'), // Spanish + ], onGenerateRoute: (settings) { Routes.push(settings.name ?? Routes.rootRoute); switch (settings.name) { diff --git a/pubspec.lock b/pubspec.lock index 2bab8663..7746049e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -384,6 +384,11 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_slidable: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 1f594ef8..6b45fd29 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,14 +10,15 @@ environment: dependencies: flutter: sdk: flutter - + flutter_localizations: + sdk: flutter + intl: any flutter_boot_receiver: git: url: https://github.com/AhsanSarwar45/flutter_boot_receiver.git ref: master # flutter_boot_receiver: # path: "../flutter_boot_receiver" - intl: ^0.19.0 timezone: ^0.9.1 timer_builder: ^2.0.0 path_provider: ^2.0.11 @@ -73,6 +74,8 @@ dev_dependencies: change_app_package_name: ^1.1.0 flutter_launcher_icons: ^0.13.1 +dependency_overrides: + intl: any # # flutter_launcher_icons: # android: "ic_launcher" From e36579310a2c9f08a91fb0ba9e1eddaab81ae532 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Wed, 27 Mar 2024 15:42:24 +0500 Subject: [PATCH 002/112] Add test localization --- fonts/Montserrat/Montserrat-VariableFont.ttf | Bin 394140 -> 0 bytes fonts/Montserrat/OFL.txt | 93 ------------------ l10n.yaml | 3 + lib/app.dart | 12 +-- lib/clock/screens/clock_screen.dart | 2 +- lib/common/logic/card_decoration.dart | 2 +- lib/l10n/app_en.arb | 6 ++ lib/l10n/app_es.arb | 3 + lib/navigation/data/tabs.dart | 9 +- lib/navigation/screens/nav_scaffold.dart | 5 +- .../widgets/app_navigation_bar.dart | 10 +- pubspec.yaml | 4 +- 12 files changed, 36 insertions(+), 113 deletions(-) delete mode 100644 fonts/Montserrat/Montserrat-VariableFont.ttf delete mode 100644 fonts/Montserrat/OFL.txt create mode 100644 l10n.yaml create mode 100644 lib/l10n/app_en.arb create mode 100644 lib/l10n/app_es.arb diff --git a/fonts/Montserrat/Montserrat-VariableFont.ttf b/fonts/Montserrat/Montserrat-VariableFont.ttf deleted file mode 100644 index 656db66684354d3b5bca92e5c395e1ffcdf4a472..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 394140 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

(*)x4p9Euo~C$6^A|e4gR-C%Lf^BDQVKK z5`Z{OYIi^oVRymp5~K%z$QjV5)=Bvg{LL9i$1BUt%9#l0OEh&9^0*Iv<6uWQH4Wvp%1Jt^aik+JB!_u zi;j$5tlSJxPm5NJX2_eh3!@26T1P2gppLN!11*ba8yz$ruFXfEPa)maCs4*_(53q{6Cj9!&guVzHOJaF@-AbBhU*r)0t(TAr+6Ul4SSOjNRwcXLMranM{VFEuvZaj9+GPxO~CvcK+YY&ot+gvv^*nTr~iB)bKW+hBQExwHxsLEx|Xi1u{8X>t^e!^TGd(hWqKH2g=_` zy&T_hAB;^U=vPDV{Z2>wmXN-PXNKzx|DL}aZarkH^<)WvnWX@Bv((vuN&wR_nhzKU zFvFb({CC4a=T(2eIBA{+vk$-p@B#(_`T`OF|6jt9r7fei!(^O<{?a_nX1ah6B5QDy z$Qm--G%@#Nk{`&q4AcSOy$0ay-VQQKQ2`V29j(B8GO%SY;1d=`=>ixD-Jzyi4%#Dy zTmTrNAT2;Q1?zKwZc0APeDEe2&?B0GbiCw7z$waHgkykTWU*Zl(A~pK(@nVv;iVrd ztCGqglbL3@l?RaD1E70Hm>ppj;Y{IL@Jr7izi040_J!FOw|}$x%KCu^?hH7SxhY9V zGf9}_350n9_B)W)9Y_o3fdQd36HvzljPL8QMN9uCv3fp?WL@T zCStZ0jDJZ^APj?iY*26eS0kUy|Ls@z*xXyz_oz+fD5I`!ps7&a4Zb-XMWunfR9av zIYq)4nC!;vG3q$bh?%B+EEz%}3#xO#+p>7?5hr-2p&Y(}+_DVoZmgZr-U{f&VGGg@ z1APG6m7vxASSLmrlGQU@(xfOnk zgg=j42OO7fkwk!>l^d`ea1UUsG&i75alr2byboaYT?9Z~c^VrK_c-eJo4OrGoyaU% z)^RYOm38_A_y&oyaxhw&^kcMR^kRAZ1o#l}4B!O-;&Wj5c>w%w5gN$^{qF@nO6iI3 zn2-@@5w{WxU9vIEpV8I=mbRIfY5tKvQKHCPC4yW4J%&U%k(AJv!AmmUjD6?k_l|F! zf7|$uwP(PuuQMaMR8e9P#=d-Y%1oQ-Curm0$wu?1mpo|*k_CtsM# zc;Zo#VYmL46163RI4>|AMirpa8wfe1iah8jCE7_KyWmgN`IzM-8nXbH*%@z?2qul# zh8nR81s%kIO9wKTq>+o1iJ!Q;%|#z690=c(i!VK z!P(sz@9gdD=X5y}okN^{XPI-lbGGvu=iSa_&Ig6z2kbH(7Su@_}-`Y&gp$#@2b9c_kE)8Q+=Q9`$FGW`o4DR z7Z1!oq~bSM?5_iH;+*;rvXs+dsqz@;@RIU2boYIu98}}g0jf*V;c48txe>p*C7J;` zbOaqv(fV;ZBw2JI^d#Dc4#g?+33Ljrr`OVrdaT}E@1rNghs8(5caHB7?~LygKOjCK zJ~@6!d{%rx{J8k>@ipb43(X z5zM-ToCWyE9`^X~PoMatCyTLruo>^O{kxlX-?qEcXRqx}`D`JciJ!em$Y``8Qt z+q%!5`Ru;WW&*os*R#8xCS=#$fSUkKfD3n>zpH4Mi;(}EXvW$3&Cb0$F2pDCzW7SP z2@xe8`<3|9&eJB~JwcnH&C;&auGU`DHbbK2f7(`UyY_*$Tl-EsAY6X?*7id86n=d| zbLd5M9=()aO%Lm}dZRu^zg)jkzgoXRUx?or+^#Ru7wb#(rTDeMO8q%~gT77wNdH9N ztFzz26Me6-1Y^lEV}X z74u_%#!CL4V)QhMj6OyK@_f-KHU=39#wo^iMmHnP=xX#ey5n~c3yd3$n~jr=7eKY1 z81wpK-VKs$QcOlcBAkR@do<$LftO%pzn?sS-+MeuUP5p9n0!J$C0`qE{Eot7++k!m z;&5B>y~;A>A!U`aS^1apE_9jhRlZezR1QN6cepxGO;88p>kFubYLz-sor+(9%rFKU zuNyAoHe;$0k6&S2X4K<%7@Lik9I?jBbb^s*+-?jpHaa@vR~fe&P)_BDH109}Y4mbL z8#=8p@{Kqn#^_`?@rxW4JXUw?{dI-*{a)ZT5{L(5;hmt>B&C!W{TMDN(k8Py7mJUcMk> zvFB2ud`ZqxJ|d%)J!GQt4XIYXSAHNh;IwO@$A21jN$S9*HQ-yFrL=&HQ^{n|&@wy_5L(oaH`e?lD!O;0)GdB}RtsX_9A zT0yp{=aP+TF?f*)GY4`SeD56TKND|8;Z$X2N=UF};#j(keQU zPQsipmDbWaI-Q#J|=`ol;I_h!y z33@NRH|CL3^uBsO%&PnZd$J(b?Br_np~A+$m7OyAXK(rx-ITCGRWMfy;Br#_4>*3Y2-(1+6{dOE#J&!9{7 zOnSGTMeosl^j_WXsCJxB@6&_yem$E$py$x#dM+PxL!tA(I@ngbhSQ8A5EXs$IvzUSo)NHCS8l)S&g7i>u1q*`q}gu{T#YpA5Wjv z&!x}l=h5f&a=JmEKwr=+=!<$K{ij|A&B>q-hZ{)-G)23WHKY()xJN1LjvLttOvi#p8QOL2=6MkXqU5{LQ3;atn!87Lpj{R;)5DfHZV1F_ihl zpq7A zA$1^EsWIegtTbJtb|hD-(PRNu`4&QR^Q~%6(yYeghQ*V}>*`4IFLgARBHn`3wpBfg zyse&1-h`C<1$fsz>iM|Wu7T`Tn~X_DwNYbCHl`V87(%(8x9d#unoZ zqqi{=zm;n=nv6Nd6~;VcmNDC?GcGqSHRc)@8kgwL>g$b%&DqO%%y`6jz!%_N?x)dm zBu+#1Qgp;ElkNtI)y7NQfplsm9)|sa84?diI#)|P0{a0ABpyk;nk+M9q5+yLv(kYi z(5^B}G#N-GO(1`{XuWigCH?6=67PsLh1Vn=M+VTt67NK!bfy)9)weT=&^?gH>&SF6 zo79tP@DP*1Lohv}F5<@HBqQNc1+x&LYT?%aTRom~98E*9m z=_LJmdW}fG0lfZTJd=f^Znsqx z4c8{^_aH{ML%1y?s2T;4Wip>nIz z3_0?4$drqeJC()CKOj@y1=;d$NIGed{+N_}ALPQJkW#l>9849GjKz8m5ZI9it8rehbiIupMRj1lZ?X8}I zb*8@13vsI2Up)=$bEjjSU=Uv^a6wmu2kVwzHAzjzx9SXa63u5nxST@ zS*lO&n?YMz=8&U`9X8H#X|Y6)cYGE$?Czz)Vp$n2vbqt;@bb{hD7 zoKC=qe?%cTZ8AIGO2o~vG{UIcv?^DwTzhaIF# zuseJynWZLJK0a1=sQ*@X;x^w;)KAr2>SyY1^>eJwj8pfhUqJuI zS6HVx8*<2A$XH+FzN>H5@6_+rA8(Iiqa4kZM#QJszXcLLiVzIg#hZ|=)YbR)3a2sk@Xc*~^_1+#@Pc2?M zS#xT=wBA_#?W6U@3h=2|4L?mApq;J_)COTac(CTe+PDW-%z3pWEm=#!I(ZtjlMK~{ zX=iA|wR9~*%ha+opXP_glAxBYgM6ovodtjn~e_>SQ_ACM&c`tqK}XCTWwkYHf-(RjbjaX|-CNHXT|}>a_-~ zQES2q=1i<%&erB=7eF)0h1x~h#o9dW675p$GVOBh3aoBkh4syAv}?8NwE5cg+6~%` z+D+Qc(4cY)R<>`|nzh@s+qFBiMcSR(VrW%aqTQt})$Z2r(eBljY4>UOYY%A4u@kUD zdq{g&dqjIwdrVuYJ+7_No`C+9C$%-&Q`%bXX>FbM40a2i)t=Ly*EVP`XfJC2)LznF z);2;z%O>qrtgyb0HP(M=TeLT{H?_C0%KEnU4px@8VSRbK_C8izKg3$|$J!3<-`Y;? zKiVhSr&xdf4C}C;YkRaWv@f-8wqP0*$6{=E=QmRvfI%pUTrx7%gM$ry5n#Ryr+L6Z5PP8*Ufp(!MLVrv*>~fq$ zd(fUVo}Nsdv={A-U5`GrFYQN9rTyt?bO1e_4y1#iXJ#;UQ8)F_MCzqUG?}K*ROp@= zf}Me3^b9(jrqc|XNwctH;->)`q}f;{&ZT)YpBB(US_B<6CA5^5(Ghec9YsgeF?1|F z6MAdTqG!`{=y>e2oJY&C$53IdEKR1>e07PfMAga_rh3|dRi-97gU+P0=xjQNUO?y4 z3$Y%3F<*PS6su2{W9{imtUR&xC$?raA8S}Q$Th45Y&8n&TFvw}dON)XT66BCi|Ie; z5_%V1O7Euk(0l1JdLO-?K0ue#2k8p>5Pg_FLLa4%(UtUZw)#U?L(|S0`V?JDpQh{R zGju(DmOe+HhxVNp=!^89*eQCMZltf!P4rdz8Z`23rvIW_=o|D+`WD?v-=^=-ccG={ zJ-VH~Pd~sK>=ODR{fK@{chG;+ozUL%3H_ArqMy;-^mDq0enG#aUqPeK*Yq3uE&Yyu zPk*34(tY$Nx}W|`571xeL3)TDroYl7*r6i2qN}>5Q)|U7T#w+ZZXK|uX0E(-(mP}I zt&4u5-c|30y_}Qu9@yE6*H6}+dM~}Veu~~l@2mIIPsNJdX;_y#9jkAHuo^d5uEr(u zRk~z7MNie!^db6CeVBfRK3q@NGxSX89P;UYJ)j5mY&}QM)${axy+AL7CZb}!L@(9L z^bz_gPtYs$O1%nNizexl^=f^JK2@*Lr(vg| zPM@xy4_!tL*mG#oXXrEaS^8}3K3t&B)h~pGql@)<`X&0M`eoRUxB@#8S7A@$8t6T` zPM@z|kKKtI^_%pY^#%GZ*r&J^I~BKKui_5uR@{mGihp3o;x6o2+>Kp}d-Y}defs_S z1Nw6PL4Ae(kp8g#2s9@>hW(7k^;P;4`fB}2eU1K96Xq>96aX^?&JG^f&Z3^|$n``rGXDfBaartj82*Z1gO=wIqzVejN?{TuyT{X6}8{RjO=eV_i5zF+@Y zKcN4jAJh-&hxK3eBYKNL48>3l&7g+Pb_$FzBix8EB8@1cgAt8gf>@&?b_+TgosAQW zF2;%2|LDf|KYCz~Bp&-8PNNrAw@$%sNnh+~oNDwpPBR7=ryB$LuE}8RQn<;T*y~8d zUPEVc0HO@22jR{7DQE5~e z6OBn&o2xdaV7H_OYjm|(d7EyWk3EwHz9KgRYjd-V+0fOv536$*U>|-zUzNMaxET8) zF?@IDAwtQ$q&N1`|4FXGeyKs?NIKT>F2M@kWmw0%0=x53WIQ>K3?~`JmDr8B+PKEJ z*0_$u8uQ62@`Q1{af5Lq$ue%juF(SQ1-(pGlP7Vq<|*=wfatne+wj!iRm zc5cV+&?4hbV==UAEivxGD&XDN!?_nbQukq<@B!>|J&2vIhm41@75fNwu^z)d*5l-I zV-bKF`hEkV%=~Z)(qEU_3%04d2)rZ!Fa)Vku+mZ=q2N2tekyI zzQYL-C-!=Jk(0@-WFff)yH@4cy~;E;k_BY3@rtntCo}FK_ZhE}+esMNXuO6!sLjT| z`1>g~xF2Z)>eeyK+6F$UV!pFuA>?G_o{$qS%d`eD%rnIZcmC%EB zEtyX)!w$k{*lpTl?8YwBi^k{JTlm8G68i~zvB&U@@h$ckzBhirZo@v~Cu2YM91a-2 z7zeTEaM<|OIAXNmn6Uz#W153Hbcf+^IKmv^jtEC2b}TwLqOpq+i=B%&C>!pK-HR^R zzv$}d=IHJ?$G#eZ-LY&*FD>!CjKZ}I`ziM_h_9laf=IQlsH zI{G~J~U4v!Gz5ASiwbTUnor|0sxJdVt1nob3O{}S!72&I_Yb>v*sH#P!c!|7*zoHxo!Kkk*=dSL6OP0&U>xFVB z83A5hBftZTQo3cRELnS>tc6dO)+cN46Seoayb*y`*}DT-vcg$rg_9itSutLEw@lLQ zbp%93Mb=q7YnMAKMN}gYFtT~cBC|u46onW}k5|pjGjgpKM+?Y;d(67?*zSOjyTd=zkt-{bD++GpHdfbERz>EuP8_8WQQV2V zt{`@bQNSC}D6oj_awlfd0#rkk)e0(0ktlQbivHpDWg0~yi6UDP-Xsy*%i9CBPu2pp zlLVD~S<)}nD7LEU4)|qL`ejCb*`$7%gkO}|BRY)BV-hjZ>;kfj_yT(Izk(4lsEB8gQNjRvAu63$=FF|Yi33kH`J6jOt$rYuT0r1 zIR!OS6GjIbq|%qyRnk}7GIoE$l#O{03;l3>X)$z+*S zvUE=q1#+hb=}2@zW2CJ(BCN~fmSjqnl}HX4qpY@Zx&4W}={)#0__q=;&18L4h}NQa zxdTC2kbp^hnP?!;VbpJFjqh%hoz^Ltj!~i;>!a8}V~paRS!A4&YK-CJi5wFmL-?4= z>Z}PtYo{zWw&_j7O!Pt<2bj(W`?R{ z`C?QL1!Y6L-N&9+W~$vsl$(_gJzbO{I@2VfJ)rQ5%;XfadxT1h6r@GY5+azKD!4_= z7aWZVOGnaSIhy$o_i`%{cfc*E z6B}rkkXiP2^4V$Uv$vBkRC5f#wqjw%;dw;|S`jiPGz-~^k|mlWGSHT=S*@BzmO{=_ zw)k#)`P{M;a?-K|%Mvv=0;?8sEc9-WAib0kG0KaRvIq1M^rc_G_P5nn5#mh zVKW@}F><-#$j#$sr1)w$enQ(XNQMX%C^om9#z7Yo^oq`HMO*QKc|^m-)R27BSRK4N7F$yg=&_$5YD6-rTP8Li| zo!lc*%%8SEUeVJvqEDUq1Exa$wvLJ};V@0;2ms=8uqj4{GrOl};HwaswcA=;YeWY`c1j5CGPnIWRb+U7tJ{mgdAnQ9;Q zf})E>iW!ne5`8Zi8gE>l#87ttL1ppBiTuUnDe=(Q5)+zDZK(%Q7)N}aw*-E zhoqbGDo#(4lq)T=BGg?YDy;FwsI(X=h%>SvE?yB7G})-)^)sq$q1-Z5maMK%7TYI_ z=abd-iRyY>NfA|6ev%@xhFN9}Qyf)xHp(rNbSF8gT8T3}YnLa9$9H+sIO~JqJ7`Se zC5)UDswK+`b3kImq&B&GctH^>iB1lQHL@t~VC3Z1X<({IGODe1MtjK8dxGKBoSzz5 zmM`jMN(Vk!K3A4nJ;hNit5z)qoN9|FM2Ad?oYFcwluN{RC#FPAom5{{Ra;YDTUlLU z)bIv1YOJ<^wBw^SsGZ0?Q3`n?cXuFB^4;DLR`3C z7C9jMkY9%K%f1$Hcc}X<7mof~XYW3^0fqCgNoGT5Mb`aB;*lwPMPK)L{6@W?Z@rB$ zNwOAhS?VOSmzX&OjRxCimdq;;iN};gQX(7Lw64c336?CAOqNL{r|C6ywUe+(z~r1p zTOmXUjNFnqY4YnxmQ_d&8ckNqV1DBA4T8&-2$*Jy-V~y==w$eEWHACJa5D~&>nj^U}lg|N>vqPSu*-~X=2a}B1 zJcw`(%C<<91Pi7ab9nL*bJ~31X^FAb+~?dWro7W(QdRvld`1&$8WI{RjB+u|m-A2( z=OnZZ@tK0j5VJ^@;EklkZ3~tq*a7Ji;(FLP&x6I5hbm}`ml+C*AzuheB9TmcUYTk3 zI3Xs9O$*#7y4)nFJ)rQ5EDueyGVM@lk%F|ySwzH_Qwg_3@cD$JF`=o2+at?EyqTlC zO2!p)j<5*nN6fy42oP!Wj}%jjNKDKxRy+tiQgW(}A@GFg zjhYKfbX6A58zR0jTR6=Q zeY~-@F+@b4-Kt?l-;h#+umnXzM2ZoHN0J_);$wOa)e=LcY?L`7e=+z-Jk%O7q0z{e zYMMw$8+q!3+zGt?~nt>4XU7GTVdk#|S`K5yPz#hMU70+{|)`G}w?< z5#4G)lc}@eOrmTsGtp2Jvw_TXHCs;%Vii%gA*`Z5PXCw$W2QSmn)~-B9YuJ(j z*q~*iJV$H5GE*=qA_gn&${2DPjq&6_=|uK|oL><>$?VqQf>noGw2fPbm63@t>_9t& zcy{RlF5ILC1cj-Xj$g3S5ILPr1Zd1 z>&pojG6Wnc3lwdWA(-1#7MfEtU?mE10Tj!3T#q&h+Hn zy4D;iXdQgQ>#Q+Bh$?W4uKP`UG2z8Z#~-Q#TiB7Q`$MJhn_mK&h4uNUx;D+sWE&X~ z6GkXyw)l-AwP|G5Bf_}EBjcbnW^^q0*ot6&UiJlW+>BqK`futXb$Ad{p$cm8^ zN;1hT9KImlUP3BD&}f@{1Z#MmNmr4pH&hm{Sr$~Ax$2B%sG!sF3TtHI1+$&cUhK0B z7cv#cS~q!8h^%h2Sop3@Qh=whm7C>B8(1nr+5#pDmTa~YlexIRJr{5sEEmXN*0d09 zlgDH#$STwal0#)-9FCa{3qaX);1DcPMYzcj@eqO?5-4YeWIVGA$vI~W38w}N!cL*6E zR8&5Q$F>p#WjZK`sGJZ7t<+OQ3tA&p7?%s-9WF$}P(V)88L-ot%-iG!E23NRf)!CV zP7tBY`q5b|=4=+zWCSasTd{!^Q8p$})}66{5@ie^;+pA+st3&m6Re*Zlou6jUq!gd z^Z_$_S_eDBCu1;n4}1(>oYjlAxI1YzXA^FX3GsP0J7@OncGgyQJIlguXZ5k{k^$uQ zPOZ5>D-6WWR&j(F8cG9pMh<&;MhLr|HMV8P2xOJ9qn%N-LLfyeM6|^++Pzy<3JHen zAr4Z653!NlE?7vjIB~5QN**BE;wrfnOr;q(Cd6Ngr1{LrnLBO|w?al+Y@SHc;`OA} z>=IToLXZ_C>eQO`vxVXOpUuvhK)c-{n&>K=9klzmYDQ4avUjv|hdf4HD;Cj~2orNf zL8C2Z(eB;0sY6{O#5>x;^U=X>x5^X~VkK?tc`KxUeOl!$gN%5VIgI>R$qRn*32Xi z!kQROXjQ+XovpM&pqy+dv)MUMDKjw#HM_T!pv=H(&j`+Eil8B8Q`)U@T&8UD1>73W zcu$UXYR!O($l^1y@(pJ^q2+_cX6xGyXG{b4iMCioX>HZ6yyR}qEZWlv^(;P+daa%r zDR@UKtYjc9JIY{{F4|%xxp(;aW|6|#w9nn5B`3LnkX^6>mR&53*h#=v zM_SpfHVtnweWEQMLF8*O3Rb$3Tj2IityzXp7{NDidq+F-V1OX1e=*;Z;6t0Gcs&98{m>`V)H5%l7m zi_Om27jBQXco@64)mZ$a;R{*zp2pU)ggu<`H6kI4xsldZA75N6Hpi9~=XJQ9t<$@_ z;&d2HvHRk6i%mMOo3Gouyx6wn;nKu;G+aR`pbVGvI2*?7e&M>eF?8emeV84=P}D?rZ3AQ&;EJkj+j?$C!)Nv{4SFYWK3H&MN5rd{TfChL(V+%OiPSaoE=7 z&6Meh!@8~{lRn~*F8pQuOkemYY(AD(H&)D!kr>;IoLW^eTa+|Qrj#X1B8~~WyyEmL zOp#KONojey)hiCxy1e2*Elk<-#7;Eql45dO)+@GY;VvmFPH(!r;?yQgnZG=>=@q9s z;Vx_9my{6aFkRk&?6KmUChRhPKvGhkT=j}Gh47d01F}bnGlwp3P}V;vBZ9$uBKQegR2lj~CmKF0VL9h!zs*C3ymTaKIPHx5=`y%cMQ4wcXRk zAFF)q7-80k91%V(wY5Dnvt7F{XB6M6zzD&I3u%F*i<5}bg1OwX$m4y&NA7mXV4-s{ zY#gw~NzJrb*m{kXnr)8)--x{g@|c)Nnk_$Caa;kL1yl(6czkw?JyW(A6iUEeHuI(=EJ8}u%3ni*bp_(VDM$)n0% zxqqgb9^dxLLk(VW^xNf?CkVXBGQSjApA?x-nmHw#c3Gb^S^hK` zFHM#sP1Z-8NWu^=N;v^INW&BKkc#|~+NUY5iAXAcOrM&Wo3*IbQ5_w`M z$((evWQoLKBn;`YWa2j!uuBSx-(0{hDdv+c;FB#P&Sc?xlPxa~jeEs$7Pw1_h~qA> z%NmITDzM9Z12Voiz=EM(QX(MZ%d_? z%J@MMKS?rONs`%0lFUz%$@HYk@ZyXGT1ups|n} zg3uu!uYG3mw#vs|f+Tw|`+)>}#q zwS1V!8?xBr$dd!21gU~le5Op4On0IjDH8=t>v0R=0A^;`oT~b|gt~@_4*Y(Nn~gKM zJ-l%;4hJ%qu!(g|^#ZA$A;L6N&teYY4fyR{Eyt>=CrxhTfoiK|LOkWhi3Up;21~bb zB6e|DvW*iRJXL10MB&fUguh4@4=6#rwE-8{ODUvQJ zd{)4ck%;F`@`j^DdA^gQcuNYrA(HhCiAV7wN=v8dRrS?%mFx$U_;pidLPdE)Rpf-G znwqLcj-S-VpACY(%#qwLLL5k9QKBc5S4<6AyR;uGdU|<1PRUkH6luqBYd!DpA`$FD z;=Xv(djhkDyknVtY86fb$N(LsLnsLUR$ZC?h>6vcnou45cuo*poUz2dhbwaOY@DjC z6&0fy zEw6SESY_Qzwxk+)ep6LLV>SDcOht@|OTUiiH`O)bXJ^P|0thWazy&8H+uC_4uZ=`gY(J(<|1hmh|puIkXBAs%1k34`Qn$FTW@eN*5g}FDoo3e~J*SJt=~# z!tcRkKNd?VunTU_C6+2+7ya6WbJ@N!(Slh?9V+T@@OBzHcw>3}Y+8v!xHQmIUnl)N z(v(9=rk~bS*OyC2&PC$52InI2TbyKLdQ}6`k=}B65=<(B$?U~?27+^O0;X`6M}x6_ zBl5)e7gjZGdgE-Q$P;vng%6KME(N*3C70LN*UfC2F8tF{aAFg7PGjkm8qS?qvrCsW z;lf%*x+Dvi33ZK=1=cjZvNlR4&ATyX!;1{?>LJ;~*fOGzH{7YXJMt<97C za>>XeM^=xNH#~Cb$s^?nkCZ1oQqD-k&&rv&4-??B;cgqwyB7RYq+1GbZ#dt?si>Pa zLAtuQD?cz`b9LL|G2BcmOUCjgl-KZPh9B=%Fny*Ui_0hlQ!G^_x-z9-CfwZNe7nb% zTOwRjJ6W#hwk-|wH%s7^DPh6aq5{KBDlpvLVRBvF)ba^+GtiFHCdje~Ste1+GKq3o zE76@5g?+aPRW)@pLxJULW1?IWOq7CQqFm!jl&hkNaw#HFE-@s^C51$}q>z}H%DFQX zmG_reTdTEoaJO~vT3rlPO0oO$mgEl6R&(0@d7BD;dnlxr^(Xxxm+DWUYwKZ8< zV?+4}V#weoZG;u%6~62=3@5NSEd$g%p$8NaVMRxgIUijT8n7MMD9DL6X^iB1-0Tyr zm>pSJh0|BHl~wf>v%zRV8WHZiEn;n++@VWb2a$9~yED&B4lT)S2(jVj(8Ao)Z0?B? z$9WPfJj2cK3^&6wJW;kJPhS*O)R#H9+B&4Qbx5>3@I2c(v`T~L-Zq3tgBFb{D2SU; zRo_@$Q4YooROA6Wv~r4J^ch)RT_b%XLUul)dNY&bO1W&BkX4rH%MXl9aHqIfgMlYW zN^r+AHr?ix7SoC)N^r+j*5Oojy*-GG?MZM8EHgQQb30hm?@O99lx&W?y0sZi(xC7#J-~;ifxZ@%KJR4f373jvD z3YQw_1y;!UcvR@%odKNbQdXf^aW3$S@TlZs=uT3gkLYo{pCIe-UJs3q3T~775buwn zdq;te#_#d|5gJ$(B}R!Qs?rhKQx)YjB@yo=#fP_F@xwg;?Wc;81O2Be^q&?2FII|y zmnfycM?hPs!tT?+`w{50SCq$bvw{kppsxe}7qr?d(Cqm+-g|H_gbMAQ2Y~;AdlyvP zbwh~)t(*o?p_wxc_)s+q?*R1FE6`gx2k#4^Nm79($vY5ck%}5YE96?dpN2k275X5z z1OGt%2=5)5gDB9e7)Dg+R_qPDkLJZYSu4i7L@R-NsWuMy+1lB_&(SUcez|rd-Z$e; zO$9mwkuo#}K8N=P?MuAB(!N5-y_D$;*C|>L8v0Jg+ew{7g*Lwazz5I)z@dc?cmgfQ zyOLJoJ&{hvdn!dOpaJhWD zHx%zP^fT~I*VFON)X`g@Q4YNYTIJAVp;s;+??N4vhd#NHc#qac<2_a%i}yHv0^XH+ z9o~&P`Y<%aflAO2cOl;M^vm$RLcb30n{<2|&;^HDL)Y5_ct510)=ZllE|xmYI1Spk z1{wqLz8KoWRA{~W3i#I!XtjstsU*B}9r<{VbX4G7?WjhdSMY_1Th4j_H!O`-&}Ri7 z%F`gwhINEQAr0K4$77@Bh}9K($p~~06Osfd#P{1#q<7N(48kA-*XO_oVYh$$$xnw# zEVn3o_a8dkqUd1}9b!6niy!2HN?@TrS=n~)2TMO#_2H8{p4hQ&$G)A<|7YE<=XY(~ z{nF>Je78AO7>>CqM4`arckELUY$=`*!c!v(MP)`04ZgpX}eW|BL;5_kaKMS3mDP@Xdj5 zfBE*8?|%9Im;DF7KlsC;?+@)e^wXjJhkibE=uphzy@&T7{`v5MUw{1dz^}jjdhpjn zzaIYe$dN-w4!8W;a-^lD#o&sZJ3y(aCe`UiK;`9+P-<#$g{G18b0|7If)7O~wv2|_ zI~~`G2=#_BP-)mt@6XlVNp*KnA!e!!gTk<|$gmD!F<~9U;=($Gbq?zi-Z}h)@Gjx; z;m(Mdh}ekE5nUoqjOZHCEh0WLF0ylEm&g+%yGC}4>>lZi92C_hs%upDsFR|4MD>j7 z+o5NN_ztIc7#Q6nx@Yvs(az{z(S4&&jXphkU`%vO=a~4IUNOC6PKoIgGc-0nwoh!| z*nS;*cI?;j)QvU?T{+&+mG_Z63&I39R>YUKo)!B2x zfD;Cv;5xzG#nUCRi?>ViiGxpco#;I=>BQ8or*uu}n%Xt3o3~qPx3q3Ux}|sXb<6MW z?LMUY(C)*!4?pRQlZKy^eo{e?AwAN2Wc0}Fk<}x&XaAnVdS>?Y^~{OyA3rQUJ>D1Z zj}PFovb>W|J9*g2!%q&J96UMOnd{7R<~xgfd3ptV74$0VHL`cGcVX|MQ;JV1Ii;*m zS)UPoOZye~E9qC-udLtbeq&E9J#}3FVf{z+AJhNr{^y)_&S~QZj2TcqVCw1Rr&kO- zXJF;PszK)@j8B*_xN>lvYm#fStJYQLYIIk+C%Nm~)7|HLhIuA?&QGjOY)owO&h*am z&Q7XLYD%7)d|}E(sTZfs8Zv0u1yH@mJ|*^9+}nxFOC^`2lIB!$X&SjKja)f|Ts?$b zHI!UEj9fE}%pXSX9!9P^gUmmJT#x_ZWKlY~G=nV2Ah%?YTQkU=8KgOjEcTIAK60m@ zEDe%dvdP`qIDRu_|HCFBA8my)MT z$%-=a;0Ur}1bJixd3FSOZUlLBBzbfcd3-c^c{Eu)hHM&34oy%Tla;P@ihB)TKVgoQU;o)iEf(&x;43hUZ#VC!th59X&}e=r24OW$WeWO-_N1!hWPL zbQGRW`Z)$U29wixX$L~*CJ8hHmJ%hff~Y~0C*XW ze+Tm*QGyf@O@;+Fqjq>$tD%lz!5%R2Ms52Az69(G>;o>sFiNn;q()JYJwqh;xlOng z1t;Jc3#h>}BRDU(5YM%MC3uzxS3y@e3FQ3$fnXLP9FV_-n{NNDS=N49e^kdm$iJ8n zfA9Ypw$?lTo!J+{kJA=qirv(KdO6sacpiXZU|vA5aH4fyW1~-+ZveM zYiQa*6sa zlS`l#9uf)kyh9d&D`XL9Wrr*R{p*lLpgkS32(+g|7J)yc5ba?mg=jA^DMWjN$sgJd zCV6PPndG7EVUh>5g+uay#&C8gsuNncXCnmU4}`cBj|VcxHP8`0ACDJWw{M27aL63c z6b_jK+QK1oKw~&$4rmO&ANsX3p*$+I!oXc^3-!Bk zHyyM}(_Ku?pu3rzK|g152K^B;!gTb`0D5OO?lubGHk?Y#_>(Z7Pk_9ACwk>SAaOTC zgYVmUiTI5*!UJb?={R@Y06IC^E&gM*Ms-GEcCo)+#+!Y`rlOazwNlS zf%Uu<=y|=>M|hw60evnV?0P2d0qB5R0LJ0gfwR%e`a(zlC2+d}{V%V*{zr*+3DaD! zy=e8nZs>m}(Vp6N^s)ZhhnPJFYP)zZ{G9i~lXx%e!Q@|Pu4fwH2h&T?|J+>rdm@v6 z(es%8_hhdBJ(cT!AHt+y=&NTv@(kW1hw~npjvl!Ty6YkNLT^3mg`?05*Q5V2t?p-` zFK&d6`q!byeFBqzaq}VMUzC9L%SlZB#cheKUpCU8bcN1jk}tiS_r)ujx&eJbN|AWj+-{(DYCwk;U`YF4s z6+Lnh`sL?L$2t80I?kVj^v?R_VJ7p^BTTBLE%c}1`}ngN@6E$s1TgzH4m*c`$!#J8 zf0y+x>kYRf!;hqgrN`NyvW)Z|fPQ5ec#pL`F5s^8A?bdboA576FXC`q+e@drkTDlePP)^{#c=yU;2{t<>||HSa zuJku8A2Wn$?n>Wf`7wM~`ZwtZGH^vptH+t)%!mSX0a(xQH5mh1JvkZ2@^~|bBV1X= z+14{LOu7}VDq58Z1@UDgTR%m+GGkjk37N<8bVsN@ zfYi(^>nX_m?K3*leAZ+S{TVv)$nODPaK_&}vKU`JltoibZhZ&#MKg$ERVOc@$R|&V;tXX(21=gIkG;2lH>a6GZ zvngw9)<tD!W zm4AtU6@QkqcWHB3bZ{km%A(6Cx82X)0%NYhm8A#$8%vx0>w_!(8~tzkKky&$@A7}+ zKM?2=a0Z44)Ib!+1_ZpYO$_7&$^vHxCYG)U+!J^$Fo(l*ZoU?{9Jb2?Hw11E+*7)m zhjrjs~#jJpOJBE(l%}ygIl*)VGWV7t6XHMBTRs*9Bh+Zh`qpaBpyb_PFd} z*|pgb90)gSvpd7qIXgbPKm0sAL=Y||z$)?7X3xsLG<$w_bN15g74p5h?8@xtvNvUK zExWSp%ADk!Xmjw${wOCS`=jjL+27?vXCKU=+^;Kqd*=+qlME~`XJpR!{Jr^G__H^E zd;TZ+d&}nLOfH+7+atFJut)LSl(QDkO*!>Bb91ib_C+~s3*vK@0biT*V$SBAojKb8 zJIij$`LgUL^U2wlb0p^oQVL@!<;IoG<*Cldoshc_Pd^T>+##_0bC={6YOo%udju)AO@%-wljOcBHLa`2v>Hz)7*ytDHr za_sWF8(`azcTe8Kd28}EBEPVUYJ4GlA`3khdrAhkPUNFb@$6_wK+F@TBHv z0ceEkbyNd$Djc!XZ@QPCQ>0)fDb4JW_b1D6Gg2 z_qd`Sc={pzA$VjCNR|DK<>|7N7Z%MZnpbo!%q2z3@obdy*EdDtSzmOZ=s>ZG*=RkV z1KF&%3lH;!5A!SOQyf*Yy|jNxR&keNXGv^n=i&i)yv4(dHx%cTbT50fxUBf>()i*X z#S`)DDV|Zm9_69-6#r0S6dx`=Tw;{OmOWb1 zy`)b`LP=^#R!Kq0=#ukFrj#_6TvT#($%2x_CHI%CELm6bQpuK*?IoX->@C?}T2fkz z=h9Mw)FOZd@pLYYFYRCIDIHdN5VjQvgAuN@l82myu=7is@hpYU>eA=nx3%=6(%q%s zl^!gk7?rz%ZyU%q7}(#KkH+ji7A$A$v4uN&dVeOBKNI&4O7)ST03kUcOi~4I-&wx@ zC6@0bWNb7`g<;|^=O7`uY`vGe3Ey0V$?a;oQAgA=giW^Gj*gB0<8Zk*5t7Gu(sS#P$6OYJx#eDIV$wGhj`y-2Q<+<{PV}0Jnyf^;>Y}Ik6a{Mv=>yo0LAMon38Xp6e_YJ}w;8ZytY}fI` zU}5uB_GW*7fJKQ=gpBGk$|>-pWBJDz?(a+GuPH&hzggzaE%Xuq=jA4YLH|4D4mai?b9U@v8?6&mM_N&))l-| zSjpU4V+AXJ>t+jAVx}_2Q?NzgV?1Mq{gqhZ?qf~)Si%*2Qm|c=t`)Y|tVh9q^q?<` z_7##bo}*!fyMOE3uG@Dw)EZIPxiG%4znMoNQWk%Ol2Qo6Y0q43SWpJDyIB;sg=^1k zT zuB0T7|D096O%}G*!ag!F)|6EZGGEyLvIp)g$Mr%tcdbl{Gk~WDM`0e-0}ef4r$2e~iDPq@dhnQFCDR$BkWS z#W+@M?s3Ps$%=7wY>^pm%&al;D?B<@wCvcz{e7wYH6>_UKE`F3v_OxZKc-pO{tQ<1 z;{Q-8o6XwUYP59B3N|+u9VreIvtRpI(YD|Ew(GXj9!}&}9LLP!qT;c|Lpau>xL>iW zja$f4!DP7a4UJ(#H4R19K%wXFZ(Nbt>m4*3ES|Oq`XIz4kZm? za#cvUm2E29TJ}*H_{rbL{vUha17}rL?Z3~t=NyJRGYs>WVgB6tKcXU|sECA!h=@pv zFbsr5MCc>pkr7QwKtzT*At22l8u4aG$&AcsGD1WpA~YjZ^vxqBA_G(+A>$dE_xD|E zpMCB=XU?5JXs_P;b@|LX>#V)j+Iz3P_S$RjbM9r_$@Zn8wD*Yb2Iq#}Hx#IPZ>aRJ z0UpK{r#org0Ona&D-ENK@awx__6_rISbW2s(ApiWuG=0WQQW{2k)Z^RwpVr#m{*E)W? z*eR0Fi40Ak0=^lCu~u76Lu)9cF2V1Bre~At9{2SNzy)5jygKD(1bULQ|qtS^MnTG z2=uo$1yWgD;$aDi+9H%zC+@q3)t;~TG;B!iNJXVnpW`g!Xu)66aJ&FD}2d;axZfo7nx;;eIKND|Pca!=NHt{6>-cz)?w)U8! zbabsdq)HRm#1)E0*NJP@-NX$ZwrS#H5|__XCq6at*@^DCgyKndop?Z%Ogu_hqUQ-r zamZ`1zjcl(Phg4?ey!_WS5Q}}%IXH_Sl!^d5p`qh>J%+_^|wln7V#wfO2ZZ_Y0Zb$ z)oqm2IuBD^=zUUe^7}#9_$FuxeQr(OsQOFlj;Z^)QwmepNv&wjZn|ra`E4*M$CH_> zFm+AHDvJM_=&u~rK&ks=KJnB|FV~)MbnrA|QtPDcsvjL;=;utOeUjIY&{OfSCrODG z;F*KeGs(rmT7cSK@M;Ug65s21i})s;o@^<8_Zl(!$GLsoB~6GbL|5i}R?%{)bRbJSr7-Y~XWYz11W~0`qun})Pu780qp+%T zs)tsOLcK&A#ritL@Z%`ss;5-X#Bbj`YCKr|EMs*>YV||a)5%WeH=$=Lu=8-e6Z$|i zehM7F_JiMm_-XaX>M_7-j7aq@)l0ebCX_CQzWa>ZP`U)P`;2MT!$}t3?k}#cg`Fe# zg^B6a1?W@6xYo$8&O81U86EY2@*XXyDrnjJ+YU2(~^>v{h5n<;tss(w{ui>2n{XDzK> z3+%VhJfrdrV84Xsk(CF5{aa-2S@o5#Ft+HdIhAdMLEjA4S7L6feuuHu(6X+2JW5f= z*%Y@U;ydQHO87glm61hfy+xYE^X9gyX_5xn9V~kQ`W_+7EQn0%ceHXAFembv%EroR z(6=Enx8ii=6vh@+yj3}vFmqeQVV2zxSyb^#=F<^r3}v|-?TuHrq& z4vXAev7_Q7VbHRLOS2$5nz6ehi~Chp4oB(TkvsYoR9l3>YKRC-Thz~~*oWGRAW_b= z3xIKdjjN!KvZ#o$Ix_#Pp%smc%|2^j#VSZdBaQhE6^j|W zgeXE_yQ=hdk994ciyzfARt7bA<;kO3N`j%#TBM zFw^ctDP^^o$I$!&W0~fGs@ihWmuc>+8dLr-Yk9gNt$ZV}FPJY?q?E7Y(zdGp<>X>VK!8)FCWOX`l`nAA`ywKftJZEyWV`dd~O+e zM1%QK`Rp?Ch-$N~a#|UB4y?Yiw(Knz8&h_WF}rej8TGB&Y^)qqMsuOs++W$hY>&%V zUbd65BbE7OWEaG@sx4*nnbuHgv22xTSDY@Jjxl-(*r_s%DzJu%V`X=O?<0`dQ3iho z*5Jy1#N1rm4Crj|Yi?7QaEWm%<-z?#gL%6gSH0K33! ztH>!`##nttw3K>&fqA4tl#;h!VD2wJRl0z&#>$&ZZ;`ahsiikdT6tUPRL1Jd_mt9H zxWKf_cb29}tn|@RQ}UH=EWL=ahVqT2=P-7pd|hb{Ji8oizQ1HYXmd@wbXUn5}dVUS;vY>?g z<$cpGJ5>TcxL3rs0QT zVyjT^W#)nMS7NXWuzlq(#O??7WAo{f{xO>8E#^xl{bI|xw5_}~Mq_>%?Dw!MyT80S zwv1`@qyUdmWQ>Ga}O#_CJ! ziXULCv2<*4GwQg;tS@_@xPh_#W%n18U9K@3%2tuAIE`LzE54PnhO*7YRL5yZJXAcH zF}rMiaSRfz=3S*`*(Sygm&lcPlX+Lk+huD(>l;Za-BFCOH2RwFmu{gR8TXiP7VnCs z09$0ni``Om?|v@rYc`jzior`DvAuLz*-XMBR_VgBDNJiFomV!Fv6|9Z>~($3)1}jj zk20;bw6=^!;V!eL=?&Nqi-rQcixFnBDTZ^TYT9_~uZ|ftH%$)f97#!H{@6 z_8McY#c#x5Q_yOP55{0qBNaWmJ%*kesj%~c!W^cZj@?oiWvn%JbBubP3L8v~k*}qq z=i>`U!9oYo^YdevdBB=u)rI{TtBDnH%=tMiek?W*5s(`GPLY@;F#Mt(tO|fdiB399cSdq)OHkQR$YtagxgBj@MNS>h?W^3_~ zV(NJYEPj5$I>u^>tBVfYHWZNUx0vyQa#@NQFoa8M z(Z2Hw#<9fqqUz%N2}4_oidQkMxhSi68Dlj?DHL;{`E=p?1u@223*RoD1#ByNw6=IA zW7~^X6xRZ~+kCU{*1o%d-Dbx7KGt^|u-u4QxTo(H!p!EvoqcJp61KJPKE}2eK3bg5 zd{*Jc;$Cj)x?-|vZX~mCb>B@)t0}y*h&(aZY%N?|L_NRStjRAZIt1)`v$f!05w-7n zv$^2qzSK9uo-3j;zuv4V*wGgwBc4Iem-Ve9ERtEYu(jr6wV66ptMX1;81=^{iv8cDs+}>w? z(NM;k`^?UNjj`4~(~J5+0=`xx3THFcTzD!UJ_%Y);j#P&z&8%9-;qx}9~ZF-w(uMr zXKpWegy$fYK2S(KABWoRFFe55>4H`H3m9uHSXQ``WityF=FdT^qTriT@El{U1vB!| zKG2#ACg-Dlz_u4$mp>R1*Mc@CpS+2%;rZt?R#PyjkThQlzW&r^<65+;ypZA_@#Po7 zrodVYdKE&mk%pe1E*!yFYoE6YNpqUn+~;tggN)Vmd8P0iU<=G`eGl<|VFa)Pgke9J z*7soEYG6mrZGEH&%Iz_3#XHVYW<42@UKC-OJuo(3%sS{~)nLBJ#*(InqB zkXTBkWV+5Go%F)wL% z+y^AIpvZhY@4Y@IFzoa4-y)is28_-q$s@M)m3-K3=hiZ96=<^=`#P}cjG--gI~YTD zlfNTxJ7mu@8}qj276Gd<>+|2pO#^lVN>g&+IlvnGyr1(vV-0=Y&UqVHUr03PyaDV| z@a@eZ-~F6v=Pk%VR1tp#wmAo_$C-lNr!I%0iUGbUISWzx9!gi_AfAdZn|I}pMXPBK zQJ=pdrxDl^(AJ_)gdNV478(GF{`nLI`U2~hGYHs)&{vexAK0gW<>!<`q77J14n-9K zzCk$@ReE3hil?6b4av%s)3%zZTbWnf+@DQWyBzvfWzS@+zR$938uRxcJ0}}fgC*;8XJs#Sv1!?4wZEE;xwYAI zAt6vYE_)iVGPJM0&pu#xfc9GU7+@HgK3UmOV7q_~&L%I(2j8wNvLwd0Pi+?2`2=Xa zvkrlFF0iz$Heh9_qdGSQr5Kq$DJ+YY=A6#j3a?9t>^XgI1|QLmWo-mj4v%<;WszOy z9nabg+6dFmnw@ngV+~o;Nfxxmthy|W0&+b&uQqEouxo%loHZTTJhWh7Rvoa*K--Wt zma+Q0wOO|UdmW{ZWl>bYUM;U7YXC5KF@B7`lCk=%oUC!cMws=PCs~%TqgjY`lwIeI zVp+n5X7yuQW8OfPooCkPY|Y96ZF1y}yb(F2z~*75%wjL08MTBloRQ@W&U^=USqYl- zPQ;Qti%MauyK-NF&(hjs=iHLHf@z0yceCsivnJ~8Yu4nxk%u~vrPbtY&C3I= z&aBBCmX`)>9W+A#*l6^3S>|Xu0p$D1@s+t7Gv=V=pb*(hn06bmg^aBQb}M0Gw=pyK zh296jw_J$aJxtqUOv`;Xa~Nn3g0_n#md97-_s^htzdYWMU!Fm=-x^<;y(|MGZ$OvS zY)*p2aF!?mt$?xB@s)jc^`bgf3(;pA)7F{=xr6eSfQGi@(y2PI_>!EFy*3eM7UT@c zn}PPNL>+JUBJZDv9$CE*GmP1wmG*-718d06>qT0AXw1rf zjNFK9xomd>D~M~21JF|6i@bj=u;+RWXRIN6M=u%`vd|W8)rR=Wj4i#&LEB(V%iwjw z{3bNZb!USR8TT{aOG0FETsN-;Cgb{CXpW^*%$N&(Im|Z~ZH}ft2ih>m)-!Dw>X?&G zF(XTe%=eg<6}AlNW2^#gxs|ce@s&C6ryfP==y*fU+o^59 zs^cqr4@unz3_hQ^pZThx1%IIZ5n7frRs|Y*1^Z1y)LNX57%t#py`>jlA79dYXe!0} zClIxw*}H+ghE-{4`Y2#`fNvLTxeyq<47A^(bS90ZaUoi8PU?7I=ymUrT>7SYIIEPg zca3RT1G3jZViCN3T{i42s5FI3@r)zmPQpwq#hL6cW?xu*bgBt`@a2qKsMLVfGS)?p zGuDu?I(mRGC2PPFGisxIK?Bx%XLJ`~Xv0wa>qzxVwp1ub)V_8`fZ zkmU76VFDQlAWB`#^nw)RY-0LLK#3Ix-D>|96hThYnqk$boDUX6U3J=>G z9Rk{;#)TQf2T}SyYMV!;#wB-tgb$gk%)`Bf?V+Btpyly+L&o}^)N_n)@9CM30i*Gq zlDP@k>(IhuDex3YMkKQo?L+K9=?3G%UaeWx!2V<&PJfDNuv$9Dar_FmNSAH?J!Z;7 zDW}2rEl4cQd>hyskXXSIzmGShH>A9bHur=C+s|AK&)J%?8+@lxZujxM@hnHg}$MTZ2~r!vBx00mN9r|`gZsM zn3#z}4$#ISK4!C22c*ECX!{O1JjfiB{bX*>OD<69&Ff#3xpum+Y~| zP?YZIF&z@HQ`#2RaxuKFpvPFyE=F|h-GlO;Nygw_kM&vr47o;nDX%?n!(MY(;u}Jw zvi*#2#8;*s?a>>2Q=oY;{(lj|8qx+hrwBtGl`L^1_?~l)f(GwOWq&blH1booq%6fK zRG2lr@+n>!H=^_bmVjSmyv5ibKwHDuVARpi*#JI_ZCcEwHKgS@cY>Dc^(Ym5k2q+( zI0zcg3ULs$rOwSnGYZpgO@EXyv~;e6o|_k#HK~KsU_bnSY9j4c*8FqS3;zHu1+A}k zC*Me^v*KrWFu>{#Pb+(;_Iu06nsngSz5EgGpt+OyMDL;tzw=nn3D%6{o3fmjw zpe3Jc>yMT~CrYFEuY2BSECx%Ch0jJzjBVP8o-}*1feoWlBO9d`Sq}hP0Esr1SY}?A zRvjGx+6d6(Ot}--E-JbVxQL7+8ye5+EQb@`SN%|t(>KMTx?p6oeXZz)TxGYfjohDRe(w2d2EX6a8GSEg6Epjff;avKJd0pzzp5#OQKpRXnV*@bOBHl*n`6;h~R%A>|?Vn0n zUlB?NFyCrHkr)!@gP@f%mIm5JF2$&(z`Id;Axcx2wif-hn1-E+I~VQ+AI1)R=(Pn7 zwD~9Ib z;&xQNo-yQ(QEoluj#263F9RFGr8SUP!`La%`ZHD)|67kcqy3mS=!59T@jb+->}*$CRie`JyKC?SjNu#zq?}dW`Og zS&RRbQuL6mx&hcUDiyDLK6x21*b6jdf<4%#lx@m6h_@Q-p1aJQ&~gn*r5{wGbPLxp z0sjLOdIdj#4dh%fpbzT<(a=|S4wi$qpCz_}hQ2`GIe0Z{CShVV>R4h8GA%b1`JO^~PkBuH!ns1DflSlcPqqmDhf2{iUl6UvY;dX#k{d55u!%m(|Au^y$EzjhnzyU^U0a*(kT zz+Pc&gL#+zl>Gu~YliF|q8SU#yHcLDw}Tc#=|graFvLas0WSR-N;lihpzStW?REA; z!1hA6j!Mn7W{thVz8|!k&6<=|_9|d_!jZBZW{5_tjd>jzhxwI)|G_d6*#=o2S^E-{P8Z8W#Kv6bdhtK6E+Jb#!f+o!V+iA; z87^STHH?28Fd}joAHi@2pdl>A?`8Nh!+8wvU|7rWVTS7&{uD4GEW(Xa#s@RJnBheX zvltFycs`(MupVO+aQy#oOdm*eaXG_cg2vel>i{F7obek7icc_}&GZ_k^kcl5p~0|( z=*CAGm)fKSzQgqEn0^*RlVJtZCon8xIEA2i4lp7vW!Q)5eVNWJF{qY^xPW1QhUZeL zA@M54KgMt>mkwZf4p9WvZW?15e}M5T7*buPaW!B>P`^y^E2faFA$l_9O@@DD_FCCqFmE6AZt?u!-SPf(HAZ7{hoL(~mHm!|?MA_Y*Xvp1YXx6vO@u*(b$k z7+=WnQw+bsa5%#s0!BnH!VNhh%}kFoJk4-3!;b<+L>}Y+!Eh|YH3W@J#@P?W&lvwU z!=E#p&G2c0#$^nvnDQrvYZ>lfcsoHuj^ndTS;FwE3?FB>o8d-=I~g`Ge4F7b41d9J zJi`?X|IF|uhSJA&F}{tUk;_nyP7%`=0Y>DkF@`ebTMWO)a4*9L8OlmZW_|U zWXXu2sA3A)=7WsOks_;_f_+2WNVxG4hO#A8yJ@i9j1=a4h#}8M<0>wdqyJmRsf7`d z&p5YGEGJz2JJY2G*}DNuf1l~OfX3SQ#YiEHMa#Ys7u~n}#)QZmMr;SW^mY?7fX^mV9&Yn&E4v-?#r;vznf3I^1;l-ZrWG z-a6C>-R>Qz_tvq_C2MbQJlRx$e}|i9HO*=~-DKh)-4`@XXfwg>ADk}62z1&1iJwZ`$B#%{r>WBTk(Of$54*+>wH%AT+A=?^ zOwr;eBo=?MV_nP@ZO;>LQppGplk_UG13;3 zRi6h!?p0|^)VW-ibq!*iI^p;Cp=(-0xN^uIetP^Fd5^YN`%40M=ixrb<=yF)>Ao|R zXlzs11|Ky>c1s=Kdw^``eq!x?k4oB&*`YxH-FC=vP-X6w+tjj_e2M%Rx)MG+5c4L6 zzk#TC9R7y3%u-F^Yd2;X1H+4(l5VyTWH! z2ig{Yw`ILg@BfvXnH_W_SmupU2QvR36}6jp@XgLX@Ll$!_|E2e@k7n)!uaDSTDB2A z-Ui?7SSdf1|2c5U0*(^-uNMkLHIk-vYfA2CsEIG(yM$T{vz2Gf5;2sPhuS; ze%OPrJ7o*h+DQ7;ht_!&=P2H?JjuT5%3$ron4gq!P)P-^a(z}YSLG(e#kw_phQ|dPW)%A*OA<->R=zcPU4pdem6^TO!v5@GM80eZCBS&MWk`>9UH> zvQ!URLLZ9Z@gKL$m3O$OzO+FXw-r>ZhpJ4!A_rq%R5Z3d))ln<9kvPD2wSi$-&4Lt z`HQNzt!0KMdqUGi>jpmFS|M)*+D*1AVB0Vb9+InY*AZGLqs@z5c7gRP(QdWQs=h?g zKab`~NW^WkM~$`Yqq!Py+YpuOzq>a3)@AY!w?1lr4#sb%yVkNIR|adK(i?xR`F0O~ zS7GYv^3!cUMZ*<(kE_(Kt1fbm@PxDDKut{;7PFOQ`>}Zqwf=7uU2g9es3t z`(*rZa|8Pb*^_L39^wOR#(5B3`!%oPa?+=L^zn^vMH`+WzlUDJ>F-JD6GSI5o}Wag zoaM(ZFL<~eJHg}n4f9fbaPwr28?IjBiEo9!(;QR!DUYSN;7#OHHNQY& z9eNwk$M|B*3)qBwn)(;~#NTLMqtjHZ@X_40T&EEpe-!!y>%a1`#9V1HmCb|l>YnDg zhaaIesHK;8k2wcjnq4s-+6R4GPq)7LMEBabAeP8n#NFR&;+>+(X3#OXQ|7-D1N?{k z_~EK2J1Sc$+;=}ij+>-m@8H_q&#T5;>e6|rwQBznq{}kDOt5$UeIM%Ik>HT}upY|w zED@vkwbMC@a?2LXHu|HF+H0ydNg5Y<_K_`01 z%^MJFPI@s}33#zt5$LL7mZHgc$2mW()nq4p;>VjGqJFZyW)cNCkS`aZvE)B#OEtzM z+t&ODN$5Eh+SbWFT8q0ZoB;7xn_Cli&`;x$^rOaBT{XsWu#xH$$Ub|~9*NfwC8vB< zU8NrO6P5Sz7!aLg@W=k$yj9+V%=V|Upv|SO4xv8hLm4&Ohn5quBReS}fB(8B16j70 zvK8*N@mHEdX1L2?6Zi*UNaHXlL*oT9#`vTE3s41~A&&QakiKfqXyEPl_o4 z$t1UG%#sv$$&ZuChS3A{seXjnkoTkkex;IZ5F*3Hq?7gHxkJd_PpRnkHCcTjig*pB z_UmUV0lxO*A7BW(RrU%i`xmX77NEJAn4eO(<+0>Sg1pH&U0u-M{8W3c?&@i;;a`-$ zp9Q>qK(LDFhTcTt_>X-o;`wT3an}W%9qZhB_?DMDd)spj)C&Iv))+9)6T&CBw1Tf zs_Ispd=05Ll+P#By_8~rk7#G2$On0kh`e~du$yy5M(i42~Zoy0it^Mb;JEJ9sS!NA!6V z7TfteQu-I$Jn$YCDNXoaVon6l|G?wR(dB)DUo}o2S6`m5>ZSP=%>UK%5~ZYrt51Ii zd}mao+fT=R$`U@JlV!WuH+*)|c?fUUe)3<}2ZFp^xyL%Jtr6`dD0a|ud@5;Ix67`| zm9+FzbtkV0|8(#9*?jx)S5is`&Q4_e^mwh9+-tIS1=#+_ZpmhU&&t~M*NX=qtloBd z1D)V<^0zL0^gJdxd;9SZZv*&v{BfnT)<7HDpVPJ1tJ>h#Pkj2H;_Bj6wL@LIC>F-X z&o;ZL$KMC3jrZUkMvkyrJEsMoxppq`!8wqJbQqI9cn$y3pe%rV&GQ<>TY6B*6vXUpx{vZc&V4W3lcD#`^!iZ1`#pM z2MlF!iAi$gjzl^v3*>RhcsU2>XJFwRNn=z8?Tz29omX_`KWdML>ZvW^tpHW8kKUgP z_7Cwr7^l5)M-Ce{_EZ<;PV56DuRj~3^}?MO#K)g5t|5xOd)MUaYWMU=Zq@fL$-1@; zl?mE8slq_}yDXPXq0*fL_5$ZgLD+Ry6x!tkKKXgn0h=~l%Xt;j{u&)|EU zL8fl_U+7pSYoD9{hqf)ryL-W=$y~2J^~@=1+|{)knnK54zDGc30Nv2UtguVFC>9p0 zg7%{^r?r~)EZ+Fj{zdJ#$hP{Jc;{cJR>mX5IaRl2hv3|D<-BL%@FRL|NAFwX9c%CG zSn87R@?pFV;%_Z?ko4g>C%vn|_W*LAg?GsG_kX+e%pSt}vnuuc)YC~d$am9Z9dsZ3 zP+t>&dcH%Pc)xZ%`j%KL)Vz>qfAT$GT_xEEeWW#j=D)Y6AvtwEMPnlG@vdj{bG+Ut zy*x&cYnLPFl>pbrGEn3j|3I0%MSsuJa>Otm)t-z__#hiP|NAD9Q}aJ;{q_7WtU)?W z^G}_8#<wcjUCF7v-6zf*udwGAoAHSJ!jDT zns_O81oC@t-nw=1Jks@(pKABSM)^PZ5_5)Va-Sf-yWz?N>nGW+ew5FtYo~I-Hezqn zsZ1vfv>)n(B~gsLhx)7ftgZBD{< zv3$NxYmd8Y8$I{K$NQcTe>aJ~)05cqqs|?=yc#R49e&>k`R=OX)#W?Gm0t97d1t(; zJoz{%j_zH9?e^vQ-BaapCu?Iex+e$(JTezNB*%@){C<<*_SUKdsT~H{eL68H!#*}t zekVY!LyBM3>*Wq^L3~eho8nPdwA)vYqIY!Vy1@XOcX|9f(ibcX_9s~WkG$u6!_66j z`%jMj6n`lvX&2uUt@d=d&jw*ne4isxP8ewZxr;h6o<4i~au>v1dY_5DN26=<>e7ha zdG9IME=|n`Mt$vvwxB(!f@Jk8UiE##u*Q(AoHuUFcE9VwHVN1}Og@xGXFqC<({cfA z{`>7u=S+d;8`A!0lhOm7!G5UzsWz}3LUIETF=3WoSNwZ; z?hAjXyvb(+P-yN*o1=`LeS6<~BKzRajhni@Gs4yQbs!vUTQb(*c!%<7{-(;q^wapD z|L{9-(LO0~1`*$?q`Po+&pP!p!=OKRLCXhb!QRlfPVw9h%&RU}GBEl3D_z!+gpt8^J}UOombJ+6*_&fiRh4hLzREfYiIrLs(#h?uJRLK z&?fC=o8M|r^HZQh#zEh__Q$ID#zbz9?|QONBEH~!!KLGzgy)@7?K?LiBJ}0pLUqtp zeWLmq7S3#9s=&Qs&yKU4_N$gACu27FNv|sp89C{VjIFHTj}gaF91&Oe$g3M2J$6*|HmsOo2YT(vnci( zIp!YI{{e)2tD`d>_B-;o@HMw{3nb1IJLgp#9m^m;NQ@JSxa$smpN;>N8r9~G`bWPN zMCHDD3MLE4OK9i@7G_VP1#QupO7bc7JcfC-*yF21UvoQCdZy)C-5sjv3SZcG zh0^dmiYh}Hy#pQi9!r<=G}y{N{#2L#*I|b~+`{hqKo@F1qd1`ZkB+o*R8=ibu zkeM!1pq)fzJG5&9w|#9_R7)Oz4zIpT8?(+7%w3KnFKn)rDBX@elmG z_W5H=cjmu;tf_weuY;z3*hMNI^y%%IJ%V!!ePF-u()erniLYw9v76nKVEC!~ULe(l zyraWC1#rf~;J(`5PQb1i%00zxUfjueL*5(>^-GDj)NkE!3oSd-3Pa@DolAu9bcf_SAL&St z{9;s#Ni3m#9EAct2a)-2vN)KG9?U1Gp3XnWRot9LT}ei@kIv{r`!@=Ed0$?@zg>mz zbjcb?CXr9Mt&q<=@SA`BX9j$xkb~dE({d{v$Ju~9gV6m^$6fVUQ)PUocDZfC{N(3C zIH#uX{>mCyHt~Ey#fJFzz{7F1Wh$v8I{uar&L8+E=}~uRM=H*L_)ynXAr!@r{*V&d-Q4HNOKg#78#at9oV^ z_|7KVgBXHs&cJ#3GirTTS7Hp-7s#E7!964O^^e9vwUcV9nw4O!`i! zYCGjhz`f^xz*DHbar_3NuifN#QTO-#s6WVcI7ip)Lhr|kzJc=}`d(yCOMU^4ydi?xMf`0ob`R^Z5+mp9nk2#*!P7o#IA7dp%aR&7*QTKA6fjery&!@m$=X=_paj(1I7M7qfRpT1=J_fZ-y-(r#t#3Vn z5-)!G{F=_`5+8mRsp=sa8Y>^a;??C^rs{p;`K!kQS44l7ue2n;O8vn;BS=d^46zX;v2 z0R5)>hxO6N7h@>*p#kOHk9o+GXfGJ}ez?kw1M0n7y)7QGi-=ldyT(qjMa38FlLP-> ziOk(-|J>dlDlfo3klyw4ubupzCiES@ZK|(7;FI|dN$@f1A-v8xT=P$r|3swhe7+-z=!9sq9Mm;dHwg; zRGD@qnRe%PRIbS(CLHtDBzj(kclP9(k-R@z6^JA59rq<5gy&n3^*?86dEcvxzLN%>vbLT?aM@QNpo?_UVaP%3Smef)F}ernQWHvJLn6Kf2^RqEddh-fg>l z&z@!6|I-b*6?Dk<(0Eb2&}~Te!2cV>JoVM*c|HFsx_3xs{b|LR0o4dIl&vX3Wq6tZ0oVB>) z>wP!G$Kl;1^Iv8N#&$J7Txot5pq-n0N_E7QQL%)J0(v}l^&6NTf$S!4e7=PLgN?r9 z!9Gi|llz+xYIpvxpOGfm67d%_e$IxoG|Ulx-A;{eRmuXcUY z&Q06t3lI`(AqsRk!u5NSQ}^ns>k6aM+zWmbA6*r$^Muj#avcxywz~&2zyGNVb$|!v zZc@&!@+DOeQs8@EH>A8fq@W#wvPsHSoIot4@7MEl!=P{B`zG74zAR@RT4(TVnAUg9 zoh7Oob*{|%)H5d(^4d@9flYCgo=+f_s^@I(@8n|5kTDH5_SKE&mcery$d6MwGQ|e+ zWzgjRK}hfYkq-X9Nr|pnhbz%fwTz)ZqN+0Lle~BJa2arZpGw;gg!wfI;se_RVzPfv zmzZxj*YWCu96b{c`=G7-;rAFN3b~W&9W46(kITWAK(598@%?rUxMUnff3&e7VbvbS z-DmzZK6I}>uqS>0PTGlnYaJivQ8vM|bhYnbyV4#^(;@u@G}7*5R8DI%*`M0tzW1fZR#U@%Lie&>Tm!#RsJGXX)7zut9)m>SzuSBy z?YDw-x~hZcj(cWK|DUGLob?4gY zdQ5Y+i|35GF5M6H_Jp-n_jez!yXT|v59Uto^FLh@{DJ+VzqGq|$?|^E6D&*Q>1zDI zgZH&~4xuNB55-odBmWJySN$FkbdanjhkX&pYRGh!mnW+7WBT_fwf18U$yk7^uRS4a zjckM7E>sc1r&sLL=@y{QakR(x@!?#!9dF2UYF(xyT*Z%eIy(~5%EEkB6`!e2C7J}tFa8#PvaDptGMHr@Y_&nCU#^KpOoek+@=oVF3SbhGf4vsv^TK^ z`)Uin(b}LGKJ;-@{qoH%Ra^K~`DJ)%A|`~6xvDQHtmPQNB6ZL8dVE^$5txU}PxS=P zNAF)b)|Env?{~kQ5zwLGV{EF6WwQj3x zdl4^(@fFcL@MHq@Y4&0n?cP^E3Nhza`}FdSu1~|gcSjRB495a3Z&A7spXmKxf3D-U zL((<9t`O+H_kooz-@3u`KOoC`kr!%xX;-(WECf+8MYB@~mq+TBZcmEV<3t{-kgi^NrBb4vFaB67PL!_ncQ3ARp??1{D99$3Nz4eR^n*q1jx9xD*e%{4-2wveo{&HTJblkEuYH2x>qzp+k^$uj@< z>VQwEby4MpbT7w~#>?d#iao!=2ZHWqm*}TP59D@gOlT~~mNfVA{R@^QUj*H=6MbjF zz4vHf;W{;c;MUBf^8>~tn1Wnz3bjMFn~BTu%wKCK(c+5%XkVuGW>y z>+3Okexc5F_}o{mzo?gN=d+(rk-Sm+w=h1mS=(E*7sgz`Go1ExodO>8kNTgWhSilQ z^<)11jaH^&T*4k+TjicP5hoJ+F!wo->r-L&gGf#s^H6v0^Zdb> z1wI((WiqA(^}zS3M>JQwo+)AQ`g~gXm8(O4W={S2JAIOl%^B9G`$&f>D9*SaC4+HW zuW0gl5Z-}seMFrP=zfQ`d*9dcENY zuIpnqHOJutO1}~(|J7;AKB~O4tG=IrZzgQYzrBt6=o}XBVXz)=Pw3Z*`A6r*o-Eti z^+U9e&kNP>y(&qZs~uCZ!lNOB^!kFjIIqAviKLtD8O$+VL3(FS>FDgrK1_Dh#>T6& zGhvjY&0asl*;@`OdPjPLWuZQ+^%pka+?{Qr#a3QRIPSwXfo5r#EeM2k}7 zHGQ!#oS7U)=ql3Z6P?H3bgIEW+c}q@Fzp-Suckj{k0&UoY-@Tg$^eCF{6>hvZ3e8D zJ{ETaY0jB*_%zcrHpTa(&m)fXIU-`spfg+RQv{s~KEEXz_(1~%4Nydk19UYG(o=Ke z4@|SbH;(xLof20AaA7%Bv;sQkFdR-Z-)Z1y`j+uql7SwAM_A{Ztj$JisfIr?JWkN& zcH6gk<)gTq;Bf(na)P%J6eN!b1bKqT38I|fZ3Ja`+EgkBM0wg&DhEV)+Egw_J5f&X zI6;&Xyp5o6U;%g}+7C+^zk|$0#_J5<1RMnk+TRjaPFfDQa?*Mkzl$F$7;U`H@J+z$ zsNU2z(F690rJja;2%axQ>QM)E0A3`b1p}PnY|92J6;T?gf)wcOo4N;jGg9}Vc02U} zj6&bkZN|}fTk3MOgeY$?{wCwcMKl$^J7pY*pGsY0{1&j*ILLkb9a9c5Ji_pGhHo-F z9zT&v>$}z*#qer|qZwYqa16t18IEO$H|oIu8-}kE6sc(Wz`j$+ zBB?oO!IbC$v_Bes&p3qsnbeDDn{gz5qVII{f;`|&v^)ovibh{UJ5KbyS!5c&i64nR z3r!W#Ezr~#_(3r-dOukrx)+*=^85I!D18lZFSKSvw?pf@(PmhPD6kOV8;rk+(r0Nb zqR*m+ccXjFi%C}GIAur=M>^#UFJ(A{;pGfRL2it5waCeT${Ef0HH?qp(yNi0$G@@sxO4><~W_uZUO00r6XLQ2b8( zUc4s$AP$Qo;;49CydmBc$BcePtufK4GbS06jgJ{qjBgna7~eO3VLWI2#`vvq&^The zVH`95V!Ue(Ft0YRF+XW;HeZe0Zq2YhWi7H6TVJ;Bv+lRPV?AVj*V=78V?Ar_vG!T7 zSZ`XV?9bVscS@Zyr`)MeM-toKHB@oliP5 zoG&_Ga=z*`IA3>`J1d-fo#&kwotMQB?E z|H2TF81(;Uh&2iLUm2ce_%1>7JcbvFSkE-`O2#)c{1L-ehCgQb7{i}1+`{mu47W0T zoZ%A;w=={uN9ccw;nNIvF#H+AodoSc46k5#JwwDx&?hkbDnocwPe***ctwaFtp?r} z13bX+w+s(5{2fEAIVk--!`B%8f#G3>cv^(gqYPhX_y$9Ka}IQ@B0U~KTqJm$;Yp^y z$MA0q-)9&nXd(;(8Vqp*Ji^doXft#e_F$O8us_2ZhKPuex_}|#BJc|tUc~TXhOkhN zR+}~0tikTd6vSxIGZ|(v%w~u+0Q6jjc?|Oz_GMVeu!vzL!zzZ=49{YS_zn%{Fyz+S z+)kU@iM0auvAKmdycC?5GaSzFN`@mDUd3=C!$}M$Gn~S3Cc~Q;V($q(pJjLp!&@2N z2Kb2mHO7}Qyo2FNhN~GiGW;$OBsHZ;q45+#&8+KI~d-{@Ggc848P8B zIm5ddu3)&5;VOprFkH>>8w?v6HZfeo@IHq3GyEpQbqv47a6QBSVA#yCh2aK<-)6|3 zY_cbt?8zp3vdNxoewTUJlTG$ylRepFPc|RnQubt%J=tVWHrX3(9(|if-{#S`dF*T+ zFPlflW((Vwk{){$!>buiWB3V%(;42(@ZT8DV)zAyUt-8(WV6L=wvWA*>1-dH?PIfj zY_^ZheX+SOHuu8jUO2aqlrx_oLa?y}DZjXZ;RJ>?48Oy$84w>pQ(VLF^9&a0~t0loX>D7!_NX5uC2x~&Mh=DsnjS1 zjEJ)d7fTqv#PDr~F@}{4Uj;OT$#`#uqZr=Ja1Nj$(is09!(9w7WcobupxA>??ef# zwq5jr<(?E5!g^1Mk+9&?;tE)ChZq1${!E+;Ywi@qu;|alFj#e$=nc#M0#du}-QpTp z_!)5#to*FF3YPw*7y)ZPCu(5vUy1&(`X0#s+Wxh;9M<0p+2`%&#XuSbk&baF7H45B zV&ZI!M~N7WF)0;8FfLWX!Pr!bD8}a;;O9E$0zc0=PYl9X4G?)4uNskxJp2N{f!H-x zVC*gwmtg!Z7HJs6O8|#E!^J3M=%a+~T#fxoA;xqx@N1lFfRAy;h-{4SSU`+1&Kt%# zc%uU&JsxnPGg0)zh}Vg8kl9ZXmpYT3$>Jjz{ToFAJYcFQf){)o_%vr4@J~3O5V`P( zPXfX#L|^#Dd{G78s2AtKKNg7d;UizdnZQD4p|}9PvQ!L(zkC&xJDfYjX!uP7dJ5kW z`S6|{q6{9iQ(Oiw`h~a>p0rz3k~g89zjA&B3&5vDFL>2HQSQ8q{e|7*)9|kzn6Kaw zMIu!cWX6%Xo4S~=QUlHF1{Q>x> zfqmFU;NKCC0RMsbp(qeP5?cWu$G>r68~$0?sr^i3i=E;(A_e=j--)xuA^gk1KJ6G< z@ken2zJ3z_4Dn|pO{5#?MlbA!GmPHCFfxs^;OjI8(v7o?^Dz@HFfI_e#z36a7{-Oh z6~IRrSBeXbk;YY^Ty5L{INq25&RS!Ns4{LezKEG~tML_)Z!9&IiBjVZV}nRDzKz{h z6uZD@V2@uKzZ7TjjJneJm9Y<$mvEX8HD19U8|Nj+<_8#mGERVU(l`mqpN)5czh|Zh z+w5tcD@?P$*&q0M*bPOogB$=#jX4OEOUz3}q4^PW1mKm}A4Scp%&{V7e$<>P9P=h~ zHfHQ+%+H8obB_51;PvJLQDH7J*FeL)=30?v-e>+0_-6BQ$Zj*Y0e`~W3H;~gub|=A z=8J&)%r;2G2e|CqDRDxl!!>AG*Swj zB1I%p895ht|HzfVM@Fs^gAr4w0slngE1)B;0>3?SJMgbXmIJ>#vQm^p?uo1gyf4x$ z`b1hHTM&1C8rd#tIMytRJQaCHltrG6>=BibUq_CL-jO#WZ$kE%Wg-SetO#Na#iNf~ zwv`4v-O3Pst=?8|M4wEnFYp4Z0C=HQ3_NC)Abyov{Xsd;IuHBlW(^pwwIS zDE*>!EAZQ_+k|B;u)YL*p|ueBB5RSzrV{{2EwPq>@)heVz?WJ}#rf7(tvkSZr*$WI z?y~Lz-e5IA+t;nH17B_}7X{Yc*4>a=VXZ)oE3H+a-(%e)26E)hw!UF~1C&Oq5jvZ! zHPCafbuaL>)>=s2XWb{x#>vC|;s)!R);Gbq&RU1kZ&}}hw)IvsC@oeCq&8R&0DsWJ ze8f4$cR;~eg($KfwjKum_pI-MvdQ{B+KlxOoR3;R6ho}d)@I;8vVH`fR_ig~Ke2uS zo-NiE;6Jq^qtl&(0^h50+ij>vnc(g^-E}Y z&f0_0Ut4=YdERkdJDZiVVwYe(mIJ+{%rjjvTs{&iwmv4Sbq`Yty9)1$o{wW4)pxh`YYOS+B%I| z{${-o&bV!ed^=)C1f0~iM2d}%NV6T=0i}l>6}Fvfr(zXMvwPvJIm6Dtde+%z%Bq!pbI4hdXjyB|2u zw$BF7IoMI#_PO@C(AM8Zw6V{#&l83A02|T9uCZ%SinPg7}{xSPw;Gbeo0e++XaaeeoJstW#X@3&@Gwe^H zB{S`tPNJqPvvyZ!HwoonBM($CrR!2fys^Wt;%e0x6hf5H9&`0MR@ zaDLJLqPWh!)xH&+x8b~cfW5$80G=<|UjolUdm-$($X*0|vAr02zHEOPwJfohLjPCo zucH08+qZ-NYxW(`aHqW-^tkz&#KoM|UBX%2Q0FYCA95hd z?JnWmZYbw=vpKi>jB`Go1zg6tT^;9kmpK>ViNG9ZkTXaOa|Szu0df8c&6hiu0}e-? zx6rx5xdJ*zI#;1Rl=BVZoNp}We1kaW8_PLg9?om86(c$G%frd-M}brRcM<1*7dSUK zH;Ah^3%tOY;7kBs>(oLgWrR~WBb>?^;atuLZ*e~6OhGB-h1YUk_)*RaujRb(qnsD! z;aqq+GEvG7^Kd>q132Y~W1P=ApGE$6i*t)GozFR+13u50C#s##JD*2pNg1T+e8Kqw zD3nJ|$I0>+f#2%f3Qo!?t2w6}%{gVYv&dP5>~OKO81yeYUk1L!`3i8#HRo}zIoes~ zECYoy&c&Q@UP7nTXw?d51>n8TTEO+rdSuoA;rs_Qv^XuGY{1!>&AI6{&eP7*sGTy@ z3C_=)pNUU9l&5~)`MHCYg0t0IIa{5?+3H1{r(WUgb@rn4dFOfPe8G7EIAyN24rQ)` zICC|6d=6)GwlGB=_Ja{YyFwhFGVBA0=V?o52THghc-L(72M!vbY0&Q26o(n!OmNLC zv;% zHLRRy@jYE@U;N0L0_NYkW=1ky-J!=%eK>kLs*~ynuczq^U5@Oe-~V63bsGfxs=ou! zQNM$7#2ZHINQYjgw@IfH9zWjH7Nq@S@0(WrW9$FtsXhM8-+$iz^Yr$^ZHfNAi;k;W zh(_-w^7|;!HFZSS-%aBCL!g~PnJuM&7wEcZUa5PmJ^Wi)xDMm@s!q69T9Xj*xV{t6 zgSyl^H6+9JfQMz!CjBGhg`5wHS1;G`u-HQN&ydX!U^EFmgxsz!$SON{>^WEm zqm8}QJ3>kZ{b;vF!;Zt^?>4=Vu(Q;{?}FhO_L+WE|8;rQ&iFcv-K%ScaaoeS^LON2 z8|pd;Z|5s+zr21@K7c#|Yq__E$B#B`(Dfi+kmG(L!Na!z29>u5VbcKxT|5DEL6`Gsxl25qf zqYE+Kbf6uni-fRtbW!vS*&0VF!T6Jnc?wrowp(!gcQ(~hxjz2LE31`EM^|N2mUn$2 ze$wxEe)&ecD}cI=oLOF`<}>*@*%tNt=C>Muf1UEqH#d$!9zMivIm0;*`7w!l*5nA$ zSf03d>r^puVgD6K8hj|p3Gg%c z&M>~Z{*3;3dmr_^2v45v*u=N-1(QXAzw z)9XeoeOHc2aGnsCvacF5d4(Nm&UtG`(_6Ymg(KDs;~e}|@E&sW{!?qF5}o3Z$49wL z8))E3=mhNu?s*My=W1a0%sFKRjWy*cO$VTZ*KPE381SiFo`G6&8aKvYME^HJAGIR} z8veN7d)D-#c6h%TNAx3&^=h5++JhXM;u!IY9RE2Bk-Yw4pOfrEF^bBl9X_69Ya;bM z%4-&#cX9pb8`eFtAM`xx(}Envy_YMkuaNWWXGkCZu*X8agElmtW+vKm4JBL4^E9u| zAd}A!kLG*c8mh+^#YepKp?fMtJlCZJruiD@2X}UT7YQooO47~Hwkh8sH zbyHvX5A7x%osa2MANjYkdspli=!3cq##Kc>ldFn39m(o_>4;A+3)B10dj1pER=qD_ zct7!F?p-btwY*F zI@MpOY=DUTPd>L)zROoNX6nl0iuohYr$_~j0sBB3>TBaX(D(e4fA@9|7^8_;rm6-% zWav(nH9aKDWbRDg@nhS7nEWhIO8jqy?)>p$f!>e!li_<9ohKR2T{AxdH)wU-%?WCcVB*&*jFl^u3pt%psW06$`|Zks2=xukzUrRoSJu< zkUBe4B&9=L75z-Eq@yD}$;yKM&&}QScx%&ib(VuV>U{diHuU^~&NL69g!b!!k6LdOneqe=e-&}?WaHTQVLG#2 zQ>xY^zpY&EfoKoT3(#J9zE9^iYOQs1N#f-BN%5Z6mad-Z;9QGk zw)NrgN&h{q-R@q-%k>g13Gjx_SMqn|^9e~{S{?;GUS8zm`H*guy*gE=wJ9mD8dD#G zKQ`+1>9{Ten}pg+=TUev9jg5Q(iL`bW37rQvUfor3bTn9^Pg-SuWSOjL_7nL)+3Tt zyoyi126e}O+qfC?0RMle-%nZBv8Ht-ix}?h=RI9GOJ&^k8LrpupT7Q6{NysUOU*Y= zM<)p0@oIN=pyCYl`s(jQ74^YqE8>@P9DU=y`28Gh^~EsM=gng&7vv{>?*2kslm4&f z{~g&|AODW{{+Y`0WXA z-~Uilv^VK{F$tc|Fw8wKUnO3(?uW_Ac`8eg`}yZHt=*Jg;{6f6YB?+G)%v6B=D4WE zLyC=@zQQBmmv^7KJ9xDG2tQ|^@uVg!lpXVjwtzNF`^JwaaruZ$- zY+Omo_vvhhnI_IP`}4Ct_q`UcSeC)xsUFhd`abn5CfgkrKWNP&AJO(z zbZ!bgbp9@N=<|x~2!HeD8O>+N)3ZHyuE}$I-1GX3_hu&3`bhVR2Uj^?=!|wx6PXnl^ZCJOvrbE8J(X%GcR$cGDxuCfv6+rAtwve-GKUaT?d* z?KS0@3)8~RZ*tr{+p8gGr|6&jsC}opmsd5P*v@1>_x-SV8~UL=Yh>F}8ObD?q3HIX!QdZKJ(9-f_bH(Z<=# zPv@WX-V^q>@e@s__)0!Q`&W8~PdeOwfKQ&4shCEcL&_}9q7vS z{if+DdR|Aod{4eZ)B8?I;+d?J1B^BQeIsW2VUJ+R>V&c>dY0owZrn zxubUfPn~s!wISHP54A07eG9Aj|3lh8xui!U z#mZ({UdrpIRw?+sJXGaiR1CUYpJjgFt|^><%J(pdN9B-|Q_y;@>Z3B`3arQV8RQTs zr*#V7^&s0&u0Xj7t^J%s$o&$@;eCmvEbHbFjGrPXKfDH$E|o((sY>YDc&C0xIQgdc z=dQEZpJ9H=oI&y_MKJ)wk?c;K2zxxo8W?0^3| zGi$9M8~g6QZQK3McFirhCxqORB)3$Ogd|ClRC449U5-zIIx?=C&a347IE@Z#e-Lmh(1p9_CkFGuw z-esYhu)e}@p}#%5IQHFS=jHLWz}WY$uD>5pUYHwS0#9KL6x@9h3gzg<&sX`ufbzC&Oy->oZITcxl*Z5X?T zfbNiYMAz!0ZNQ~%ZR4$8o4ySf`?GuJPJj5!?Y9Ei*mh$FMIA)fG@RW5yur?g-I^FS z(r;K@F@51Y+tz{0A90->RhUZb99ut))e&~qdH3UeFKm<8TDZG0t`pANDVO~Y)7C|_ zez4I$u_!^0TZiGEo4ey5=WO}8YiP@MVq*e#B&}$k;3&5Jxi!f7^R0IGyr}Om&y+Ko zKYK6E{|nj+#nxK#amo4jS$*N(i6iqDTQ|S|u`u-G`JQ6t$u}By{PM#-o)^Qm*}N;4 z-`M!cx(?b{huUWEQ*U+i!WGOfckEhcN}jH$-dH*Kc9!^VErs&;a`~{j3yuS)$bGc! z5dNR@AJ5A})D`wOzAJg!rI~Va84Jd-*Tm!h9v957<(R}z92dfV7$4*F;y68yA5%B3 z4Y+kPTUJ+xiTcAlgniG&wQ~*r2p10@ucv%-lLfJPTRgm7pG)|bBdXo{#q{M{(~aJB z>9}~&FxaZZ__NDrtiOa|-MNtGk(frluwi`5t64{<9^LcK3lq&-^g1?H+i&G#f1zI5 zaM#f9x196hoho!REqm9k&&Hm)<@~H|?@Ns3blG;9&@S@s=jqAw%X3lQXx-aq5RM_? zZFik;Kjt4B|9MuVNto45n`*P>^h8@G~cPd<4+bs7Dn7toWNI1rp*gTCg z5T}=YSKw#A*W&EjcZ{pJwSU@>OFRCoPP{RHbyOR1Y+m?wm$-Ia8e1mn%&!02wrAfz zHZDMaw9MAdZ9jf?EVXC5#%|k~8~>x>PRv7}ixbARXB+S2`ibTP85`42Y@ff5eB^7D zlrL8AvC#SUf6z@n?4Qf8%U87jVkbQ8#DlT8vH72^V>fo&eIW9je|;cUuP?>oB>tw7 zZ8M)!PWk{k>RNkW=DGZKW?nxCZ2{uX%GTjV!rOYX9Lm1a?RxyiSiOehj{P2u`Lli2 zCtjkS?DrJ*dpqmzzB9AW$);!Z;1|}d)ob7X#Nqiga{E@+Z+rCpL9doLuk?Zoo_C;LC4UdHD*M@iIO(EXpcmDqZ1tiOi(?YczbI34=i^U3~&%#RWy z*f{nb8vCAvcVzrqZl^ESS6$h6E$nz=>-_glYHu-He&(SI!@cMe-^|~cn2cL5w|sGX zOn)Kv|B2yU+VC~|&IVCl`tke&HhyBb_`5dI)4t<*cZTm<$2DW)t9>S6{!eV1&l{34 z&4!l+xlt8`k8#m^$k6uQ)>+(6AbOYgDZB#xHotbxR5pKJqoG1cda=13V^dwq<>E%~ z;?9Iu?O!m^@;1l+qR%K+_Eb^wH=4y zPwVW``fV}XI>oOAJ>~oE?c_U@|37&D|B_yp)@kIiu)KwSC->p-PW0^hqUE~< z#szyfF>bV-pWOd>?uEXa^QZEE_tmM|c42k)-?gNtvI9A3t?CyF@Ly40#ydBroR~-Z zi_QN|l_eXNaq>5|zu20cosZh_EVk#G*oRN7Oj!F&NR+WTUmA?BdE7K+OG-ZSy-O0J zpVEn57l-%Tfl~(h-+ZIsye)j6{T|6CwwLf(Ci;bGkcT#*yRb9;k2aCWxlaz2H}3y( zI2#kre^Pp+5r3xnwA(qaod?qvZQc{}9~~d_*4je*zc7B7r&Dq_%N4Li4Z|m%U3!V_ zKPkFS<2VNEQi=JnbF?rn&(F^9lf!Gm_lVB<$fwhhmtPkqJNEu(y@B=^*W>P4zCfJl zyWet|m_30#N8kT>^Zx`ckeBwq?Yqx zKi37cj#K~T4;zMyadLR%fA>GyI%8n|_y4Kt<+qh3HXaw4TZQ$+y4E1pMGqIIi}vlt zV>=Izjtzx{iu#4)n{6vrH{<>hyLRiY?ffL)+CsPnYs<-=U-I8v+ zMm^9rY#+7!AT~FQwi7tF{gx!&_8gzssQt|<8>LYv%ILk zo^jI6hXy3GURpB#@^&1#NyrAD1>vy4H5f+EQ6NCw|w| z^<8VnX4e?({BsO#y*2MnyH6eK2lO5HZnx@)pErLD%jNn_!Z>HcZA2f>i12nijPnDl zx%9M2zu^b_6*1@E17ozULG zdx`5np`Sh5vEOma&{iXX$6;sDH8E`7_JT6o;}-dSZG^3lPI6dchA~Uu%2M=xv=|V^CS2C z@p1hj8Y8U##Q49bJKpzyMd@!1_bX}&yK}dm)`#>J%#n}Un^5$oN(S;Sbpuh zurUA74?VGWU+8o4Ilc}M@{5y${Gv}{Uh@UC94Fy@L0%m{v0-?37MkzyU6)VKNf-3T zQ>^_u-IgOH^uLg2hidZIeRRFb#dE*Yk++XwbpW^L5%Ty@M>M>ZvGF}Iy@WuvJe1r0 z=8}t(5H5Ungo*O1SUmjW>njPW3Uw0K?SmA06VKD>i}~v86besApJdxL6l@WA9`?_c zE9ycfEf~VRAiUNi=N#(dkFFO<@b+X**N***|e^-;g3Yal1_1ej_9{?#7(#N`M(5<@MFy^e>`_D8s6R~J;G&2^I-MZ zv|XH7TL{y)@$8zaZJ$xw606s>pQv4B?7IrWSY91lBecAlaJH>l8%k@FV%K)VZ$>N! zw>;I^Zdl&zblUl>{l3E5V#enuE`D@v&+2#Ic)C3C``j*Hmg~m;;6&Jpla93|v3X?e zD?WdS{r-auO1}7CY0+_jaBav7oGARW?SW_Y(t`M^f(;YB%Nks4jn~$37^C2sbo1s8 zv76yDbai3vjj5l){tAwJc1$9D@AJ6O9)=J9oVN=(llCmG?sYZM$$fwl8RAf~V9_)&Sj>s&q4CKBFbd7%=$U zhdkLe<-9jQ662s7KZzfGZ|9%0x;9K7w`+X~e8y?F?|kAo9$>i=-$_MNb-JSK$@cpx z{=)n?_mF5_?Kiw9hAfyAjgu!`dz~7Mm**RG6&k*I;bCoz6QdSPEvTcgYxFXYiT<7F zP8|(dFoS*aa>Sn%_uv29e%s>2ZDBoxG08{$Jomrj3is;&ow&beoD<#i>gnInYuiEM z|Fg}{ZS(rDU3YZzIBSDr-FAP-%?G3N1;zwyH1TuooVM-SaQ+;*wCsLS$bEld9f>h; zJ^dp3`vUg6Q|#@@o3$UxTi38_JNCCB(P`&ViK)4HRjki32DtD4+*ljq=2mwYzMvhT z^-t^{VYskN0m*Ls!FEFRbTg%RS zMou|#+;d8N-^BPfd2?ex!32;GyW0QdP}uly$NAVFd1~XFR= zK^XfR6E?1W*Vr;9{ARaR;qJF)onRULVNGmYYZT-4jcAj$KJD+H+B9QaF?72;#`1Mi zey#44>dJaX|9-LXO=HBD6j1+RReGkOjLm@$&mmNb+buaX{ z&m?sJZ#^f}bz#pUjvv{3Hnu=L`XB*b>OXBgH^Iaeef}m$C2u!}q`4Yp{8?WeCe@%NqVp%NyK#ESi=}6TaZ;!P<}c=ydrd zZtT6pxOLFwA9%y;I@oK@wsq;sPRk2 zw^Q)8guS*;qhU_f|Hz;HO{w?{Gp@W4hbxPlgE8mF2JXb3h0Qs)k<>i?d0OqFKpLmY zV}W4#FJt>f?j4cv{zwc&UAi$M(eL+hpK`4GPtxpI!NN*Uo~SttLBRFdLkG;g0f z|K3i{a)WdVn;b8xx72pEUj0oSRyJ3r>W}pg`bGVt$)79K$ zDw`SRPBYN_(X2Bg&3f~NnQy-GjCs-Xy|(5(ud_G8OZP^4fAku9cX{)@i@b&2U%ZRG zmELaeTJKZun77>f$yeUXzVVBAuldFNE4?lLRsI~mfj`%O(C_I#T^`G)r`(ymI z{)_&^piEHKpA=*TS^ngpQc%UeKBy7Y^rr?bf|mZY;H=;*e|pd^Xy@M?bPPKAGlFhG zH-BbuZg8%DYj9q0o_|}=C+O?n9$XL%^zR6U1Vj8k1jB-1{+!^dV7z~4a7}QHKR>uO znB*@AZU}Dj?+#`LGyO%u9l>n>&%vBvj{iV#cW}4AIJiG}z<)4U5-jl_3SJIg_Ll~) z1h4oH2d@UN`OAWB!FGRn7=*GC4s&>fssv|y~R41uJ`#u}lMRmdF z9MuDNFLfTWx9THC^;H8US6!&66Z*h7lgL_VdSB3DnVO@w(vy+IiIk2Iv`d`R4XsYB9AeX9-=@`yT$Jf?m`9@j<0 z*F|+133OSVEobVAx;E}Qx{i3duC9l>fo>+X^clK^RHW~)%W7QPp`!Nlzxi1^jK+44_%F1qt_tU>b2Z` zQEx=&tNIP;L?3>iSRd#Q$RRyhvgyemBX{ZVC0QTUKS(OQT1j)GO+<>SOO;|? znpYNgIj@{(ue?_Qcea;Y<^&*HlV-%{)r#we{Lc3&yf@ zarf|gqpgoO2=_(aP^s<>^M*@%#<>wvl#y?^%4F^PVH* z^WO8gS9_~*|J7SV&A;HSrJi5())Dt5?r3xTeD-q$kwzF(j4 z4g3a#Y3w%^-*4hK!F`5*hII6s`^|~f!f%03OTQ)BTKTQe+}dx=-820&x!cBXLr%`} z+v0BLx06@(1I8u|EV2L;a!n5A%nU)=2+yd`9`B(KFT`i_WY4aoip6k0+Ih z{zUw*^{*v|ll)19yxzZ_SX2Bdly|B>m5?|3H{x@%e>1tg#lMxbX8V7jPUiS?2tU`K z%iTZve?;3ne;)ep^6$d`K7SGUdC-3l_rv}&!Y}t9MXvBykk()PC%F5h|0H*x_n*gS zwZB@5!h6;tU-Vy;mX`fU6U%;(m4eDrA*d2mk@l7YNe9b;@PPv%;XwGnfd~l)!Uqn7 zgahH`$2lq?S;DO)) z;=-TASpI|?{)Bs5unqZ6@D8PWH+UEK_F%iThf8f11wSh0Sd?-s%7broz_%l8sixyf zN-SIQU`wz8$B-JqkfMy|A^exh!}wdS<2kOQ9M>u5xK268b$U6j<2kOA0oVCRia3^2 z%dwnH$8xe9%gJ#pM>&>L!m*rUu$)x*hvhdZs-~(LV>zBWGG;@E?+NJ(x<8uCMFkWBH2j_)2-l zSIRrSlH~YGwmw&nfPduil?n-br3&+jg=ny>r8unRDcn!%7tn0kiFWKH33l=p8s661 zk(Q%WaU3N>f9N>MPQ6n)#F@$uFqLEam>9=YA~2PTVjMe(m@1|UZp%?3aFhR;$Yylw%Tg9g|RwNn|=EQ4=O{4RaER;ix9q`l>>yT33(e_AtTNeW})p47=v<*p`2q3o?{F(6Bt7yZ=N@gSe7>^#~U)e z1@MLp#~U&oZ}2?J8)`Y;aGv80%JGIw#~W(G8x|ASGKLHoLzE@ZA3e(tG8{k1a{M3@ ze()GRkHZggy(hdUiDg+r%LJB?2}^hmf6EMV9WzicgBRdxYheb;F$2#rgG|Q^YQ~wt zYoz!({Gg`e2bqo^3Bd&0uN~Act8oq1FAV5P{#294<7I@IOsvxK!#%jMPLJmcrM?<36$dm zjU6ZG?KnX-#|cU}PEgEof|LYKP{wfr8Y!Hhh|ixCcg(CXVgBkdKX}>gg%lKt+Tb7{x@~{Nou>|c{LcIi*pdCx7;8*dh@D8i$*Cb>u7(+e3 zwqF}}9ls9R>cSp;#~#W%_MjbmsNv`O4e@W}HprKJ->tBiBvknC$!@e^%D3*1;4xBo!p-5 z_aOh4TO>JdahBs2NpOq4IJ9bjuzrnu&x8*1m97n0)PxGgv-!hdXe}+GU@KL^Un?D=>Kfqe* zIo6Wo-|62;9xQjM;kb)-+{Jg?rJq0FpU>R|{sQzb^zSC_J+K+=|Jh%R+j5!#tk%Ht z{bewl5&k3oBe<9Q%SrK3SdQ;MW>-RBIe(#ko`B_O|0(}D!dR};!*QKrj_VY2Tu1rq z{B_d8f60GIF7?;@>t(Y4vj4J7^f&k$WT^j&|B4LuH~Je1^Q!-axUz7I!>;CI< ziNDF;BscnR_;1K%{$_u(T<^c>zbV)HTl_6D%zw*&OD^`e`df+nw*R(V<8Sk~5%(Sc z9U193R_&l%P+rF5#$EBa%RvlXej-IMnNOoO@byeI%pO&lQu!~ zpgGbqxl)eFl?vJhZDoq%a}6Dzs~vO>I!m+Q?BHza9&`!1;65if2Y1(?E3quw>lkzo zSXpqKuVc_7=n2E?74(vZj{kKEdI!C6TNc>KvB26vzo4HC4EhKCWl(T_aK4NQ1_T3S ztYe3@gA0QTrCTs47$oNg7X=sL9vlqDeQ|IxsaWpVIT#uY#cdg6=U{j+Lb^I0={X*$ z9gp-JkF4%^WVv8MFhR6qlhuQX!9*G2IAwLmDZOBFFj=Yx*9X_b9j63SaObhi>W*cy z+zr319!w9W%edg?;ATQvu30^}HMmu#2D5@$)W7AOr5x`p1@F8Ex8y!6rFBcq7N&Qm99#8*9l;Li8@w01C(R<4M|h9hwLtM%$yFT5GFK{#)M_uLW9ROD)u7?mjT^0o zj2=2+jG8XZ)N-{_A6Kh6)~ih%+tmANxB5aIR7bUN6p0_Hx{S`zHFd6T&e2v6&|P#d z09;+wmY5F!jSKq@5?{d9Tuh#21HtB8peZ5<%4jnprg6TWF(fHwd@$jMJ zFVV|}55ID(8RO*S5u-1^R6jmq%vD$Fr$>$(I^0-~p?dY`G1pwF*Nwhv_-MV+$<0n~ zbMieWcRKm0lV3P_z{$f-9<$PjlYx`PolHmZI8){-PA2=RaU;fbT*fC+J1v zZEkCizkJL{lRN&(;bTp+@#AwFn%3j588+UuAAil*@utfJ8@`9$z&5}-@!Ox>J4YXA z-=|BCUeTdTzZ|{l+-@CnOirKP?Q=|T!|bZvz)m?{@eb|!=6G#7^hS>D)^1>qx8&TO z-E+JhJ-TZ@(Z$^l4l>8! zI+zQ-PsGlT z$IdHa=jE~Uvgp|_6U~o46!T{d$mM5V?93{WyPgw0N4iAMMf*n2!RlE2HSx0xU*i7g zeb}YDW`!fFr+e&rvMay#_Oha3YeM_tr#qJi*XRXL2yFut>*ADH>N#28$!sSZI9bEV zOeae^S=Py7PL^>p!^u=9OF5b1q}?I5{n5(OPNq4T?qmfgYddLeVwB`MS>8!&r=p~x zlXlwuAC5JU~p_Vk`KoNEWuuF-%xjJ!ztKwFNb0x=I(GqDi z_|y)ow8SjKI(s>G6DlzOjq0r|Rbt_zrOO|_*lEW|JM9=HPZ>jHEMmT{G8U3|l`$zM zS)0t*%6wgAY+}x?GB&VJp)y9E_!9Y?v_>vtUs`2McXB2+H!5QmJNYVO4Z9U8qdoI( zTT@~Ec)y{3R7N^6b3|1x$C){LWsh@l&RLvk1?VfR{*q2vwo}C@aoRCbPCG{GX~#%E z?HC!S9V7F!W0X4W7^P1cL*k8 z%}Se}c7NJ({Fl-%pO=^QS^6BVmM|-1W#7%lb@~%&`_gBo?W1=}+Cc6ugU#LrBVOQ` zu#M|8>-*T-1&5yNV*8ORBBLW$M#e<0qTi~tA)-=u(ckR|SlRh7nx<}v`LKq;)kea# zkNH${K2PJ*Ji&+fY2$d~^l*BN4UQ$*u7;$Saq(#JIrmFS z+GT0EX-(1wr8Q4$oi;XYQrfh%wrL&HhNX2$yDg1Uprf?+0W;f=m|;v|W-*l+#WepW ze>$^?8O$PP`nUSG`M3MC{5$OGCo7*iZH82jl!=s$l#7&)WJM}OvLh8EIgv_{%8@FO zs*!4u>X90envq(O+L1bux{-R3`jG~a+(^Snqe$aOlStFZpvXm$!I6t2Ln1>X!y?1c z_=MDCCF|?oS?g?AH*2PF^g2PUpfL=*Dg65k*mt|2eb51}d>$ORPp~q0DtJ10CV2OE zPJg0`um|@Ky<2~xKh^)#d-P{|ul^j?_NCsZzta2l*ZP3|mp-V!fx~^P59{yr5&ga0 zv12XlM}1uXq<_{Yc;Jflup-8=@#UMqL~s{1Nv4=7Zc3PBlVVa$nn^bqCexHOrA%p4 z#*{VXOnH-KDwu3j(Ntm=zX~g8)l79$!_+jjOl?z#wX}MszG+}`O+(X&y}l;w`ki5# zn-->}X=PfQGff+F7Q27#O$WQ;#(LY?rVBfOy-YXL-JENBn4Y-V1!NDfuj$7gV1IMI z8DK8JTHr#i*bQWLZipFbh8Y;8xdi)xOU-5Gax=**sttv(LE1JY<%dhs`qch*@qPH7nS4eBAuSJYk+R zE7^N|+B{=cnP<&&=6SQ4HNrLK1+&(?h|R-GtP;L#Hken;M)Rt9&Ae_lnKxK7eA8?( zZ<(#8DRZlS%&E?2F2yQ4v#3GLo(3~(8p3R8n4KjBJ0j;qx<PToMd7XDze}6QYZ3SVw`vnAbCar>>6KVpVnc~dCAOB>QR2fAyG!gX zvA@Kj5=Tq?oa`khC8s8rO3q5IoLn=xesYuKmdS0CJ12Kf?wvd!d2sTGEyHoe3?oU0GdNlRtG%qbFEj6uFT2@-+w3?ZjY4v%hwd76KIjwtI z@3aAFgVRQ&jpF?_F>OlPblz-pc;nxfwm5BB+T&?Yr>#y~m$or&bK17F_tJKzeVX<~ z+JUsgX~)tfJxDK}o}OMNJv+T>dhPVw^k(U;)7z(aN$-)~H+^9Gko1x1qtnNwPfDMf zJ|lfr`rPz|>5I~rq%Ti@B7If*n)LPQuVrSXZ%KbQ{r&V^>3h=mr5{W`l72ixXB5du z&dAItmywfEJ)>?$qm1SmZ8AD$bj|3M(LZBQ#;}abGR9;~$gG+%Ib&MJ%#7KYbu;E= z+>_Zlvuoyn%#oQBGN)(G&AdPJ@ysYmha? zDyouHF;(2|ZP}eI_O;SghRReWRVh_kl~H9?IaOX|sR}AvRa7~ulB$eNT2)m|RaZ6G z|Ei^Gt2(N#s)vnQ1C`4zSR;17nyO~%4AoqyG~73*Q+V&1~paPsHUl#*lD|2 z%}}?fnaWznP1QHDesYtZu5Z>e^euX(zLnLK+x0Achn}tfpy%j2SzGy|o~Q59^YsF~ z(C&S)^L3y8lU}6%tnb$kuY>kax9y^)=>*YxYG-MoQ~-kW-heoJppDC2$Lw2eGw+yp&33cH{LQ>){%+nkAD9o#M`ow_*z7X@FuTns z=2P=ev&Vd9_L|SJ;QP|-W2bAs`Pv*X|1t;7H|CJ})*Lq9nIq6P?Kd8NHFp4}HK?`3%v z?4B4qVwJqgUKOvZSIw*L)$nS1wXnv)5{F%~`d$Ms7t6s$USqF`*A#19z6B!ZxR!*WT;kb@V!6p>wv^#XHCA>UHzFd*@=S)6?tao#*vtf32_A&+G4< z?+x%S@CJGpdV|<)8;m955N{}ZG@r0H^G|P&_nEiX`@;JiD~)~Z%3ztnehfAl?7)=?(Uk-ef=N zE%uS#X8-6N|DgYkf5`vVKkR?!AMwBUkNQ6(@c){pm}w@?3x+cvSQ*YZgB`*4e{`9-Z{x5`SphOB~0qEfV|Zi0p>J(P$Qj$R`s~(E-zQa0# zb-n9<7IUqO`yC7HDucbdj@>swr}mby!^&Cp#-5Thdo?o&p`#(tf`tm{bWa&5Uh;>@ zyOZ}O@5dEmp}3ADA9uOnC6bbqlA2NqEuK6p>-Cwsi*sYWtZvoO(vVY|zQUe?^G(jz zXP>(W``hKQWmBxs+=t!4GVIUV*emv?#J7D~mV6_tZ@GME|O5Si5&!i*$luckmTY>uYutRPb%^6Zzy1 zS(KDjq;KRxo8wqGap8))aH%d_c^59rg|ju1g1$Y$-r$SiE5aTK4hG*4`upI=;CS#; z@G~JwV|y~un}(%;t;ZBB1Je9-KLe}5(tcT6uYMJF`K$TWtz95ie;Qk*k7#9r)e*Jk z@~d4wl3hO1T|O$fd}OdkkFHhFT8gu)d9EY}%YtQ) z^5wyD?9EmLDFea$7CJkB6q$A6l3}lwcL{=~* zk=dpcvZ5)C%rRwDZfs%5GoYny7w zI);{^>Y5tJdZs3_zM)5`2BtPL7wa#rSf@g=R)vI1Ae)+INY<^8tX&~lze2Kxg=8HI z$yyeY^(-W7T1eKlkgRPX+nV-BXXCEgn~u0UU|ptFN7D=0$@D>XHhqz2n|{bHW)Sim z(;wN@oR92g1|Yke3y|j;){a#VYZI?}x{$rhMYzwimhq}L_Gwz4H+SLgW9S#Euelf5 z&)kRXZ~lZFVE&A}z&wB)Xci+cG!G&NnI*`J%tOe*W-0Pw^DuIVS%w^H9zhN>ta7X2 z=27GbZ0ohU#5{%^X|T#rmzuvIFEdXdFE`j`s8LwnYjuUeeou`yPb051&mhN`RmiK% zv&gaLIpo#mdE_{3^tBpq)*vUC7m(Mmv#QlZ^CI$Evkp1QtVdpFUPewf8<5wVSCCW8 zM&u3VRpeCj8uCW-I&zxXguDrhf32pQ&B&Y0o5&f4aaY}9-a^jgO8~8!@MVH#rbdrr zwzeBN&GtBEZJ#2i+aAa4Z4YvW?QzWF_9AE69>;9%3*>FK$1$thhn!`59J4!m95Xz6 z9J4%n95X$79J4)o95X(89J4-p95cUfk$2f1#|-d0qn>HBS8(+}9brWf13rXRF@O)s&1O+RG&nqF%Ants^!HNDLC zHT{U~YkIluYx+^!*Ypb8*Ysnyuj$8aU(jNW3~jDE|u8NJoE8U40xGkTkCGx{CdX7szZ&FJm6&FCGr&FH_`HlyFOZASmy zwi*4tZ8Pj`&_dYX;JIVD$MbbId)AU_K0IZbPj1=mAh+yzkWcnI79wZ+^elEemLb>q zJCQH>A0yZMyO1yYv_LGBb|YW$(T{}^Ef5POS|Aomv_LGBXn{d8)+Ll=GYkBCIp6Bv?JvPj zx&}KMb+N131k2hBvpE)cT)p9M_dkcB{uuaNZT5HgU%*z62lg9*H~qi)U&35}3L;!> z@!#|J!D4?7ig5Lo|9Af@810FmC|6tk_x=6;5h5jV^|t?k|F!>ppn_stZSz0$5BNs| z9Tey49seW$Uoc=3(5CsaExI>eoxSiZsVg1Wx$caGc2mA)8!2tXezDezuhedm^Tb+Z zUkuZGR)%1M{gDinkL45Y{F8V0OlSYRkT12~kf)u^^P7%wY;ji2Z}AmYQF+gOdG&XA z;+gWkvsnH>kL25`Pq0#+EPI_j?RU;@_K35I{oZ|-a@2hz@q@F6JOhB* z<#@s}9BAV@|0AX0E0t7^wfIt%EIUz^E!$Al9doEbY1zBBd-0U@mrFY>R@%X?oEN)t z-ss9X!Jw)@_Qi`#W-k+rNGCl9 zu8+tnTHSNl_xF{Z90Q##|Ako7uarS*GpnMbu%Q1?MziC%Unax+4#^$rIQ(xe)T@Zh z*GamzEW%#CwY;d?zzDZu3xA31a9{0x&DXTo%K`T!{^g#;H||N4a8IJTdlC)YlW6Xq zM0@unI=Cm%(>;k^?n#VwPvRQ)BxYEy^qxyq;26Npr!0wu7u+Z9B ztGlgjwYtYWk9*zoxX(S0#qN15anIvn_dJ%l=kW-SBchi3Mg5{YkK%r+dfdQ-&AU+eJ9?DN~` zp5JEo{Op&#SE;w%^V{a{^gmPYFg6+Wk>%6sGt0---k@?&S?#lSlSO$)cdZmGcN8to#Np`6Dwl9ef+<>-_sU|NhSZeCN+wfZcN5 z0_>aHw?MAl0cXE_kn_LD`44vfyfq?N&M;G=Z0xK@Eud`LHs!#bt;-@3*!Ru%0bBq>}ZCRJL~m-eJrWKSAydc$1+AmV*zBhdPGq z;B(CRz;*EX0l7C)j<`9IvdHX6d8;SFI}e{)$TE>S&ZmL%spov^BlFKp4@Bprgw8@o zPNW*OQP-8q+D?gBYpfoi85js!gOQ+p?A(Pj78A&*%|tKf?(JmMeyzWAN5|{23GRUj z?#>DBCf40>WLsCa_3vvq(q307U;jRPu3WE5d3&yyRyk^`)`XO`G~qpGEx_!#5iT$0 zYHY*uhy4Z&Dg3j3QJXw#afY>iS$`P9aS1<1Ubp2*l~A068L?ViJ*fA__AUwyy-=-0=-IrjaJdw)FqIqpZycZPyBr11ar)vw67z&7_0t)ThA}FBsG#A z$;8Sdr$~t+=|wV%WELq|q+HR=q9u!#E?O=rC8=~$*`%DLs>R9{D_5+1vFgRk6faji zt9a!SStTlz$SzT_MCB5-O4LuzPOg}olUymeYI3#YnknT|Dx_3QsgzPVrAkWGlxnF} zQ>&%cNvn}oGp$ZqZhB67jr5x7b<%S)if7cysFztMvwmj7%tj^alx$Ekw`9YT%}RDI zRliijQjJPAF4d$|(^4%k3N;fT2sZ5nJP0BPY)4XimvdzjiFWaJQ%d)M? zwk_APTRqW%rM{K=Rq9{4d*yR0_o&>nN~bD4tMsaJUX|We238qawRP3rRr^$HRjqHee$~#e z-mm)k)i11ZL5&M*TvX%Y8l!3ssyVpk&{_j(T~zDhT9?!wRcC0OVRc5;xw7tvx|h@) zS?`j1BkNsSZ$kaS^)IhKs{R%AN7tXwU_gV58w_i3NrTH9T#w1XGOM-BYb|%2DYMU%`De->+Q^(Xa%UTPtc}b) zOYUkb3);y-et4jrti;h??rAUgc98oz$h?knS4WxOQU26X?(HOZcb27R%NZf%qW7DvS&dzt#(`ouV5Ir8`{)4}8e2qcTGw!&|D~VBf>@cag=JP77 zjGm9<+N{n;-Bm7z<^Sn%nX8Fh-Mhdsmr3+oa^ubk@-AJ~e(;xYWa^WT27II#9tG}V z^pq7IUPVl(PClmS@Mw~+)M0)8+IcKy^(Ard&IMz6KuCB_~YQm8aA~E!--R$7Tj>5u(^)!VI?9)Hag&_B~KUk4)^kXrk zU+j2=4e--Ctc{~d(Zll{)AC)t$;No0hnE}k-^!->R$guP$OyxF-SwL`gemDht{??Z z^7NV{=YE3i`rmducFJ(2V*P+0?Z|h0hmqfRro5H;j>VV=M*D7_%wPWK)jSrW!lS@_ zw%wb=kE&dqbkLS#hgSz` zP%?L&m-i|d19ZSRperT@r+?J)YB4S>$akE>SRNjKKh1g>s;}f2pVnoT)(o$n2l_%=EX_g~#Oc_E8V`Hx3= zKRjy6TbX!ZUYhUF?Fu<2=)9xAeXJ;Q;zwN!T2DGKiU|)EcuxCx8Z(;@nVg@_F;rih z@Ay&tS#og6~n7iaV62rvZ6Zr|C@W`iy5ZIi=j?Vhz z<0XuSqDN2N*Yotn?CD;|aXThLv+d#4z+KiI7hq)cq8_8GVDnuJ;(v*5ZYp4syhp$0 z)zsJUL0KI=5VMqSELNA*)d=yNZpaS>+|Tl~Vp;tbor9^<1}~G?$1zE2>?NUlCg#fP z;1|twDnE$S((1${DA_B5Vbm(LUZWRcl$@y_A}8PKa=ND;tnam-)O#(-Um0D-<#3tH zVKFopBSo91J;c0@e7uPb$?w$XXwW<7ViR2+dxkj?Mx}6k~V6MBo`lcAh>ThG(c2u{Z6df3clNcR4 z#K!-SVfG-F9kF*}(A5q@_cx4oV`!U%aBf8B?m<(EwlzRE;rt9wVk28H%Xy1Fje*=N zl;KHz>B)YUPye6z3mJ6c8Pj@q1j>!uv-B)e)~gL$S%A44Ey=5`bFGUv>{I%A`vVa+ zd_K4RDUR5mbw#g;+0!02G$w9c_z2(!n95Uece+dODm{w(z3hQ$f3`J{<43I zgZ7SI1^ZKEr#u#L=NyxvBRs=2_bweks_EVtu|ma9LEIH}X!{vg>`zyYyQ*U#m_k3{ zD+f#|D^ccL*Pfd4$%FM9O>3Nl@nD9Y?%Bm4;Ri?D9~*sBqOSj`k_|sGY5Iiz`PWNG zZ@Sd$0k2bxX70K3)U&z1n`eBX*VbyVYlrMk;>yG}NBC}0Uwi3g6YPS(MhJ7<@iZ)N!InzFEj<9!*MDvW@a}hM=;FqTOTGQ%Q>1cChMkcM7^;`;- z=q05}(cWbw<^3Ef{pXsJ^FXfDZr5Czywg_N+8{QLThFVopJfKFDjc-lvAf&C&yQvs{7MbT3f zJw>@!lzTXQ_!D+{uK15pg#ruDFuKOB(f( zMu$qT47z~PfIMV)U>KMQRsh109mzyTCgCy(mpK=#0`G(4A|OqAAC;COY$?K) zB5WzbmLhB^!j>KZZUc{lZ7lxI0Z)VXz%h}s*`Oo149o^A!47a#q+Awg3(!#x9p%tb zp1hT(3|W*Rt1}n{(3yqKEOcg}vjRFRwCA7WOb0yc?9Jc+E7$3O=T~u{NKQF`zDmtm z+3pPvv(jA#v<5@K46qz*0S6f{b_+l02Wo=B0NvHlT@BsU&|Mwf)zMuY-PNbDWd~|b z0Hjfqa@RzEE%etye=YRaLVqplv33sV2q=H;*?{ubru?;!iqxU}b=ravfb!QtR~>ZK zL04UL)kRlbbk#*y-4!DBW&(TO3J$Tn-U!?W)`3q&8U&y=xCd}Qw-jgzC{Hfs$)!BG zn*rr%NO>Ako`&@_wVLoHvLx?hPga^fyL-<2@oxih#PH7nlG@r^#AC+D%Ej zDQP$D0mgxaU=7&C28RaKL02#a%mdGX4@J(Pd}mO;GnRu*BF#ywIr>_luLb&AkX8%Q zYC&2pxYvSvExFf{do4+;C26%Jt(K(KlC)ZpRx8qKMOv*$s}*Urrfg>lm@3kyFPID# zgV(@5k+V`kGm*Agfc&)GEz-^dO8{Zo5vF}IXaoj;DS-IxH-axjIur-Fpg%x&hXW!V z(?N6LCrSW$?eqkA7aS4kTn@Abq}6%4$k{EyU@#3V73o5r&!Nocpr>ml;C@%acAW`m zBVEzcjkLOvR=4}X2C!G8dlIM*dV`7JKCljaD*W6DARp)U0OPkuP^cX60ctoP#2K@e&oL&`R_;m`;q_tpgQO(GGG;WU*rPP9!MGkNn;>s3?z+#q<Rc`+`E{27jy4o?hQ!?&A>n~6)XX-fqf!FlR+cUUu4)!utH=w zbvm4MhLg^SHX@gF1ebx?U?tcAj2wQvh+U+62%uHWf4h14OPS{?)|4dJve#hGtFB z9gGF@!D_HeWV{B|L02#a%md_eJoy|?J||H236%XB%6QFaKpC%D1>P6Awhb5tW`Y%f zd|gYvt`mUH>(F@}IfX`#q;@^^D8mh#W*fH-$f2g|?~a8P7!CP3fZL0}pn&AFSw0g*qF)*qXJfdD;!Tms0)ANPsO zO9nifdHum;a6i}}GQSLH4TkVP7qdZoFcQoHE5QzMl>gVqy@lLc$i0Q!TlfTc7f_D7 zd46}d0mHydumWraheYm81x)~XxNidZROC+qs114m{Qh(gSO>Vbhi*ee~YsK_4lBFs-O!P4d#MX;C*mhWJwOV50Ksx(tC*X z9wILf?Gag;1abj&^f2d#X93c9_&q?}WrSPS3rqxyzy?5jdL$XN2E)K@;0Zv!9yunm zob;A=2IOV=Jg^$<5_!}E=zA1>k8T17L{=;od5nBNM%c&Z0`mRXZjr|c`*=;j_2ZP| zaq{w)EYKE=0HpbsE#RQY6Pchn!2b#SpLiS)=LzCGNnW1p2rdJ&!Ad|rpFAqE5`8Pt zw~}}(iMNt?E4P8eZ2hhld3qq23f77|L;0Vf4xgb8pP>#{QHQH2%c>qC&z1p%eU`A# zE&;EBeIm~#gXUlWm?H8#;ht{|hJYDhIiL*BQ-;-)VKre_4+7J`ago20_rFq)e;oxr z1V4+cA+Kx5>l*U9hPZ3+d!aHQ+zW(zVGej2ybsW^79DG61Iqnk5l|QO0u#VJV6Diy zE?_j63s#A|M44V12Nr@gV3)}HBv2pp2GqrR>SFymKwZ2{UA$Zy5btH;ZI}%12OGd% zkynWO3UOZ{?kmK7g}AQ}_Z8x9r0lO!_E#zUtAhY#e|0I?B=XvHk=Ikfe5R`Ce4`v_ z1BQW_UbiKJ>WDB~sGywwu^}l5`*eUXsfU1Cc zc#C>?i+Xr#mB`jy&=*Vsi@qp7nlI<0c*i-k!>ER3A%%^U_Kz7ZKU%K z=XW^2OM35;-n*l~ha%g#-d-ILXFK(`9X&gmgF#>#SPC|Q{UU!$1x>&JFa@COZ%0Jl zqi)`#Zr-DA-lNX{PM!aqI{$lbFcmBTuYr9c?zqfi0s6FC;mI}-+4bk-%j*>jJ}V_*T>}R?#FXg28}%>>?k#h_{P){~+G(-e980CzSUS;(a;_%mGh>_rNice`bUBB6|qG zhxGRle$Ra(pEUym!BjvQKBEku?GxFX3>pE#?wt&dh=pSJ@&8pH^ac~bePA8^W{|DOO4}|++J=i01Y^KPMBf%>0J~%3JJR3|0%S3)^28jC;`S@w4$j{W>&$OSP zM}f8c?o?f1t<$VM+G-Z8sssKPfZEM+8efI!j$nf*(-n*X^F(>rw0YR9`E5n9exrhx zU^Bo%F~YiBkRivYq_?FGh) zs+JBKf&O4Jpf0LW7u5(`9lh1jS)(Nw45or5qH4|)RjZ9CnxLw^T2vj%TNl5&Pm8KI z1`wwn{`Gc(BQT2Gm~z^fwqNDwlA%983qxz-B;sn~_Gd+eDpF8O#FY?TiDWnxm^ZdYexH_%$bN3({_J zR8-3>KpHLgh-yWcR+O{V22rg$gKeVD90AbTCK==c>gKG4;5qOiI3}v?Tv6=?0n%!Z ze~0d(I%a|O{-l1cA{5NaSHJ@g_)P!s`0 zS=X*>*=%o=oZ_llgz|E14vd!N?!W{&wem z4hhN4E$5tj?zyME!u5b7gqgGuaDXtAF9rM&@FD=?PQm=9G!kYi);RS8!c4OOfWK)k z1GW-oI{Kb|17T+Pz(kq=m<_&_b9?0s$F-#ekKBnKKn| z6W|HJM#9Wp2Dl&a4qy*q=B)y}1;AY9H4|n&{(k;M0NTw*yZP@C=F)kDS)c{@2DSoyLUzg$Q)wdDm8mwu#1OR+2$6A+Tt;^BZwV2PfnCrE*gt^X#Fe@+? z?!U~6d;r?5K)V%a^Se<1%z4sm0$v4dBh2qH?;FqtcUk5p1>hsX+vTQSb9g@Ee;4+Az3=C(TlTM2XfJA}CdbG-v|`@LvPYYrGIGr$m!kqpLI^B!$??sz?PZQ?8zX8e!^B4607p&JR z1H=F@uC<;pwtN7-u6znmOPHb;39|}gt;SsMHxlN7FaYrVApYjTorL)-aQWBmg!voz z?r%>3stEIth%jq_yEO>_^tT3cSaUaEEdYJ3*#^K|)_~vt?gy{}_7LXbIRK3LNH*XI zVIF-80Q^0M@zw&bYk{}5`1xA=>~R$!3NR6{5P*3+z6S6HU^4(XeH?grLI;QgBL-IJKllg)&ADgbZ?0PA{M14sp+pQm>c=9zJX zc{UJ$cF)ZOd`TFDT{6$F18fJN?{(;V9r|8}G1p=K>#7O!0{;I3+Pr}EzgSF|mp%gE z=P!o=u=bai0IYzQ0h19 z;{hKK<~7jkwdnx-?Q8V^!1L=y0OtGp3IK42yBzcSA;P?o2Ef?3w=r)XC(K*#5aw+Q zpb&5aU@c+ZkpTV(K)ZLg5$0V2z*z4t0pR!VZUHpA;XNZ^-b(|_0o=yJTEe^!T;fi~ zd{9A{e;y$W?o`Z&z|%+15$0p8<>MC#v*B*S{OdsgaP$f0`Kb|rpMTmzn2lK1#sh@; z>?XK&d;o6%$_TS*Apq?^zZP&mBE91PlL3DQpv@Omg!vNl{}QjuCfKnr2MMZe!-uHRM=W}A#K-vPE;2(#l$ z!t4Z&c1{I63c%WS1p~liyWRrS6K3}cz&65suK}R{@1Fsj;$RQfxaU$HFwZ@G0pso2 z4rn9H-Wb3A^#G0yR12B&&;Is;OsKR*Xu+DSi0CNC0 z05HZm;NslB0fzwfgsD~lu!iak0PtT8d{zGqfH_v9pXy=&`l`_YFo&9Kz~umpRr4_5 zEx;DQ2>|F*>jS{NYx4n%0e1t|0x;j&Z2-)_7W1w117IC>m|NY00Q|lVzpuy7>sJz{ zfdFO#{s?#jP)e9atfvv=Hm6;LiZ8(~kb^Ere;o`dSJB z>i|ax)0zah7JxRb#{rm6TM%G8;Bvqp0nY*c4LA-!AMF^g9euaw0XmcvC%+5Q|PtgRLO%V$|O`9eB;X=4Pr z6Ad6m-<&w{%_6oxIr^ae$@%`Qq9F9L+A5lWwyU`@FIF1`KbArmOB_T8yWc9FKu5d( z;*NH)W__{x`R`u+#lqsn?nf!`q9~i?`)u;K)y?@bo?~TPD_TH<2^xjhATbl}WJ)=H z9ZH*_%sQ1HD}M>MvjbZWrlyt#%?$}mP5oVd{)!uOa`gJ#+#5-nZKZbo`Vw}R$HpEz zHhXpvvwnS%j~YSEQ8;JLoWc?QvYxuKh)_Mz*}@$TM^_I)PAEQ|^&8fI z{PD+|k2Dc|LiUUqsP=D^JBoZ6M}0+UX=z2hgNZDhvGs7bHuaW#cpE-vpI213q-whl zZ=F#XNy2SfI%F4-sSsc z3M-G!wwmQrRX75c`pNjAwQ`>XcxM(p2^uj&p5}rKQw#VKchUhN!5dX*WyAI80!BRl zypnkuW$|nDFDVg8lt7eHBFgNk`1*qnKKQz#C$p#sL8+wMX;aOfJv-f>)PA>~-4xu8 z;Qyrw*c&9O0E;C+B`G9pkgRx%D<97-uI`m$nWEESqi5#p;y)xFc_`bps6YPPm^nu} zC}wt(Isr2(ewIQTu~I{nHY*S!_6s6@v^7p|7}?l8BNymJnu}J`kh#-V>l972BXHy? zI+|CV;y+=ui-n_~uOC#ep>#cU@#*^W&H2J8?>Qe-)1hmR|7mLRs}H-c!$Ut}@t9{Powt!KB9)-S^~kG=B0CfAaYx(vxpePN&16 z&}uu2d|e%N-09aPiJmrh`%$M)THn)8htto#^Si7h>FU*4S){A~31}}VaIJ7Hai4&t zBy3>;SiL2tVBUT|20;kw~6icZh1a=k*wn$X1>uT3G*lR6dRD&Pm^<><#?kI z#a$T5_Kv&XMjN+Y$io>!|i040cWrIl;T`*R}U|l`^*VXs-Mk$s};8yraG>hZ; zbPUgXMn7doQ*^Z1x4yohQ3_g^Kx>-s1D2nizc->@Mc`s#zOKe-%amFQM7 z*+x!hlkGOfxpEcrbP}&&drATsdc+KL_yc|hLuu2y%eh%fkmU&JR+4G(v69&~f;;yb zCN>&mdCk_3AKi5GArmkz6Ak%yzxR=K#D~rBEHK zT#d#Hr~A#?EgwAl@x+!7YflhGlRLc6*|Q%{iGLKAek)Nx;=e-D@tqIPMX@}G#PS?s zC@D$uuRRbNw(Z*^zBMuF>BMDQ$z){}<+yHk-OMyJuwPff?yx-d;M0?*KCt?wqp8}pIKh7P$|o-L3QF`)g@D5j0uTtON1~SS)>_Qt?3Z5#2k#Ap z#P34q_uNy&Jn+COr2;op5tUFVo4EXoY}ZYq>_^7tko#RNwrtY1GTSBX&n0ercaa!6 zY73b!jOvN+U-!Hl%6!szOcn4H!!1AQEX7h~WyNWwq_N^lind@IMVjs&^1uVc>8vkL z%77FKvx(CDoJCR)?+X@ZLwDIOxn}sn32@@@yCXo8Dv-xmVQ$f=?JeyRjaI9Xw71xEpmMJkF9<#Jb}ppm zQrDlvZ=VTWkWFB5@Ur{yenHBOGNSR0sh_Wnr!_!K2ZJ?0MrY*J8u0VY$dmW~d&Uy( znJ;j>9T$tD(;Q#2qK^L-{OM+Sa4a}KmNL9U&UD!;&zw2qYl54ozU08pnd3vbE%24y zH+2r(1+iV-tQ8iOGrK$5l~U)qg9i^DJz9RIieO(PHXepywuxlVK$@D2@_%V*Wiv9- zU3CYyY}xY7mejFXSy}S(t*<=>1G4J(ISC1LbI3~8<@37(`$Mv>M3&t5?kc_|8LSjz z$3Afqi4t2ytJmwXTbk;O>aM!)UU}t}x8K?E&He`B#16`3FRiO2ms&{aJNd3Z_g-q> zDJ7OmbEsL@tLF3H!zsVyE_r}IY5u{VG+Dl`rlzJgM~6Wp6}ud)`QPCZ%QZfDb(3jW za9}9dBGM8P5)u;`D7GK|3O0|g4%@}PsjOol)fW|AZCQ3ZqtKg7zPNDry>rW?A|jSc zNw-UBFo%YQ1_w6S?K5WNBpFEKA-1POjl__YGovUaMO9N%)2&v<2B`&JZR~-(j>hmK zGqcAQ;Py6c^5nvT`E%2U#G;Ai<=xtl#Q5-*7O35BZq+DJ%2%s&wRIc9Q^$=PH+uM) z@^X$(S4$Rzk~44Tv%;RbAO6I-A9ASi#VemGIGL~ib!7g<;vLw_SY2&7C#?cd6`K=H zkV*WZOb=%No;F~!tw$o6IA_j8)V`P$S{F7AZyW1@G!T>Z>%Xh@A3vM$W^!{N;m%)r z6mtTPc0xa@?$&dqrRQ3^RkDeB1>~Gc$c9W$?k3NqjTmu_^NFwl~zA zEh#C{ke=bghie=5!(DQwNWEc0VAQz${QPlIfl0Zzrr{AK$-l^TT~8m;7xEfpTyi<1i^l8m1RZmJv%Am}XM_C8X+FO}9Q|Rq`5GD#iSComq+q`*mpiK#b ztp_7{(K2PQ^g+wiQnlQhCi;J)%`%=kck|R4E@N71<$9gG^~B!2d-osx;dDh+RaLXp zV2VmKKoJQW2fuk<=D1NQNl8f&c>lI7+2Lre8=p0K^5k(Ay{qQTsWatO=j;ToYo+3g zO&d3E{O)uE@e2(P3kfvo7)Md4PE>x-5D{jmeE-o$AARbT_dnYTQ)8(nX7rq^V?!b$ zrxwC~!}+40B@dI8iaUS5eEIU3ab%oLVz-|yzAF#g@d^4EZqKy1ino5bWyik#WiIGR zMxT7wAK+`ffj-)YzC7iM&B)76ACYPid$<2cu?EmujsCsT+Ov(|Bk|?&CT(b#J`wg5 z+|5Z(5p(QV4vbQd!1{8(P3&YCr?;D*XV0GJ&Hs%yo_8lHT^R08YKnXQ?sPrRk5(S9 zMx9=+FluE?HJGGEB3J83z0IQ5N8!Z5>2l7g(wZWoqNWC!O{TyIs50Sxu-TX$j*j-c zLhxjQuIVs7N4mvdQ(oLxW%EDR)C1;}D^&Z+LV|}48y28bN_!kd#)MD}XK zQ@J4c^y{y`{>Gba(tOvwu3I^tWM157^FLVD176kXeb;?EdSqH!T3nD(-7WCv5`O*n z@#{}vdT>VA?Vo-+>XJ+HlYI~mxcQ&>Y&zI1l`A#I;$syKnNp*pAB_y5o-qtj6&V>)Wfac?PbUGBOZm2znK z$P1Dc(af2bsFSRaf0hP3exOzA8xsHaJ6kK;MaJN;u&@x53NA_-Thhj;Vq!l1w74td z=3Mf3`p9n1=sKpXc&D)UMzR=3_Y&>tN+;H?RY_g#jZMOu)%=N(3HZ|A)(}Yrr4X@Hjxy%-$#?{z3=y5w@m_% zk93{~e0%D_>R|X_SLxSZe~p`hj&$3^4u?!_lj#zuOGalCsb!8LN!L+usi0ToIX4RS zDFi2lk~Yev+5j69ypTJ-Ut$&p+e87{0nt8g+n)>L09Q`@saM(fzczjGGZ;@cOKC*k zX_XMs=PBV`+zrP`ROiDpYx(*OwfVVu!|h*Vc?{aKh;gB*g2AR#~h)_R$S6y9QOGk@XMEdO^u(d5ztwfP7rH}jG%-*pB0{q!4cAvdf1ao;f zcF?G_>_S{!MvWLTJY`}=gvoyB(4mU9X1UlkaNFh37(gp_jV(05SLPx*i~A*Ww8Lw)cmdex@&ZyES&PHGf?Z*ZvVqSd} zPP3CaK0;;thobF~S7(z?tmHnncN<24`(&bPqE~-NFb!F;in8z* zUZvB|*Cv`@_eg%-q}iscyL6ngdgl1?)6d99T}dX|tV~$3jR_C4F~?&7$5)9Y5wfO7A z*|Yol;z)hA>t@kI_5#WhZ!y!5M7z@UCX^gl8pvg2fag}u)1F>T{V9b)NUC=VU92_= zZY*E-SXn$TP8H@8!p4k{uBsh7cJ#)KRGv*8wr{stLJ&LRbTYEpGiS}3m87vrj9RfX zz$OkLfq^zAFmRRE5EA9KFK?W<_HXGb8cNdHDbnVX*T}2f!z>E4Nn(b{I#X=o6q1%^ zW75(%OUxL4c7mtR4Be@+)hYFZdk;>&Q_kQC6DF9=u-$aotcr$K7qnqlYlBVQaReIj zkq&Y&GV)*%)%LenIyA}f?Bzlc#v}T$BP*9W_{oFP@#8=K82&!1;?y~+%=er-Wn&uO z$>pr?vUeKE8wCY#c)RoceBM&eJC>6UhC7yn#v<_&+wj`iQY`d<>$7dBQf zSP@by#~l?nn4aV8qI!;_MbLAG(q<_0iQ(nKI8JIA4V+gHH%-&bGp^K94@4f1LDoA5{?}#fpiG($jwZ<)@#1dbC~vE&J%vqh(H?_$gDSWR0nAb`+TlBASmKJ9hBk ziIYcSBze~IBH5B>?9x4NBO52snN+-&&wf~*!=8v zhtjClnM{q1_NH@<1aj4PSib8ouDdwniRS$ujMJt~gCF6$&hUA8oSlW(#J3zcD_9ad z`M^N&Vim<=0I#~tg|+dNHU`=eWNj=R&8w{aPZ;f&#N+?Q>YE+w$sLdKJNb2fCujLH z&CSi7cCp;=r|jvZ;lmRX6QjdIL#3f{(Lvx;_>^5Ty|%lq1sC3-?)1ztHJ!LK2U1_N zm^zz_BGYt;*HkEEJ}EzW|NF7~|C$?rw|Md5S<|OaopRZNOza&?dAUO!NkG|t#S7W@_k6i_eC0LjqOn}@v)7LVdH+s+u@|6N1M&WVzbIVD5Ekhlp2I@ z;#I{bJ|WMgr$5Kv`{(ntzJVV--qG6B1RNk=uz%)6eu_cdRdHP6tKGGW&z*>&aRHpC zP$uimooH}s6S5#R3$yhy2XV@^+Eu=lr%#+>QwIl4o>=FzB2Lk^?QNN#eB;JG=@Tuj z?JhPNWndWoTPHh*%`bq{=6Uvcj1c7v$~R}+Z{aJl4&NzkZC8fB?!3`L!qCktSl(#r_xZ}n@(}z zbo83LSDx3E+?5Xx#(d*qvJ^1P(w`j+b#Gwlef?VJ1i^X3}}mqgBe2=lhTa7px@ zZ{SZAFRN%cSuAJ>zwP_2u$$c00M8Zt8g1PBh@B6+yN53pthK+!jDATBxufdyS$@hU z>#S~$8p`V9cp1{04PlUVG(|-C>kzip)&?az5gq^R*$`peZs?N@ANhs1muZ?=?qqqWcfMAolci&S-fG%?;kG}ff$ z&tYNBZVtlx{HT<$yYH@orjWz0I3NtVRVe&(XO(gMI)fr2anK11q~@igT}5J|J~LiaaWYD)|*DtL)d722U#RYGtafS z=;=$ndXAscM!0bbI9bW{;=0(qj`_Jy2|-JQQbe(wP0> z6X6hzXzhn>9gFQksSviGNBuMO@s4@0M0dlSs7@Njza)=X3DWk->!QMQo}}onPYC#- zi5g)P&kiz0!1KkyAxdtrk%WI)!dja{f)RxVam%^Q*~oqxTgE>48jOhL;OZc#VBo93I+&@;VxUDz(KS5viDn+kH z@c)aV>*F+5ec+s%<^=ZU065tcfFkj{kWyGrY4q}+#qX4cz#vdWUb3=!+CqM{f8hBc zfoZQUulQ_NT;6cik48hpIUHhBtY&lFgxnvCgpe@Rd$xU_?YfeA0ItPXB)9qvIR-*u zw@YHP6wkKaLm5Q~fN=is;{g!t3gh_|X7DTY^=s?)u_R^}#Ky#00{j~qX3RijkIUqY9WsGAhgVzBf+%}A&K|5)*aYb91d(?S3K`IX zoN=EM7B0UmpU}w+u)h3qtvuxPsZ)G3MeAXRlF-m^zb!lQ1C`Sbhe%-sh3?AFy;{$cmM)8SoL59QAKN$#_L zFlxA1YM`IjjO?lAcW_VXx8Hsn85t?B-u>>o?<$qbp6a^lGqUb( zQbo73TxXLRlCYhV4DN4~Iyo#Qr#Eakjolqk?%v(QCK*pZ_uO;0-F90_*LOCX?Xt@* zi)(Y(PoxIU|CGUcm}>UC{PG^JyWWm@K_g&8hrMYHKVKUG zkJkuzY;7tlA)=m^Q;>sYCr($Fa%dgadW02>p?(bLZge_ZYsVF!>QS<$p}e}iy&but zGDR%T(-@IWOue~9irSKIKO?fP(;xBTQU3VD|M=tsH*Q54jt}`?$)NY*1y&B5q_ea7 z`0X@~oAv1`7X>zMJ%MLa5Dv6HZk?{dezK-YZ6e)?UfMsUime4`1wu< z;Y7^j`M|%UW9vSrGd!F|D>OBkQxg*84Q$lHI2yH}*@379@pl*v}rlyJMxx#+O$)r#@~F^Rr=$I5wJ41Kat~F=2`{~@!=b3g6B(C`KHN}^YcIb zbd$GRi=K-yh;YXkc;f70wNY_n1-i!)>Y!Z3<0G-O^yJBtwe4cHuA#*x9X59C*q-hd z7`a=eKBc7r36myGN;GtopR7FBLhFFU**hAGans#j92|s{E@)2(caWlzD3|XG2vkOL1&o z|IMz`NE^1sRWzL0h)DTY-XAqQIyzc>kaTv6b;gKf1mGVyaG+;c?oBt{lxwLv=QX?7 zpR1^mirxljVQwzDur{7PFgfiAJ}^BU&8rXW!bbDtiC?#$|EAT;IUdqqd>;Dws5+LL z^Iv|QIlsnhE$exylBMe5L`Y?2Kq5p)k}rXjIa%8wVa1F@IV`rt(bFUK2?z>8HbZoD z)s}DeR5<;U$KVsAg+HaD+|QusZfmSA4>hTz$cD^vI^{YeFK0USRL(@W`pTlv5y=q{ zNqUV`)PYpzkPxHv%=Ycu&xrL*z*rpM+U&7CFq$~qn;IG$TAW4dfKE;r{rlgUxA4L! zd}*o!LTmlOIzpwETqlpot9QzXJSZtWJ$>xx+i!m+$91Rc&fw>cbVpnPiFV(jNO9wi zZ7H$7q^qg)=!j51f8=>&batwPVpH+K2*i>Hp*5!G%qMQaR=E6%0?4=M$N*K>=_5x{ zQ)5Kmy!hga--u!qNh|oY0_{D^ySreLX(&B)y0p%_PN1TxqBN!gsXd&YHJ7J`;8}}9 zCW#L|TDjhY91xSftPI#oPw%PSi)^vIwLLz`85tSLKG6L1P=MOyCMw$v8adPBTOjF*Nya% zJa(Wf3VP&U=_6hqg)B3DXJ<1An27a91?k0Ioh!4+qaxiJl0%*%Pibx$sjqqe!3Q6F zzeYdumTdAAcaG-rYnsh-Sg4P@le&iGK9OTa)!U`|@J#5wnc;e=y?)e~NK}~#K{%LH zuF_#Cq+#cGy>p*BwXh(}$64ePrEi1|*r<=1eeYdI&T1lO7!Jps=e<%~$p*&}z| zJDU{R{5v~)lzRVA%(wICqkk8smQQDk=TY*oXi~Iy`slcdH{s~X>xnd!HfpXPv%4Qp znT(8~P1bY0q@j%F+2#_S0!w)c#K~N3pg@~T#?Wo$66>9(_wV0-+9{CY&>>{i z#m9rIBAw12My@e{6hS6=d#iIGKauV7!u!olP1R*(Wz|hh&8HAtd8RG4=Zj~befEo< z*xC8O^1s;UQRVEHUw-n*C$GMmL{LuZ66=GaK$*lyJ-BLc4ze<9bYL+aAGh)ASjn$r ztV-5}b#zI@UA46xhxdK|{rAV}Iy<^u&F$@-iV(zjhWHq}O6bzM^~qqetSEVNTqX&! zji#k*MKYCItqx4hO^wzWT&2)b_U{X#saAecM|+1OKR-n;YC42FMuo_4Wd2^U{6JAs zpt=d1S6N$8{Mq`iAAi7VwXWNCtg5xGqUl_vJ{P&^c~J>%A3yQL6Q8z6{4S4t$UcwB z=5?Q0bSD{aQzKA7rZ@VVOr|u%K0WBaY?>v~x$UjD-g@ud2@{~f#i?8B8(?iLB1P)U zERwVDz+;7cJ~!&@w#nB6~P$2-RlCle#W@_ z@jUs4(ngNtXw1hzrU~Bqkz4 zm86m zr^;yb?X410WKLFAS655Bji$(ydNdP|tA zx(N!}P&U1hZu$;~))E~zsy9%}oAmU=yCC(h1S^_eL8Z|q%p%Z z-Dlx_K6tiUsgHTlla+9cHf8@mz=A20R{fi(H1|wq6Y|Q z7yDV#^Yg2#J37!6gT%Fhg0{AV1mtsB{q|Lf#bUYo+s!Df zvExwd9yui|H79qFt&tCC5&E1@dvKXL>tY?Sn{DpHT6 zr`zRnb@%wV%0Qknmrr;G6p4&*BzvSeooy`>@^L{K6>wCOtJjBWop60AH1wP@27{#C zvbl3}!ZhuaRK@L@u$;L?Nm55eaez)-zZI&`lP|vvx+PTARDf(1HB}Y+Hf`FpuOh1J z^QWJF`tz=+zIv@_299JHBkL+*jI^QT03PvGk?*3o-UEIXOIAoHTxbR}J;S1t(tTl$NSTS$7S#%1y|EEOe;qz7$r7|65#Q_@9_;oLp zho3mHY}u(}$3f}i#V3omgVH;WMLE9&rN4AWP0hzGi@U-6RWud3-zd!2Q2D#Na|vQa z$SUz%^DC6lfgp55=lHwshKf{}IW{#8(JQIrN2g{?%O!j9ys26?RsD(G(`!A5|;m_LJXy^Ua~Ub`+J& zOf(j0X3kiESQbcyy^7JebF#IM?+@`iR!;ttt{5 zGRE*yWH60Xt*08P`8*n_lH*E0H&+hUk3mm;Y%vkuy*fPS#<=_O)EPX-@@!+E9au#% zWV#^Pgf=P;yKMbpQQ5=@Oq{S7nht5s`p|`zZi}Y(-u~By;Bfi*@#FUKN059_mYI%7 zfaeF&_I%V3^mDZ!am0p+V3PZ-Bqp0YYz3p-|Nl?@c=y{WqWImM!jI=86LoiL6{Hz= zaO~x9jIDDz9qpO$VWp?&^<#n%rZ&t#I>G`RCs6W_<^|yqU4kxgqO>;Lmy3*PJhDGr zWw9(9;oTy_Q=`vZgz8qpT=c0U&rZwsrxQ6ToiGKt&(brO>h<>TS1~&RR*7!D!3O5Q*y$RjqgIh%YWwpc2jUd23|%7uE*Q)X!cgGkvR=idv5oBJMz z^uHR5#W!OtHG3tD8o{570xsQ@>%fe0#?+%%UV9$NV@c4S2RXs%iU&EtZBo7dN6v68 z<$PzjO=_{YPjS!LdOtMX<3td5d>P5bZQ=qO2t3JK=yN2=|??RRG(52jT z(6G7`L~&p7EdIk){dB7zql=!5pj;F|ZoSy}PT;w5-V!#p)6bXCH&!6DlMB0KBXz{S zuzANziKDINv4of-v<*;<8?+H)=cA0;{IL<8 z8(~D<*cma6R;%I^{4*Hx-fse!sW$s?9EE2gDM7`gwmtlo3#7++6bBg zFMo+utfPa$k{3#6bRN6^uQ_YaUHbE3=$9M|J}UO)xtBjr#^`0dXG*Wv$ebr=s?a{a;8UcmVkbvSksn@-un&k)~QqqnbhQ~mbR4s@WT(MPHPl0 zxrBJQPKr`^uGdFL#6<^+kndbyw`kc7H{38IL{`7`-2>b z^pvFJdiriMV2KExhGBD23gkDF08bt>m)G+Q*RzM`?D=E5GI zJ2<_K(@uW-!5eS9@!^giD#a-EX7XRSFwb?jYayO{jT?XH83%{)qH)aGeQ*3jhgimr zp(;0h{golwo}u_F1wVvvcZ!p1X<&&??T#!-Pshb+kjN5vUt2pAfox=nRv|)#Z@qq! zVh2>XaY2eU*0$ZI2pUI2OGe})v?M3FZ)gd0TFzQ{{?HO*XQ$nvk4}O(jznmQqZ1cu z)GrnJJj@4|+=}25){Kqdl3QtT2`9^XBWAdrKn7VCRyF9lXv9pvb*=OrbXg(6Lg^KJ zr5_|MA#9YE#-{)1=%V|qS-2w}cr1s8(TE<4TAo8gXqe?8TCB0p66vdXT@RC|l(&w= z(mtped29bQ2@%llcnz_ON-Snzyau8*4jp3SHKGx(AyPnwAzmX;(Lv)i`V)!lP)yS6 zSD9;T%b{?W*VZbpPqky@nSCa$AO5ANDv4ry~EDy-2=&DWghkc z-5867%iW3Q_w#6eKO4%*($iDZQj?QoEkVg346@IxsMxF<4R_b3&+($ z7`T37e!KlF=5Z}Vk0q<+-EF9W;oFJ`zLK+5b+kx>Y*<+IsPTa~OmqSM*YoSsSR5&O$qYbvX18to$b{)d3T{d>Rr?z{31X<&GCRQRw!tq4)V7L&6v zA~`j(5k&iX`~G96VSaSR7hLlDdnRRMO}?#=yv#o9@Vf0aWR?8hd+xbsc?P+bb!}AL zh$v!s8;LbyW~{FMWbyGcH4P+?GFS3jZy=y=UfVJ z)}rYseubCixsP2Jp*-?4&_`yB9 zc7=sm0)16Id^Ed9t^z_96w&dC$-_dT6UL$%YilcF8Dmk8rN3vJ^J}XSdge3blB=)J zopkwf>fB{Fj1UC{yN(+8;}XJyhbKm| zj`dKQB%@FC^^G3~$3P~OU)HNG$<@KAmB+sS>qUf}T|GT}#gdtDb6+HJF_Fv9_cp=aNXE(DceiJo z!R8Yf%18(^b~2;#HXqM^Jm>7$W)zS2ES}>7J6dbY%geK}vchF8C&289iARo9oT-2( z&<9*C!z+@4)9|vk2@!#CFo?Skmf?+UhmY)rua$Sf=;xYiKV+jMUw(PVmTzF?S9Eqd zb>SAv; zMfVv_<&YQ1KjFi85WlooF1rkhF1Nn~O;@OlVrcK2G2S4Wp6(->HM`TCHVdN8s^t2k zecG7MK3m0<*V9aR8xzrvSD=b+3#g_2zacu2cx^VDAO8^kh8u)BE}uVXWNZ7JF(7FG0^Uh(A#UwisgW2s z(pTi{)ayqTX)l|Z5P8+2g)<7`1C@TK@<4~ZWGi`9bVmiHJ@Y5v^g*gFIJ*nT18|@} z$v#DzWs?^`I>$;on=O{#_xC%vy`y0m8nFda*-i#X)pRJM=?e*gMJYhzn0$;9|AWb7Mui$C|*)qd7b;2bYy) zX13Y05|iS>LsH@`2B}mEg$)}$7nQ~JaU|Uo@d4m&mpH+k@hS)gN%`n%iv< zO{}&l)H)e4YE-13L8}V%)A_WaqH3#JXY`XfR7$@fT4M+nQ>TAGSYmSW%+Sb)xcHP& zSaYymiTw7?&fI)xsfmWx6Zo8Dbo+MUo_V6h=F=v^z0)@!=v0jb6|sW@eT#zbymR5` zr%xr~ny=X;CT zg|+d#HTu(zaBCbvNAv3Kys*)J$(0RdtpD!S4+TTNZX2531}T5l#pnB>tm`>mhQ7f| z`61=qcDHrw%mHypC7ZuJP|>Q4MZ(zFSe>iA{H#%@>h7@DRk10ziXo@m8bo!?siCb6 z#|NZRITh#6whiI4Z4dR!wk2&$T6!)Y=i9yoHo>iZlWaA}%YXx|_VoF4Y`chpQn{6uQ}A{V*3u#i z{o-VV_heqdQzyzGrP&&t5|tq$IUysf^~mvxE>&}D)SgL<$OmP*gIi*Z#G1xUUDshwAYZevdY)r+CgX#xR9W>S~(*n)ZVZFshc^r zAa|w;kB$zCj&Hhy(u9;_J~hqT3JqM2dHnfu%rC5sr<6l|akjPs{1NA=t?-{Pn&&>g zuv!1FpT4^YU^HzaujYJ&2cSK7-t}AK#l15m27v;=*ZiZ&Y{y_;Wm)mgYxV zJ78^wQvIm&{&xIbunt73SyWTrz7kwnr43 zjTY{zYJ?~gveCTlaXu4GV~L6$DFg|4^-XwUS&(V-c?^cD1L;e(BLj^ZM}70@ld*-l zW5SKDvoJ=Nb}4ibQSHb=gG_U0q4j9OhLto1g^s2vXnxZ6W4#$@`k+yBmn~a1E7f9b zJYMpze_l@0&z>>fofFc&>6vGq`MlLPV& zyB1wK_mTxu#*pi%A;E%IXU)GYpSP^9g}2-35PV&N)uyji-H^;igmgFRzm` zjihO)5hBC9h?Bk=R6m_T@E{3q6z~gVI7dcW)Ubf~=#ap`s3@4j2lpV2X50=8&7GHK zja)Q0XUv#6b5L3H{0=0JjspMnrM1dTJxHbr-aSb1oOS+6TE5ep-lOE&`2DmtgU!ci zrXHk(3En+O7dF-`o`;1x!oKbG9Nq)lk06Q@mYQ?ly)L}b9k!Ld+YTPy-BjH~zOaQm zooaZLd{W_18m`vs)x+^ks*heTQ{zypK7PCb;zwEQCXIToZr7SMYmg8fT>NydYd(FH z2&!_NtSsIduCtK}N-mYwVhM&twj@?V@0dMXSPDb@te?vtE5qr!YC_ z(=F)FD`kGZHo`e4U^EI&xI}Gh!-;+EZLLi-7!VG*0e(6-AR^fOT`u7hff1tux=++0 zn^&%fr!IQJ{Q2|q6T^$ls9tilrJ>}T_4PI9j%|dW?wgI9`}yzWoc|8444Cbal-oaH zS9?`tKy@ok)QuQzv0OpTQ5)IkDdy^_UeEGh(ibz7v4(N}nyg>PUn86`ZhNigoCSZp z;EO>aAh)GBT-DqhoHk|*wHO=S7GqLgQ4t>>7gt^+Z=?oe`*qi`CS&!DH%<>MDapG1 z&wqxI)+&ejc#Q=H`F&(|iKmoLkCt&gdy zvMK%i3Ja%Bn+rj(Qa>zh(o$5p^7FgtrpvBeNU~r9Mm0s*`t@YcL||se4jVIl`XurS zp3li9@-6wEJ`!ZfXWp4l{sCKZ7k%&^)qM85@5ny#y%kk_Y}Opt6?iQ+`>*v!vxNmL zxqTIBWS-!wSVM~YTknU~%B`0qk{OUutW)PZK}yZ!afMvCVQu(6dJ0~NV>U+(9}gQf z;whZLsgtk09iQv3Ty*(mSInQmhE-f`Q+0RiqRV%~n7q5(7EpYq6(K6EXNu#;BFv(& zu&2A5jkCxmZ^-T*kI%dt^2jPK+(L@Ti-yrR%pk9kbBuy}NHaM?_LDtiH#q?R(}xl^ z6eF9I+N2#FAu~RHB$umfz&!G?P4)ifa|lW~xB2~fx6(>W^g)~k(m^}=#b^jwnz8)K zv@Olkr!@H_PxDU@2a-(CT#c7>pFT~BLqdv+nDUYw@;@d)i5u#mGB;REx#5vcP7(jLzS8i%E51_HJo4h0dPyzrIO# zSYMC*FUMyQyyQ#e_LPsFAhMYab;gS)=||u4!`PbeOG1OkUUKa$)9l-FtvdCVEj5rA z#qp(6hOyGtuO%`wHPqZil~h6!`>&_n)#VO)FO(hSd0Q)^_+^QSy-2 z3kSn(elDa(4ob{EB}k7{es=ShuyWZHfXT7bbI*~!{6P{>ig3cT^a)7+2-IiFcJ7po zAXU4o{FQ1oBXhY71{GfNo0F5+S%x^%Gdl^+9p#Yj4LwI-$#Ym?bYRt8VNTP!C8E5)t#39)9}QbO=@JCRfgYnDOYz2$58 z0FSgt14iNem@-)>b`<&Om|A25)iS!_a~2;xD>dci!;86reg3A*GfB@LT|8$vO3eAU zv~-BoexcCoeHv}nl`B`iU8PRGF`s`C<6OVwoJDx?uOAxPh~py9ORydl@MD@vOXVtG zoaw$Qd8V{(HzJpJ*GV&p8hRaS0czD!SC37F&{JyOI*L*WMXF7k^Z|(|A(|MV$BWNJ zs{Ie-x|Y*N^uT_kuK(SNHCW}~4YR+R=>c0jOCQP2De7}?^7l55Cj?8mfTNXkRAjkZ zMGS|lKCwD|aowTDeqid&!fufAyd~w=WJ5ozZ0N#k1bjPM;67GEhw*k(9!i@w5=Hwt zN9G9qAk?3Y1PI{fBA4-RtCac>+)v~%9qTDSN0VvY4%>&J8L zLEPFif7;sT@Ow?DO%SUPb>K|dwQKmaY3aeLu452aTMpYL>VS~i`W}VOgu?E_0(7{m zN8@afs3Iaxo|G9=5saRqb1B=7;E36_N29@kqf<&rm%~w{@FCSWV~UDy%4JjTSBl3Q z>t4y@t{bkKeV;uk4M@v9aJWlv8Ho_*@hQOw;*Q37BlAm1*}An#JrgM&Gt}pNYu~}K z^VjDB191q2`l(5KOA99hg|}u+;bm8tSl-j3574{Hafa3^o10IRb#z2Wr)w;{Ed1^S5cVKr>i_9DU|vCrI%hh9&q;T z=ez6c=gs@0Id{gAB}?We$GR8x=!j=$oXW0kVNKAOUVs%(?^^oe!r@Tvq~o4KtG$G_La~VGM11V z*;^mEtIKR23RO(Dm@+O zq%;cqXt2FDu#G1lc#b8s=~sWPG&2-x57|VQIGLEZo0X^T6iRic$%5`Q*o^d{bk@ja z;cXccc^nHeEQD!3d$QZr z(>kYFtu{OT{hbtw4C2x+{@ISu&3(^5|NM%K)WC*0(}SN z6R^^X?EHbWR`sFv&}l5-%WWmeWbwt8qwCG48VbhZcy1rbuhi%-v)9K&1^G2KHFb2r z;gpPGl|ERxD?JOB;IJ)Q)anEuN0DZfU)`xWv&KZ>D5|T=CI6(4=tlB;o1~?st>-U! zxICjYH+e*!wQ{A&v>=?<5C)r5WD4DZvwkn^K%t5oZ>=EuQNvG6%+{5bW@a7`O&E_I zqi9{MR!jC0ST&g=L90Y}-S9yULWCa|h0^Usld+$c=Af|9YAdWetAjgDRbhe%(+64IYO;C9fx5FUWO?W ziAyuhW=1`Q6V=T4bYjXTPoGCd`?&P=nT zND3kyeTPNM13sq??fgpC_Wj!rJ@gQwtAe0|P(MW;P{p{CTuD|4ocd~1(&gTGx_rFJ zbYB`TZ9Lblpox4|krBz?JncN&To`TyAIt)d2XtCSBxNKbRFFV539(qqG|P3tI{U%R z_6aj5=(G-z!60%>8r=dz;AjGyCpB@hH78iREG<0&^QTxNsy$sR3LBj>I?QnPS+3&5 zvuCqtIbmuX{3{7pLcxc6Z;^DiA;mH}{ovavhZ?hVb*r zlb@@Nr2b;j;2kr7iO$WILm ziHXf74=C@Lmy?q-Iuu)ge|wSm*|Ub;U4VTc$^uTJ+?QS4cO!Lbg(N=0C~4h;cbRyOD*gY%`Isfx=mKTS&og8O`bfDWqKfee@VJrEc*V|`VlH|{*~jmC@386k66mF z9fT+Q5oBnjjFv#IYin1^RPttdaIjgc4+)_q`OE=oL9#}o`jJC3yC(Zrp!*xA0B4)?;#p3Jds<9JN!pYp^nHY zB)$~KC1n@32lkv4`VlG3VwgCq#pWPO9xep*h(K7gE@6aN9s@RAD(D2`VdD%sK2mBgE{S| zqN2J}5gs0e*!^MWDk^$6XL#?9gyI9a9~Rho=))(jyDB#(q{lubH~vTVq{V#TBhIJG4Q%5nan#%! zY0b2#uy?)j*X##aW38XR=V_BXa%6-~A#OS+*Bf*+G5Pq()8$nt&4ZT-1*eRrFYrjf zr6La{uttxBGbVAEx(6oqrn<2c@Z(scw57VTvbv#(pRx&3Hrz=bq>p8KxUBr(-UG+WDjj~%OQIqlf9#P*9@%Brr{zzXG;y?d zyN@!2Qr183e3Tv7#?u}#)&_gTy*7Ry55_?Q`xr_aPYzO2hnH344eu*4>d5HHqeWZPTWq3(u6uIG>*Q{c)nx4-+0*y7 z;y;?HBg}}qnIF9Gs-V%7&KY+LboRta5E)Hzn?ddta66PXgVFKl8cVR5j^lTyzqGR& zr2%kO;xK|vPtQ&RQQCYR4n~QP9d$C&jFRwGsbp~DS2yiJc0Zr!ubHCVkLx~;&B-wk zONy2jk---s7? z<(6Nxk{elL@9fzo6Xykp=5-1olfY0@H+7t{WBM4SH`9V?Oz0 z6|?tn4&F0rW&G;1$@`)|`8Ct(I$w!SCSJ!?b$S?oV=~Q|!vW07*SW6i?{(-G`#BN2 zj7);_X5c>iL^lOFs6W|pEA5kt&WdZtE<9SiTCWW@6RUhiS7}hjNuF9PXzT7t>h+jUa%Lg zr3EI_-h%$v?R)+PrcxO;_NIZj{UzFX%ECZ!CuHGRO#eLc``4VaK%3qwOdTD&k2oCB z(U(k$i=)+il@rcVFW|noDO39TG9-1YUv8e4gQSsHnMG5jf81&{y@1L(PkGmje8MPY zqNkpZG8fXu6YCnTw(l@9Rls@#zwa}au=jf!5#4K1KzauvqM^Igc58!UVs`D4WDcuQ zSat1ArNN+dqD1LdapZAAe4wx#XjO&gE?l_q{`>FWrJBO4FVcw<_wFTrHmjoE;R}V| z*HLd%%f5lN@f#W0FlEXH?;1bnxl#F@4<{GWM$l&6(Yd&&Dr}tQt5RXIZq0YFllMZ# z{H^u#e;o&&e9wEbD0$B#ZGKJKdd@k9i#59J*O_w+FBisgCzH|8Yop}F10y!n#Y~Ew z6k`rNd$v^`=o2x1e5gUaHLeWrX8(WGy$3*4SN1=C-<#fNfMKXZ?@dHRqzD6o4SO^i zjm8*v(-YH;N#;42o@_R|DZ889G&j8`rpK085;d_z>>^cqZ!-hT?{nw9Co1Z0_P5{f z|M%x94Dfh!@45G$d(P*4&bh~2QjKQQrcIUoggLa(MqVY0$g8Ra*;$)5)f=;7X7EV` zr4q~fIXh78&@P+&X}8j1v7w$0F7~_D%S7x7A|6*kS z2%v*lL6@ebp(mHurT>3<&;ORZ{#(x(J>#j^G2^MoFQec76M6r)+Wg;o&eOt5eo0u# zlR{~I#i4$=Ht;tr=&=CyGcr=*;c-gGq(nk`le)V-a-C|hsq42a^H!JAARME^BC6(y zoE!o5XtC%+vwz#-H}i}Cj4A`ciwok z-_IJECi<&Q&sJr6EPDK4C=vS0{>pF@i}>_PvGBMDE~gn<&uXa z2Ob^Hww=qq-@MfgHp5x=y~5CUXy@MY_pSiZOL}9dp#{wQTlmZO#p4pSCE@*#YjvSs z=6xDv-XqgX9$)DHt@7^sA9&z_`6hvPUx=g6AJp`*P>ttt??wDg^x(`eV5MeDaIi#f zvZMlrLspb8HA;P|ho}k<_~j?02pl^@D#F4l99r12Y+7b+o?M@hgZuz*y-itmHtPSU z;!nQsqnbGVuTMK1j!*WI_ww`K<89bkg3QE9YO%_p?vBw^_e_gX)?TaeHP_V%e0KQKJI_%n8HO-E zzKrD3Xx_i`oD1(+D2$6((=^fJ2@U=C#>T?MQP%svH9i>6goNKTM*dt7CBFaGak^wC zT2*d$Vs~PwTp{zOsgkb?$dl5VYiq78Vf4t~nlbzv+2I$o|6=p>!an|Q-ZOenH}FxUD2&Tx_VoX$Hj7$R zjI@LKefVIX6U=YK)6ZpoyWJk?^r`eL9lb_l*0=+}{in?Dk2f@Tg87ZpUsqhf{O;@X zD2u`He~!<+QC}Hmu_OodrGx8#X*}Sh4({3eNAg83bIKJy!=rwnK1 zV_OTOm`{SiDKft^FT(up?Cf^mUj(WS}S>E15cb=deC zv?DLH8jalIhfUExG$z30@GYLrBRac0nWzTx>Z`9-2hI|>8w@2(pun8w##`^ad-Y9s zBxV$2PnASP`6)U1@Mb_f+s=7`oN{L@J=ZQKAtNq|mxI_xg`h!bA*DKM#mYxK-ZY_y z;wVcw{J|4$)R4n6bH}YOzWRb z^Dk((bor_kpctdUJ}OS`{s9f%A?Lt<*5xEeUB*_Dsi`lev50!`Vmji&dq($EjwYk0 zI<(+2Yx_TWj+l8UR#gx8N-SRA+uPo(mv=*Sqh#k#WtWI>q^qqa9%hG?Tp&h2uNbci zsXASABwX_g2C?;z(BvePwTxUu?TyKrMw(XoPNOFI#sczZVJ;>Jtrt%|^7ZW-^o>X>nVy=Q z6cJ$V?na5nLe98VPGJePd@HT2u$9!+mCKTw`jTecR7hSS?>GR-XLjwnz#2F=1`}M!G=hSH2QUZDx7W_SE4&anlVm!* zOQ^9Rj^)URhojXP@#z@x=Pw-b%ikrgy#Kv-6j^*??Lhy=T0XEJJXD8u6(4`#Ku2>U zmbM;9krJ`TB&?=Hnw%pUz`30c>33g`g!c7Q?e?F_e5}+r4ptRaGZ4K_n^1Jgo<+y4pff~_Jd(VDLlR)?F6INq&M|k zwmA5l?{rJ>U7!)$XT|5AS6n7nP}<12kz;)M_}Kr@JtAjav^%4Q`p%q|$QABpXu*!= zmR2fRm}jC|j1N^~>?54cuGX=+lyRu(ggSJ&r042LliK5S_zpDwyj7uK8h3&9^!bP1 z?%gt?FttWUD24WjRf}?ScNROI^@1p%Z zm$AHsd2+Vu%thBDzmEP_?uk}2a>C3DWOV26tLN#E|HbxPC?C-;6nP@%fq{KThldjq zXjHtf&nG@1!NSn!xDOv4{{_);QcdekR#jCy6kT0Uy)!hlY*`^H{=KPLzPzQ{d<(*YR#mS#$%$Pp?#~**Xj5Y4#jhv^xTXg4Bnut|3Wdqdt_L(XDhf*EhHI5-k_!?CR;L zM^NZgm0T{BN?ona{{CT)9OryCG&Bq_+R#v(cYU~_-;wakFQ`6#tkI>=*0&K!G}7yv zYXAf~l{lNzhQ*NW-?MM~{)$?ZFpul1X*j*}`21{yIaybC8uv z*}?wUmP3b(u|%h3kjP83`@Daml{OedCxkY9_F2|VH-%~2JW6GM+qB^0?;Q`mAfhK& zZG`oZv0OQ$g#Guhh(B3{b`|jLq8Wr@vIH6@(N+5A;@9(dXfV|&>mw3-?w=d(TjP1kk8rf z{J`c}Mla@rPH$DVemvUg8ftG32r&B@#MWw-$F|_9Hk(a*_;nkPpbH~w654O!B}kN& zl|H6~oLp=`>)4Mz`o3HyC6JPY-I$1__!x$uz_WyTSQw+xv%jCZ>uQ1 zvVnX|c9SYOJJ3>JS6A-^CS)q*op;iL1A9QhB8xe)*jta4Wg=HiCNGdTFy0%;o8%dG zWvU;?EDoV(A#Y$pLU0xUk57mwsi1jrTx|eXjv8hW9FLffmXZ^9KuR4Wxk~@eJ)%TJ zk3F>3ymEGC=9DQn`1D+{wDV;0tnThvI08<0q@^qs-jZF}6-^FAM<3{MJDBJ$hx7ox z>EQ^z`zgDGw1R%d;d&pJiy4b!7k85rZ2i}_6p-(j=4O1B#W|gE?;kH9Uoy92*}Z`$ z)=VX@O`ZB$L!X10TH}zuhHn};(kINO<-(YW`39-|Mg!YXdGO%D9<#@z?Ls|}6Ak?e zL+_w2G-=$pabwdnGRD#nTY5^2MFx8>x-Kn$+LVbA#y;pFEC*Rj<*qM3`FyihEthx( zov!}gUb$StA<@#~?rnCY)`bQQ9eV#yfBMs@#J)cBF_fQvV_Tg%_;iPV?vh(?z4gZH zZ@%TGn@~jL`sHP*669$xyRWsO%P6I&ySFI3<=uDR#iGz0`R)%zp4&XvdT#VQU=Hxp zDab%qcUx1FRx77^!86cwgdb^((7y;_wP-3Ub92A9TDNYUNQSs|I8x35jZsdkzIinf z**KXz=DCX$du}7^Jx+T8lgJee9};raM~`_wo`QMNN}S^A5$Bdz+io4bW8KK_#b=Co zz+1g}a0Q;*?6klIucgHL5UGNeGJWrwoLpI%lM@k%aZ(0IBJGhNZ;GJd+Ow|VaL zbd$fc*M0aQ&9r}nnLeFQ&G<~(`j7j`9Nb+qwOqze1+*BI`oxxu_-29pPB;O#3+)gy z-Ajaa1V#kw6&i&?;_B>Z&&a5#Xh_X3wAu2lNnu7zbJJ zUDdKj)5b-s#rYa1jAxuEm&(dybIXCS@EzMLe4ArY6~V);VetAL7#BRHZR++OX_$6Yj@M%V$; ziyJyfGbcPjC$;KsG;=OEzvyN-Fd$^ekjJucm&?PEO+q ze7DK^OSZ<~ZB6v0TH_=N+|W5vO)*fAS(MnC)>a~yj~zQ<+B9Htb{4JSuyg!SuGqid ztyJD}%l$OvsQG zd`=eW|aU{c`(1%L9yQLrC4c;Svm9FqTEvYLYJK1~54cPhq3WfhC_KsT~;$$j~fiui5J3Bb{u8s}qbEIB zMBedUMI~4IAkR@-wp!Rm6_6)d#V2e8j=P!U2>px1=y2u*Ztk3Ph|`dd`uksZ1gh;g9aHK@ zX8RIedp|(tKpDQ|d4QP^ZKsu4m_+nw0~0IQK#{^T&+67Qzy6w@ZauzhS4<4u9ukR^ zV`k@alHA#|bJsJuvmM%P8#(r3Z-I4nhm< zlUF)P!r$i$qir_&qNbo0CSh)_=Q#Z9V;;pZkueewFdPG5pd>LWxDY0g~GdABBBvJ z3=Qb$kju-;j4c??W@A|yeUA72*U_r{=e9vzG6QMA`PfC2%0jv@GsS&XR^?rYnJo*(9u+k+qQ)vEQoAl z?dfgk{Fc*Nd>a;~?RMg{fWCI9^L0#Us6)4RFUf#g5O3&(W@%d|S0G9k=%ZX87~q|; z)NO&|f-h%17?x~Ai4)IiQiA`Fu_Ym2*gUs;qCL^<7a=7Dp4G~dkm`=1p~j=9?Kt~| zeSsjs+w00`<~4u(@o{1(Dk_RLt>fE%0k%O{8D?2IK2PEVoh{bhyj~csIFBbO$=%=4 zicL$hesJQ>WsA>9~jSSez#!A87sbBOL6q zxuTO85(`n~an=kUh09^_cvh_FYdKkgssj}#Tl##{Cw#c2m5s!1{|BBGN&cW-9?7?l<4e?e6aGbrYEeCyMAgk4=V6x5RUe_gX7`yNZM@oJ`8$2hi(v=%W}z zH$VHt{`^ktk4$#-s7mi=fiGwA)2jyCTjC>hlAdEb;7IK_)+5nH#J98$Vr|D9iHtmg zZpc_N?9C=p`j*W`FA5V4q_bi(diL>WZBDr(z|ZgFk3-|f=OI5kZ+v{Hr~3HHd9kLB zPs?pI*~RlaP5GxCrr3Eak5_wWZ$6kj`2%!9gG!{m=vB8db}~{qHVBO`mo5w=Rc}xB ztQESq)U%R3-lgMvBUaGT33E?I=N?whBeY5cW(r-B`NCM|2=jE3(DTsBN&s?t9GIgI zj)SU=V|r?8YI+!5SXh`2*nz{+(&APJAi5f$cDJ1S+QEGG89lx6$-q3YQHLV(t^^C~ zO34{eP|rxLm|s>LaPF{FRP_0!&zm%_SyRvMTtv^dCX zfn;UD0x6mh8xoB|sel(7C6T4XUoc42Fi1$S5B6YJ11CHB<7c0Jw!^_2DEHobzm32^ zL9L0kb8=@O3=AlCrv%IQ?{<=Lfz6_Pm`sSmuG;-G$9(*ZpySA6ywt^ZJ;X~rI0&+a z>r87I0r{W{7T$#LC8#ntFV`Yvq?Ux_1Vzh{y?c+e#Mu^HbIk&qzdbPV5OKM&I%LD{ znT1J)&O@6&*?g$ekW@$_!s$cLc@Y1+b01Bpaz`lfF>``NB~e)t3g<4nZrR*IshONN7h{d^y*-TZ1(IQe=Z`gk+~h%fP0s# zbfNJbXb-!x9tP8{ipsj4a;a8JQlGYYmeNc1dQAvU2IEJfMAW^)42fuKgN>S-n>~Gc zaHOIAD5giXVr*&gwBju6F^Mr@SR1_M8b~LKyL3kBcne#%bJNZP(ZOoZkc2@sONVsd zK9@pKObZi|HCTxo)LEs$2VX@Z%NHu}<=fAKlW|@aw3d!)GP_a_Pv=IvJEqDo~r3rhYs|k=fx;N1O_@MWbV+G^`+5E*TSI#KJD{0E{CsN$h!m!z; zAhlY3MUY53|GA=H1)Bz~Copoz&4T=5x=vSB9zVL7VRCZTf^&M+RZ|)yx|B&%rgU}= z>QlzgSrr<3h;~@sM)W8yvx}4O!58gtDb;B+ibnD{7V>2d91D|tU0eM`Z)Tr4v{`tkua;CDefb3JuXlP7WHUF9i z3$fTfwUe807ZW7$3G|iPJSCoD&rReH!fqKPJU@&dQ=)Bcjf-n&2o4%sJQ-(3Nsa~w zALZdT5jv1aPG466pW6;Yri@A1B*1Ro^;aM~?Mk7wVZiKs;0z9Fd-o%iVsC>oVM1Y1 z-k4}w5n9W@fm;_ur*(H;L8`jz)V9w)-FhI#7ye9-tG}zg!y%=vBkwaxoPiC`+dQl2 zC4FL-&sFfPFpJe|SI$5HY)qH}B|LfiN%AnMc>pRwy4+m*4QGRvxEdteS8Wjk)h8Q! z+Ul#SF0foj5Qt9@+32YcX-WK z$+&TAV1=J#%%9Wj6LKg16u^gy0v~O|!)*)h zq^2e$#OAr%(@S1vfA{gn-nV7S%52`$(9fmquRK8Jaq`MBV=BoxkP9z0@m(hg^U6$3 zVWXI`T|GX+pA95Bg8=e{e&zNv=b_Y!<1$^!BZ^MZc~K*2{n2Qcey zfm3yuF>Wn{AAKhf@Fle8>m(HW6D$XDL`Ft-C+6CE+U<3jR&~ID4|;Ab+w%e{}ddXni44YwC;vs@M9~Z zvZm+exLwWxw}+K0VBD#6Iu!s&mqRU)_Rg0yNU#S=^4$!1nHiC0)_mRNt`no zbj3~H>us{$vLJVIZc>N|;TmIj+Qeem^b?{DELM@FtE;U`8my2ScJHV+#V&xCzjT6G zTaTj+vGIA<2ESgb37P!+`|s)P?r7^Clxhty2K@q1!J)mQi`QzSCEMhcKl}6L&b8?B zGN;%Y;4#A76}|j;L9V*iR<>_ZKHFeJh7-kfnBZEDiH_!&+Te1@$&-2{Z~sbOVDtxz z$Sa`sZ6q7*aN}@a{uYjzJC|d&4TPePV8x<(4Mh;PrW&;USrC;4)Dp)-p(kj*)!T_ zRE#@VTagfC*Z=Slf%5ds@_2kbvwVo`z=1(k9-_%_V3oWf|LZM({OYe)6hcSR72@?Q z5gnl}^;wv}D+#fE3PHwp_5@$A`ExQ=Y~5I)b)pUlY-&nMI^D=>U6|y6l~RLDT_-9k zGBV&EsMTh(dK4z2QLAUqz8o&1_D@Rkzc@A`>XHJt+NNT~7+wQ;r{#&mqNRRW8PoFlCjN>w0SjmHoQmevBR_oLfS2euqlZ_su zOzBH2l#%YE+pzGr9zmIgl)|#IvZ<5RtjnQWb`^WM(B2`i=mgxiB)iZ8v$0NF*Jlw3bI5^%%@@;dt<`8|hP zdmSAE5)+~fI-NP#Pu{a1ry+lTXeeCc6P*Q%nbdt?7yJsD{euQ+^wPwn~uUIes9j>xP`;2R=n?m(=C~Jmanq)AzyQyR5BHVzwgmeG z#KfR9HbZ9&iqSH2z{j8^-9KeIHxv*Q^lCjOYyXuVfc@NC2M27}mHtW|kv;Sfie<0D zQ|T^T)yJ_tJ-tQ5!Lwv^x6dn%*EAi@iWxg&Mx?-t5&3vFVJ=yYHlI1R2kA+Mk4kjuJh*7wDsNW%dYv0bd9xe8)rkB@X-MF!cex=_lDB*|s z5n)}X{Xxnyc@7oy?q0EBgM%q8<)kZZeoirtE{@rVmfD6Gzp&4Rh%y%a$Wo!TA?g8? z=)%^KY|*zLJ9&oe-J6yc85MQl08%IQoW$eN1asQ>?Afztm*%(kc@X&I7(e|Z($F3R z+-%g0CU5!OkQ-n1(U*H=&pvy{9rG6~c=_c!?x2ju+r)cDdS|3zU^_DgGw9(<-xbK;RdnuMA_{Oe z`Y$2V5&bvfp1*T~RV}{XNSiwNxa!G~xa!ryd|e~RG6g__8({c=tG~bKiuqH=`myZ? zH=)|;=3m=A>hNS>%#1{-_wn)3$^h1LNhq}3-4Cu%c=+klL?1s11>PscYlqtpZpI&d z@lD?lbc#YL^$hg%yBv0vWUw6tHyhg;8t8!`n^4=~Rq3rs%;7&50}Y+-y?*ESVuj16 zco|TUAx0mJlh*>2!=#_ncXv0}wYYR?g@rg!GI(w=Ebo`Rmt8tHaPY+IlRaxZE4UTE{3@ilp@U%LtY|auKHoPDm?t`qm z`}i-nAwAlACbQy-@H4Nx@=D~}g%k{ftMs6%pT1>ugjFeMOHneS2Y6u|^Px(9KtyHqCs^wS?|wNX*p+8;hGE6WM)K5?QuIH%0v-{;YqgMxz0T2Eiw z>BB%s51(%9i@vRd{1Y?obI*9s7*8qSlU;qgN`T;$cv3x?5&qO z^>hRJ86p(?@d{6|ZnG{sTeo=~JUR-zDApEq{_sO*!P)}y@};cK(UKS~EftYcX<1>q zTrd;GxoT$v`6%3^ktp2g=lr+s(bI;|h+oR3+f&PPS$0zObSb+fl&>;Zh`^0-Prfh< z&ep?hXb1_JJlW$JXdW7FIezHSq4tIb%+64GOAAboNN$}D)Rn2YyoMZ_P_!73-iNHoVe~fgy49O+%E0w>uv{d z;x$v)TNmTR?VD~|IzipHDJ5l-pdmy?=Jmp=jcRDDofXr+WJ&z|5Q|nBq?h)CSJo@@ z^_#u;>V?=*3gTg)+Mx-7{Rc^QqVT-SosE5cOoab%{r=qsx!f2WVnjVUw)#i~qOZ)A zbwwbO93;!hA$@*EkTEAp)eL*Fl8sF-B_EOR@yo5$Wx(}EW-+wR>v()WqELV2h`PXY zuU$ehe7c{b{4aUVaLbHwp4~4xQo_TMatmTuVLitRQWhEZruO!kGwbIDRnJ;5`*hG1 z4b>!@lN=5VJbYe=5(gC&kAse>bxaQ1R&Kt&S}z(ye#Y(kt_sQ_FduWRmg zdl-g`lE~$~z5OmHLI?_tZp#;+e)VHziwqtrBAR{1h>26C<)=A<%F?8D2Yv)Hx?{%= z+ke~%B)y_9#5UIwUv^s&koLdROSUjHH&=N@kq{YJFI$R2p3u|&yN@*W55v77Qc4zV z>Fnqu3cV$`$nyY*F4uZ))BWMw!#Mr3@QpX#Xb3I1lSbv9XC7E4%oI_-i>IqaG!Hpj zPQjqaDJUq+O$`gu$y7M#YoNWYH64JYuM2tI0fP1P(MOg*UpeC39s;0$-mFX?(UMZ^ z?rz%sE_gb{py51$E<8;fek%$y{pC1wZRpIe`+vUv`s?RJ(^K$9tSRR16<*IunKmv~ zJ1{UXNQz+!dZWJNHRi?`(a7?8T5@5GM7{+uq+!GlI!G%g*bNcF9fB7~Obu_Xytazd~|P=lO?*`sngx-^pBIx_^!2ZiOc+%PE{bJp+u1=NP|j29)p@{ zB0AV6vgUmN>vu^`osu{-8#e~VWP_KT9TT`rNRwliDL2_LpK!68l*^D+DbpRUwg8B5 z82hSz-SG(s3kOILwtV%k$aeB#_0p%6C%20ngHg75kDTeLKXKwjcJ}7YAt9SL!vjkV zmH;!73$u%ZW$ut4JjmPTiZcfJ8Omj)2k5M)R0hUoE2dxR_W&qwE>J?hoHv^|SmqA- zh7IT1<~CtgEEFUaeo<~xQT~|y`)eyIpt-H|nDes}+@a1j2BbnyA|q>RA|uPe!S%+DDDp=!KLt)m_w0c}{+xWm?1q;LG9Yuj8YB<^ z7^)BwLP|=uZ!akk_-Z0oG)Rz;YD&Se{>)k3%?OjNV-6mCn4XdTSLV~+LIg;@V_S|w zpVF1_`s)vSSEgu-g9hh4O+Lj>-rEY#rnOh@7nPBVdW*RkQGN!}fl`hg#NZd0kPX$D zoe08y3=%ti}vq4fH7+5c8Q4#sK3gd(rn-y!2=hy~b6#17L ziv_Z6@(A$%pQGge9wta}TefNhH@wgu25Xc<#H5E4bg0PLn#1?Y*N1qg6rEOxRcv>OqQ%dF zC5#@-5qmJ&wlv`mNFi>7ulVoWGg?yEZg6n(rQfH|i*2(_xMw{-t^nT&77H1vHP`n& zZhF{GnhHF3*>NMkf=0K;!#`_i_i|y*@If#SY(W= zw-XGoecxK*GBY!Mx(`9QA80Mtef{; z{~Kd0YQMFj_A@K`+b}k5{R(qrMh+y9lM!h)4!1x`EyG50P;wrSvb^LVQTw^wgG2BN zB~o+?sT9OBH0UlXD@-zyjzgO;bej%!5MxqdS?KB0p$={8S?!lvwz?QTfj9e!lT8W034-2`iw643rto7v4uEbc!^ z`zg$8BY&b7TO#?!=DD6;vL|-7hb&o3^AI>yQD{;Q5a4hG26&3vZ|H$&t&6y9)a9k^ zbS_u`&-Gul{*m7z@y^advYl+V!xR2@+WiQx`9zfeDM9jCk%3y7N~UzRoM~)@XHlP= zJ1IXaB|5zI1Y8d|8ivjTAAIn^7YACjF>%S`POSmja7|+TK@HP^y*D9 z19jzc-cE`+xqth4Sao+lT&w=3lRtfclSj6m#$?uakPc4nat+E&zx?80tX9sC7RT1h z23;j36Ri3Hq+sZ+StX93Kz^g92F+PRie_cejr+qtm3Z#uA#Tq`3T~@Ps$2W}`&;&Y zj8uQC?2D3;u;a&py$$GNU*MF~!_AD+JHZ!%&XBfz98quw+<5!>w#vx<>pkW18d0Z; zYfkhpqjacq&;!1InyCxL?+U<1r1nC~crU9gTz`JV*yZY$ex`&T^pMf29$$N(Qdt4*;jNW~GsD%M>@{%6?K1$w_ z@f)#ZMn8k0&tS!8h`(0|>u?=t-Ppw$N^8B;yNtFyMz`euwR?hjye@A9uM>MdGEZex zGFnkG;ynGGxHq^_UcM?HdyMBajF;`FT|pU{6N|?O`S~L{sdKx-!@-f}HS52ar=Ft# z#%#z&!o|+id`}s>xTJsjr9XNl#qpjdkEy1|WE8<-i%0Sa&BURM?F%QXq(oi$s?GBd zy$l~zu9<2!oBjQ;y^YLR(aJfCiVS;`)cO%J6lT$F!hZcHp`YU=!@aGIjg80m{B+vm z7Zwa>iGD;;PB|^=uo{JXVUH5d89|`pAIBxtOar#hmc8UXYYyK`|F$@ z_d6ed`t^=uPJ;qm-@HUQ3aEB;_Vf<8Y_?Q&=aEledF7Rj$9r^XHiwU1)pZ;vM1A-1 zXB9&!B@^>z|Neo=lue53Dg1v-zvS-wuAV;c3aE%&tEL8tjNT4QU$53=+%A^FxIF`i zs*Dx}cy3f}ttEQw*s<}}@EE|jv7tGpUSM_|+MFD1FOJmd)#gC7 zb}d+ zEdX0y%;LP@Y?sI7Fi~jFVqr!Fx3uIH6c$gJImg-8 z)!EU}UQ#kNR8Y{`3Je5rW#YDNE?HFWl;WAQ3KR6K!H}q%Ia8TYhRudSi3;afm83h5eRPMxAS-DW$vpOd4eY>&3|{$hmTo`8S&janT8BnFsaH`oZ5)UhghpopFIAF1LoTKg&R7~JDG!fMDD zWFqE*hq}UlzcMdx?%dU(%2kWno5n5}8d_jMWzf^D(=tK)va4N*PB=9hqG(2kQDo+mrV4o1(ESqs6WJjB)>dk`E&Mh5k^Pc})XoAiBU zA)M-RdjUC!r}iu$U(TEN<$xTf0<)lpQ(3KF;s*m(t6Y%DDxsxfE@!$qj*>32b0+5H zp*?KEFdy65=lKCAM5y%(kX>woBQ03^r-w*V2$6i=H4}H@pa{dU_)D_$|oRD zb`WOYFVb+CZ2TZz{pbv^Sp6D?Eo3qmhjc%MuYW**+bz*(1Eb^PVx!~Ue(mos{q6k& zZSn*h?uJk!iOEIAg9A!+y>#`}6=(YR)$JqnQoyuC`Xwu`%|AWvSatwGQq4M?t^O28 zwgB5?Kfn8J3X_c|)&fS&fY9zS3+UMB(f9DtXoeo3%dfT3_sIBrv?KS3Sb*q{+9k3U zc-#-$CE9}s#XQVEDOPBA7QbqV>9l<2wA$MI{OIWH>?yKhH_=0u*g}ww{{o9@`*lFegwEK}!94Um=^sHTj31TJu1UbL$BQ{Ssoz`|{8f>0t z#U6@lUgYN6gQ%V9adx-2wdLiZ{&(WU+`NfndY z@@7}pho6-*TQKVX&`<68^8N?5|4>!Zb>%(x0I#Jw`OZ7>J~U=Jm8q#I^epzQ{zsRB5J3tyfsd=fX@HrH!1#2yN5@O(SR{ zF$XhL(5#x;+PJvAdn=Oxqi8Vh=z-+Wwrz*X6>dV?AIJAc{QX(W!3jap)|{;ZDz+vH&P>v87oqY_5>2-B_V-dFA$1wk1u*=`(tQCwR1VrE>qAU|gY91+TLdQpD&wCvm~`uhv1&uB+} zB$q%leY$&xO_4F+rNza?$Cw7Y*REZfZ0gzk5AVl!U8a<)*W!ccD` z(CapU`?%z{6=e+U+p)vDB<)y#K1WX@^J6I1YRxRW>#nU~jWrD3Ll43e2T;$0B(XO}(u&9k%8pOh;%(C3oEW z^%iU+%o`bYHptsa>>>R7qzcavaa(g@ItC#zlJ?Bv1VZk#V09;RzLAj@A1%XRa3XBB zB){QWSV0bE`K>l6a9on*WkUDl<2n(#>lo+ltDRiOsq^wvqXQ)@MkuEcMWG*)Ele2P zv-?McY53hRO=!bpp|A3SDX_K+vpAhvy?Ak&Pj7E;+Tz8en3G0Cm`$2>TDr0$VA=X% z3KTjfgR}lORM?=`Q__2!PNR{s>UYRif+koA9fa3*n!h2<$w`XxUnk`_Z%a@eRJtf0 zd{f#GUK-8JP(lYWz_%`E1^Jq|omC}pC&ivTISDyD)NVifM*wGJNlTWD z57>Z+D|YIqohBTly%JfefVrY&!#^|XNN&&H-R}NXnoPE z5$(_@tu`h`G2D$D_wHeZUu0bOfJ_sZ4!AZwP$L`Yj*IjIs1}jX)Rf?M4@neSlb@fT zVrb7#NToV8pzu!za5=fiq;NaHOPV)N@2-JQRO8ks&sYS*W%ET(Q5t|!T(Y@|-CYbdr_j3`7& zBu!09Q%FQaM2JZ_*xC@{ua@@HgrigaQni0bL+c=@_7U|lG4+0aK1hWhcDvn5pP~}9 zHr=9hoHDFsgfWK$newj z=|3eV#snE$QEYY6k(-=^z``o1qMYzppZio<4*%7H8pv8@yT&u ziz-@!f?9oiOzL%t?vvn?{My>@koe^#`8bSKRS5|*%ND{TMG)>6W#(;SCEU%My(>k! zXvH#Y6Ut+mna5&cqAUuIIsK^(Ay8cGOTRQYB&OW)F?`QOZFW1q4*bn@KEvjOF$lYp zo>q=mtkhhapPL^Mpp)wYA~JI$YHGSOW-VJ5XEuyEMTUlm+UVnBR8I})J-q#JZvY`s z+>>E0J>``+zN)8B2nGBbI$`?N_X$VGYJd?$RwKYr9XTCQ-_OWV@AVmbC%Fom!fL(t z+HbxgPNxSMA>rUR;B;!G$4Sq+dtQ56hN1cWM<0Fk{boZ3;E?A9T_oDHMS_IEN^DlS z;JG-}>FL!~IfeLM69X_*-wdD7uIho8-|d8cHgH;rg!mnWn2-13y&O7NK_MC3H(f17Jl+1lJcWDsngj@>CZrd$sZ+mEjxc^ z80gIK&Y2bIPC9@1eq;*$m?88daA07{lx)fn&ra{|E-Q;w!cG88hp4@stmV{)OG*ys<)_31NZ57c z;=7=TzpoNn72Q#Lrm>~#+8b`UZS^W+baK)3nKLC4wQoXtNxW-e-SF_dc{h?PFlyaW zU)22a_my>X(wcf~*_E7vm_4Y~+Q3r#g^^?HJc)OyRwtkqSxSPYnv;IF)lHRC?K{gyK|^iseX z^TCSXjGD+L5Fn9maDJk{Ue=jyzgFE*g-)vH%djV23_b&BPPmUwKyp|}o*Ux9?hbxEW{ys9-06(u4LMunS z6Dd7N&(1`U0oq*Z3};UR9No6B$`pc&)K(hE{_NHTdI< zD}h7B8!yr^1iRmn3zhM30+vUcCGi#>`c!U zoE`=sMZ}y6tJM`8>=M>ck}yW1&tV=MOiVl_oiT;(s8LZ_Sqqrf>EN2m8=@l{h%2#N zA%b-d6kV7#>r*wwQ~t?(`z_59eq1tZ)`P(1wlk7nk#C9R@-!!>>X7s-C|8Jp94{fU z?*+^GD4>Fx;DeDjtl~6_7Z(&fhtwANdak!w-1p^O2s>37%Mc+n8os38^P1 zJw0R_jH}Pd5R;=VB-Lbx-nt%b7=e6v4I$3s5sSAHF*w*Kn~6=F#iQ@(#;U_T)u{F$ z*f68-IRu;n_q;vAI1*RGBjRc>$@*Z8)*g==Pk9hY5&mxMt1e6Y#DxgQE}vbPlQ$tL z+=7kEKO)h~9-Dw1g9I+a1?~?CedU*+ilU$nz`a}jQ%=*TMg(o%Eun`lM-*eABi&6qyUW3vd z95?0n_ubjw)6wNpTf*ZL6BAPsqXLv}AzNv*wE6(KKw7P&M3iWdFfU_xX=ybgvO?`F zF8~Ah#i{9^F~zQ~*hbM8KQdEIyts=EZ3XVaHkj&YX|5OS3Lbum$7*<)@e}+}c;Ey- zAPK^F=mxuIjgz(&0_y;LGLBPL7z{~C217+MN0J?k2dd~h_936jBBZK440`T6?1>Zj z`^P!u+g9tMMON$Ei&0vUpWCs*vonQfo1D%G6E1kZwk9;R=KS{<7$`)(-5)OVUfKgG zDF;TspD0n$4!5&iaD~>dqaX?7iugu=(4ttrMH;o&|MGrf)dO=|OWQoHg`t|UYU;*Q zQEoF3QU_L)XE%9~-P=p`BAaczP6RHzvXuC7qIWO0U}Pn=dGRW?hTJBOsb~#}+AgrO zbIh2geucERqoV`1Us|xAyRoir(j=H${*u5z$;I#*OzX0;e}&oj`xX@VUJ|zvF(uJ% z03zr$9HKdX7Z-V5XZK(n^wKO17@MCT9+MCs6&Z&KO?~vEN9FtW;W(@i&Ti~D2L8)0 z4Lz11x?)WlNjakiO?Ku?wL|{wv(N5RjYsqdG#$;f`OB8fntA2&<;$tFj-M#sd{h7I zvny9(1GSI%8yffbR(O{@ zCckwy+|K!TOvUnemV5{eOs_4-%IPJ&Qsfs$Upp0!%?G5JG4dB_29WX$`_LRvn7#y1 z`YJYzzi^2lH&jcLgF+IJQtLg|-0R51hNwNY$BvB~7t4MR8|Hg9R+)^5hnMs!z3)2Y zmt1P+O+!avo7{xe`WJC7j>;UR`yIj%LIokOLpbA-nWNFb1@Xk?c;Z3viBp6T5zp6( zG;3LZt(2xVb`MKt&YeNIzR`5voDE^*ap54k&_dwj60Gupp@hJIsAzxLAY3bQG9lq4 z-RT|L$!P(_X~E>wsZ))EN*d4j8mUfR?g#k;yG)ox%)EIvFFr;?9N7IK$v<-}xGhD9 z=6HRUz?GM2a=PMO+fTDLqqNX-W5A>f>Rm{KtK#*0ucG=JX7&=U(3EvUVQOIuj4J^ zm5LW%L|KD4SnytN3+Zp(Ek|ilsY(KwC#-o0mJ?-sEGFqzj2urk*+#mGaaSC6=nrfU$4m z3nCb9niRa}=T^hkt!vjVc<7;R+q_!a4x|n?Ow3HHb?II7RC0Q)moQ4TpO;n0N#p$} zbbKkxV}M6p&yn@$@zC+nv=D4hm$W>5`Fr95zF49a1r)7dZavw}|F)HD!!m5tcxrMoJ0z`u)T zS8w<#GCJmxv)qa%VwT6_ffq=1#J@@8SNx6VuK3YX3*vc6q?FrC6TQhZ+FmcNS7wiN0S$AbZctZ}F#LTPcgvhgiJ8OYdif^;Z}}qKuxFZpFl@#k+SL`gOF|()Wjwf5@Pa+Et)%bZc(g{rv`k=8jnwYF@oZ6lGi-to(H9`o$;xEr5O2P z4tVqLkcZhxB!-I+K{63Ed->&`EK{afetP+#hvv!-9+b^}=u#3=z;N*PEJhsf(Gt=D zp~XE(fLAX$yMp=H-VDsH$Nwkq8qt*j{G6Xar}d>YQVVUeojplOGUwkjvM#L9dh6{> zFUX|1Mq8*uGsc=;E7q`O-)EN8Uy=@Vi?d5gU(!f zV(Nr6WQoq4nS}Ex+Y=Jn9g@n*)vIat&HMV~gkV)-oDb6o#;3NjQot1z4@^09XxTDy zJ*XcP!~g)=+kWHSf+AqApC84kZoYX%zQK8_sOXfS3B;2$h@cl?dqzHMejzsQjL1-5Pix$macPl3Mt0D_R@EIY zAe)(`Lxto3*`%9W7&B{XX1or4uJ84w38JsUihBn;IKBSrHA>zEod^MU(5Ug5^!N7^ zLwh~K@7nqs%8D}dwbPg1^1GQikwjN>^e74}q9P3J zhjsXK+fMj4bFJ2jQck}0GjedkgoAtwRtaN#mms@zy_+8T(A>~iUq=srP=P&`8szJ1 z3LJxhP7lz9gh*+L#PQKVfoA`NsKEb-JrfwIsDwTG^X|QSe#F<)y2SAdR^?`-CKs%x z+*e%ky9#3p3Jg<)Z`EsOq@>2BFP)MKmHdChqY)A5-wFMVRmnYWozmS7|M^_b2hRrS z@v=ekq5u>`k61wh{i7E#nqe}1Iw~#j#E|sBA%`}^EFFvv8mz)uh3z9O5QCQmat>2O zI4cK5Q0AX+BigA#1jf@DMrr@q89a!>3@#->Z@|5q5(>PU1K^$t1K_-+y)@% z8TRYoSq0=hJ7URpaImPKO#g#ef&@n4-NaaEsUX|HGiM45Q^tYUloAs(h|v6CP+_6l zjS8PQco?xzFco}s3I=JAu?FX%L%$Y6i8MKw{rgM2Rb+0*>hb0wC~v=dGP`x_R%SA- z@%0Z{-kiGE-YRDZlvu+f0{o2N7LvwMjkA+gc{0AefH3L$>} z0YPw-f&yx4va@MUPy0cfF86CYF{RMfn&O-l^hmzMp&{px!pBTKK{OOrkHJu?+(o8N z%?eN;*0UYa9z{Ub)QF+*5{D@xy?D{0MTIFD<8$FZ<&NLHnJ>ZU^=$0SvA@}HzB4ZA zOUFpub+q;+F2!|mQJr75BjVxXbauN8G0D_b3^GVuP8gYh7+K@fgpc~%j;PNEi28hh zsL$<)`bc7iZ8!7%6s>uiAo+l!85u{9qGQooB^lJKhB{!$!O=y&5#`+YoH_;jePlvY z=-eUQaQp2WHrNo!#HE=TpdacD_3b|jci3AimEC~7jdF5S-+Tkxo$6)Lu9w}pj3Vim zw9A@#@1uIe`w-)!&o1}c4bf3vRETH#Q_F#65lyD?Xdw>g{ZSP35%{}NQISEWfbgg& ztG2lyrTfT^CZ(il*RCVo#E?>;jFR=aQIB+x8SL#_oHz{xf|8671AFEG&l!>4kf5l0Lm=-m`^{b=iAuR2 z=VZTCBZ<9UAeIDi;p&z?R)xdyP*kO#fuHE>t7Mg|8)rcD4h%}oxrk5lM>^e}Yp#Rs z25Vb+@~g*eG=ssjntl3*W_}b`2($GTVHDGXOha&Unj2~>Parp}O`%dKRGltXs*M^y zetdRrL2)U3`BbyP`+7QBTiTr} z|0Ha81rx?~^$a?~Qi40-@a^64-KX!p`R1DkkSQ-!9cvzBjFVQbTzUO%_t6>r7)3Ww z*W`*Q|KRAz*?EarzR?2%Y+&lx99waIineDD!q2b0_gVT_fQ(jITXW5cV^v+I1Qbc~ z+V8S^Z@9LuaX^?KqqLR_8Fl5zeh(70R<0liF(d0Yb59+L|3357p}2r|3WT1(S|T?H zqcz6IN6q>L`f5lMT!Lngc4$b_g;!0CA;foBVGfB&&&tY5iwdzO;%iDU;HFd*b?h9M z4?lKdl)tJI+!P2yTv=XoOdcr2fJ9TOKb8lX=X3g(s$SP0h?5Qtwb$NUgpr`!+vj8Moto-f zg)AMEJFvQrzfFstMaM$tL`Q`BN?Bb*`j~JNJ9MeBV!RAL7S^_)^F=#Z#Ng}z;ov2# z!yW6-w>3v>RvGU{Xh!ad5@dO{(!oU{7nCJ>PSk=CBNkLYT|8oec*&?}g}?Alpv8J~ zyH!&Q>&Tc=eyrJ^ice`aHcn8!p}IGl1lC3b96U zzEv#(9nOL{PgZ7(FGV^On|CyO&VbHjSGm* zyBk?(LC6u6B4Qgf1_~@Y9Jav7D^5MIzZ#}hcl)U(w?lUL@Xt`zg1Mw!7~1~PGtWGO z`uX8!zA6HtV==v$`1nH4b)M@qe|Y%GzyI?eFCP14FKOVEPN!R8v0C#{^O)LD8we+x znta~(68b%-)>NOthSt^7)Otxw>Ia%&WM|hAnK-XSuR}za!!^Cwpb84|#wI7F;i#ZE zv)Wk=a#5EqY$E7M5y*$J;_OAR7AGbm8IRUP8gNaVm~2+{103jJm0=Sd(vW)CAv`(Z zNz)xGuDKCR#YJNRyEnc5`s-DpQ)tGY7X)O>5K*&scS}HLyn6v+$XQ9|!S?QZ@4YI? zrxjaFrOa4xFTbnI5XR|RVVt7X8qL)SzEY|5>Z`AsJ#A_kHonOj@fL#Z%9xaQC1g7Z z%(+NPnfq7mWl==Afb3|*u-R^e@md@tQ zeBurTreO4_R?Hd)O*n4W3RIbU#tYNGOrBBQwIbUI48obcq6GW+Zh{m>T)PQQFyz+kHqD~U0BIW6h_y@vT1%Nw3HL(&REusqEHPr#}E8cQ3>VIBR89q$HHWe zGa1b^ky9=0qV>@ab@6#t>HhFY^jKR11D$o1l{FQ64pw%ovu^zS^Q}Af*Y~@Jh6mkl zXJKKgZlLyia6rGW9nhr~I{frQHGl-@Ha(=J~EjOPL5{H!s|$ z@h#Ae-fHy8#qYe8CnalgU;Yb!3FJ9`tnhYTE8;;x!YN;VIbp(Y(4^L`$jGjLTbmY9Z3&ZZ-T#GJ)iz9< z*6<&xR=&sLz9&izc~ewqp%+S3+&9@#_TlI!gwQ7xicc6VcN2^)$UT9U5WLhH8GVoF zRf*_KfU~dFtKthH6}>0_4}0$c-d1_GkH1HIZ&~sl@``sH$9A^uI3}AALc%75QA$`X zl+l*f$}xljU(0Mu%h!h0GD{dC1Oj0MvX_%Mj`!Y6mTg(GCH?RB=$tH*miFs+{r=bW z)h9|6>*zi2eD-rckef3yPMzv(>4Z3A@cRQY1kyzT%yapi1Ur;0@#OI~KloSmVeDW& zqh5bS7^4OB31iOI>lOBLQ+T{{&AkZn?^yt-KEQe z(OigvoVq(8S2?Lzb+P>ixy(reUN1IFqR^>T(2&>AJyUuA7`HJ>=cRGHKh>%lYXa{d z)FsTp6gjX4Jnt{frM%w)uvYN?X-0()yx%2K#GKFj|I2vq4IJ;k8oYlOcz;v$l7*mG z|0?glMOaPn{_Fl-ydR*RMdW~FT|7zxEk*p&L8OrU4ZQzF*s5T8#PytFn6F z|3GRv>mR(2@B44~6(|&oq*AHRHHbojCF=CK^XC<0rz9j;q}p*X){>I4qU@~cK$A(c zX~roajLVQX57wk4lH$w{Ub+%Mhgp)&erjbu)m!;(Wv36Q5&SqWy0cUYxk9DzbT&2C z*THqpjNGyig3NEA)IX|v@YXfUaW~yP4*ZCye<+of@$<5hpO<)Q zpYr+U&zBA$O2Z{Xxf2`Hg?vchfXBlTZG#E6JVviiOgwdp6c)y6d{C{!Qwx1QRg_-u za5y4iGGhe?G{EpUhjh56?vH=`V{O>RjT>i?eTX*LxN+`Ul-Zn3!(c(ymM(qkE%M-l zr7=D{G-1huZnq*WCI(J|*-3H%b48$tf_EX&O1LnWm5U4VX`*>%RM7 zQ{xf}RCko5OOI{awrx23nuRckbCWH)fkECFY@+3GkRZ8UlH!bd@Jd8i6lR9`Iq5&c zJowQ^A2rL3#ShjlU0NH`0H*RoeaM%UOdahPqk7iRJ=4$LGnKL`DCLCOd$BguA-)@P zmhTF)d4;gi)#UE+yL`ij4VUJ`n1*T^x4nCHF=)~6O%E1Fdp<>o!p>21!phY> zLkxOjI_q%uY186%cc_yQ+Rj<4G}pvS`p!C=FQO0gBjcdQFE;wA+;!?oe4l%!N{v(7 z`Jdf$)(<$1LUEKc*TLkmL)aU+{8``GPuqZai%Mdf%9DwxR#9mzh1Sj}S?Y58;fVP{u7}v*`Z& zf5}_MRd<$V$}3?#7@2e4M%a(P7PJoRcK?1+))QgKodT(4fcubxSyALakTeT|g*fE%WfGf_l z9V-SW`-AlK+lCD&KEaY=E-GJC{N|gX)~?`N`x)Qbv|#YR_tJWD!zd2f2-r9Dk$E!%12f{EDKEYvBk-zlPvIrC~rx^dpI9ErMU3#h0uw<@XI(qs`Ky`n4 zdQ@tkv!sFvpv3eIy8i}YI@!=OG$vA`P|-qwiHTcUUVO1Mcw2BbcU>WQbl;HeYD&>L zCz0eKke?=Jc?m}{p4KeONQnlFveq1(oW7J=7C=dmOZYpdaTH48zEln-Mvar-?aG&U$lH=wQE*Zryst6_EMNjs1vn!48W-w%6X?afyOF z^Nf>u<{7>(tNFfMCG3Nd-o-_Y^7PBCX5k)b{~W<{|9tL%_DxwHD_NHKG+U!K}*XV4ey|MA_U8AE{URgw* zP)0378p6$Ma}b92k6`Q-6vjR|?hJ~3EWZND{K?RdjUCLsKF0w}n$Aubtzk+(X>-bK zNlA!RPkL0`-TfH$_hH$cmtD4N7tPs5ykI$ukj(4ZPFeQy<-kr^9zvEB=0J!^iIXb) z16H^$S|GvJPK0^Jl9R2=R!63%q(X#DGy|g!R!n{lk~E$g+(t3ing-$jwHb{X)K4+1 z4gU7j!UWOhK;3(DG`F{V-MZ<;L`sJsTqEoES_~jt>}@ylKtKH8Ax8wy%z(IQwA)fAnmXOLhw20W!WXSap0041O3!n!c*egv&4YdehTaQn6lIkM;QaYbW`# zLcHg>J&4()8HO&`20Y~ba+=&lKIVW1MY~v*R!!i~!~J}_kMr%$(#R*M0wU2^XvSoe zQPU0ALANFg6P=}z`tX@grZL6fvskmH7q*994G!z7Ohj51KthpgOaN!GhZ!~UAf`3d zKy?hCA+@x#vwLvF$Iv708yW2GjEj>Fo(87Y=>bU`Ym73CV!l1*sH7r9X&0wP9ir7J zafuE^-Ch!!c+>4smT}zW)<&h3;;scrQAc>!vZyi&!2nzwk?1xgRThB4sx7e@P;4_| zE$T`4FMqi-dKihK!_iBBdFasbrruF8mP9<-+jRWU{Q2tUkDN~DM@_2v{A>&RPOvCu zo5B)s6yo%fiJlI*QYz}j5jc9%-QMCR%mj@7L9H#d7}JnrVcL=AIok|2i^$odwBH7NJ2Rg@1aC9U9AN1Hx){&UG3}r8tCn`q|e`Bz! zC5Ik={PCy%`@kn(HM=}67>;~lc~E738yc$W?o82FP{=+H(w(N&hDC)L2o^}BECqSz z3xG??Tpio~R1~~T_1Jc(f+(grEJ68)hl3BR|8RK7apR3Q7HbBoUnvSc%#S^h-x1fZ z=Ok65ftHq}NUfnXUhn~f7_%3tJ+gD>kytEOQLMq>qd335eAB>z4-O2N@>dXIGRcS0 z;bFNcCYNe>F{Y+xc_2*jvrVQ&)H@JjQBUEdBvKZIV!kq3%vUX=WpFtWRkAUK)PO~C z;G>e~5%d8TC0MEcCp=1^eF!jZuLTz5u_0AtcHxj)VTwux9ZpM1zIjPFPRA<8sBt%@f%oAqhpPzZZ{U6r=TVIT79+*y($9Cr`e-t+#jOO31=WQ}Gg1 zF@@*yKRoJR;Zaj1z!)k4E)pcb|1HWr^|^NX+_sEfPmn)kUC8GisDhVey zY~A{ZW}_-8sk++z%rgV^^&43-pGy=9r3*3hcW_m2;KMivuUfF7M30U(ocI=jS_gZj z#`tMnU1FWm1g#}LA%4x8urRhfazVJ(Kh$2k8?x$0JBK`=1Mne3Mg5J0Ak=@coGxmi*+^>?u*s3|4?3a z%9;=A6C-_}lt6REW%^cq@Zf*H-`BTn*-yjgFJ8B9-LfQB;&!*tka_lEWtT1{uL|}7 zZD;4f>C59yrrO%3ro23sN~;Q9TAi4Hl(OfsTZ_nRie=NLz4g}i?GHS_Qb|?8OR8gI zAzHYIAN`g5>clRAEfWoDFE{91RPx zy}PdJfrT(^h3Ze;TWBBov7*yNSGilxJ$mtXS zydWke(PpwlV3UO@yq$-k1s>`4>(c-Plwn|z+3Fb`bB_fnznOghLrATA`&BAO=50$; zXay|;9Y|^E47(kb-ORj}_uez6tt?3Do$P_I`R+Uq;A=@zY`AaXo^!bn>0jdv7KHNDA=VwDWy{hA% z9<(o6GB{{3%wW%zTFHME1=lja%I9k0N@{8n6Mw>9L}nHI0gv%}qC7u13JiJo1d(U~ z+ocwfYJ_i8lN9(7Q;2^ApN;s5ScA_rVp0R+ZY@cMH7S{e#2S$4ESON6&5T4p%xJQ4 z5)$jAF}bv>tFv#|huS?dv2VDqvnwu6G*AnPwYFabiItgXM?gbYfRThlQH+u^ZF4DPavnYT-V>*ytVms!K7P?2>kAJ3g-VR97J>znFF8pfK!^EyCP?8fv>45 zmCGQp7Fxze8;<{e+i8fby@PHq6^Br3G@XM6lKePN(Xge2ilM=WnLpIB^jzpH^c2Cm zqM*)^7ef-P^xl--?j5fd1%IS^@?*$pCmTWnEE0D#e>ys(FS+4{8%p#;^{*ENf64DT zL4H~n;%uZm#z!MA1|g(U2ydf|^c=t`InYC_)Brxy%EIC@fgJ+QCX#s4MeZ;BhyGE!PVe7;TAz}ipK|o^Vp_0I{P@vq0F2Qf>-)2n z?ol6PTD8nKN&~^~NICsnF+EG-=T4_!(SFCBktrN5OTu$FuiKr)iX0&h=ioTptx|!* zwY1#&_c)wT4M^Y{QGRR@$C&BUSt{s8PFz&b ztq}y>5OpZwse{l*p0@#S??1fl|Bt*)#IKi#r@R1L=j{mp8+88SPy64acjo{1^e*|I zrFR#fr~f;j2r};nrJ6qg$?ARlkvYB>!N5}phJ4U*@%UDq%O2;Or4 zem#GBONt1Aw~`3CFEN4O=%7@kKn+WT)ryCQ8@hcyizQWVw19z{<*aFPa(px)8O0hR zlwRb;s1Ro0RMz_8CQ>UE$o(siW(J#7VW!DSgg?~E8yi160A7}LsUal`c^6qW)-*mo z*nP}ZFE8e*qg)#}d9fq{esmg&?v z6}qsnPSP3X_g83ZYu_)~I6Wd_@7|i46)RZgV3bo4m63tSnhc+hA8ipo+9JNq=rK=! zr(Z)4t#DkU??Mh^~mRx?^r z@0Wl0!yonqPgNsLX5~6{ShNFH(r6j08z1j$EnZ58YH`Ey=hVFN%4rW^y^jL#wIsVl&3a;WY|i=P-fSUV~5egjPE(f6ZJ75aAZoB_3bC zJV`ZxWgJk2&0Kzg>>tk0v#RlE15)Hhaayn^r8pkY(w(HXLbdIg4;)ur)!AvYEyo8{ zTej3}-|i$I@arYWb2qQ&ERykYoa6;5EOfxBAVx*9P`)%|G!YXQ0A!7pDK<2Qy+(>d%7G zy%Cnl@g;~_Nn6sYTtbG%}?7DIoPl{bmfDh zYpwxSW`^5+YX952kuuTQhqCsRKI(L$@xnsmSkD0{Ts33HLVo2%{0W;XC;aCV3;Dk@ z2LiH;5E~=y>Pk&TQ0->vzJ1qTOOl+MLnlDa?-w~wDV!n$4ZU@Wl5o$X|GDS;%uftI zhiUvAY9nO`&yYoC0r@)%E(k!-*t5&v?k%9^6Ae56(5tUn#ns*7EXtb8n=M znGllsQ=%Jlz5IzzN`f@hv56`~vPJZayL0)gpx;?w*SpOxOYwkUFpu!^6__U^4I%QH+sQk*a( zLDx-!GaPZGniRj^mNpNj(s^k%Kk}_#M|+9~5=T(Ca3m3y9WLEdv<877gqo+l-kfy+ zO#Ogf;$N)G;iJ;0JT0%RrZ@DQ&@<`NAa8V;OrEx5K>j?|<}tAZCdw`1*N>ffj$%#d z!Src|ozlZeNdtQj4$c+o75{n90FToPvm7Vo{g|JJw2qF}`qRfDk@RUJb7r~66xOH| znDufC=awv56vjZ*VZzc85R?u-SZYeF-D*;fcbz~tKH1er4d7DZh1Eo+i#mTcG$&6U z-1+v4&p!L?QS+QTX{o-(2I=(qR|3uEM-MGT>cr#JASurkL0%B$ZYZIiFY=;j144Qf ztBP`xBb7ZzUMmfm9BDL%nTzJoh(;$Fxi)&%cT8r8LI~r#Ll~cEVgO@kZ>l+2Sveh` zGV@De?nzhqyBZSXbxa?&Wgi1sAUlkX4<;ZnBqf=|Kit(d;2!n()%Faem0nV8QTReL zA6f-gFZR@;>tBER{+qA8cEb&~Jy;6Rh~FdD0hjgWc<-L~u2`ETszkVCr6?DJ&c(ni zBO~C~MwADdXgz$mwsUY??wE6ZDXk2E>sdtY&5a!?rc0)v3&yQrQ4lVSa_X%R&UWer zXPchA9D25EYDTq*FjyyQM{97l>50?MyHhyZcjClI-g~b*0>Nvr)gu0FX+-yXeA~hv z%;VcO#+wm=*yA4W*EXNug>(4lg`*DQ9GE_H2_rFjhK4*w zDMNB$2PL^qQ&Z=#_rN!MPoLiV%>nOlXOrGybc&1?J-ZMM(`4Motjm9J&%HsBD!I3= zt~XgN3f_Cq50;aAou47VNpJZ751DRNAU3DK5#z8CSrs0Rkp z)5pdV5(Wk{(#OXgi2$o)#r089^{luJF*mHS>eNjedU{r_JXL-3P5u2ScQG3`Y@a=Q zJ1hQn$&zpR*%UaQj&E1$@syR3dCtu!M8U;ml+!%eP(26XUOvW(NXu|Dy%)zDx8v{7 z%@^T+lp2n+POL2v>T6#}4V_p!dJkO`+;rYv60&!-+6gFd6WSO=%*PO^Q(af*mPa6R zB0}!2W3|zvhz%Z%E=3Y$DUwvwAAQuJn~74fGj$yw{jZN%*!OY#Y-+6%$iWh867Zpt zkeIFR?gm;PY|+uWKsTyDYk)wa$zF|$8LP1oUvR3A9`!~q0EFm*Xzx+Jw{iT+PvhIv zceNt7vbAgeY$X29o)3!a6rXDy3z|D9-c57CJY@CGBXLfrM1v5#5vMp9Bus_k=i9$RVC7fa ze@=-AXB$Uu2PwmCb`u%sa!LZI%LGFjO0q5n^#^g8FL(oT2vc&lPEt|}+f$!YqFdDh&?Q7gOq3 zVZ1FBG_$L-r?0Q4lfFy6Z84X)@GkJxKjN=HiGNsB^uxt4atput5J{^@Z@`9q98a2m z_h%nt(mFCUOQ(9a<5R^(0_-S(N+KJ(9(zfi6r{l%2 z>l^c9D(nd^SM5o-WKQ(QEnOPdPv4!ab-5BYtROG**DGWTmkCL;Gx*;z8?c=)uu?v% z<|)+b`?xl!QjLu=NsCM2_q`{?t~P1Ee0t#$j2ol>__Mp`^BSz0UpG@|WQeAOwknb| z&Yd-PW;wIt5-0g^A!dW(MEtZI4g&JKP*pYIdxrDB=biMf#rH1R;S{;XU9{8&zD0f) z1mY9r7E?X{Tukbj8a`7$kE4+TQ$8262c4MT3eXS~e>725yl#Um5W z|6IY(7BBaO0^>bei72;&i27nwqMHwq(0Q0T5(#~hN_dh$59NGMHj9T+Q-|2i;^tMW zn)x&JeeRL*J>o~qxqc=kOjH{)reX^Aa7MCS_t2@@w-x9AD{I*KI3G-DK3 zU=)88Mj@a9oRPYQdh@bEx)bSQrFBOhxEBQX7^F*fxM}|Am!p{3X z_XrfmiE(k~@`q>7rO?jbyGM|8&S>w^3Lx$&qI1DZav^F$dp}3tl$V%b&NG$3o&Gkx zm>**{Dkuorg=%JKl?569tX5lBnr9e?Ry%G;hE|)5xzeYo)zIU@lJXEala~}mwc2+u z$IxmAq16s1BB~*z)m{lbQ?bfsgCdr>0!jwOV*a!E&J~##)oM%YdPC0%J(I3Xn^OZg zzR`{=qj=ajq3LgX z4o;#Bsa`Afi-2}(KYu3dd-s0&`t!(>-m6Ss|3G7dBr$U_;tp=T`=Me|PRixUF8I}5 z$yf6ry`rmOB8XizCpl6(d}7|9;#x?pchT%4Za%>RrX`m3E7oyn7v0l7|za%AqdwgHci7~-en?$QN% z)nsUfL$l3l<-u0W&NrXF|JGYK-E2yZc669rupZjp+DeAcl*`_9l?@3~f^ zr3>d$!;~RFtwxz8D2rQ?IW1N_5nz=AQ>;d>a#o|;Kyjs$uo`7wOXcOyxa%?LwO15H zOu*?xr61w6srfk+if;rc!Ayz|bU`sSWVjT)ry$*GK`s(s8v9!6%z%T{aa_Qy+tYw0C>eEY8B z<8~WQzl0~w;zwzk&_^plF;p?RNMc%ERy3VH@x7k+-{0Rjf_**GSXa4g>wB!y6+Pbo z&yT6-&P5csAJ<=DfY>bBh(|6AUKgwk-VnS&`P66JQhxRkN=^R^xE|M?KeuPOMOp~+ z^ajwMGnl8s3Y>e_DoV4@yUWC%TV5vScuHD{3nzLXz{5O3;m zyHisQa_{gk4zaf`63YxCmuQujb!z60E>JPt6pfVPy%RXTX+$l(4xU?~8$ z45yU>$`-{L{4B~QUVCk#eh9{fA${VihaaeF)i_p^f`*2G9-dULaA;bq9(Z^aM3r(o zGF`pifKqRbg)z{3>Z$({YL%68cCX(;b^f*Jk|e=CFX+y<^DB_v+Zz?t)@HSSuT|Lm zeO4jz=+UC0UAwZg|CyE8{4cMB5aV1JmS+wzQig~< zFSpZRjqctJD8Jp^By0{WA9KRk8MP-=#<7f~!Lh-lj9R1Wgj%hVOT?nUB=+58KqQvP zRcaKOM}dv~(AoF*i^Jz$#&W)2=G-5!1?q5?;BQ-M*I@JwG`D0*x)H( z3FUJ%;RpQAdzfFr8DnD^88T+1Pp;R=N9&MycVX4uUm~I62TU;Sxc^A$r z%*#S_X@U_sSZt=xH{3sa0SwoLG5TO{b3=1`SGODKIWncg7^)d-JvLiWdHymwwquzL6BU+p`3tSyMcXEKxqe**Ie7Z|U7;`4@J z%G`xTv!>_7h=nY_oA{C6%a1%q797KQL+mr)V*UOgP#RKG_5LPAe>VAr!*}8Y2ao6R zXep>T#I*o}LX|jt5jMGJ)ISmzH?nkTLHHSnS)4?&S6;SBJQx`{$VR(dJ+ONAxLm^x zFuyeedgjI(Qv#nMuKTk<$|~vu+s0i_X;*F8^8EA9-*l79EJ_D$^Z$ z@36NMh&~}OoeN6}mNQR6F?ni}xUQg}j;Ewo@ngM*AFC7DRn8=_Si($tQK7;Muf5rk z+~pFf!e=f;?8VZV;VO}=D>{OA&tQoq+^5RY|t z);IdYA{@zDU07tw^cjT(#q;Ca`{Tk%nlt(=i0;uYD8Mqs*Plb-*i$)r7zn#NoMZ=U zi#9Xkxfy!biDNrB?m*GA|oXUmGV59*aKY zWVVv>5>V`0$quG(LowM+E)o0xJnIi=>c(>J9IxZ&;4Xd+($D3E-hjv$m)JEBL={zm z7y7z8qb%Ytzl@3^0VkVu?%Mi>K6;<$hlX^@4=*Y9`g{tl)*Ir9!SVhOPn?h>ExUa0 zDZe52T%M={Pjv6!vmitI$Ro%Yp16Q7x*HcEA9ej%z6b#XAVZJvNBtS{h-`SoZHR~% z4)I0+CUac=SNzBd6wCm)S=Hf(tF@>O3vvOK{ynW%}ee^{buWPVr52)3yZ%ukEAb|3R z0~PWJbraOZH-5K>_(?11CkJh9xPP8WqKqnw)P4HtiWT%#5*P>?f>&4(o%+&gnDU4B zcZ_*tGl49<@ux&gvF*I(96Rz{$E5a{dH3?bnCAO$+I?cUDle~!zKF=(((w5c3qyn} z_%qe75^4ES#lW$)3Er~f;OAqSaF)3QUU+=gtcgT^<9pbdk$Al)T14)1irXS1+kWFL zW-@T~^(`S^;F^yh@#mNsWIi*4c@6?%5uX_i)PXm&e1s)!ZBwMm#85nV_N!k*E@!3dh(UMEQR^=6Fm6{=d6rOr44> zbRJh)`(lmPemP)(ckGxkgY@B>)2(t$irfMm?->oHNFL&HK7v1I8fH8eS~HGRf6Wr1r=E5VLheh-6sA-?v)WJ4{lNGb$;` z?T$&zgnKVDF(w7OC&fMvW9GO$&FlYyl0a~(| zbuw$#IJIlmw6v71z7;TEx2`UO(SzGUimPY#!sXpN^Xek@6s1*@N_hs z{1zq>JDG&pB&q?y3D?n!d=Xkd0Vibz-`6mY$B~XW(R4=!cwk2SBm&_k<1^Me#V8M( z;$*`_lVb?dO(Hf#Cqz$F)4m-G29F`Lt8dkfaR1%7>gE#AW?YJ!myILPZG73yMPxTJ z0ckx4a+Q-+NXPr&OI%KJcwiOL+|hUVZb`oQv)}(`o->s2^SF%fTWn*aq!(1E*=IJ( zWJycsB4X8UP<{4UY#jXskvWy!$l;2fKvj+tPUG?8LmmCz;ok0UB9)R840D1NfB2#M zV?L)@_pv)8L#thL?^PH{VWPbl*=RqIFJ3}_3ArZv#J%_4Tcoaf<<-|1=G9jlPoC;( zJays(QLD*c#Nxk%X0MR%;bOjrhVLK|v9UafuumZm*k_~-$^xso7;Pvk<7vZp5(P1c z0tpcf@t#?;_VDutU^|Xm@V+Y;rl`+LB$CyR#LpUuSBs7Yjyjo2B73R2NKic~Q-{V~VnM?V3)Q|bE zD>Dby%~g9Yzj`Dh|5_)5BPqsot#WQ+GBcfcv8tC}CT9pN)8i{9HRLrW2NQCD{F;d# zDkh(k!%TY-H54Al{`;7G9QwPw2=6vAhzG}uEvCl&a`_qJ8anG)e2)bDYHMfb{uq2bGlWrhZLjSlG&y z^hIvQ_au)x8H>fKdQ?K_obOZjJC%!?=Nx;6Z4Ma%VeXlSVr$y2-or!sPVrS!Bt-dQ^`)! z#OUconl$oO(B)QnI-*h2LEpZDi7w-^2Y7ZMe&DhUQVbbpz39pJPHhsMdhf}i;Cg;N zg%Ow{+w@f?$^M_DmPs@ z@cO`&rq}uY&*%F$UzlM~MTgc84bZRUf*#I&k5(h=6BFxq@2=?&0`)%FU$eWfPh?33 zvM>Pe``BoZ##J$11TJ}FO76SwzLIm_03o-Z2i81E&PlLo{cl{CT+t7)96U(3%yo1#lQz_N`yPkMG5lnWah~-1<~A? z>CC=bn0b8fwJYDhSPNWdbUNA}`SF_M%=VtJNLI;pA~u%xL;mXfE3e&qJX45p7DkoI zuMM8B)6qWAmS`*5HOsBqHCJey%q5qw+P=QnSUMuwB3dJnw1Cr#Oa}MwR_N_;-;>|* zy^H48Jw<4n>z!6B%$Q26xnhmhx_k{myoQ$RWOTGJVN9f*GP!q{NMLQgNZu*uTIMBI zfhO~N@+?jEIJjLeyM!#6c3l{e^{wJ|KFv@pfxYPp@)?uOujj3N?*v=lbd5$XQ35t2 z)jcfI>C9n9MbJH*l4`%$?=d^sLqmP-@ILj8j+!uKDHMS;H8z$Rs;jG}fKk=W%>fv# z%``dMqE`3UvC|`?BO{Y$lwEU8Yl}2KHX+`o9BXO5>YDtE{T{QN-PBaI2T8P5-Q8hu z@?O3Hv3Qpk6`7j0Z-3`c!0dSEi!b`);^NX~EnK)T4O;bfe*T3BwS0d5ffe@MBg9B- zot>?9@Wr+E^(hhPACp8uh{D3gJK6BR(=*$lLtlT0DEqIgs>Bd;iY|p}Qk0n)JjC}v zh*;%iJfN9@af%(MJQ3pNh9n|hwY6`q_=|1JLtJ9Yd1&j+o;l);OM(Gc?iY(uy<*VM zD!)9k@uBvirB}e4DEG-^K3_wFkAGeUzoupDIa{06g472XybyW8S-m*EEtXisE_<48 z*r&5O(j7M4T9w<9il=~Y)P&5j%ExGqQE61SY+ahv(xZRXcw zfkYhic{~#`eMAOgwlX60vI&pJ7ZgiW7JzbDR0_re`;muHD77Yw)gYT3YDAn*H$ChGf}1LNu{hx0Ix~=twkR2IyKpuxkdqL}AANBctP!Qt)|< zhKw}h{?oOMt?ixc0^~=z`+7&Uj(N8tEbP{K4((`fAChELwk*V_W!cP6g1IG2R^szHwqV!Sxc~j_pY7gvkYB;M{2U3IVw730kXQ{6a%qruY+`zL zbZlzY9Pr<=bTY#kan|N?yqDSr)!%-Jld}ILtx0OhN;IoyOw$em$>^kI>6%;aT(tE1 zjWk?~a}$zRL^qQMrx;pZJxQ&7w#OC%QsO7{l05xaTA(zvM+IJdR+<+ z+!GVAvCFT?%38NHJ|3{E<>CeL4PQFtTelvMYsv(=ytgILjZAY0O0%ZGJ z@`f0t=TSlq*d5Fw0N(u~BtnW`Dc-gIT&xZo|3o2PQGGIbc0KHRbIcOzOp!J;Bqc%E zWBvpq(Iet_2WgP!W^uX_N0Jq90|PDw!1JzL^bHNR_Vo8MVaU`nh@}ISyLazCJ}8PSLL{$^olbo(A{h{^ z)%Ki{oFtvmTMP8Gqld$z==}sZgn&fI(u-UtP&=$cWSLRQY9aK=1_3PrNDB2;F_P9dH*em2NRqnYEFv08J8=5N zuR}B|C7B~QRMqCw^zjCCGxQ7kTkb!MDB0_sJ$qurH8LUB8FliJy1Eg4vOXgzAt|G9 zLCJ!`L~UZxx^+b}*aSZUG=Y0Xg8npfe^r$w?VMlqRaNzy(+FW)h`*~K6-i=mH?2zS z6>FkVfGAocuKnBJ{#Gl_povpIzU@lb?ykJ;$3LU)o)9qClk%VacqvrJr9Uo(zb}+< z@yBxV6DM1M)GxTMVD*yArDS5+TBzpDV`z*9?1S?%rXkKO&e$RQ~h;(SW z_?asFelt~!z}eZwE7q)Avtm}ltSj!g-Z@isk-75+gOtT^)BA6n%}dVCCV3gE z#A7sMcPU~8evkjY1MAQOiI&P5L@~Fr%1=HKm6eG;`e^xbR{7GjWz$}IA3nuz zczQael|vr8W4x>ClvK(pJ;~u?d)lN@!0{@d?90D&VE;=mYcz>O6_}gz;<)!kkzLHVYT3nFnW5~eSJ>00O-!&#Wlg7QR@B5q zb~bzN^OdIe4_baQYjkwIpgB&N-TsFDyv)4V*zj;x*&-!LhE8>*#iw(6NQM z7*;fk?5U_gdFC%!1PlQ{EckFm1tbx?`31kzto%v|nbyj{a6lEP3M7+Br>vJ)NeTJ9 zLOIbmX`g&)Vl7PI;**3LQ#PZG2YGoy#<#&+OGJ!R#8js;na7z|uVt=%wfwsx%UKe1 zKFY#v^=N3X3UMu3e#dNLa*kGP62-@FXE!l-JyWrXDJ?Au{*dqWl)FVSF`whc12fOu zxQTg2sEjJiix4xjNt8p5vYSMWOB(U_UE~>d6WIxcmFx`B*{Q9=)qvJ#9zg3m>7AiI zg?j!8Kl*CE=L;l3E_!9e6Obr06#g36Y(Tu+x&7mhLE8hPL$oegWAB7S6O{(-H7!ab zkx3NcHm%Dw3e)sxgv&M14vC;+i0MBFcjm!<#*zmuG!OZ|&IO1)2r?uPq=hVyq^(v# zN%Nc2CEl!off=(PoXv<*PPCtdDtx@jP1Mopc*OMFiAf(V3+)*hw!?Jo^?Q&KUQ&{w z^0a*kl!Y%^JnF0x7Ijhj+hNIV>zh=WqvN4o%WJ>>!=ey6G$gf~gE!{@KOitzyAxmf zw92E3F1i|ax2ua{R0geWR$<)HW|&$%uBM~=-Tak0=L`aXMz)c34}j=tYvC#& z4P1BqsK@Q|x%>M2I~6Eu+uqwhI11A#1S#<~Vf|lINOdmiE%*!Z*ZpDFAh?y^GsxHE zq`nvVb(%xbT_H?L6^s`+taAG_*t_Nw=I6;=uEE~k-Z8a3aVEk&3$xP;F9DmFpBiaW zO2x~T7RI53^(^3jN#(`}6p|zEZVISZ+c)f2=;j2wTHCsMTmhue2i(2wHK!Z%*hS6DSWIU(@x^Md(Xh|$jFFmI4+}DTU@+gPQi?9fMO(?5oNI;n3fg^RBCMG_Rj8pAHo745bypP z0FB4{CsgJzi$SGSp)Tjd*ht}QWL9OE<%o0W9~^d%`9-KGrS?k9QL(X6;Xo_#v*DKp zn&Bhb_W8a_fDtwgSPJq=ufH{KT3Y566e^uwPm+q*hwi#{{rdGA;v?1LLkXEVu|u#t z@A&HAsV3-EZJwpKmLdj~UQdzD%7^dUh%C5k=8=`o4FB47`37&zzOTO8d-zz*2Sv*+Aij2`H9f_ITA=1wWpk|6+!=l9|-NZLT?k?&6Sm>n))Rcop;PN8)3GoM;(R$6>MJ)I&WTEm+N#jviu=|Mu0&9@9#M4X-ryNGf0bt=!;* z)9u;#MT=&qXvuI5tsVSr4RAt}XDC;53QqsgdB{D>f7DdQI3R} zFxA=dkBzx$)NEvA(|!^Y%{9vDKxivuyb{{Q4vc7d;`b)$@g3X*48_sGf7UrX+*vbg z_VJ?N{mk**keXjf)XK>F z=TKZdWT!B7bx!G`MYr9CG}2AX(xvb#tq!hcdV9Hloy?Xk^i>h+Nh;ryg3z3rO~}B- z;4z(;NX#r|Q)CKy2fRUzLDJXO)+aYbM4043Q%47oQi!WVF)`3u(>myr8wg;c@fGf( zYeC73VWhRXRS}*TKDcMkpmyd=?WAFUD1N3Fw3FhV{NmWu^}QMKV3uo^Hb&S z!4`nOG`F(TM!Y>ozBu{y-fcTu0}%*EGb>_Hz#`E)-fGf&ueMji($g`n&z}V(jTEo9 z>%gZ~(YAM5Q1@c6dGEF_+Qm6=E#GsMJ?Q=AYJGddm+!sz-WP&)spm&v360>apP+~I zlxCM^OR53PQSB5R4jx_zC&L|hZIryToGgDQWO);0dmgn(tqO4+x-G=OGkL)oh8 z)LK%TN?U`7$~7cGo590HaE{!uQT4agz)M*Dw-sbXXl5_4iHSud-VDUZj!mMLmff2| z_XyVe^`TuI8A0g+-OBi(dzv0^Zi8ZvMl@!$ejatiJ};P{mIQ+mLs)z~a1WT+!dN4X z&9H1H`qLh-KPZw&f__hO-^r7PWO8AXbk}n&qeZdk!&^Q>SedBkHw6Ha)dyBaC<1}x z87o(o&Is(^zoG=(e-lFOguo6{?AHDvPe3mBd4~FzMAW=h6Tw@(FBmHVEJf5JDi!R1 zckyfF42_fIi$vH1IynX>*O|lPpex6Pn_NQ@HVDC8YcFyQyX({2c0v?u!lhGdy6Fz%F%Rw0_`)C4P*S&cH*kr0~H zbH|S9r8I-18}whXUa}@mCy`{#TC-;9EXmQMmlwkh^O$($in1~udzSfl2{nm58T=4o zXOD<(x^23B>V#;ulY^xD4Gz7Td27@uo`8(No#1=;IS{aR^P|iRvY@3J8KSZMx~Ozc z7@TVu9fQ0)p^MBY0oFin*6c+HIGdgjZZsIztu9JMEvr0W^s7--BGM$A7;c5Lpl#Hz zF&6}edQjqB0qLI^9cXRoa!U->G)&&S!s$_V$bk9fM*4U1qTrx!#( z^0+dov%9XYZZvM*&9wLuy&hxky}guFAjpYB#FpN*qA(>XwFG9V?c^!uYKVW&JM%_H zh&e95Y^Fow={SIFkwd)`;i*5KY&zcBHEzHfihAnyd{fz@a!kMS7x=mFmRY$*!HOd6 znzK1;vz--;1PwpJd%YF>oC#DZ+ z{GECH`U>$iHZ4KNi8dUNV&U!%oO~dg8I8suYwH7Sm>o84yJ`Zyq_gi4mCHcrXQF{= zcwJ%Z9+cSJ(;9F%90Ar=RW)Xre);8>Pq&OA+34(herAPTDtLn)DJKam{wn)7eJ(`v zCWLl{LLRb#iSz z&ybu5ormw}aWd`kD!#{4*Yo1L{5#q@Z}d~!y7=DsM{WJ1&&~Wk2rCL@S;$9g(`O!d zU!>+vsFR*j$?*0o?|il>cqQWn0woTslO9;^YztmF0a?k(l+DI1dOZghK<>hOgaL#DWw`wAlY$0Q_N?7Q_x!!l0vt?WfIa>Fi3tW)>jw~!Jr)Nb z)^1n(*>X+YwhvNLP>`$o^opg4tk&zb<>nS+vlr*)+Jy5h*iPq#cA(KfsNg{bYX}P* z87bFK^!B=BdaG6M2i_>i6bc|yDise(VmBL9DuabYo*`B`2g;H-bPNTB1e`dfTx{eS z!o?Gp{QR_}Se#l)#X|cwgCE_ZP(P?=|AKx{PF-%kurJ1bQJQ5+e{|t9EhP5u^(pzJ zWIY@E_xcq*EFjYer~51&39OuX z;AGM{bc7j(Q1QCt&Szg=av>d=g7R8dKST@(iT(W^gkYH2a)}21XpIxOEJH)%71|HB z)se)dD^6FV93C{}a!CXtZX=u$F1e1U8Nvxn6wb8{XruK_UG7*dp+QGxR`2&KEH+1G za2)a8s(%EaZ$H2#~WW(HUSHIPcE*qs(ih+(KC5+F_hIO_cIfA0j z4X2T+Qr&jo==8jKh{)2iVKDhMI?@o%8m*$J0a8#SpJ=3=e{v4LMmhYGt-}q#(K}Ul zifHvP&x-s=dXb7etkvyi6na1f6N%1j499_svJbl5thMn|!~*^8^G||mJyh~Zuh%ms zlk~9G_V!6_bVgb{k(guSbD;Ro%x-QMp8B1<%Ak`HpKFNYRd||OZNgbGsnrZpS~Yba zeGnUmxTVHsj#ss}i)^+O#8;q*h)8JlB9tm_h)VG#O&q8Hu6st+On4*H8O|i_Kkpu1 zP6cBTG2!!>*lL3K{@*aucXD?LejLHSB~BGx`3qKjm|1LLnH8pDa+<-Lm&XyOO9V-L zibOO%91Y&j=yVlg&+zO8cx$uq=U&9GjEG;Evl#XN`2@bF|IE&R<^U)e|9AGmcTuh` zJL9Nh_7yO*zu{<-V0RE`l4zO;iMr*WN@Q_Zh$_`Fwh&eN4VlIB0KrBg=P8Z2<+#NG zaIpg)JMvlHc6{-9p33D>rJ%Bxz*UfCWz~(19#s^DWYml|g3BL#=9y;>k{Ng1b=M45 z{pqLumf0vVINv_-Dc=`C(#z)iV(P9&vB2skB7(%>9d{48#)nxGN~fx9b|X=ltx<@4 zjtCoYv&@0l`8r_Q4-NzaumW^j=sUqo_O2l2h2 zIt;lUVPicoQ1^_9kc%zitOvYI!C4Q^yk~9p0OYZNoih`39fqCja2Er)jG@+p5q%nD z_B8zntOsY`^JASlbLYuNy}drA4IQy5eZ3dTM<-6Wjadl8&oa7C@U2bZEv;3l(O@W0 zV#T}vas{=-oY7&Y+}n0K9WX?pd*8bHyn6+S_&j~L@6r6U1@eU6pCUN?##%`w||8Xd1P4(H@ z_dbY?)R58k<`t`ws6Gqy&-t*B&IbmlAn#6*chr)J@d>|FT3g%gnUqr4Tz^uMowdTF zi=R;s#la8#L`Et`SgT&@^#Ghjz4hH=E}udr4vdelx@-oEjHdS1)>agAu)c41#k7^9NOCB59)6?Xm^9Y;TjXmF2rA~-SV4oY+g;5M?R3B>S=s8Ki& zW=EX9UV)m$rns?Dn8%05eWSH)ld2eO@g(Rt_HaD}Dn!Pn(t2ER2B{DwKSh!@NfB}& zHN_x7GG?F|M#bg275Df1RrD~}RFgohJo}!tB_kK4Pn$d+d64sKze2&ZuWC_o zz~cUgHnZ>CPlKmZjQoD$>?iMCy0(3P{uKL(uqR^Ihpas18drUt9>bh)xe{TeywJwM zMFPN1fJ@Q1?E@4KX;`sb0Xs+WWtSD_+PHb2G8;-cnE<4QSd7yT{3+!5iu`_5l0H{^ zH&E?82^A~iV`CN2-mQ9(&ofCBiud0?-0KR+loFI&S-EmL)!w^0;dbvI9*zekShgIw z!=*(ZlXS7Ow)Y`gw7tuKqT`q*z>h%|Dl}ZJygw#TVL4UBV zarue{w>F_%9x*F|3^g|og{)ZL_1vCVCb@$-atX7bnwuHno^$13`x3^{Lf{g5otbrv zyGxLR1>2dpy*VzC6$jO*I3hlJV(u(f9I)F3%p-yF2tG(BQ!3+RMK@IMHn;yEdD>Zmnd;?s<;m?^Q4l`10Y(6<&N zli&wTDk&m=W-Po#dP;wkgI(Q8i3TMzIGC2k+1X@PD|K{6SgkTIt2Le4v+uG?6HUyi zs_So9$s+Jdn~{-^7@vG3&${@TxJZA-loQKmpg*g0MAWJsD2DI+b|ww|d6oJ9sypA9 zrmiS}pZ8u{Y71>&ALXCVqLc~&9E=Hu>9Bxd#0cvcGh3DnUHmlM=FD`7a~YSyvJd-c zvP4~&a~}waS)59uF`>h`nYe8J8K~$)Srv$e0qtNwX?N~>w+LCGcHh>Q2Wem5d-wL- zbMJlkobx*}E6);VPH6o#h3w3md_Rq`YJ9pgC-svr7HTBewgUJ&nmZMUOL>jU!FwLz zBzDgz>pc#-%Dk1;=06w8u41&Ub(r++bI= zCrbI9w0yO!eoN1m{+~yp+GEz=welu2@cX~ZW`dcjl6F@e-5)l+0vR&C0P$l{GkSJm@=j z9HFTl7kq*VS2YBhEPibG?!bT~b#-0J+q4M=N$U6u6=e>sf8hI*-+HggNwX7Uf6bsn z<2X*XFpRsEKi<<`jq$t%VUx0zhWClx32QR4R_Z5k73TKk(`U})=U31anjC3Vl7%*d zmvHw#MhmCrgBrtw^Ht$b!fzr9^`P;qGI{Ecdn19-Vc%dYv?*cV(8lIik@0JIE z?nQXnIJjzIm8`7tqhk_wfT}MIjw^UI#XK&U5AO|)4GoUz%yOPnHV+)FLiE2IwmVjI~ z2nLZD12|Eo9?12qemhvJ%UPbyM#)ihM@E}-c|IG6A`F|&!ye0Wj5aaCXrnMUxN28IaS4wquZS#gl2z+pHdh)uXvMrks4^DYi!er+mX_)B7IDHl*ieKZU$D=!uY( zgc1gA(ivr=(H$eFi{k^H!P>RZN1)G>87K72!k}lAmqvGlpT)&Kvo252C)Au8cF#zr*({&0u&}pxsGz)j+8F#D8F0T1&DmD3 z%6+ydAE&&T$uwY-KGB#D^z7 zZ#~@QE?=z==~ArPnZH%-i13Vd?NH`n8R^vXgbpLr(UltNl)uVPmF~AA%?D9F$eLQI z(0nM%C*%w{og_8re}n`d-7VcM3i0`qVshvk0OLY{PlZZ=(&-4N!)KRsi%32zW-Sd3 z;&ej;5`8>rPe48qxX)sskKP;kob_`NS?^S9VliXUG3WskAgI=G!Q5YhhC$hX-Rt#l ztgG8-GGhP%FY?vvwSgb{0;%f(QaU;g91!`(Xv}@gieCD)EMqxTYr`(4Un+l90ohYQv5o1A<3l6c8R { initialRoute: Routes.rootRoute, navigatorObservers: [routeObserver], locale: const Locale('es'), - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: const [ - Locale('en'), // English - Locale('es'), // Spanish - ], + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, onGenerateRoute: (settings) { Routes.push(settings.name ?? Routes.rootRoute); switch (settings.name) { diff --git a/lib/clock/screens/clock_screen.dart b/lib/clock/screens/clock_screen.dart index e359c0d6..286f39dc 100644 --- a/lib/clock/screens/clock_screen.dart +++ b/lib/clock/screens/clock_screen.dart @@ -10,7 +10,7 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:flutter/material.dart'; class ClockScreen extends StatefulWidget { - const ClockScreen({Key? key}) : super(key: key); + const ClockScreen({super.key}); @override State createState() => _ClockScreenState(); diff --git a/lib/common/logic/card_decoration.dart b/lib/common/logic/card_decoration.dart index c31af779..1c90bb67 100644 --- a/lib/common/logic/card_decoration.dart +++ b/lib/common/logic/card_decoration.dart @@ -45,7 +45,7 @@ BoxDecoration getCardDecoration(BuildContext context, color: color ?? (useMaterialYou ? Color(tonalPalette.get( - Theme.of(context).brightness == Brightness.light ? 96 : 15)) + Theme.of(context).brightness == Brightness.light ? 98 : 15)) : colorScheme.surface), borderRadius: theme.cardTheme.shape != null ? (theme.cardTheme.shape as RoundedRectangleBorder).borderRadius diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 00000000..f95dd0cb --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,6 @@ +{ + "clock": "Clock", + "@clock": { + "description": "Title of the clock screen" + } +} diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb new file mode 100644 index 00000000..515a8567 --- /dev/null +++ b/lib/l10n/app_es.arb @@ -0,0 +1,3 @@ +{ + "clock": "Reloj" +} diff --git a/lib/navigation/data/tabs.dart b/lib/navigation/data/tabs.dart index 472ba9a3..108e8158 100644 --- a/lib/navigation/data/tabs.dart +++ b/lib/navigation/data/tabs.dart @@ -5,13 +5,18 @@ import 'package:clock_app/timer/screens/timer_screen.dart'; import 'package:clock_app/icons/flux_icons.dart'; import 'package:clock_app/clock/screens/clock_screen.dart'; import 'package:clock_app/navigation/types/tab.dart'; +import 'package:flutter/material.dart' hide Tab; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -final List tabs = [ + +List getTabs(BuildContext context) { + return [ Tab(title: 'Alarm', icon: FluxIcons.alarm, widget: const AlarmScreen()), - Tab(title: 'Clock', icon: FluxIcons.clock, widget: const ClockScreen()), + Tab(title: AppLocalizations.of(context)!.clock, icon: FluxIcons.clock, widget: const ClockScreen()), Tab(title: 'Timer', icon: FluxIcons.timer, widget: const TimerScreen()), Tab( title: 'Stopwatch', icon: FluxIcons.stopwatch, widget: const StopwatchScreen()), ]; +} diff --git a/lib/navigation/screens/nav_scaffold.dart b/lib/navigation/screens/nav_scaffold.dart index ddb1a25a..98c0d608 100644 --- a/lib/navigation/screens/nav_scaffold.dart +++ b/lib/navigation/screens/nav_scaffold.dart @@ -1,11 +1,12 @@ import 'package:clock_app/icons/flux_icons.dart'; import 'package:clock_app/navigation/data/tabs.dart'; +import 'package:clock_app/navigation/types/tab.dart'; import 'package:clock_app/navigation/widgets/app_navigation_bar.dart'; import 'package:clock_app/navigation/widgets/app_top_bar.dart'; import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/settings/screens/settings_group_screen.dart'; import 'package:clock_app/settings/types/setting.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide Tab; class NavScaffold extends StatefulWidget { const NavScaffold({super.key}); @@ -51,6 +52,8 @@ void setUseMaterialnavBar(dynamic value) { @override Widget build(BuildContext context) { + List tabs = getTabs(context); + return Scaffold( appBar: AppTopBar( title: Text(tabs[_selectedTabIndex].title, diff --git a/lib/navigation/widgets/app_navigation_bar.dart b/lib/navigation/widgets/app_navigation_bar.dart index bf2a80ee..808f3aef 100644 --- a/lib/navigation/widgets/app_navigation_bar.dart +++ b/lib/navigation/widgets/app_navigation_bar.dart @@ -1,24 +1,28 @@ import 'package:clock_app/common/widgets/card_container.dart'; import 'package:clock_app/navigation/data/tabs.dart'; +import 'package:clock_app/navigation/types/tab.dart'; import 'package:clock_app/navigation/widgets/nav_bar.dart'; import 'package:clock_app/navigation/widgets/nav_bar_item.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide Tab; class AppNavigationBar extends StatefulWidget { final int selectedTabIndex; final void Function(int) onTabSelected; const AppNavigationBar( - {Key? key, required this.selectedTabIndex, required this.onTabSelected}) - : super(key: key); + {super.key, required this.selectedTabIndex, required this.onTabSelected}); @override State createState() => _AppNavigationBarState(); } class _AppNavigationBarState extends State { + + @override Widget build(BuildContext context) { + List tabs = getTabs(context); + return Padding( padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 4.0, top: 0), diff --git a/pubspec.yaml b/pubspec.yaml index 6b45fd29..23839eaf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -83,15 +83,13 @@ dependency_overrides: # min_sdk_android: 21 # android min sdk min:16, default 21 # flutter: + generate: true uses-material-design: true assets: - assets/timezones.db - assets/images/ - assets/ringtones/ fonts: - - family: Montserrat - fonts: - - asset: fonts/Montserrat/Montserrat-VariableFont.ttf - family: Rubik fonts: - asset: fonts/Rubik/Rubik-VariableFont.ttf From 53eeece26f273b981cdfc1f07a1bb2d874b7f24a Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Wed, 27 Mar 2024 16:41:46 +0500 Subject: [PATCH 003/112] Add localization for screen titles --- lib/common/widgets/card_container.dart | 20 -------------------- lib/l10n/app_en.arb | 16 ++++++++++++++-- lib/l10n/app_es.arb | 5 ++++- lib/navigation/data/tabs.dart | 8 ++++---- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/lib/common/widgets/card_container.dart b/lib/common/widgets/card_container.dart index 48a0f47f..0ef2794f 100644 --- a/lib/common/widgets/card_container.dart +++ b/lib/common/widgets/card_container.dart @@ -39,26 +39,6 @@ class CardContainer extends StatelessWidget { ThemeData theme = Theme.of(context); ColorScheme colorScheme = theme.colorScheme; return - // Card.filled( - // elevation: 1, - // // margin: margin ?? const EdgeInsets.all(4), - // // clipBehavior: Clip.hardEdge, - // // shape: RoundedRectangleBorder( - // // borderRadius: BorderRadius.circular(16), - // // side: showLightBorder - // // ? BorderSide( - // // color: Theme.of(context).colorScheme.onBackground.withOpacity(0.1), - // // width: 1, - // // ) - // // : BorderSide.none, - // // ), - // color: color, - // child: InkWell( - // onTap: onTap, - // child: child, - // ), - // - // ); Container( alignment: alignment, margin: margin ?? const EdgeInsets.all(4), diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f95dd0cb..b9c76e54 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1,6 +1,18 @@ { - "clock": "Clock", - "@clock": { + "clockTitle": "Clock", + "@clockTitle": { "description": "Title of the clock screen" + }, + "alarmTitle": "Alarm", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "timerTitle": "Timer", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "stopwatchTitle": "Stopwatch", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" } } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 515a8567..7cec8db5 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1,3 +1,6 @@ { - "clock": "Reloj" + "clockTitle": "Reloj", + "alarmTitle": "Alarma", + "timerTitle": "Temporizador", + "stopwatchTitle": "Cronómetro" } diff --git a/lib/navigation/data/tabs.dart b/lib/navigation/data/tabs.dart index 108e8158..dd70ab1a 100644 --- a/lib/navigation/data/tabs.dart +++ b/lib/navigation/data/tabs.dart @@ -11,11 +11,11 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; List getTabs(BuildContext context) { return [ - Tab(title: 'Alarm', icon: FluxIcons.alarm, widget: const AlarmScreen()), - Tab(title: AppLocalizations.of(context)!.clock, icon: FluxIcons.clock, widget: const ClockScreen()), - Tab(title: 'Timer', icon: FluxIcons.timer, widget: const TimerScreen()), + Tab(title: AppLocalizations.of(context)!.alarmTitle, icon: FluxIcons.alarm, widget: const AlarmScreen()), + Tab(title: AppLocalizations.of(context)!.clockTitle, icon: FluxIcons.clock, widget: const ClockScreen()), + Tab(title: AppLocalizations.of(context)!.timerTitle, icon: FluxIcons.timer, widget: const TimerScreen()), Tab( - title: 'Stopwatch', + title: AppLocalizations.of(context)!.stopwatchTitle, icon: FluxIcons.stopwatch, widget: const StopwatchScreen()), ]; From 34d589037fbbfc228baa80653afc7e1521457380 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Wed, 27 Mar 2024 17:47:54 +0500 Subject: [PATCH 004/112] Add localization to settings --- .../fields/select_field/select_field.dart | 4 ++-- lib/l10n/app_en.arb | 4 +++- lib/l10n/app_es.arb | 4 +++- lib/settings/data/localized_names.dart | 21 +++++++++++++++++++ lib/settings/types/setting_item.dart | 7 +++++++ lib/settings/widgets/color_setting_card.dart | 7 +++---- lib/settings/widgets/custom_setting_card.dart | 6 +++--- lib/settings/widgets/date_setting_card.dart | 8 +++---- .../widgets/duration_setting_card.dart | 8 +++---- .../widgets/dynamic_select_setting_card.dart | 6 +++--- lib/settings/widgets/list_setting_card.dart | 6 +++--- lib/settings/widgets/list_setting_screen.dart | 4 ++-- lib/settings/widgets/select_setting_card.dart | 6 +++--- lib/settings/widgets/setting_action_card.dart | 6 +++--- lib/settings/widgets/setting_group_card.dart | 6 +++--- .../widgets/setting_page_link_card.dart | 8 +++---- lib/settings/widgets/settings_top_bar.dart | 3 +-- lib/settings/widgets/slider_setting_card.dart | 6 +++--- lib/settings/widgets/string_setting_card.dart | 6 +++--- lib/settings/widgets/switch_setting_card.dart | 7 +++---- lib/settings/widgets/toggle_setting_card.dart | 9 ++++---- 21 files changed, 85 insertions(+), 57 deletions(-) create mode 100644 lib/settings/data/localized_names.dart diff --git a/lib/common/widgets/fields/select_field/select_field.dart b/lib/common/widgets/fields/select_field/select_field.dart index 7b4341d3..8bc599d5 100644 --- a/lib/common/widgets/fields/select_field/select_field.dart +++ b/lib/common/widgets/fields/select_field/select_field.dart @@ -9,13 +9,13 @@ import 'package:flutter/material.dart'; class SelectField extends StatefulWidget { const SelectField({ - Key? key, + super.key, required this.selectedIndex, required this.title, this.description, required this.choices, required this.onChanged, - }) : super(key: key); + }); final int selectedIndex; final String title; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b9c76e54..28fc9274 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -14,5 +14,7 @@ "stopwatchTitle": "Stopwatch", "@stopwatchTitle": { "description": "Title of the stopwatch screen" - } + }, + "generalSettingGroup": "General", + "appearanceSettingGroup": "Appearance" } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 7cec8db5..e4c684ab 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -2,5 +2,7 @@ "clockTitle": "Reloj", "alarmTitle": "Alarma", "timerTitle": "Temporizador", - "stopwatchTitle": "Cronómetro" + "stopwatchTitle": "Cronómetro", + "generalSettingGroup": "General", + "appearanceSettingGroup": "Apariencia" } diff --git a/lib/settings/data/localized_names.dart b/lib/settings/data/localized_names.dart new file mode 100644 index 00000000..f0d199ca --- /dev/null +++ b/lib/settings/data/localized_names.dart @@ -0,0 +1,21 @@ + import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + + +String getLocalizedSettingName(String name, BuildContext context) { + switch (name) { + case "General": + return AppLocalizations.of(context)!.generalSettingGroup; + case "Appearance": + return AppLocalizations.of(context)!.appearanceSettingGroup; + default: + return name; + } + } + +String getLocalizedSettingDescription(String name, BuildContext context) { + switch (name) { + default: + return name; + } + } diff --git a/lib/settings/types/setting_item.dart b/lib/settings/types/setting_item.dart index bc882e63..f5862720 100644 --- a/lib/settings/types/setting_item.dart +++ b/lib/settings/types/setting_item.dart @@ -1,6 +1,10 @@ +import 'package:clock_app/settings/data/localized_names.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:flutter/material.dart'; + + abstract class SettingItem { String name; @@ -16,6 +20,9 @@ abstract class SettingItem { List enableSettings; // List compoundEnableSettings; + String displayName(BuildContext context) => getLocalizedSettingName(name, context); + String displayDescription(BuildContext context) => getLocalizedSettingDescription(description, context); + bool get isEnabled { for (var enableSetting in enableSettings) { if(!enableSetting.evaluate()){ diff --git a/lib/settings/widgets/color_setting_card.dart b/lib/settings/widgets/color_setting_card.dart index 32fbb2a1..87492d47 100644 --- a/lib/settings/widgets/color_setting_card.dart +++ b/lib/settings/widgets/color_setting_card.dart @@ -5,11 +5,10 @@ import 'package:flutter/material.dart'; class ColorSettingCard extends StatefulWidget { const ColorSettingCard( - {Key? key, + {super.key, required this.setting, this.showAsCard = false, - this.onChanged}) - : super(key: key); + this.onChanged}); final ColorSetting setting; final bool showAsCard; @@ -23,7 +22,7 @@ class _ColorSettingCardState extends State { @override Widget build(BuildContext context) { ColorField toggleCard = ColorField( - name: widget.setting.name, + name: widget.setting.displayName(context), value: widget.setting.value, onChange: (value) { setState(() { diff --git a/lib/settings/widgets/custom_setting_card.dart b/lib/settings/widgets/custom_setting_card.dart index c9ea5ad4..a0381e82 100644 --- a/lib/settings/widgets/custom_setting_card.dart +++ b/lib/settings/widgets/custom_setting_card.dart @@ -4,10 +4,10 @@ import 'package:flutter/material.dart'; class CustomSettingCard extends StatefulWidget { const CustomSettingCard({ - Key? key, + super.key, required this.setting, this.showAsCard = true, - }) : super(key: key); + }); final CustomSetting setting; final bool showAsCard; @@ -38,7 +38,7 @@ class _CustomSettingCardState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.setting.name, + widget.setting.displayName(context), style: Theme.of(context).textTheme.headlineMedium, ), const SizedBox(height: 4.0), diff --git a/lib/settings/widgets/date_setting_card.dart b/lib/settings/widgets/date_setting_card.dart index 3b5c8c32..094601f9 100644 --- a/lib/settings/widgets/date_setting_card.dart +++ b/lib/settings/widgets/date_setting_card.dart @@ -9,11 +9,11 @@ class DateSettingCard extends StatefulWidget { final void Function(List)? onChanged; const DateSettingCard({ - Key? key, + super.key, required this.setting, this.showAsCard = false, this.onChanged, - }) : super(key: key); + }); @override State createState() => _DateSettingCardState(); @@ -23,8 +23,8 @@ class _DateSettingCardState extends State { @override Widget build(BuildContext context) { Widget input = DatePickerField( - title: widget.setting.name, - description: widget.setting.description, + title: widget.setting.displayName(context), + description: widget.setting.displayDescription(context), value: widget.setting.value, rangeOnly: widget.setting.rangeOnly, onChanged: (value) { diff --git a/lib/settings/widgets/duration_setting_card.dart b/lib/settings/widgets/duration_setting_card.dart index 73d10674..e1d8f1fe 100644 --- a/lib/settings/widgets/duration_setting_card.dart +++ b/lib/settings/widgets/duration_setting_card.dart @@ -10,11 +10,11 @@ class DurationSettingCard extends StatefulWidget { final void Function(TimeDuration)? onChanged; const DurationSettingCard({ - Key? key, + super.key, required this.setting, this.showAsCard = false, this.onChanged, - }) : super(key: key); + }); @override State createState() => _DurationSettingCardState(); @@ -24,8 +24,8 @@ class _DurationSettingCardState extends State { @override Widget build(BuildContext context) { Widget input = DurationPickerField( - title: widget.setting.name, - description: widget.setting.description, + title: widget.setting.displayName(context), + description: widget.setting.displayDescription(context), value: widget.setting.value, onChange: (value) { setState(() { diff --git a/lib/settings/widgets/dynamic_select_setting_card.dart b/lib/settings/widgets/dynamic_select_setting_card.dart index d7e26efb..7e2a633b 100644 --- a/lib/settings/widgets/dynamic_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_select_setting_card.dart @@ -7,11 +7,11 @@ import 'package:flutter/material.dart'; class DynamicSelectSettingCard extends StatefulWidget { const DynamicSelectSettingCard({ - Key? key, + super.key, required this.setting, this.showAsCard = false, this.onChanged, - }) : super(key: key); + }); final DynamicSelectSetting setting; final void Function(T)? onChanged; final bool showAsCard; @@ -28,7 +28,7 @@ class _DynamicSelectSettingCardState print("init ${widget.setting.selectedIndex}"); SelectField selectWidget = SelectField( selectedIndex: widget.setting.selectedIndex, - title: widget.setting.name, + title: widget.setting.displayName(context), choices: widget.setting.options .map((option) => SelectChoice( name: option.name, diff --git a/lib/settings/widgets/list_setting_card.dart b/lib/settings/widgets/list_setting_card.dart index fc70d2a6..a8a1012c 100644 --- a/lib/settings/widgets/list_setting_card.dart +++ b/lib/settings/widgets/list_setting_card.dart @@ -5,10 +5,10 @@ import 'package:flutter/material.dart'; class ListSettingCard extends StatefulWidget { const ListSettingCard({ - Key? key, + super.key, required this.setting, this.showAsCard = true, - }) : super(key: key); + }); final ListSetting setting; final bool showAsCard; @@ -39,7 +39,7 @@ class _ListSettingCardState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.setting.name, + widget.setting.displayName(context), style: Theme.of(context).textTheme.headlineMedium, ), const SizedBox(height: 4.0), diff --git a/lib/settings/widgets/list_setting_screen.dart b/lib/settings/widgets/list_setting_screen.dart index ea698eb2..5c809d4e 100644 --- a/lib/settings/widgets/list_setting_screen.dart +++ b/lib/settings/widgets/list_setting_screen.dart @@ -54,7 +54,7 @@ class _ListSettingScreenState Widget build(BuildContext context) { return Scaffold( appBar: AppTopBar( - title: Text(widget.setting.name), + title: Text(widget.setting.displayName(context)), ), body: Stack( children: [ @@ -70,7 +70,7 @@ class _ListSettingScreenState }, onModifyList: () {}, placeholderText: - "No ${widget.setting.name.toLowerCase()} added yet", + "No ${widget.setting.displayName(context).toLowerCase()} added yet", ), ), ], diff --git a/lib/settings/widgets/select_setting_card.dart b/lib/settings/widgets/select_setting_card.dart index 40c4f5e3..e4b45815 100644 --- a/lib/settings/widgets/select_setting_card.dart +++ b/lib/settings/widgets/select_setting_card.dart @@ -6,11 +6,11 @@ import 'package:flutter/material.dart'; class SelectSettingCard extends StatefulWidget { const SelectSettingCard({ - Key? key, + super.key, required this.setting, this.showAsCard = false, this.onChanged, - }) : super(key: key); + }); final SelectSetting setting; final void Function(T)? onChanged; final bool showAsCard; @@ -24,7 +24,7 @@ class _SelectSettingCardState extends State> { Widget build(BuildContext context) { SelectField selectWidget = SelectField( selectedIndex: widget.setting.selectedIndex, - title: widget.setting.name, + title: widget.setting.displayName(context), choices: widget.setting.options .map((option) => SelectChoice( name: option.name, diff --git a/lib/settings/widgets/setting_action_card.dart b/lib/settings/widgets/setting_action_card.dart index 24f8dd0e..72802115 100644 --- a/lib/settings/widgets/setting_action_card.dart +++ b/lib/settings/widgets/setting_action_card.dart @@ -4,10 +4,10 @@ import 'package:flutter/material.dart'; class SettingActionCard extends StatefulWidget { const SettingActionCard({ - Key? key, + super.key, required this.setting, this.showAsCard = true, - }) : super(key: key); + }); final SettingAction setting; final bool showAsCard; @@ -36,7 +36,7 @@ class _SettingActionCardState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.setting.name, + widget.setting.displayName(context), style: textTheme.displaySmall, ), if (widget.setting.description.isNotEmpty) ...[ diff --git a/lib/settings/widgets/setting_group_card.dart b/lib/settings/widgets/setting_group_card.dart index 3077a48c..065aac58 100644 --- a/lib/settings/widgets/setting_group_card.dart +++ b/lib/settings/widgets/setting_group_card.dart @@ -91,13 +91,13 @@ class _SettingGroupCardState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.settingGroup.name, + widget.settingGroup.displayName(context), style: textTheme.displaySmall, ), if (widget.settingGroup.description.isNotEmpty) ...[ const SizedBox(height: 4), Text( - widget.settingGroup.description, + widget.settingGroup.displayDescription(context), style: textTheme.bodyMedium, ) ] @@ -145,7 +145,7 @@ class SettingGroupHeader extends StatelessWidget { child: Row( children: [ Text( - settingGroup.name, + settingGroup.displayName(context), style: textTheme.headlineMedium?.copyWith( color: colorScheme.primary, ), diff --git a/lib/settings/widgets/setting_page_link_card.dart b/lib/settings/widgets/setting_page_link_card.dart index fc5b89d7..4b0abd32 100644 --- a/lib/settings/widgets/setting_page_link_card.dart +++ b/lib/settings/widgets/setting_page_link_card.dart @@ -4,10 +4,10 @@ import 'package:flutter/material.dart'; class SettingPageLinkCard extends StatefulWidget { const SettingPageLinkCard({ - Key? key, + super.key, required this.setting, this.showAsCard = true, - }) : super(key: key); + }); final SettingPageLink setting; final bool showAsCard; @@ -41,13 +41,13 @@ class _SettingPageLinkCardState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.setting.name, + widget.setting.displayName(context), style: textTheme.displaySmall, ), if (widget.setting.description.isNotEmpty) ...[ const SizedBox(height: 4), Text( - widget.setting.description, + widget.setting.displayDescription(context), style: textTheme.bodyMedium, ) ] diff --git a/lib/settings/widgets/settings_top_bar.dart b/lib/settings/widgets/settings_top_bar.dart index 5b9e2ab4..ef5a9050 100644 --- a/lib/settings/widgets/settings_top_bar.dart +++ b/lib/settings/widgets/settings_top_bar.dart @@ -9,8 +9,7 @@ class SettingsTopBar extends StatefulWidget implements PreferredSizeWidget { Size get preferredSize => const Size(0, 56); const SettingsTopBar( - {Key? key, required this.onSearch, this.showSearch = false}) - : super(key: key); + {super.key, required this.onSearch, this.showSearch = false}); final void Function(List settings) onSearch; final bool showSearch; diff --git a/lib/settings/widgets/slider_setting_card.dart b/lib/settings/widgets/slider_setting_card.dart index cd46df04..e2be84ff 100644 --- a/lib/settings/widgets/slider_setting_card.dart +++ b/lib/settings/widgets/slider_setting_card.dart @@ -9,11 +9,11 @@ class SliderSettingCard extends StatefulWidget { final void Function(double)? onChanged; const SliderSettingCard({ - Key? key, + super.key, required this.setting, this.showAsCard = false, this.onChanged, - }) : super(key: key); + }); @override State createState() => _SliderSettingCardState(); @@ -23,7 +23,7 @@ class _SliderSettingCardState extends State { @override Widget build(BuildContext context) { SliderField sliderCard = SliderField( - title: widget.setting.name, + title: widget.setting.displayName(context), value: widget.setting.value, min: widget.setting.min, max: widget.setting.max, diff --git a/lib/settings/widgets/string_setting_card.dart b/lib/settings/widgets/string_setting_card.dart index 8024e40c..1bfff865 100644 --- a/lib/settings/widgets/string_setting_card.dart +++ b/lib/settings/widgets/string_setting_card.dart @@ -9,11 +9,11 @@ class StringSettingCard extends StatefulWidget { final void Function(String)? onChanged; const StringSettingCard({ - Key? key, + super.key, required this.setting, this.showAsCard = false, this.onChanged, - }) : super(key: key); + }); @override State createState() => _StringSettingCardState(); @@ -23,7 +23,7 @@ class _StringSettingCardState extends State { @override Widget build(BuildContext context) { Widget input = InputField( - title: widget.setting.name, + title: widget.setting.displayName(context), description: widget.setting.description, value: widget.setting.value, onChanged: (value) { diff --git a/lib/settings/widgets/switch_setting_card.dart b/lib/settings/widgets/switch_setting_card.dart index 3d06f13d..7203a373 100644 --- a/lib/settings/widgets/switch_setting_card.dart +++ b/lib/settings/widgets/switch_setting_card.dart @@ -9,11 +9,10 @@ class SwitchSettingCard extends StatefulWidget { final void Function(bool)? onChanged; const SwitchSettingCard( - {Key? key, + {super.key, required this.setting, this.showAsCard = false, - this.onChanged}) - : super(key: key); + this.onChanged}); @override State createState() => _SwitchSettingCardState(); @@ -23,7 +22,7 @@ class _SwitchSettingCardState extends State { @override Widget build(BuildContext context) { SwitchField switchCard = SwitchField( - name: widget.setting.name, + name: widget.setting.displayName(context), value: widget.setting.value, onChanged: (value) { setState(() { diff --git a/lib/settings/widgets/toggle_setting_card.dart b/lib/settings/widgets/toggle_setting_card.dart index 39d8eef6..cefc568d 100644 --- a/lib/settings/widgets/toggle_setting_card.dart +++ b/lib/settings/widgets/toggle_setting_card.dart @@ -5,11 +5,10 @@ import 'package:flutter/material.dart'; class ToggleSettingCard extends StatefulWidget { const ToggleSettingCard( - {Key? key, + {super.key, required this.setting, this.showAsCard = false, - this.onChanged}) - : super(key: key); + this.onChanged}); final ToggleSetting setting; final bool showAsCard; @@ -23,8 +22,8 @@ class _ToggleSettingCardState extends State> { @override Widget build(BuildContext context) { ToggleField toggleCard = ToggleField( - name: widget.setting.name, - description: widget.setting.description, + name: widget.setting.displayName(context), + description: widget.setting.displayDescription(context), selectedItems: widget.setting.value, options: widget.setting.options .map((option) => ToggleOption(option.name, option.value)) From e187a411efb9061b5ba122d3dce7d645b37d5b4b Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Wed, 27 Mar 2024 20:16:51 +0500 Subject: [PATCH 005/112] Add setting to choose locale --- lib/app.dart | 5 +- lib/l10n/language_local.dart | 218 ++++++++++++++++++ .../data/general_settings_schema.dart | 12 + pubspec.lock | 8 + pubspec.yaml | 1 + 5 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 lib/l10n/language_local.dart diff --git a/lib/app.dart b/lib/app.dart index 8be4df97..bf9c2af3 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -54,6 +54,7 @@ class _AppState extends State { late SettingGroup _appearanceSettings; late SettingGroup _colorSettings; late SettingGroup _styleSettings; + late SettingGroup _generalSettings; late StreamSubscription _sub; @@ -100,6 +101,7 @@ class _AppState extends State { _appearanceSettings = appSettings.getGroup("Appearance"); _colorSettings = _appearanceSettings.getGroup("Colors"); _styleSettings = _appearanceSettings.getGroup("Style"); + _generalSettings = appSettings.getGroup("General"); } refreshTheme() { @@ -176,6 +178,7 @@ class _AppState extends State { final AppTheme appTheme = getAppTheme(lightDynamic, darkDynamic); ThemeBrightness themeBrightness = _colorSettings.getSetting("Brightness").value; + Locale locale = _generalSettings.getSetting("Language").value; return MaterialApp( scaffoldMessengerKey: _messangerKey, @@ -191,7 +194,7 @@ class _AppState extends State { : ThemeMode.dark, initialRoute: Routes.rootRoute, navigatorObservers: [routeObserver], - locale: const Locale('es'), + locale: locale, localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, onGenerateRoute: (settings) { diff --git a/lib/l10n/language_local.dart b/lib/l10n/language_local.dart new file mode 100644 index 00000000..f038c080 --- /dev/null +++ b/lib/l10n/language_local.dart @@ -0,0 +1,218 @@ + final isoLangs = { + "ab": {"name": "Abkhaz", "nativeName": "аҧсуа"}, + "aa": {"name": "Afar", "nativeName": "Afaraf"}, + "af": {"name": "Afrikaans", "nativeName": "Afrikaans"}, + "ak": {"name": "Akan", "nativeName": "Akan"}, + "sq": {"name": "Albanian", "nativeName": "Shqip"}, + "am": {"name": "Amharic", "nativeName": "አማርኛ"}, + "ar": {"name": "Arabic", "nativeName": "العربية"}, + "an": {"name": "Aragonese", "nativeName": "Aragonés"}, + "hy": {"name": "Armenian", "nativeName": "Հայերեն"}, + "as": {"name": "Assamese", "nativeName": "অসমীয়া"}, + "av": {"name": "Avaric", "nativeName": "авар мацӀ, магӀарул мацӀ"}, + "ae": {"name": "Avestan", "nativeName": "avesta"}, + "ay": {"name": "Aymara", "nativeName": "aymar aru"}, + "az": {"name": "Azerbaijani", "nativeName": "azərbaycan dili"}, + "bm": {"name": "Bambara", "nativeName": "bamanankan"}, + "ba": {"name": "Bashkir", "nativeName": "башҡорт теле"}, + "eu": {"name": "Basque", "nativeName": "euskara, euskera"}, + "be": {"name": "Belarusian", "nativeName": "Беларуская"}, + "bn": {"name": "Bengali", "nativeName": "বাংলা"}, + "bh": {"name": "Bihari", "nativeName": "भोजपुरी"}, + "bi": {"name": "Bislama", "nativeName": "Bislama"}, + "bs": {"name": "Bosnian", "nativeName": "bosanski jezik"}, + "br": {"name": "Breton", "nativeName": "brezhoneg"}, + "bg": {"name": "Bulgarian", "nativeName": "български език"}, + "my": {"name": "Burmese", "nativeName": "ဗမာစာ"}, + "ca": {"name": "Catalan; Valencian", "nativeName": "Català"}, + "ch": {"name": "Chamorro", "nativeName": "Chamoru"}, + "ce": {"name": "Chechen", "nativeName": "нохчийн мотт"}, + "ny": { + "name": "Chichewa; Chewa; Nyanja", + "nativeName": "chiCheŵa, chinyanja" + }, + "zh": {"name": "Chinese", "nativeName": "中文 (Zhōngwén), 汉语, 漢語"}, + "cv": {"name": "Chuvash", "nativeName": "чӑваш чӗлхи"}, + "kw": {"name": "Cornish", "nativeName": "Kernewek"}, + "co": {"name": "Corsican", "nativeName": "corsu, lingua corsa"}, + "cr": {"name": "Cree", "nativeName": "ᓀᐦᐃᔭᐍᐏᐣ"}, + "hr": {"name": "Croatian", "nativeName": "hrvatski"}, + "cs": {"name": "Czech", "nativeName": "česky, čeština"}, + "da": {"name": "Danish", "nativeName": "dansk"}, + "dv": {"name": "Divehi; Dhivehi; Maldivian;", "nativeName": "ދިވެހި"}, + "nl": {"name": "Dutch", "nativeName": "Nederlands, Vlaams"}, + "en": {"name": "English", "nativeName": "English"}, + "eo": {"name": "Esperanto", "nativeName": "Esperanto"}, + "et": {"name": "Estonian", "nativeName": "eesti, eesti keel"}, + "ee": {"name": "Ewe", "nativeName": "Eʋegbe"}, + "fo": {"name": "Faroese", "nativeName": "føroyskt"}, + "fj": {"name": "Fijian", "nativeName": "vosa Vakaviti"}, + "fi": {"name": "Finnish", "nativeName": "suomi, suomen kieli"}, + "fr": {"name": "French", "nativeName": "français, langue française"}, + "ff": { + "name": "Fula; Fulah; Pulaar; Pular", + "nativeName": "Fulfulde, Pulaar, Pular" + }, + "gl": {"name": "Galician", "nativeName": "Galego"}, + "ka": {"name": "Georgian", "nativeName": "ქართული"}, + "de": {"name": "German", "nativeName": "Deutsch"}, + "el": {"name": "Greek, Modern", "nativeName": "Ελληνικά"}, + "gn": {"name": "Guaraní", "nativeName": "Avañeẽ"}, + "gu": {"name": "Gujarati", "nativeName": "ગુજરાતી"}, + "ht": {"name": "Haitian; Haitian Creole", "nativeName": "Kreyòl ayisyen"}, + "ha": {"name": "Hausa", "nativeName": "Hausa, هَوُسَ"}, + "he": {"name": "Hebrew (modern)", "nativeName": "עברית"}, + "hz": {"name": "Herero", "nativeName": "Otjiherero"}, + "hi": {"name": "Hindi", "nativeName": "हिन्दी, हिंदी"}, + "ho": {"name": "Hiri Motu", "nativeName": "Hiri Motu"}, + "hu": {"name": "Hungarian", "nativeName": "Magyar"}, + "ia": {"name": "Interlingua", "nativeName": "Interlingua"}, + "id": {"name": "Indonesian", "nativeName": "Bahasa Indonesia"}, + "ie": { + "name": "Interlingue", + "nativeName": "Originally called Occidental; then Interlingue after WWII" + }, + "ga": {"name": "Irish", "nativeName": "Gaeilge"}, + "ig": {"name": "Igbo", "nativeName": "Asụsụ Igbo"}, + "ik": {"name": "Inupiaq", "nativeName": "Iñupiaq, Iñupiatun"}, + "io": {"name": "Ido", "nativeName": "Ido"}, + "is": {"name": "Icelandic", "nativeName": "Íslenska"}, + "it": {"name": "Italian", "nativeName": "Italiano"}, + "iu": {"name": "Inuktitut", "nativeName": "ᐃᓄᒃᑎᑐᑦ"}, + "ja": {"name": "Japanese", "nativeName": "日本語 (にほんご/にっぽんご)"}, + "jv": {"name": "Javanese", "nativeName": "basa Jawa"}, + "kl": { + "name": "Kalaallisut, Greenlandic", + "nativeName": "kalaallisut, kalaallit oqaasii" + }, + "kn": {"name": "Kannada", "nativeName": "ಕನ್ನಡ"}, + "kr": {"name": "Kanuri", "nativeName": "Kanuri"}, + "ks": {"name": "Kashmiri", "nativeName": "कश्मीरी, كشميري‎"}, + "kk": {"name": "Kazakh", "nativeName": "Қазақ тілі"}, + "km": {"name": "Khmer", "nativeName": "ភាសាខ្មែរ"}, + "ki": {"name": "Kikuyu, Gikuyu", "nativeName": "Gĩkũyũ"}, + "rw": {"name": "Kinyarwanda", "nativeName": "Ikinyarwanda"}, + "ky": {"name": "Kirghiz, Kyrgyz", "nativeName": "кыргыз тили"}, + "kv": {"name": "Komi", "nativeName": "коми кыв"}, + "kg": {"name": "Kongo", "nativeName": "KiKongo"}, + "ko": {"name": "Korean", "nativeName": "한국어 (韓國語), 조선말 (朝鮮語)"}, + "ku": {"name": "Kurdish", "nativeName": "Kurdî, كوردی‎"}, + "kj": {"name": "Kwanyama, Kuanyama", "nativeName": "Kuanyama"}, + "la": {"name": "Latin", "nativeName": "latine, lingua latina"}, + "lb": { + "name": "Luxembourgish, Letzeburgesch", + "nativeName": "Lëtzebuergesch" + }, + "lg": {"name": "Luganda", "nativeName": "Luganda"}, + "li": { + "name": "Limburgish, Limburgan, Limburger", + "nativeName": "Limburgs" + }, + "ln": {"name": "Lingala", "nativeName": "Lingála"}, + "lo": {"name": "Lao", "nativeName": "ພາສາລາວ"}, + "lt": {"name": "Lithuanian", "nativeName": "lietuvių kalba"}, + "lu": {"name": "Luba-Katanga", "nativeName": ""}, + "lv": {"name": "Latvian", "nativeName": "latviešu valoda"}, + "gv": {"name": "Manx", "nativeName": "Gaelg, Gailck"}, + "mk": {"name": "Macedonian", "nativeName": "македонски јазик"}, + "mg": {"name": "Malagasy", "nativeName": "Malagasy fiteny"}, + "ms": {"name": "Malay", "nativeName": "bahasa Melayu, بهاس ملايو‎"}, + "ml": {"name": "Malayalam", "nativeName": "മലയാളം"}, + "mt": {"name": "Maltese", "nativeName": "Malti"}, + "mi": {"name": "Māori", "nativeName": "te reo Māori"}, + "mr": {"name": "Marathi (Marāṭhī)", "nativeName": "मराठी"}, + "mh": {"name": "Marshallese", "nativeName": "Kajin M̧ajeļ"}, + "mn": {"name": "Mongolian", "nativeName": "монгол"}, + "na": {"name": "Nauru", "nativeName": "Ekakairũ Naoero"}, + "nv": {"name": "Navajo, Navaho", "nativeName": "Diné bizaad, Dinékʼehǰí"}, + "nb": {"name": "Norwegian Bokmål", "nativeName": "Norsk bokmål"}, + "nd": {"name": "North Ndebele", "nativeName": "isiNdebele"}, + "ne": {"name": "Nepali", "nativeName": "नेपाली"}, + "ng": {"name": "Ndonga", "nativeName": "Owambo"}, + "nn": {"name": "Norwegian Nynorsk", "nativeName": "Norsk nynorsk"}, + "no": {"name": "Norwegian", "nativeName": "Norsk"}, + "ii": {"name": "Nuosu", "nativeName": "ꆈꌠ꒿ Nuosuhxop"}, + "nr": {"name": "South Ndebele", "nativeName": "isiNdebele"}, + "oc": {"name": "Occitan", "nativeName": "Occitan"}, + "oj": {"name": "Ojibwe, Ojibwa", "nativeName": "ᐊᓂᔑᓈᐯᒧᐎᓐ"}, + "cu": { + "name": + "Old Church Slavonic, Church Slavic, Church Slavonic, Old Bulgarian, Old Slavonic", + "nativeName": "ѩзыкъ словѣньскъ" + }, + "om": {"name": "Oromo", "nativeName": "Afaan Oromoo"}, + "or": {"name": "Oriya", "nativeName": "ଓଡ଼ିଆ"}, + "os": {"name": "Ossetian, Ossetic", "nativeName": "ирон æвзаг"}, + "pa": {"name": "Panjabi, Punjabi", "nativeName": "ਪੰਜਾਬੀ, پنجابی‎"}, + "pi": {"name": "Pāli", "nativeName": "पाऴि"}, + "fa": {"name": "Persian", "nativeName": "فارسی"}, + "pl": {"name": "Polish", "nativeName": "polski"}, + "ps": {"name": "Pashto, Pushto", "nativeName": "پښتو"}, + "pt": {"name": "Portuguese", "nativeName": "Português"}, + "qu": {"name": "Quechua", "nativeName": "Runa Simi, Kichwa"}, + "rm": {"name": "Romansh", "nativeName": "rumantsch grischun"}, + "rn": {"name": "Kirundi", "nativeName": "kiRundi"}, + "ro": {"name": "Romanian, Moldavian, Moldovan", "nativeName": "română"}, + "ru": {"name": "Russian", "nativeName": "русский язык"}, + "sa": {"name": "Sanskrit (Saṁskṛta)", "nativeName": "संस्कृतम्"}, + "sc": {"name": "Sardinian", "nativeName": "sardu"}, + "sd": {"name": "Sindhi", "nativeName": "सिन्धी, سنڌي، سندھی‎"}, + "se": {"name": "Northern Sami", "nativeName": "Davvisámegiella"}, + "sm": {"name": "Samoan", "nativeName": "gagana faa Samoa"}, + "sg": {"name": "Sango", "nativeName": "yângâ tî sängö"}, + "sr": {"name": "Serbian", "nativeName": "српски језик"}, + "gd": {"name": "Scottish Gaelic; Gaelic", "nativeName": "Gàidhlig"}, + "sn": {"name": "Shona", "nativeName": "chiShona"}, + "si": {"name": "Sinhala, Sinhalese", "nativeName": "සිංහල"}, + "sk": {"name": "Slovak", "nativeName": "slovenčina"}, + "sl": {"name": "Slovene", "nativeName": "slovenščina"}, + "so": {"name": "Somali", "nativeName": "Soomaaliga, af Soomaali"}, + "st": {"name": "Southern Sotho", "nativeName": "Sesotho"}, + "es": {"name": "Spanish; Castilian", "nativeName": "español, castellano"}, + "su": {"name": "Sundanese", "nativeName": "Basa Sunda"}, + "sw": {"name": "Swahili", "nativeName": "Kiswahili"}, + "ss": {"name": "Swati", "nativeName": "SiSwati"}, + "sv": {"name": "Swedish", "nativeName": "svenska"}, + "ta": {"name": "Tamil", "nativeName": "தமிழ்"}, + "te": {"name": "Telugu", "nativeName": "తెలుగు"}, + "tg": {"name": "Tajik", "nativeName": "тоҷикӣ, toğikī, تاجیکی‎"}, + "th": {"name": "Thai", "nativeName": "ไทย"}, + "ti": {"name": "Tigrinya", "nativeName": "ትግርኛ"}, + "bo": { + "name": "Tibetan Standard, Tibetan, Central", + "nativeName": "བོད་ཡིག" + }, + "tk": {"name": "Turkmen", "nativeName": "Türkmen, Түркмен"}, + "tl": {"name": "Tagalog", "nativeName": "Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔"}, + "tn": {"name": "Tswana", "nativeName": "Setswana"}, + "to": {"name": "Tonga (Tonga Islands)", "nativeName": "faka Tonga"}, + "tr": {"name": "Turkish", "nativeName": "Türkçe"}, + "ts": {"name": "Tsonga", "nativeName": "Xitsonga"}, + "tt": {"name": "Tatar", "nativeName": "татарча, tatarça, تاتارچا‎"}, + "tw": {"name": "Twi", "nativeName": "Twi"}, + "ty": {"name": "Tahitian", "nativeName": "Reo Tahiti"}, + "ug": {"name": "Uighur, Uyghur", "nativeName": "Uyƣurqə, ئۇيغۇرچە‎"}, + "uk": {"name": "Ukrainian", "nativeName": "українська"}, + "ur": {"name": "Urdu", "nativeName": "اردو"}, + "uz": {"name": "Uzbek", "nativeName": "zbek, Ўзбек, أۇزبېك‎"}, + "ve": {"name": "Venda", "nativeName": "Tshivenḓa"}, + "vi": {"name": "Vietnamese", "nativeName": "Tiếng Việt"}, + "vo": {"name": "Volapük", "nativeName": "Volapük"}, + "wa": {"name": "Walloon", "nativeName": "Walon"}, + "cy": {"name": "Welsh", "nativeName": "Cymraeg"}, + "wo": {"name": "Wolof", "nativeName": "Wollof"}, + "fy": {"name": "Western Frisian", "nativeName": "Frysk"}, + "xh": {"name": "Xhosa", "nativeName": "isiXhosa"}, + "yi": {"name": "Yiddish", "nativeName": "ייִדיש"}, + "yo": {"name": "Yoruba", "nativeName": "Yorùbá"}, + "za": {"name": "Zhuang, Chuang", "nativeName": "Saɯ cueŋƅ, Saw cuengh"} + }; + + + Map? getlanguageDisplayName(String key) { + if (isoLangs.containsKey(key)) { + return isoLangs[key]; + } else { + throw Exception("Language key incorrect"); + } + } diff --git a/lib/settings/data/general_settings_schema.dart b/lib/settings/data/general_settings_schema.dart index cf335381..cd9e5925 100644 --- a/lib/settings/data/general_settings_schema.dart +++ b/lib/settings/data/general_settings_schema.dart @@ -1,10 +1,14 @@ +import 'dart:io'; + import 'package:app_settings/app_settings.dart'; import 'package:auto_start_flutter/auto_start_flutter.dart'; +import 'package:clock_app/app.dart'; import 'package:clock_app/clock/types/time.dart'; import 'package:clock_app/common/utils/list_storage.dart'; import 'package:clock_app/common/utils/snackbar.dart'; import 'package:clock_app/common/utils/time_format.dart'; import 'package:clock_app/icons/flux_icons.dart'; +import 'package:clock_app/l10n/language_local.dart'; import 'package:clock_app/settings/screens/ringtones_screen.dart'; import 'package:clock_app/settings/screens/vendor_list_screen.dart'; import 'package:clock_app/settings/types/setting.dart'; @@ -15,6 +19,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:locale_names/locale_names.dart'; SelectSettingOption _getDateSettingOption(String format) { return SelectSettingOption( @@ -30,6 +36,12 @@ final timeFormatOptions = [ SettingGroup generalSettingsSchema = SettingGroup( "General", [ + SelectSetting("Language",[SelectSettingOption("System", Locale(Platform.localeName)), ...AppLocalizations.supportedLocales.map((locale) { + return SelectSettingOption(Locale.fromSubtags( + languageCode: locale.languageCode, scriptCode: locale.scriptCode, countryCode: locale.countryCode).nativeDisplayLanguage, locale); + })], onChange: (context, index) { + App.refreshTheme(context); + }), SettingGroup("Display", [ SelectSetting( "Date Format", diff --git a/pubspec.lock b/pubspec.lock index 7746049e..e786a49e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -592,6 +592,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + locale_names: + dependency: "direct main" + description: + name: locale_names + sha256: "7a89ca54072f4f13d0f5df5a9ba69337554bf2fd057d1dd2a238898f3f159374" + url: "https://pub.dev" + source: hosted + version: "1.1.1" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 23839eaf..878b8c03 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -65,6 +65,7 @@ dependencies: watcher: ^1.1.0 dynamic_color: ^1.7.0 material_color_utilities: ^0.8.0 + locale_names: ^1.1.1 dev_dependencies: flutter_test: From e1e6ba989ee1353109cb50fe30f03a7482dce495 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Wed, 27 Mar 2024 15:25:45 +0000 Subject: [PATCH 006/112] Translated using Weblate (English) Currently translated at 100.0% (12 of 12 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 28fc9274..1fcf4f74 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -16,5 +16,19 @@ "description": "Title of the stopwatch screen" }, "generalSettingGroup": "General", - "appearanceSettingGroup": "Appearance" + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Appearance", + "@appearanceSettingGroup": {}, + "accessibilitySettingGroup": "Accessibility", + "@accessibilitySettingGroup": {}, + "backupSettingGroup": "Backup", + "@backupSettingGroup": {}, + "developerOptionsSettingGroup": "Developer Options", + "@developerOptionsSettingGroup": {}, + "aboutSettingGroup": "About", + "@aboutSettingGroup": {}, + "restoreSettingGroup": "Restore default values", + "@restoreSettingGroup": {}, + "displaySettingGroup": "Display", + "@displaySettingGroup": {} } From 25e19eabf236d6135974eb9e2cf68c5967395034 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 27 Mar 2024 15:26:50 +0000 Subject: [PATCH 007/112] Translated using Weblate (Spanish) Currently translated at 100.0% (12 of 12 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index e4c684ab..b0bfe1aa 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1,8 +1,26 @@ { - "clockTitle": "Reloj", - "alarmTitle": "Alarma", - "timerTitle": "Temporizador", - "stopwatchTitle": "Cronómetro", - "generalSettingGroup": "General", - "appearanceSettingGroup": "Apariencia" + "clockTitle": "Reloj", + "@clockTitle": {}, + "alarmTitle": "Alarma", + "@alarmTitle": {}, + "timerTitle": "Temporizador", + "@timerTitle": {}, + "stopwatchTitle": "Cronómetro", + "@stopwatchTitle": {}, + "generalSettingGroup": "General", + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Apariencia", + "@appearanceSettingGroup": {}, + "accessibilitySettingGroup": "Accesibilidad", + "@accessibilitySettingGroup": {}, + "backupSettingGroup": "Copia de seguridad", + "@backupSettingGroup": {}, + "developerOptionsSettingGroup": "Opciones de desarrollador", + "@developerOptionsSettingGroup": {}, + "aboutSettingGroup": "Acerca de", + "@aboutSettingGroup": {}, + "restoreSettingGroup": "Restaurar a los valores predeterminados", + "@restoreSettingGroup": {}, + "displaySettingGroup": "Pantalla", + "@displaySettingGroup": {} } From d5d770db5a2257eaf7994c7b1b34217b215e7742 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Wed, 27 Mar 2024 15:41:50 +0000 Subject: [PATCH 008/112] Translated using Weblate (English) Currently translated at 100.0% (41 of 41 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 60 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1fcf4f74..de296b76 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -30,5 +30,63 @@ "restoreSettingGroup": "Restore default values", "@restoreSettingGroup": {}, "displaySettingGroup": "Display", - "@displaySettingGroup": {} + "@displaySettingGroup": {}, + "reliabilitySettingGroup": "Reliability", + "@reliabilitySettingGroup": {}, + "colorsSettingGroup": "Colors", + "@colorsSettingGroup": {}, + "styleSettingGroup": "Style", + "@styleSettingGroup": {}, + "useMaterialYouColorSetting": "Use Material You", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "Brightness", + "@materialBrightnessSetting": {}, + "overrideAccentSetting": "Override Accent Color", + "@overrideAccentSetting": {}, + "useMaterialStyleSetting": "Use Material Style", + "@useMaterialStyleSetting": {}, + "styleThemeSetting": "Style Theme", + "@styleThemeSetting": {}, + "systemDarkModeSetting": "System Dark Mode", + "@systemDarkModeSetting": {}, + "colorSchemeSetting": "Color Scheme", + "@colorSchemeSetting": {}, + "darkColorSchemeSetting": "Dark Color Scheme", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "Clock", + "@clockSettingGroup": {}, + "timerSettingGroup": "Timer", + "@timerSettingGroup": {}, + "stopwatchSettingGroup": "Stopwatch", + "@stopwatchSettingGroup": {}, + "generalSettingGroupDescription": "Set app wide settings like time format", + "@generalSettingGroupDescription": {}, + "appearanceSettingGroupDescription": "Set themes, colors and change layout", + "@appearanceSettingGroupDescription": {}, + "backupSettingGroupDescription": "Export or Import your settings locally", + "@backupSettingGroupDescription": {}, + "selectTime": "Select Time", + "@selectTime": {}, + "cancelButton": "Cancel", + "@cancelButton": {}, + "customizeButton": "Customize", + "@customizeButton": {}, + "saveButton": "Save Button", + "@saveButton": {}, + "labelField": "Label", + "@labelField": {}, + "labelFieldPlaceholder": "Add a label", + "@labelFieldPlaceholder": {}, + "alarmScheduleSettingGroup": "Schedule", + "@alarmScheduleSettingGroup": {}, + "scheduleTypeField": "Type", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "Once", + "@scheduleTypeOnce": {}, + "scheduleTypeDaily": "Daily", + "@scheduleTypeDaily": {}, + "scheduleTypeOnceDescription": "Will ring at the next occurrence of the time", + "@scheduleTypeOnceDescription": {}, + "scheduleTypeDailyDescription": "Will ring every day", + "@scheduleTypeDailyDescription": {} } From 7fb9aaeddb1347800b226177bfffede269393891 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 27 Mar 2024 15:47:35 +0000 Subject: [PATCH 009/112] Translated using Weblate (Spanish) Currently translated at 95.1% (39 of 41 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 56 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index b0bfe1aa..8577b944 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -22,5 +22,59 @@ "restoreSettingGroup": "Restaurar a los valores predeterminados", "@restoreSettingGroup": {}, "displaySettingGroup": "Pantalla", - "@displaySettingGroup": {} + "@displaySettingGroup": {}, + "reliabilitySettingGroup": "Fiabilidad", + "@reliabilitySettingGroup": {}, + "colorsSettingGroup": "Colores", + "@colorsSettingGroup": {}, + "styleSettingGroup": "Estilo", + "@styleSettingGroup": {}, + "useMaterialYouColorSetting": "Utilizar Material You", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "Brillo", + "@materialBrightnessSetting": {}, + "overrideAccentSetting": "Anular color acentuado", + "@overrideAccentSetting": {}, + "useMaterialStyleSetting": "Utilizar Material Style", + "@useMaterialStyleSetting": {}, + "styleThemeSetting": "Estilo del tema", + "@styleThemeSetting": {}, + "systemDarkModeSetting": "Modo oscuro del sistema", + "@systemDarkModeSetting": {}, + "colorSchemeSetting": "Esquema de colores", + "@colorSchemeSetting": {}, + "darkColorSchemeSetting": "Esquema de colores oscuros", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "Reloj", + "@clockSettingGroup": {}, + "timerSettingGroup": "Temporizador", + "@timerSettingGroup": {}, + "stopwatchSettingGroup": "Cronómetro", + "@stopwatchSettingGroup": {}, + "generalSettingGroupDescription": "Configurar los ajustes de la aplicación, como el formato de la hora", + "@generalSettingGroupDescription": {}, + "appearanceSettingGroupDescription": "Establecer temas, colores y cambiar el diseño", + "@appearanceSettingGroupDescription": {}, + "backupSettingGroupDescription": "Exporta o importa tu configuración localmente", + "@backupSettingGroupDescription": {}, + "selectTime": "Seleccione la hora", + "@selectTime": {}, + "cancelButton": "Cancelar", + "@cancelButton": {}, + "customizeButton": "Personalizar", + "@customizeButton": {}, + "saveButton": "Botón guardar", + "@saveButton": {}, + "labelField": "Etiqueta", + "@labelField": {}, + "labelFieldPlaceholder": "Etiqueta", + "@labelFieldPlaceholder": {}, + "alarmScheduleSettingGroup": "Programar", + "@alarmScheduleSettingGroup": {}, + "scheduleTypeField": "Tipo", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "Una vez", + "@scheduleTypeOnce": {}, + "scheduleTypeDaily": "Diariamente", + "@scheduleTypeDaily": {} } From 8e3c3fc1a9569c44062739293aed0574d0afb752 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 27 Mar 2024 16:03:37 +0000 Subject: [PATCH 010/112] Translated using Weblate (Spanish) Currently translated at 95.1% (39 of 41 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 8577b944..5c0cbb55 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -76,5 +76,7 @@ "scheduleTypeOnce": "Una vez", "@scheduleTypeOnce": {}, "scheduleTypeDaily": "Diariamente", - "@scheduleTypeDaily": {} + "@scheduleTypeDaily": {}, + "scheduleTypeOnceDescription": "Sonará a la siguiente hora fijada", + "@scheduleTypeOnceDescription": {} } From 52756cddb5103f3de721c3e22dd9c95fedf80073 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Wed, 27 Mar 2024 16:04:11 +0000 Subject: [PATCH 011/112] Translated using Weblate (English) Currently translated at 100.0% (46 of 46 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index de296b76..bf1bf9f0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -88,5 +88,15 @@ "scheduleTypeOnceDescription": "Will ring at the next occurrence of the time", "@scheduleTypeOnceDescription": {}, "scheduleTypeDailyDescription": "Will ring every day", - "@scheduleTypeDailyDescription": {} + "@scheduleTypeDailyDescription": {}, + "scheduleTypeWeek": "On Specified Week Days", + "@scheduleTypeWeek": {}, + "scheduleTypeWeekDescription": "Will repeat on the specified week days", + "@scheduleTypeWeekDescription": {}, + "scheduleTypeData": "On Specific Dates", + "@scheduleTypeData": {}, + "scheduleTypeRange": "Date Range", + "@scheduleTypeRange": {}, + "scheduleTypeDateDescription": "Will repeat on the specified dates", + "@scheduleTypeDateDescription": {} } From 53f876c73a14e1b4718f15e601fd04289ce03564 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 27 Mar 2024 16:04:06 +0000 Subject: [PATCH 012/112] Translated using Weblate (Spanish) Currently translated at 97.8% (45 of 46 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 5c0cbb55..04a0a5d7 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -67,7 +67,7 @@ "@saveButton": {}, "labelField": "Etiqueta", "@labelField": {}, - "labelFieldPlaceholder": "Etiqueta", + "labelFieldPlaceholder": "Añadir una etiqueta", "@labelFieldPlaceholder": {}, "alarmScheduleSettingGroup": "Programar", "@alarmScheduleSettingGroup": {}, @@ -78,5 +78,15 @@ "scheduleTypeDaily": "Diariamente", "@scheduleTypeDaily": {}, "scheduleTypeOnceDescription": "Sonará a la siguiente hora fijada", - "@scheduleTypeOnceDescription": {} + "@scheduleTypeOnceDescription": {}, + "scheduleTypeDailyDescription": "Sonará todos los días", + "@scheduleTypeDailyDescription": {}, + "scheduleTypeWeek": "En días de la semana especificados", + "@scheduleTypeWeek": {}, + "scheduleTypeWeekDescription": "Se repetirá los días de la semana especificados", + "@scheduleTypeWeekDescription": {}, + "scheduleTypeData": "Se repetirá en las fechas especificadas", + "@scheduleTypeData": {}, + "scheduleTypeRange": "Intervalo de fechas", + "@scheduleTypeRange": {} } From ef1366101105f00a90400015cb91db042491a260 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Wed, 27 Mar 2024 16:11:03 +0000 Subject: [PATCH 013/112] Translated using Weblate (English) Currently translated at 100.0% (69 of 69 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 48 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index bf1bf9f0..a637ed31 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -98,5 +98,51 @@ "scheduleTypeRange": "Date Range", "@scheduleTypeRange": {}, "scheduleTypeDateDescription": "Will repeat on the specified dates", - "@scheduleTypeDateDescription": {} + "@scheduleTypeDateDescription": {}, + "scheduleTypeRangeDescription": "Will repeat during the specified date range", + "@scheduleTypeRangeDescription": {}, + "soundSettingGroup": "Sound and Vibration", + "@soundSettingGroup": {}, + "settingGroupMore": "More", + "@settingGroupMore": {}, + "melodySetting": "Melody", + "@melodySetting": {}, + "vibrationSetting": "Vibration", + "@vibrationSetting": {}, + "audioChannelSetting": "Audio Channel", + "@audioChannelSetting": {}, + "volumeSetting": "Volume", + "@volumeSetting": {}, + "risingVolumeSetting": "Rising Volume", + "@risingVolumeSetting": {}, + "snoozeSettingGroup": "Snooze", + "@snoozeSettingGroup": {}, + "snoozeEnableSetting": "Enabled", + "@snoozeEnableSetting": {}, + "snoozeLengthSetting": "Length", + "@snoozeLengthSetting": {}, + "whileSnoozedSettingGroup": "While Snoozed", + "@whileSnoozedSettingGroup": {}, + "snoozePreventDisablingSetting": "Prevent Disabling", + "@snoozePreventDisablingSetting": {}, + "snoozePreventDeletion": "Prevent Deletion", + "@snoozePreventDeletion": {}, + "settings": "Settings", + "@settings": {}, + "tasksSetting": "Tasks", + "@tasksSetting": {}, + "noItemMessage": "No {items} added yet", + "@noItemMessage": {}, + "chooseTaskTitle": "Choose Task to Add", + "@chooseTaskTitle": {}, + "mathTask": "Math Problems", + "@mathTask": {}, + "retypeTask": "Retype Text", + "@retypeTask": {}, + "sequenceTask": "Sequence", + "@sequenceTask": {}, + "taskTryButton": "Try Out", + "@taskTryButton": {}, + "mathTaskDifficultySetting": "Difficulty", + "@mathTaskDifficultySetting": {} } From 239ec68c2d9dc16770b56c8392d52dd3bbe47fb4 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Thu, 28 Mar 2024 11:33:46 +0100 Subject: [PATCH 014/112] Added translation using Weblate (Russian) --- lib/l10n/app_ru.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_ru.arb diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_ru.arb @@ -0,0 +1 @@ +{} From bd59a9ed1ff959e7fec450863c0fc66243bc0284 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Thu, 28 Mar 2024 11:35:16 +0100 Subject: [PATCH 015/112] Added translation using Weblate (French) --- lib/l10n/app_fr.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_fr.arb diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_fr.arb @@ -0,0 +1 @@ +{} From ab2467423af8a316e8088eb8e5399f2d597238a0 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Thu, 28 Mar 2024 11:36:58 +0100 Subject: [PATCH 016/112] Added translation using Weblate (German) --- lib/l10n/app_de.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_de.arb diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_de.arb @@ -0,0 +1 @@ +{} From 668a813866366361b1ca590790c5fc29effb7094 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Wed, 27 Mar 2024 16:21:12 +0000 Subject: [PATCH 017/112] Translated using Weblate (English) Currently translated at 100.0% (87 of 87 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index a637ed31..f3db25b7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -144,5 +144,41 @@ "taskTryButton": "Try Out", "@taskTryButton": {}, "mathTaskDifficultySetting": "Difficulty", - "@mathTaskDifficultySetting": {} + "@mathTaskDifficultySetting": {}, + "retypeNumberChars": "Number of characters", + "@retypeNumberChars": {}, + "retypeIncludeNumSetting": "Include numbers", + "@retypeIncludeNumSetting": {}, + "retypeLowercaseSetting": "Include lowercase", + "@retypeLowercaseSetting": {}, + "sequenceLengthSetting": "Sequence length", + "@sequenceLengthSetting": {}, + "sequenceGridSizeSetting": "Grid size", + "@sequenceGridSizeSetting": {}, + "saveReminderAlert": "Do you want to leave without saving?", + "@saveReminderAlert": {}, + "yesButton": "Yes", + "@yesButton": {}, + "noButton": "No", + "@noButton": {}, + "noItemCreatedMessage": "No {items} created", + "@noItemCreatedMessage": {}, + "deleteButton": "Delete", + "@deleteButton": {}, + "duplicateButton": "Duplicate", + "@duplicateButton": {}, + "skipAlarmButton": "Skip Next Alarm", + "@skipAlarmButton": {}, + "allFilter": "All", + "@allFilter": {}, + "todayFilter": "Today", + "@todayFilter": {}, + "tomorrowFilter": "Tomorrow", + "@tomorrowFilter": {}, + "snoozedFilter": "Snoozed", + "@snoozedFilter": {}, + "disabledFilter": "Disabled", + "@disabledFilter": {}, + "completedFilter": "Completed", + "@completedFilter": {} } From 98f21e240f005d1f3fd0f7eece6928f2bcba0a73 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 27 Mar 2024 16:20:51 +0000 Subject: [PATCH 018/112] Translated using Weblate (Spanish) Currently translated at 96.5% (84 of 87 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 82 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 04a0a5d7..2a49dc59 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -85,8 +85,86 @@ "@scheduleTypeWeek": {}, "scheduleTypeWeekDescription": "Se repetirá los días de la semana especificados", "@scheduleTypeWeekDescription": {}, - "scheduleTypeData": "Se repetirá en las fechas especificadas", + "scheduleTypeData": "En fechas concretas", "@scheduleTypeData": {}, "scheduleTypeRange": "Intervalo de fechas", - "@scheduleTypeRange": {} + "@scheduleTypeRange": {}, + "scheduleTypeDateDescription": "Se repetirá en las fechas especificadas", + "@scheduleTypeDateDescription": {}, + "scheduleTypeRangeDescription": "Se repetirá durante el intervalo de fechas especificado", + "@scheduleTypeRangeDescription": {}, + "soundSettingGroup": "Sonido y vibración", + "@soundSettingGroup": {}, + "settingGroupMore": "Más", + "@settingGroupMore": {}, + "melodySetting": "Melodía", + "@melodySetting": {}, + "vibrationSetting": "Vibración", + "@vibrationSetting": {}, + "audioChannelSetting": "Canal de audio", + "@audioChannelSetting": {}, + "volumeSetting": "Volumen", + "@volumeSetting": {}, + "risingVolumeSetting": "Volumen en aumento", + "@risingVolumeSetting": {}, + "snoozeSettingGroup": "Repetir la alarma", + "@snoozeSettingGroup": {}, + "snoozeEnableSetting": "Activado", + "@snoozeEnableSetting": {}, + "snoozeLengthSetting": "Duración", + "@snoozeLengthSetting": {}, + "snoozePreventDisablingSetting": "Evitar la desactivación", + "@snoozePreventDisablingSetting": {}, + "snoozePreventDeletion": "Evitar la eliminación", + "@snoozePreventDeletion": {}, + "settings": "Ajustes", + "@settings": {}, + "tasksSetting": "Tareas", + "@tasksSetting": {}, + "noItemMessage": "No hay {items} añadidos aún", + "@noItemMessage": {}, + "chooseTaskTitle": "Seleccione la tarea que desea añadir", + "@chooseTaskTitle": {}, + "retypeTask": "Repetir el texto", + "@retypeTask": {}, + "sequenceTask": "Secuencia", + "@sequenceTask": {}, + "taskTryButton": "Probar", + "@taskTryButton": {}, + "mathTaskDifficultySetting": "Dificultad", + "@mathTaskDifficultySetting": {}, + "retypeNumberChars": "Número de caracteres", + "@retypeNumberChars": {}, + "retypeIncludeNumSetting": "Números incluidos", + "@retypeIncludeNumSetting": {}, + "retypeLowercaseSetting": "Incluir minúsculas", + "@retypeLowercaseSetting": {}, + "sequenceLengthSetting": "Duración de la secuencia", + "@sequenceLengthSetting": {}, + "sequenceGridSizeSetting": "Tamaño de la cuadrícula", + "@sequenceGridSizeSetting": {}, + "saveReminderAlert": "¿Quieres salir sin guardar?", + "@saveReminderAlert": {}, + "yesButton": "Sí", + "@yesButton": {}, + "noButton": "No", + "@noButton": {}, + "noItemCreatedMessage": "No se han creado {items}", + "@noItemCreatedMessage": {}, + "deleteButton": "Borrar", + "@deleteButton": {}, + "duplicateButton": "Duplicar", + "@duplicateButton": {}, + "skipAlarmButton": "Omitir la siguiente alarma", + "@skipAlarmButton": {}, + "todayFilter": "Hoy", + "@todayFilter": {}, + "tomorrowFilter": "Mañana", + "@tomorrowFilter": {}, + "disabledFilter": "Desactivar", + "@disabledFilter": {}, + "completedFilter": "Terminada", + "@completedFilter": {}, + "allFilter": "Todas", + "@allFilter": {} } From 422b72b94dc75b93b9fc23d490f410a2e17ca9d5 Mon Sep 17 00:00:00 2001 From: Languages add-on Date: Thu, 28 Mar 2024 11:40:38 +0100 Subject: [PATCH 019/112] Added translation using Weblate (Urdu) --- lib/l10n/app_ur.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_ur.arb diff --git a/lib/l10n/app_ur.arb b/lib/l10n/app_ur.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_ur.arb @@ -0,0 +1 @@ +{} From ad2cecb3f8f572debf08a09f8946ac8c247a712a Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Thu, 28 Mar 2024 11:42:31 +0100 Subject: [PATCH 020/112] Added translation using Weblate (Italian) --- lib/l10n/app_it.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_it.arb diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_it.arb @@ -0,0 +1 @@ +{} From ce5e230601a7607a0be3433e3d24686aecf6768c Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Thu, 28 Mar 2024 14:53:52 +0100 Subject: [PATCH 021/112] Added translation using Weblate (Portuguese) --- lib/l10n/app_pt.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_pt.arb diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_pt.arb @@ -0,0 +1 @@ +{} From ca0284ecbadced3286c37fd6e8e9c0c7fce84573 Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Thu, 28 Mar 2024 13:54:09 +0000 Subject: [PATCH 022/112] Translated using Weblate (Portuguese) Currently translated at 4.5% (4 of 87 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 0967ef42..70ce51c2 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1 +1,18 @@ -{} +{ + "alarmTitle": "Alarme", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "stopwatchTitle": "Cronómetro", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "clockTitle": "Relógio", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "timerTitle": "Temporizador", + "@timerTitle": { + "description": "Title of the timer screen" + } +} From fb337a0eb58b38e89e05d67b0fa3c3803c7352a2 Mon Sep 17 00:00:00 2001 From: Languages add-on Date: Thu, 28 Mar 2024 14:54:51 +0100 Subject: [PATCH 023/112] =?UTF-8?q?Added=20translation=20using=20Weblate?= =?UTF-8?q?=20(Norwegian=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/l10n/app_nb_NO.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_nb_NO.arb diff --git a/lib/l10n/app_nb_NO.arb b/lib/l10n/app_nb_NO.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_nb_NO.arb @@ -0,0 +1 @@ +{} From 1f502bbb1b4fcfd220544a5e37b6723d14a78bd9 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Thu, 28 Mar 2024 15:24:12 +0000 Subject: [PATCH 024/112] Translated using Weblate (Spanish) Currently translated at 100.0% (87 of 87 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 2a49dc59..c59adf2e 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -166,5 +166,11 @@ "completedFilter": "Terminada", "@completedFilter": {}, "allFilter": "Todas", - "@allFilter": {} + "@allFilter": {}, + "whileSnoozedSettingGroup": "Mientras estás dormido", + "@whileSnoozedSettingGroup": {}, + "mathTask": "Problemas matemáticos", + "@mathTask": {}, + "snoozedFilter": "Pospuesto", + "@snoozedFilter": {} } From 7bb2bd4d955529e1e4e392dc31c28e7a15c6c220 Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Thu, 28 Mar 2024 13:55:10 +0000 Subject: [PATCH 025/112] Translated using Weblate (Portuguese) Currently translated at 100.0% (87 of 87 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 164 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 70ce51c2..a4dda82b 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -14,5 +14,167 @@ "timerTitle": "Temporizador", "@timerTitle": { "description": "Title of the timer screen" - } + }, + "backupSettingGroup": "Backup", + "@backupSettingGroup": {}, + "developerOptionsSettingGroup": "Opções de programador", + "@developerOptionsSettingGroup": {}, + "aboutSettingGroup": "Acerca", + "@aboutSettingGroup": {}, + "restoreSettingGroup": "Repor valores padrão", + "@restoreSettingGroup": {}, + "displaySettingGroup": "Exibição", + "@displaySettingGroup": {}, + "colorsSettingGroup": "Cores", + "@colorsSettingGroup": {}, + "styleSettingGroup": "Estilo", + "@styleSettingGroup": {}, + "useMaterialYouColorSetting": "Material You", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "Brilho", + "@materialBrightnessSetting": {}, + "overrideAccentSetting": "Substituir cor de destaque", + "@overrideAccentSetting": {}, + "useMaterialStyleSetting": "Material Style", + "@useMaterialStyleSetting": {}, + "styleThemeSetting": "Estilo do tema", + "@styleThemeSetting": {}, + "systemDarkModeSetting": "Modo escuro", + "@systemDarkModeSetting": {}, + "colorSchemeSetting": "Esquema de cores", + "@colorSchemeSetting": {}, + "customizeButton": "Personalizar", + "@customizeButton": {}, + "saveButton": "Botão \"Guardar\"", + "@saveButton": {}, + "labelField": "Texto", + "@labelField": {}, + "labelFieldPlaceholder": "Adicionar texto", + "@labelFieldPlaceholder": {}, + "alarmScheduleSettingGroup": "Agendar", + "@alarmScheduleSettingGroup": {}, + "scheduleTypeField": "Tipo", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "Uma vez", + "@scheduleTypeOnce": {}, + "scheduleTypeDaily": "Diariamente", + "@scheduleTypeDaily": {}, + "scheduleTypeRange": "Intervalo de tempo", + "@scheduleTypeRange": {}, + "reliabilitySettingGroup": "Fiabilidade", + "@reliabilitySettingGroup": {}, + "generalSettingGroupDescription": "Definições globais da aplicação", + "@generalSettingGroupDescription": {}, + "appearanceSettingGroupDescription": "Temas, cores e esquemas", + "@appearanceSettingGroupDescription": {}, + "backupSettingGroupDescription": "Exportar ou importar as definições", + "@backupSettingGroupDescription": {}, + "selectTime": "Definir hora", + "@selectTime": {}, + "scheduleTypeOnceDescription": "Será ativado na próxima ocorrência de hora", + "@scheduleTypeOnceDescription": {}, + "scheduleTypeData": "Datas específicas", + "@scheduleTypeData": {}, + "settingGroupMore": "Mais", + "@settingGroupMore": {}, + "melodySetting": "Melodia", + "@melodySetting": {}, + "vibrationSetting": "Vibração", + "@vibrationSetting": {}, + "audioChannelSetting": "Canal de áudio", + "@audioChannelSetting": {}, + "volumeSetting": "Volume", + "@volumeSetting": {}, + "risingVolumeSetting": "Aumento gradual", + "@risingVolumeSetting": {}, + "snoozeSettingGroup": "Snooze", + "@snoozeSettingGroup": {}, + "snoozeEnableSetting": "Ligado", + "@snoozeEnableSetting": {}, + "settings": "Definições", + "@settings": {}, + "tasksSetting": "Tarefas", + "@tasksSetting": {}, + "snoozeLengthSetting": "Duração", + "@snoozeLengthSetting": {}, + "snoozePreventDisablingSetting": "Impedir desativação", + "@snoozePreventDisablingSetting": {}, + "snoozePreventDeletion": "Impedir eliminação", + "@snoozePreventDeletion": {}, + "chooseTaskTitle": "Escolha o tipo de tarefa", + "@chooseTaskTitle": {}, + "mathTask": "Matemática", + "@mathTask": {}, + "retypeTask": "Escrever texto", + "@retypeTask": {}, + "sequenceTask": "Sequência", + "@sequenceTask": {}, + "taskTryButton": "Testar", + "@taskTryButton": {}, + "mathTaskDifficultySetting": "Dificuldade", + "@mathTaskDifficultySetting": {}, + "retypeNumberChars": "Número de caracteres", + "@retypeNumberChars": {}, + "retypeIncludeNumSetting": "Incluir números", + "@retypeIncludeNumSetting": {}, + "retypeLowercaseSetting": "Incluir minúsculas", + "@retypeLowercaseSetting": {}, + "whileSnoozedSettingGroup": "Em snooze", + "@whileSnoozedSettingGroup": {}, + "soundSettingGroup": "Som e vibração", + "@soundSettingGroup": {}, + "generalSettingGroup": "Geral", + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Aparência", + "@appearanceSettingGroup": {}, + "accessibilitySettingGroup": "Acessibilidade", + "@accessibilitySettingGroup": {}, + "darkColorSchemeSetting": "Cor escura", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "Relógio", + "@clockSettingGroup": {}, + "timerSettingGroup": "Temporizador", + "@timerSettingGroup": {}, + "stopwatchSettingGroup": "Cronómetro", + "@stopwatchSettingGroup": {}, + "cancelButton": "Cancelar", + "@cancelButton": {}, + "sequenceLengthSetting": "Tamanho da sequência", + "@sequenceLengthSetting": {}, + "sequenceGridSizeSetting": "Tamanho da grelha", + "@sequenceGridSizeSetting": {}, + "saveReminderAlert": "Deseja sair sem guardar as alterações?", + "@saveReminderAlert": {}, + "scheduleTypeDailyDescription": "Será ativado todos os dias", + "@scheduleTypeDailyDescription": {}, + "yesButton": "Sim", + "@yesButton": {}, + "deleteButton": "Eliminar", + "@deleteButton": {}, + "noButton": "Não", + "@noButton": {}, + "duplicateButton": "Duplicar", + "@duplicateButton": {}, + "skipAlarmButton": "Ignorar próximo alarme", + "@skipAlarmButton": {}, + "allFilter": "Tudo", + "@allFilter": {}, + "todayFilter": "Hoje", + "@todayFilter": {}, + "tomorrowFilter": "Amanhã", + "@tomorrowFilter": {}, + "snoozedFilter": "Snoozed", + "@snoozedFilter": {}, + "disabledFilter": "Desligado", + "@disabledFilter": {}, + "completedFilter": "Terminado", + "@completedFilter": {}, + "scheduleTypeWeek": "Em dias específicos", + "@scheduleTypeWeek": {}, + "scheduleTypeWeekDescription": "Será ativado em dias específicos", + "@scheduleTypeWeekDescription": {}, + "scheduleTypeDateDescription": "Será ativado nas datas especificadas", + "@scheduleTypeDateDescription": {}, + "scheduleTypeRangeDescription": "Será ativado durante o intervalo especificado", + "@scheduleTypeRangeDescription": {} } From 8330dd155c365926e290d2a4a4622a12e9f3bf89 Mon Sep 17 00:00:00 2001 From: Rick Phaerom Date: Thu, 28 Mar 2024 22:35:07 +0000 Subject: [PATCH 026/112] Translated using Weblate (Portuguese) Currently translated at 100.0% (87 of 87 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index a4dda82b..8b397177 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -176,5 +176,9 @@ "scheduleTypeDateDescription": "Será ativado nas datas especificadas", "@scheduleTypeDateDescription": {}, "scheduleTypeRangeDescription": "Será ativado durante o intervalo especificado", - "@scheduleTypeRangeDescription": {} + "@scheduleTypeRangeDescription": {}, + "noItemMessage": "Nenhum {item} adicionado ainda", + "@noItemMessage": {}, + "noItemCreatedMessage": "Sem {itens} criados", + "@noItemCreatedMessage": {} } From 4f153af2f8e4680d7a98e3734bd1a8bd1911b9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Fri, 29 Mar 2024 03:48:50 +0000 Subject: [PATCH 027/112] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegi?= =?UTF-8?q?an=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 42.5% (37 of 87 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/nb_NO/ --- lib/l10n/app_nb_NO.arb | 85 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_nb_NO.arb b/lib/l10n/app_nb_NO.arb index 0967ef42..496a261f 100644 --- a/lib/l10n/app_nb_NO.arb +++ b/lib/l10n/app_nb_NO.arb @@ -1 +1,84 @@ -{} +{ + "timerTitle": "Tidsur", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "colorsSettingGroup": "Farger", + "@colorsSettingGroup": {}, + "styleSettingGroup": "Stil", + "@styleSettingGroup": {}, + "stopwatchTitle": "Stoppeklokke", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "generalSettingGroup": "Generelt", + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Utseende", + "@appearanceSettingGroup": {}, + "accessibilitySettingGroup": "Tilgjengelighet", + "@accessibilitySettingGroup": {}, + "developerOptionsSettingGroup": "Utvikleralternativer", + "@developerOptionsSettingGroup": {}, + "aboutSettingGroup": "Om", + "@aboutSettingGroup": {}, + "clockSettingGroup": "Klokke", + "@clockSettingGroup": {}, + "timerSettingGroup": "Tidsur", + "@timerSettingGroup": {}, + "stopwatchSettingGroup": "Stoppeklokke", + "@stopwatchSettingGroup": {}, + "skipAlarmButton": "Hopp over neste alarm", + "@skipAlarmButton": {}, + "allFilter": "Alle", + "@allFilter": {}, + "todayFilter": "I dag", + "@todayFilter": {}, + "tomorrowFilter": "I morgen", + "@tomorrowFilter": {}, + "clockTitle": "Klokke", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "materialBrightnessSetting": "Lysstyrke", + "@materialBrightnessSetting": {}, + "tasksSetting": "Gjøremål", + "@tasksSetting": {}, + "deleteButton": "Slett", + "@deleteButton": {}, + "alarmTitle": "Alarm", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "overrideAccentSetting": "Overstyr kontrastfarge", + "@overrideAccentSetting": {}, + "settings": "Innstillinger", + "@settings": {}, + "selectTime": "Velg tid", + "@selectTime": {}, + "cancelButton": "Avbryt", + "@cancelButton": {}, + "snoozePreventDeletion": "Forhindre sletting", + "@snoozePreventDeletion": {}, + "customizeButton": "Tilpass", + "@customizeButton": {}, + "labelField": "Etikett", + "@labelField": {}, + "labelFieldPlaceholder": "Legg til etikett", + "@labelFieldPlaceholder": {}, + "vibrationSetting": "Vibrasjon", + "@vibrationSetting": {}, + "scheduleTypeField": "Type", + "@scheduleTypeField": {}, + "volumeSetting": "Lydstyrke", + "@volumeSetting": {}, + "scheduleTypeOnce": "Enkeltstående", + "@scheduleTypeOnce": {}, + "scheduleTypeDaily": "Daglig", + "@scheduleTypeDaily": {}, + "audioChannelSetting": "Lydkanal", + "@audioChannelSetting": {}, + "risingVolumeSetting": "Økende lydstyrke", + "@risingVolumeSetting": {}, + "snoozeLengthSetting": "Lengde", + "@snoozeLengthSetting": {} +} From bcef7d4c235e34c113395d63b44bbb35602df52c Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Fri, 29 Mar 2024 10:15:11 +0000 Subject: [PATCH 028/112] Translated using Weblate (Portuguese) Currently translated at 100.0% (87 of 87 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 8b397177..5d8ce9df 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -177,8 +177,8 @@ "@scheduleTypeDateDescription": {}, "scheduleTypeRangeDescription": "Será ativado durante o intervalo especificado", "@scheduleTypeRangeDescription": {}, - "noItemMessage": "Nenhum {item} adicionado ainda", + "noItemMessage": "Ainda não adicionou {items}", "@noItemMessage": {}, - "noItemCreatedMessage": "Sem {itens} criados", + "noItemCreatedMessage": "{items} não criadas", "@noItemCreatedMessage": {} } From 2ba77b5e8a839c657b9a15bd3877e63452ced8db Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Sun, 31 Mar 2024 18:05:35 +0000 Subject: [PATCH 029/112] Translated using Weblate (English) Currently translated at 100.0% (103 of 103 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f3db25b7..b51486f1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -180,5 +180,37 @@ "disabledFilter": "Disabled", "@disabledFilter": {}, "completedFilter": "Completed", - "@completedFilter": {} + "@completedFilter": {}, + "skippingDescriptionSuffix": "(skipping next occurrence)", + "@skippingDescriptionSuffix": {}, + "alarmDescriptionSnooze": "Snoozed until {date}", + "@alarmDescriptionSnooze": {}, + "alarmDescriptionFinished": "No future dates", + "@alarmDescriptionFinished": {}, + "alarmDescriptionNotScheduled": "Not scheduled", + "@alarmDescriptionNotScheduled": {}, + "alarmDescriptionToday": "Just today", + "@alarmDescriptionToday": {}, + "alarmDescriptionTomorrow": "Just tomorrow", + "@alarmDescriptionTomorrow": {}, + "alarmDescriptionEveryDay": "Every day", + "@alarmDescriptionEveryDay": {}, + "alarmDescriptionWeekend": "Every weekend", + "@alarmDescriptionWeekend": {}, + "stopwatchPrevious": "Previous", + "@stopwatchPrevious": {}, + "alarmDescriptionWeekday": "Every weekday", + "@alarmDescriptionWeekday": {}, + "stopwatchFastest": "Fastest", + "@stopwatchFastest": {}, + "alarmDescriptionDays": "On {days}", + "@alarmDescriptionDays": {}, + "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly}} from {startDate} to {endDate}", + "@alarmDescriptionRange": {}, + "stopwatchSlowest": "Slowest", + "@stopwatchSlowest": {}, + "alarmDescriptionDates": "On {date}{count, plural, =0{} =1{ and 1 other date} other{ and {count} other dates}}", + "@alarmDescriptionDates": {}, + "stopwatchAverage": "Average", + "@stopwatchAverage": {} } From 8550c6d13e25399691fba3f6c6442dcc2a1de7fa Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 31 Mar 2024 21:10:03 +0000 Subject: [PATCH 030/112] Translated using Weblate (Spanish) Currently translated at 100.0% (103 of 103 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index c59adf2e..a5232d33 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -172,5 +172,37 @@ "mathTask": "Problemas matemáticos", "@mathTask": {}, "snoozedFilter": "Pospuesto", - "@snoozedFilter": {} + "@snoozedFilter": {}, + "skippingDescriptionSuffix": "(omitir la siguiente aparición)", + "@skippingDescriptionSuffix": {}, + "alarmDescriptionSnooze": "Posponer hasta {date}", + "@alarmDescriptionSnooze": {}, + "alarmDescriptionFinished": "Sin fechas futuras", + "@alarmDescriptionFinished": {}, + "alarmDescriptionNotScheduled": "No programado", + "@alarmDescriptionNotScheduled": {}, + "alarmDescriptionToday": "Hoy mismo", + "@alarmDescriptionToday": {}, + "alarmDescriptionTomorrow": "Mañana mismo", + "@alarmDescriptionTomorrow": {}, + "alarmDescriptionEveryDay": "Cada día", + "@alarmDescriptionEveryDay": {}, + "alarmDescriptionWeekend": "Cada semana", + "@alarmDescriptionWeekend": {}, + "stopwatchPrevious": "Anterior", + "@stopwatchPrevious": {}, + "alarmDescriptionWeekday": "Cada día de la semana", + "@alarmDescriptionWeekday": {}, + "stopwatchFastest": "La más rápida", + "@stopwatchFastest": {}, + "alarmDescriptionDays": "En {days}", + "@alarmDescriptionDays": {}, + "stopwatchSlowest": "La más lenta", + "@stopwatchSlowest": {}, + "alarmDescriptionRange": "{interval, select, daily{A diario} weekly{Semanalmente}} desde {startDate} a {endDate}", + "@alarmDescriptionRange": {}, + "alarmDescriptionDates": "En {date}{count, plural, =0{} =1{ y otra fecha} other{ y {count} otras fechas}}", + "@alarmDescriptionDates": {}, + "stopwatchAverage": "Promedio", + "@stopwatchAverage": {} } From 49ac3eb747ecf812bd78293560e4c22c4ed37c66 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 2 Apr 2024 09:07:02 +0000 Subject: [PATCH 031/112] Translated using Weblate (French) Currently translated at 100.0% (85 of 85 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 181 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 0967ef42..effccdfe 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1 +1,180 @@ -{} +{ + "stopwatchTitle": "Chronomètre", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "colorsSettingGroup": "Couleurs", + "@colorsSettingGroup": {}, + "generalSettingGroupDescription": "Paramètres généraux de l'application tels que le format de l'heure", + "@generalSettingGroupDescription": {}, + "customizeButton": "Personnaliser", + "@customizeButton": {}, + "scheduleTypeDailyDescription": "Sonnera tous les jours", + "@scheduleTypeDailyDescription": {}, + "vibrationSetting": "Vibration", + "@vibrationSetting": {}, + "audioChannelSetting": "Canal audio", + "@audioChannelSetting": {}, + "systemDarkModeSetting": "Thème sombre du système", + "@systemDarkModeSetting": {}, + "clockTitle": "Horloge", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "alarmTitle": "Alarme", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "timerTitle": "Minuteur", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "generalSettingGroup": "Général", + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Apparence", + "@appearanceSettingGroup": {}, + "accessibilitySettingGroup": "Accessibilité", + "@accessibilitySettingGroup": {}, + "backupSettingGroup": "Sauvegarde", + "@backupSettingGroup": {}, + "developerOptionsSettingGroup": "Options pour les développeurs", + "@developerOptionsSettingGroup": {}, + "aboutSettingGroup": "À propos", + "@aboutSettingGroup": {}, + "restoreSettingGroup": "Restaurer les valeurs par défaut", + "@restoreSettingGroup": {}, + "displaySettingGroup": "Affichage", + "@displaySettingGroup": {}, + "styleSettingGroup": "Style", + "@styleSettingGroup": {}, + "useMaterialYouColorSetting": "Utiliser Material You", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "Luminosité", + "@materialBrightnessSetting": {}, + "overrideAccentSetting": "Écraser la couleur d'accentuation", + "@overrideAccentSetting": {}, + "useMaterialStyleSetting": "Utiliser le style Material", + "@useMaterialStyleSetting": {}, + "styleThemeSetting": "Thème du style", + "@styleThemeSetting": {}, + "colorSchemeSetting": "Schéma de couleur", + "@colorSchemeSetting": {}, + "darkColorSchemeSetting": "Schéma de couleur sombre", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "Horloge", + "@clockSettingGroup": {}, + "timerSettingGroup": "Minuteur", + "@timerSettingGroup": {}, + "stopwatchSettingGroup": "Chronomètre", + "@stopwatchSettingGroup": {}, + "appearanceSettingGroupDescription": "Modifiez le thème, les couleurs et la disposition", + "@appearanceSettingGroupDescription": {}, + "backupSettingGroupDescription": "Exportez ou importez vos paramètres", + "@backupSettingGroupDescription": {}, + "selectTime": "Sélectionner l'heure", + "@selectTime": {}, + "cancelButton": "Annuler", + "@cancelButton": {}, + "saveButton": "Bouton d'enregistrement", + "@saveButton": {}, + "labelField": "Nom", + "@labelField": {}, + "labelFieldPlaceholder": "Ajouter un nom", + "@labelFieldPlaceholder": {}, + "scheduleTypeField": "Type", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "Une fois", + "@scheduleTypeOnce": {}, + "scheduleTypeDaily": "Tous les jours", + "@scheduleTypeDaily": {}, + "scheduleTypeOnceDescription": "Sonnera à la prochaine occurrence de l'heure", + "@scheduleTypeOnceDescription": {}, + "scheduleTypeWeek": "À des jours spécifiques", + "@scheduleTypeWeek": {}, + "scheduleTypeData": "À des dates spécifiques", + "@scheduleTypeData": {}, + "scheduleTypeRange": "Période", + "@scheduleTypeRange": {}, + "scheduleTypeDateDescription": "Se répétera aux dates spécifiées", + "@scheduleTypeDateDescription": {}, + "scheduleTypeWeekDescription": "Se répétera aux jours de la semaine spécifiés", + "@scheduleTypeWeekDescription": {}, + "reliabilitySettingGroup": "Fiabilité", + "@reliabilitySettingGroup": {}, + "alarmScheduleSettingGroup": "Planifier", + "@alarmScheduleSettingGroup": {}, + "soundSettingGroup": "Son et vibration", + "@soundSettingGroup": {}, + "settingGroupMore": "Plus", + "@settingGroupMore": {}, + "melodySetting": "Mélodie", + "@melodySetting": {}, + "volumeSetting": "Volume", + "@volumeSetting": {}, + "risingVolumeSetting": "Volume progressif", + "@risingVolumeSetting": {}, + "snoozeSettingGroup": "Répétition", + "@snoozeSettingGroup": {}, + "snoozeEnableSetting": "Activée", + "@snoozeEnableSetting": {}, + "snoozeLengthSetting": "Intervalle", + "@snoozeLengthSetting": {}, + "whileSnoozedSettingGroup": "Pendant l'intervalle", + "@whileSnoozedSettingGroup": {}, + "snoozePreventDisablingSetting": "Empêcher la désactivation", + "@snoozePreventDisablingSetting": {}, + "snoozePreventDeletion": "Empêcher la suppression", + "@snoozePreventDeletion": {}, + "settings": "Paramètres", + "@settings": {}, + "tasksSetting": "Tâches", + "@tasksSetting": {}, + "noItemMessage": "Aucun {items} ajouté pour le moment", + "@noItemMessage": {}, + "chooseTaskTitle": "Sélectionnez une tâche à ajouter", + "@chooseTaskTitle": {}, + "mathTask": "Problèmes de math", + "@mathTask": {}, + "retypeTask": "Retaper le texte", + "@retypeTask": {}, + "sequenceTask": "Séquence", + "@sequenceTask": {}, + "taskTryButton": "Essayer", + "@taskTryButton": {}, + "mathTaskDifficultySetting": "Difficulté", + "@mathTaskDifficultySetting": {}, + "scheduleTypeRangeDescription": "Se répétera pendant la période spécifiée", + "@scheduleTypeRangeDescription": {}, + "skippingDescriptionSuffix": "(prochaine alarme ignorée)", + "@skippingDescriptionSuffix": {}, + "alarmDescriptionSnooze": "Ignorée jusqu'au {date}", + "@alarmDescriptionSnooze": {}, + "alarmDescriptionFinished": "Désactivée", + "@alarmDescriptionFinished": {}, + "alarmDescriptionNotScheduled": "Non planifiée", + "@alarmDescriptionNotScheduled": {}, + "alarmDescriptionToday": "Aujourd'hui uniquement", + "@alarmDescriptionToday": {}, + "alarmDescriptionTomorrow": "Demain uniquement", + "@alarmDescriptionTomorrow": {}, + "alarmDescriptionEveryDay": "Tous les jours", + "@alarmDescriptionEveryDay": {}, + "alarmDescriptionWeekend": "Tous les weekends", + "@alarmDescriptionWeekend": {}, + "stopwatchPrevious": "Précedent", + "@stopwatchPrevious": {}, + "alarmDescriptionWeekday": "Tous les jours de la semaine", + "@alarmDescriptionWeekday": {}, + "stopwatchFastest": "Le plus rapide", + "@stopwatchFastest": {}, + "alarmDescriptionDays": "Le {days}", + "@alarmDescriptionDays": {}, + "alarmDescriptionRange": "{interval, select, daily{Tous les jours} weekly{Toutes les semaines}} du {startDate} au {endDate}", + "@alarmDescriptionRange": {}, + "stopwatchSlowest": "Le plus lent", + "@stopwatchSlowest": {}, + "alarmDescriptionDates": "Le {date}{count, plural, =0{} =1{ et 1 autre date} other{ et {count} autres dates}}", + "@alarmDescriptionDates": {}, + "stopwatchAverage": "Moyenne", + "@stopwatchAverage": {} +} From 1334377539b9c52bea6e1cf73b9eda9064282a9e Mon Sep 17 00:00:00 2001 From: Alex GWarp Date: Wed, 3 Apr 2024 13:16:02 +0000 Subject: [PATCH 032/112] Translated using Weblate (Russian) Currently translated at 27.0% (23 of 85 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/ru/ --- lib/l10n/app_ru.arb | 65 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 0967ef42..004a4e62 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -1 +1,64 @@ -{} +{ + "clockTitle": "Часы", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "alarmTitle": "Будильник", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "timerTitle": "Таймер", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "stopwatchTitle": "Секундомер", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "generalSettingGroup": "Основные настройки", + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Внешний вид", + "@appearanceSettingGroup": {}, + "accessibilitySettingGroup": "Специальные возможности", + "@accessibilitySettingGroup": {}, + "developerOptionsSettingGroup": "Для разработчиков", + "@developerOptionsSettingGroup": {}, + "restoreSettingGroup": "Восстановить настройки по умолчанию", + "@restoreSettingGroup": {}, + "displaySettingGroup": "Экран", + "@displaySettingGroup": {}, + "colorsSettingGroup": "Цвета", + "@colorsSettingGroup": {}, + "useMaterialYouColorSetting": "Использовать Material You дизайн", + "@useMaterialYouColorSetting": {}, + "overrideAccentSetting": "Изменить цвет акцента", + "@overrideAccentSetting": {}, + "materialBrightnessSetting": "Тёмная тема", + "@materialBrightnessSetting": {}, + "styleThemeSetting": "Тема", + "@styleThemeSetting": {}, + "useMaterialStyleSetting": "Использовать Material дизайн", + "@useMaterialStyleSetting": {}, + "colorSchemeSetting": "Цветовая схема", + "@colorSchemeSetting": {}, + "darkColorSchemeSetting": "Тёмная тема", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "Часы", + "@clockSettingGroup": {}, + "timerSettingGroup": "Таймер", + "@timerSettingGroup": {}, + "stopwatchSettingGroup": "Секундомер", + "@stopwatchSettingGroup": {}, + "generalSettingGroupDescription": "Изменить основные настройки приложения, такие как формат часов", + "@generalSettingGroupDescription": {}, + "appearanceSettingGroupDescription": "Изменить тему, цвета и внешний вид", + "@appearanceSettingGroupDescription": {}, + "cancelButton": "Отмена", + "@cancelButton": {}, + "customizeButton": "Настроить", + "@customizeButton": {}, + "saveButton": "Сохранить", + "@saveButton": {}, + "vibrationSetting": "Вибрация", + "@vibrationSetting": {} +} From 29a72118f31abf22a6e6be33acaf39a4cfab5940 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sat, 13 Apr 2024 00:34:44 +0500 Subject: [PATCH 033/112] Add initial widget support --- android/app/build.gradle | 40 --------- android/app/src/main/AndroidManifest.xml | 15 ++++ .../chrono/AnalogueClockWidgetProvider.kt | 73 ++++++++++++++++ .../chrono/DigitalClockWidgetProvider.kt | 73 ++++++++++++++++ .../main/res/layout/analogue_clock_widget.xml | 32 +++++++ .../main/res/layout/digital_clock_widget.xml | 84 +++++++++++++++++++ .../main/res/xml/analogue_clock_widget.xml | 11 +++ .../src/main/res/xml/digital_clock_widget.xml | 11 +++ android/build.gradle | 12 --- 9 files changed, 299 insertions(+), 52 deletions(-) create mode 100644 android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt create mode 100644 android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt create mode 100644 android/app/src/main/res/layout/analogue_clock_widget.xml create mode 100644 android/app/src/main/res/layout/digital_clock_widget.xml create mode 100644 android/app/src/main/res/xml/analogue_clock_widget.xml create mode 100644 android/app/src/main/res/xml/digital_clock_widget.xml diff --git a/android/app/build.gradle b/android/app/build.gradle index d24368ef..08ef8d71 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -52,42 +52,6 @@ android { } defaultConfig { - // Map for the version code that gives each ABI a value. - - // // For per-density APKs, create a similar map: - // // ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 3] - - - // // For each APK output variant, override versionCode with a combination of - // // ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode - // // is equal to defaultConfig.versionCode. If you configure product flavors that - // // define their own versionCode, variant.versionCode uses that value instead. - // project.android.applicationVariants.all { variant -> - - // // Assigns a different version code for each output APK - // // other than the universal APK. - // variant.outputs.each { output -> - - // // Stores the value of ext.abiCodes that is associated with the ABI for this variant. - // def baseAbiVersionCode = - // // Determines the ABI for this variant and returns the mapped value. - // project.ext.abiCodes.get(output.getFilter(OutputFile.ABI)) - - // // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, - // // the following code doesn't override the version code for universal APKs. - // // However, because you want universal APKs to have the lowest version code, - // // this outcome is desirable. - // if (baseAbiVersionCode != null) { - - // // Assigns the new version code to versionCodeOverride, which changes the - // // version code for only the output APK, not for the variant itself. Skipping - // // this step causes Gradle to use the value of variant.versionCode for the APK. - // output.versionCodeOverride = - // variant.versionCode * 10 + baseAbiVersionCode - // } - // } - // } - applicationId "com.vicolo.chrono" minSdkVersion 21 targetSdkVersion flutter.targetSdkVersion @@ -155,7 +119,3 @@ flutter { source '../..' } -dependencies { - // implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - // -} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 368da343..971fc3ce 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -126,5 +126,20 @@ + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt new file mode 100644 index 00000000..917a2e42 --- /dev/null +++ b/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt @@ -0,0 +1,73 @@ +package com.vicolo.chrono + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.widget.RemoteViews +import com.vicolo.chrono.MainActivity +// import es.antonborri.home_widget.HomeWidgetBackgroundIntent +// import es.antonborri.home_widget.HomeWidgetLaunchIntent +// import es.antonborri.home_widget.HomeWidgetProvider + +class AnalogueClockWidgetProvider : AppWidgetProvider() { + + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { // Perform this loop procedure for each widget that belongs to this + // provider. + appWidgetIds.forEach { appWidgetId -> + // Create an Intent to launch ExampleActivity. + // Open App on Widget Click + val views = RemoteViews(context.packageName, R.layout.analogue_clock_widget).apply { + // Open App on Widget Click + val pendingIntent: PendingIntent = PendingIntent.getActivity( + /* context = */ context, + /* requestCode = */ 0, + /* intent = */ Intent(context, MainActivity::class.java), + /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + // Swap Title Text by calling Dart Code in the Background + // setTextViewText(R.id.widget_title, widgetData.getString("title", null) + // ?: "No Title Set") + // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + // context, + // Uri.parse("homeWidgetExample://titleClicked") + // ) + // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + // + // val message = widgetData.getString("message", null) + // setTextViewText(R.id.widget_message, message + // ?: "No Message Set") + // // Show Images saved with `renderFlutterWidget` + // val image = widgetData.getString("dashIcon", null) + // if (image != null) { + // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) + // setViewVisibility(R.id.widget_img, View.VISIBLE) + // } else { + // setViewVisibility(R.id.widget_img, View.GONE) + // } + // + // // Detect App opened via Click inside Flutter + // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + // context, + // MainActivity::class.java, + // Uri.parse("homeWidgetExample://message?message=$message")) + // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) + } + // Get the layout for the widget and attach an onClick listener to + // the button. + // val views: RemoteViews = RemoteViews( + // context.packageName, + // R.layout.appwidget_provider_layout + // ).apply { + // setOnClickPendingIntent(R.id.button, pendingIntent) + // } + + // Tell the AppWidgetManager to perform an update on the current + // widget. + appWidgetManager.updateAppWidget(appWidgetId, views) + } + } +} diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt new file mode 100644 index 00000000..112748a3 --- /dev/null +++ b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt @@ -0,0 +1,73 @@ +package com.vicolo.chrono + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.widget.RemoteViews +import com.vicolo.chrono.MainActivity +// import es.antonborri.home_widget.HomeWidgetBackgroundIntent +// import es.antonborri.home_widget.HomeWidgetLaunchIntent +// import es.antonborri.home_widget.HomeWidgetProvider + +class DigitalClockWidgetProvider : AppWidgetProvider() { + + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { // Perform this loop procedure for each widget that belongs to this + // provider. + appWidgetIds.forEach { appWidgetId -> + // Create an Intent to launch ExampleActivity. + // Open App on Widget Click + val views = RemoteViews(context.packageName, R.layout.digital_clock_widget).apply { + // Open App on Widget Click + val pendingIntent: PendingIntent = PendingIntent.getActivity( + /* context = */ context, + /* requestCode = */ 0, + /* intent = */ Intent(context, MainActivity::class.java), + /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + // Swap Title Text by calling Dart Code in the Background + // setTextViewText(R.id.widget_title, widgetData.getString("title", null) + // ?: "No Title Set") + // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + // context, + // Uri.parse("homeWidgetExample://titleClicked") + // ) + // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + // + // val message = widgetData.getString("message", null) + // setTextViewText(R.id.widget_message, message + // ?: "No Message Set") + // // Show Images saved with `renderFlutterWidget` + // val image = widgetData.getString("dashIcon", null) + // if (image != null) { + // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) + // setViewVisibility(R.id.widget_img, View.VISIBLE) + // } else { + // setViewVisibility(R.id.widget_img, View.GONE) + // } + // + // // Detect App opened via Click inside Flutter + // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + // context, + // MainActivity::class.java, + // Uri.parse("homeWidgetExample://message?message=$message")) + // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) + } + // Get the layout for the widget and attach an onClick listener to + // the button. + // val views: RemoteViews = RemoteViews( + // context.packageName, + // R.layout.appwidget_provider_layout + // ).apply { + // setOnClickPendingIntent(R.id.button, pendingIntent) + // } + + // Tell the AppWidgetManager to perform an update on the current + // widget. + appWidgetManager.updateAppWidget(appWidgetId, views) + } + } +} diff --git a/android/app/src/main/res/layout/analogue_clock_widget.xml b/android/app/src/main/res/layout/analogue_clock_widget.xml new file mode 100644 index 00000000..8f85f743 --- /dev/null +++ b/android/app/src/main/res/layout/analogue_clock_widget.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/android/app/src/main/res/layout/digital_clock_widget.xml b/android/app/src/main/res/layout/digital_clock_widget.xml new file mode 100644 index 00000000..7da2af89 --- /dev/null +++ b/android/app/src/main/res/layout/digital_clock_widget.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/xml/analogue_clock_widget.xml b/android/app/src/main/res/xml/analogue_clock_widget.xml new file mode 100644 index 00000000..023ee094 --- /dev/null +++ b/android/app/src/main/res/xml/analogue_clock_widget.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/app/src/main/res/xml/digital_clock_widget.xml b/android/app/src/main/res/xml/digital_clock_widget.xml new file mode 100644 index 00000000..9f49f20a --- /dev/null +++ b/android/app/src/main/res/xml/digital_clock_widget.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/build.gradle b/android/build.gradle index e0f6c98a..abc3b441 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,18 +3,6 @@ allprojects { google() mavenCentral() } - - // subprojects { - // afterEvaluate { project -> - // if (project.hasProperty('android')) { - // project.android { - // if (namespace == null) { - // namespace project.group - // } - // } - // } - // } - // } } rootProject.buildDir = '../build' From e3165d2e8ad883c5cb59ddca3840224878839fe0 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sun, 28 Apr 2024 08:24:59 +0500 Subject: [PATCH 034/112] Fix issues --- lib/navigation/screens/nav_scaffold.dart | 2 +- pubspec.lock | 26 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/navigation/screens/nav_scaffold.dart b/lib/navigation/screens/nav_scaffold.dart index c57b3184..644a532c 100644 --- a/lib/navigation/screens/nav_scaffold.dart +++ b/lib/navigation/screens/nav_scaffold.dart @@ -115,6 +115,7 @@ class _NavScaffoldState extends State { @override Widget build(BuildContext context) { Orientation orientation = MediaQuery.of(context).orientation; + final tabs = getTabs(context); return Scaffold( appBar: orientation == Orientation.portrait ? AppTopBar( @@ -165,7 +166,6 @@ class _NavScaffoldState extends State { .onBackground .withOpacity(0.6), )), - trailing: IconButton( onPressed: () { ScaffoldMessenger.of(context).removeCurrentSnackBar(); diff --git a/pubspec.lock b/pubspec.lock index a969ada2..3257899e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -384,6 +384,11 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_oss_licenses: dependency: "direct main" description: @@ -400,11 +405,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.3" - flutter_localizations: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" flutter_slidable: dependency: "direct main" description: @@ -592,14 +592,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" - logging: - dependency: transitive - description: - name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" - url: "https://pub.dev" - source: hosted - version: "1.2.0" locale_names: dependency: "direct main" description: @@ -608,6 +600,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" matcher: dependency: transitive description: From 80295cc0546cf9400c8b0a0fbd1e5b13ba1ddde2 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sun, 28 Apr 2024 18:30:04 +0500 Subject: [PATCH 035/112] Localize all settings --- lib/alarm/data/alarm_settings_schema.dart | 204 +++++++++---- lib/alarm/data/alarm_task_schemas.dart | 80 +++-- lib/alarm/types/alarm.dart | 2 + lib/alarm/types/alarm_task.dart | 8 +- lib/alarm/widgets/alarm_task_card.dart | 2 +- lib/app.dart | 2 - lib/audio/audio_channels.dart | 17 +- lib/common/logic/tags.dart | 2 +- lib/common/utils/ringtones.dart | 2 +- lib/common/widgets/time_picker.dart | 6 +- lib/l10n/app_en.arb | 282 +++++++++++++++++- lib/l10n/app_es.arb | 2 +- lib/l10n/app_fr.arb | 2 +- lib/l10n/{app_nb_NO.arb => app_nb.arb} | 0 lib/l10n/app_ur.arb | 1 - lib/l10n/language_local.dart | 2 +- .../data/accessibility_settings_schema.dart | 7 +- .../data/alarm_app_settings_schema.dart | 117 +++++--- .../data/appearance_settings_schema.dart | 67 +++-- lib/settings/data/backup_settings_schema.dart | 14 +- .../data/developer_settings_schema.dart | 20 +- .../data/general_settings_schema.dart | 239 +++++++++------ lib/settings/data/localized_names.dart | 50 ++-- lib/settings/data/settings_schema.dart | 6 +- .../data/stopwatch_settings_schema.dart | 41 ++- .../data/timer_app_settings_schema.dart | 111 ++++--- lib/settings/screens/about_screen.dart | 8 +- lib/settings/screens/licenses.dart | 8 +- .../screens/restore_defaults_screen.dart | 9 +- .../screens/settings_group_screen.dart | 3 +- lib/settings/types/setting.dart | 189 +++++++----- lib/settings/types/setting_action.dart | 12 +- lib/settings/types/setting_group.dart | 10 +- lib/settings/types/setting_item.dart | 22 +- lib/settings/types/setting_link.dart | 21 +- lib/settings/utils/description.dart | 5 + .../dynamic_multi_select_setting_card.dart | 4 +- .../widgets/dynamic_select_setting_card.dart | 4 +- .../widgets/multi_select_setting_card.dart | 4 +- lib/settings/widgets/select_setting_card.dart | 4 +- lib/settings/widgets/setting_action_card.dart | 6 +- lib/settings/widgets/setting_group_card.dart | 5 +- .../widgets/setting_page_link_card.dart | 6 +- lib/settings/widgets/string_setting_card.dart | 2 +- lib/settings/widgets/toggle_setting_card.dart | 3 +- .../data/color_scheme_settings_schema.dart | 125 ++++++-- .../data/style_theme_settings_schema.dart | 74 ++++- lib/timer/data/timer_settings_schema.dart | 43 ++- .../logic/edit_duration_picker_mode.dart | 9 +- lib/timer/types/timer.dart | 2 + 50 files changed, 1337 insertions(+), 527 deletions(-) rename lib/l10n/{app_nb_NO.arb => app_nb.arb} (100%) delete mode 100644 lib/l10n/app_ur.arb create mode 100644 lib/settings/utils/description.dart diff --git a/lib/alarm/data/alarm_settings_schema.dart b/lib/alarm/data/alarm_settings_schema.dart index 740af8bf..baf93c0c 100644 --- a/lib/alarm/data/alarm_settings_schema.dart +++ b/lib/alarm/data/alarm_settings_schema.dart @@ -20,42 +20,75 @@ import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/timer/types/time_duration.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const alarmSchemaVersion = 5; SettingGroup alarmSettingsSchema = SettingGroup( version: alarmSchemaVersion, "AlarmSettings", + (context) => AppLocalizations.of(context)!.alarmTitle, [ - StringSetting("Label", ""), + StringSetting( + "Label", (context) => AppLocalizations.of(context)!.labelField, ""), SettingGroup( "Schedule", + (context) => AppLocalizations.of(context)!.alarmScheduleSettingGroup, [ SelectSetting( "Type", + (context) => AppLocalizations.of(context)!.scheduleTypeField, [ - SelectSettingOption("Once", OnceAlarmSchedule, - description: "Will ring at the next occurrence of the time"), - SelectSettingOption("Daily", DailyAlarmSchedule, - description: "Will ring every day"), - SelectSettingOption("On Specified Week Days", WeeklyAlarmSchedule, - description: "Will repeat on the specified week days"), - SelectSettingOption("On Specific Dates", DatesAlarmSchedule, - description: "Will repeat on the specified dates"), - SelectSettingOption("Date Range", RangeAlarmSchedule, - description: "Will repeat during the specified date range"), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.scheduleTypeOnce, + OnceAlarmSchedule, + getDescription: (context) => + AppLocalizations.of(context)!.scheduleTypeOnceDescription, + ), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.scheduleTypeDaily, + DailyAlarmSchedule, + getDescription: (context) => + AppLocalizations.of(context)!.scheduleTypeDailyDescription, + ), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.scheduleTypeWeek, + WeeklyAlarmSchedule, + getDescription: (context) => + AppLocalizations.of(context)!.scheduleTypeWeekDescription, + ), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.scheduleTypeDate, + DatesAlarmSchedule, + getDescription: (context) => + AppLocalizations.of(context)!.scheduleTypeDateDescription, + ), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.scheduleTypeRange, + RangeAlarmSchedule, + getDescription: (context) => + AppLocalizations.of(context)!.scheduleTypeRangeDescription, + ), ], ), ToggleSetting( "Week Days", + (context) => AppLocalizations.of(context)!.alarmWeekdaysSetting, [ - ToggleSettingOption("M", 1), - ToggleSettingOption("T", 2), - ToggleSettingOption("W", 3), - ToggleSettingOption("T", 4), - ToggleSettingOption("F", 5), - ToggleSettingOption("S", 6), - ToggleSettingOption("S", 7), + ToggleSettingOption( + (context) => AppLocalizations.of(context)!.mondayLetter, 1), + ToggleSettingOption( + (context) => AppLocalizations.of(context)!.tuesdayLetter, 2), + ToggleSettingOption( + (context) => AppLocalizations.of(context)!.wednesdayLetter, 3), + ToggleSettingOption( + (context) => AppLocalizations.of(context)!.thursdayLetter, 4), + ToggleSettingOption( + (context) => AppLocalizations.of(context)!.fridayLetter, 5), + ToggleSettingOption( + (context) => AppLocalizations.of(context)!.saturdayLetter, 6), + ToggleSettingOption( + (context) => AppLocalizations.of(context)!.sundayLetter, 7), ], enableConditions: [ ValueCondition(["Type"], (value) => value == WeeklyAlarmSchedule) @@ -63,6 +96,7 @@ SettingGroup alarmSettingsSchema = SettingGroup( ), DateTimeSetting( "Dates", + (context) => AppLocalizations.of(context)!.alarmDatesSetting, [], enableConditions: [ ValueCondition(["Type"], (value) => value == DatesAlarmSchedule) @@ -70,6 +104,7 @@ SettingGroup alarmSettingsSchema = SettingGroup( ), DateTimeSetting( "Date Range", + (context) => AppLocalizations.of(context)!.alarmRangeSetting, [], rangeOnly: true, enableConditions: [ @@ -78,34 +113,53 @@ SettingGroup alarmSettingsSchema = SettingGroup( ), SelectSetting( "Interval", + (context) => AppLocalizations.of(context)!.alarmIntervalSetting, [ - SelectSettingOption("Daily", RangeInterval.daily), - SelectSettingOption("Weekly", RangeInterval.weekly), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.alarmIntervalDaily, + RangeInterval.daily), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.alarmIntervalWeekly, + RangeInterval.weekly), ], enableConditions: [ ValueCondition(["Type"], (value) => value == RangeAlarmSchedule) ], ), - SwitchSetting("Delete After Ringing", false, enableConditions: [ - ValueCondition(["Type"], (value) => value == OnceAlarmSchedule) - ]), - SwitchSetting("Delete After Finishing", false, enableConditions: [ - ValueCondition( - ["Type"], - (value) => [RangeAlarmSchedule, DatesAlarmSchedule].contains(value), - ) - ]), + SwitchSetting( + "Delete After Ringing", + (context) => + AppLocalizations.of(context)!.alarmDeleteAfterRingingSetting, + false, + enableConditions: [ + ValueCondition(["Type"], (value) => value == OnceAlarmSchedule) + ]), + SwitchSetting( + "Delete After Finishing", + (context) => + AppLocalizations.of(context)!.alarmDeleteAfterFinishingSetting, + false, + enableConditions: [ + ValueCondition( + ["Type"], + (value) => + [RangeAlarmSchedule, DatesAlarmSchedule].contains(value), + ) + ]), ], icon: Icons.timer, ), SettingGroup( "Sound and Vibration", + (context) => AppLocalizations.of(context)!.soundAndVibrationSettingGroup, [ SettingGroup( "Sound", + (context) => AppLocalizations.of(context)!.soundSettingGroup, [ DynamicSelectSetting( "Melody", + (context) => AppLocalizations.of(context)!.melodySetting, getRingtoneOptions, onChange: (context, index) { RingtonePlayer.stop(); @@ -114,21 +168,39 @@ SettingGroup alarmSettingsSchema = SettingGroup( // shouldCloseOnSelect: false, ), SelectSetting( - "Audio Channel", audioChannelOptions, - onChange: (context, index) { - RingtonePlayer.stop(); - }), - SliderSetting("Volume", 0, 100, 100, unit: "%"), - SwitchSetting("Rising Volume", false, - description: "Gradually increase volume over time"), + "Audio Channel", + (context) => AppLocalizations.of(context)!.audioChannelSetting, + audioChannelOptions, + onChange: (context, index) { + RingtonePlayer.stop(); + }, + ), + SliderSetting( + "Volume", + (context) => AppLocalizations.of(context)!.volumeSetting, + 0, + 100, + 100, + unit: "%"), + SwitchSetting( + "Rising Volume", + (context) => AppLocalizations.of(context)!.risingVolumeSetting, + false, + + // description: "Gradually increase volume over time", + ), DurationSetting( - "Time To Full Volume", const TimeDuration(minutes: 1), + "Time To Full Volume", + (context) => + AppLocalizations.of(context)!.timeToFullVolumeSetting, + const TimeDuration(minutes: 1), enableConditions: [ ValueCondition(["Rising Volume"], (value) => value == true) ]), ], ), - SwitchSetting("Vibration", false), + SwitchSetting("Vibration", + (context) => AppLocalizations.of(context)!.vibrationSetting, false), ], icon: Icons.volume_up, summarySettings: [ @@ -138,25 +210,53 @@ SettingGroup alarmSettingsSchema = SettingGroup( ), SettingGroup( "Snooze", + (context) => AppLocalizations.of(context)!.snoozeSettingGroup, [ - SwitchSetting("Enabled", true), - SliderSetting("Length", 1, 30, 5, unit: "minutes", enableConditions: [ - ValueCondition(["Enabled"], (value) => value == true) - ]), - SliderSetting("Max Snoozes", 1, 10, 3, + SwitchSetting( + "Enabled", + (context) => AppLocalizations.of(context)!.snoozeEnableSetting, + true), + SliderSetting( + "Length", + (context) => AppLocalizations.of(context)!.snoozeLengthSetting, + 1, + 30, + 5, + unit: "minutes", + enableConditions: [ + ValueCondition(["Enabled"], (value) => value == true) + ]), + SliderSetting( + "Max Snoozes", + (context) => AppLocalizations.of(context)!.maxSnoozesSetting, + 1, + 10, + 3, unit: "times", snapLength: 1, - description: - "The maximum number of times the alarm can be snoozed before it is dismissed", + // description: + // "The maximum number of times the alarm can be snoozed before it is dismissed", + enableConditions: [ + ValueCondition(["Enabled"], (value) => value == true) + ]), + SettingGroup( + "While Snoozed", + (context) => AppLocalizations.of(context)!.whileSnoozedSettingGroup, + [ + SwitchSetting( + "Prevent Disabling", + (context) => AppLocalizations.of(context)! + .snoozePreventDisablingSetting, + false), + SwitchSetting( + "Prevent Deletion", + (context) => AppLocalizations.of(context)! + .snoozePreventDeletionSetting, + false), + ], enableConditions: [ ValueCondition(["Enabled"], (value) => value == true) ]), - SettingGroup("While Snoozed", [ - SwitchSetting("Prevent Disabling", false), - SwitchSetting("Prevent Deletion", false), - ], enableConditions: [ - ValueCondition(["Enabled"], (value) => value == true) - ]), ], icon: Icons.snooze_rounded, summarySettings: [ @@ -166,6 +266,7 @@ SettingGroup alarmSettingsSchema = SettingGroup( ), ListSetting( "Tasks", + (context) => AppLocalizations.of(context)!.tasksSetting, [], alarmTaskSchemasMap.keys.map((key) => AlarmTask(key)).toList(), addCardBuilder: (item) => AlarmTaskCard(task: item, isAddCard: true), @@ -185,6 +286,7 @@ SettingGroup alarmSettingsSchema = SettingGroup( ), DynamicMultiSelectSetting( "Tags", + (context) => AppLocalizations.of(context)!.tagsSetting, getTagOptions, defaultValue: [], ), diff --git a/lib/alarm/data/alarm_task_schemas.dart b/lib/alarm/data/alarm_task_schemas.dart index bb32d11a..78361a32 100644 --- a/lib/alarm/data/alarm_task_schemas.dart +++ b/lib/alarm/data/alarm_task_schemas.dart @@ -4,25 +4,38 @@ import 'package:clock_app/alarm/widgets/tasks/retype_task.dart'; import 'package:clock_app/alarm/widgets/tasks/sequence_task.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; Map alarmTaskSchemasMap = { AlarmTaskType.math: AlarmTaskSchema( - "Math Problems", - SettingGroup("Math Problems Settings", [ + (context) => AppLocalizations.of(context)!.mathTask, + SettingGroup("Math Problems Settings", + (context) => AppLocalizations.of(context)!.mathTask, [ SelectSetting( "Difficulty", + (context) => AppLocalizations.of(context)!.mathTaskDifficultySetting, [ SelectSettingOption( - "Easy (X + Y)", MathTaskDifficultyLevel([Operator.add])), + (context) => AppLocalizations.of(context)!.mathEasyDifficulty, + MathTaskDifficultyLevel([Operator.add])), SelectSettingOption( - "Medium (X × Y)", MathTaskDifficultyLevel([Operator.multiply])), - SelectSettingOption("Hard (X × Y + Z)", + (context) => AppLocalizations.of(context)!.mathMediumDifficulty, + MathTaskDifficultyLevel([Operator.multiply])), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.mathHardDifficulty, MathTaskDifficultyLevel([Operator.multiply, Operator.add])), - SelectSettingOption("Very Hard (X × Y × Z)", + SelectSettingOption( + (context) => AppLocalizations.of(context)!.mathVeryHardDifficulty, MathTaskDifficultyLevel([Operator.multiply, Operator.multiply])), ], ), - SliderSetting("Number of problems", 1, 10, 1, snapLength: 1), + SliderSetting( + "Number of problems", + (context) => AppLocalizations.of(context)!.numberOfProblemsSetting, + 1, + 10, + 1, + snapLength: 1), ]), (onSolve, settings) { return MathTask( @@ -32,23 +45,54 @@ Map alarmTaskSchemasMap = { }, ), AlarmTaskType.retype: AlarmTaskSchema( - "Retype Text", - SettingGroup("Retype Text Settings", [ - SliderSetting("Number of characters", 5, 20, 5, snapLength: 1), - SwitchSetting("Include numbers", false), - SwitchSetting("Include lowercase", false), - SliderSetting("Number of problems", 1, 10, 1, snapLength: 1), - + (context) => AppLocalizations.of(context)!.retypeTask, + SettingGroup("Retype Text Settings", + (context) => AppLocalizations.of(context)!.retypeTask, [ + SliderSetting( + "Number of characters", + (context) => AppLocalizations.of(context)!.retypeNumberChars, + 5, + 20, + 5, + snapLength: 1), + SwitchSetting( + "Include numbers", + (context) => AppLocalizations.of(context)!.retypeIncludeNumSetting, + false), + SwitchSetting( + "Include lowercase", + (context) => AppLocalizations.of(context)!.retypeLowercaseSetting, + true), + SliderSetting( + "Number of problems", + (context) => AppLocalizations.of(context)!.numberOfProblemsSetting, + 1, + 10, + 1, + snapLength: 1), ]), (onSolve, settings) { return RetypeTask(onSolve: onSolve, settings: settings); }, ), AlarmTaskType.sequence: AlarmTaskSchema( - "Sequence", - SettingGroup("Sequence Settings", [ - SliderSetting("Sequence length", 3, 10, 3, snapLength: 1), - SliderSetting("Grid size", 2, 5, 3, snapLength: 1), + (context) => AppLocalizations.of(context)!.sequenceTask, + SettingGroup("Sequence Settings", + (context) => AppLocalizations.of(context)!.sequenceTask, [ + SliderSetting( + "Sequence length", + (context) => AppLocalizations.of(context)!.sequenceLengthSetting, + 3, + 10, + 3, + snapLength: 1), + SliderSetting( + "Grid size", + (context) => AppLocalizations.of(context)!.sequenceGridSizeSetting, + 2, + 5, + 3, + snapLength: 1), ]), (onSolve, settings) { return SequenceTask(onSolve: onSolve, settings: settings); diff --git a/lib/alarm/types/alarm.dart b/lib/alarm/types/alarm.dart index e008b4d0..90d6c2ef 100644 --- a/lib/alarm/types/alarm.dart +++ b/lib/alarm/types/alarm.dart @@ -46,6 +46,7 @@ class Alarm extends CustomizableListItem { DateTime? _skippedTime; SettingGroup _settings = SettingGroup( "Alarm Settings", + (context) => "Alarm Settings", appSettings .getGroup("Alarm") .getGroup("Default Settings") @@ -388,6 +389,7 @@ class Alarm extends CustomizableListItem { _snoozeCount = json['snoozeCount'] ?? 0; _settings = SettingGroup( "Alarm Settings", + (context) => "Alarm Settings", appSettings .getGroup("Alarm") .getGroup("Default Settings") diff --git a/lib/alarm/types/alarm_task.dart b/lib/alarm/types/alarm_task.dart index c6db1bc9..a1c83c02 100644 --- a/lib/alarm/types/alarm_task.dart +++ b/lib/alarm/types/alarm_task.dart @@ -16,14 +16,14 @@ typedef AlarmTaskBuilder = Widget Function( Function() onSolve, SettingGroup settings); class AlarmTaskSchema extends JsonSerializable { - final String name; + final String Function(BuildContext) getLocalizedName; final SettingGroup settings; final AlarmTaskBuilder _builder; - const AlarmTaskSchema(this.name, this.settings, this._builder); + const AlarmTaskSchema(this.getLocalizedName, this.settings, this._builder); AlarmTaskSchema.from(AlarmTaskSchema schema) - : name = schema.name, + : getLocalizedName = schema.getLocalizedName, settings = schema.settings.copy(), _builder = schema._builder; @@ -91,7 +91,7 @@ class AlarmTask extends CustomizableListItem { @override bool get isDeletable => true; AlarmTaskSchema get schema => _schema; - String get name => _schema.name; + String Function(BuildContext) get getLocalizedName => _schema.getLocalizedName; @override SettingGroup get settings => _schema.settings; Widget Function(Function() onSolve) get builder => _schema.getBuilder; diff --git a/lib/alarm/widgets/alarm_task_card.dart b/lib/alarm/widgets/alarm_task_card.dart index 4fed60e7..07b7aacd 100644 --- a/lib/alarm/widgets/alarm_task_card.dart +++ b/lib/alarm/widgets/alarm_task_card.dart @@ -38,7 +38,7 @@ class AlarmTaskCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(task.name, style: textTheme.displaySmall), + Text(task.getLocalizedName(context), style: textTheme.displaySmall), ], ), ), diff --git a/lib/app.dart b/lib/app.dart index fc5bca9d..38356c4e 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -22,8 +22,6 @@ import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:get_storage/get_storage.dart'; -import 'package:receive_intent/receive_intent.dart' as intent_handler; -import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class App extends StatefulWidget { diff --git a/lib/audio/audio_channels.dart b/lib/audio/audio_channels.dart index a41e7884..1d102b30 100644 --- a/lib/audio/audio_channels.dart +++ b/lib/audio/audio_channels.dart @@ -1,9 +1,18 @@ import 'package:audio_session/audio_session.dart'; import 'package:clock_app/settings/types/setting.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; List> audioChannelOptions = [ - SelectSettingOption("Alarm", AndroidAudioUsage.alarm), - SelectSettingOption("Media", AndroidAudioUsage.media), - SelectSettingOption("Notification", AndroidAudioUsage.notification), - SelectSettingOption("Ringtone", AndroidAudioUsage.notificationRingtone), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.audioChannelAlarm, + AndroidAudioUsage.alarm), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.audioChannelMedia, + AndroidAudioUsage.media), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.audioChannelNotification, + AndroidAudioUsage.notification), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.audioChannelRingtone, + AndroidAudioUsage.notificationRingtone), ]; diff --git a/lib/common/logic/tags.dart b/lib/common/logic/tags.dart index 8a532224..0de51c58 100644 --- a/lib/common/logic/tags.dart +++ b/lib/common/logic/tags.dart @@ -4,6 +4,6 @@ import 'package:clock_app/settings/types/setting.dart'; List> getTagOptions() { return loadListSync("tags") - .map((tag) => SelectSettingOption(tag.name, tag)) + .map((tag) => SelectSettingOption((context)=>tag.name, tag)) .toList(); } diff --git a/lib/common/utils/ringtones.dart b/lib/common/utils/ringtones.dart index 5a0a90eb..3a38aef5 100644 --- a/lib/common/utils/ringtones.dart +++ b/lib/common/utils/ringtones.dart @@ -4,6 +4,6 @@ import 'package:clock_app/settings/types/setting.dart'; List> getRingtoneOptions() { return loadListSync("ringtones") - .map((ringtone) => SelectSettingOption(ringtone.name, ringtone)) + .map((ringtone) => SelectSettingOption((context)=>ringtone.name, ringtone)) .toList(); } diff --git a/lib/common/widgets/time_picker.dart b/lib/common/widgets/time_picker.dart index 69f50c14..07874ce1 100644 --- a/lib/common/widgets/time_picker.dart +++ b/lib/common/widgets/time_picker.dart @@ -304,12 +304,12 @@ class _TitleBar extends StatelessWidget { onPickerModeChanged(); }, title: setting.name, - description: setting.description, + description: setting.displayDescription(context), choices: setting.options .map((option) => SelectChoice( - name: option.name, + name: option.getLocalizedName(context), value: option.value, - description: option.description)) + description: option.getDescription(context))) .toList(), initialSelectedIndices: [setting.selectedIndex], multiSelect: false, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b51486f1..42956a5e 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -15,20 +15,152 @@ "@stopwatchTitle": { "description": "Title of the stopwatch screen" }, + "system": "System", + "@system": {}, "generalSettingGroup": "General", "@generalSettingGroup": {}, + "generalSettingGroupDescription": "Set app wide settings like time format", + "@generalSettingGroupDescription": {}, + "languageSetting": "Language", + "@languageSettingG": {}, + "dateFormatSetting": "Date Format", + "@dateFormatSetting": {}, + "timeFormatSetting": "Time Format", + "@timeFormatSetting": {}, + "timeFormat12": "12 hours", + "@timeFormat12": {}, + "timeFormat24": "24 hours", + "@timeFormat24": {}, + "timeFormatDevice": "Device Settings", + "@timeFormatDevice": {}, + "showSecondsSetting": "Show Seconds", + "@showSecondsSetting": {}, + "timePickerSetting": "Time Picker", + "@timePickerSetting": {}, + "pickerDial": "Dial", + "@pickerDial": {}, + "pickerInput": "Input", + "@pickerInput": {}, + "pickerSpinner": "Spinner", + "@pickerSpinner": {}, + "durationPickerSetting": "Duration Picker", + "@timePickerSetting": {}, + "pickerRings": "Rings", + "@pickerRings": {}, + "swipeActionSetting": "Swipe Action", + "@swipeActionSetting": {}, + "swipActionCardAction": "Card Actions", + "@swipActionCardAction": {}, + "swipeActionCardActionDescription": "Swipe left or right on the card to perform actions", + "@swipeActionCardActionDescription": {}, + "swipActionSwitchTabs": "Switch Tabs", + "@swipActionSwitchTabs": {}, + "swipeActionSwitchTabsDescription": "Swipe between tabs", + "@swipeActionSwitchTabsDescription": {}, + "melodiesSetting": "Melodies", + "@melodiesSetting": {}, + "tagsSetting": "Tags", + "@tagsSetting": {}, + "vendorSetting": "Vendor Setting", + "@vendorSetting": {}, + "vendorSettingDescription": "Manually disable vendor-specific optimizations", + "@vendorSettingDescription": {}, + "batteryOptimizationSetting": "Disable Battery Optimization", + "@batteryOptimizationSetting": {}, + "batteryOptimizationSettingDescription": "Disable battery optimization for this app to prevent alarms from being delayed", + "@batteryOptimizationSettingDescription": {}, + "allowNotificationSettingDescription": "Allow lock screen notifications for alarms and timers", + "@allowNotificationSettingDescription": {}, + "autoStartSettingDescription": "Some devices require Auto Start to be enabled for alarms to ring while app is closed", + "@autoStartSettingDescription": {}, + "allowNotificationSetting": "Allow Notifications", + "@allowNotificationSetting": {}, + "autoStartSetting": "Auto Start", + "animationSettingGroup": "Animations", + "@animationSettingGroup": {}, + "animationSpeedSetting": "Animation Speed", + "@animationSpeedSetting": {}, + "extraAnimationSetting": "Extra Animations", + "@extraAnimationSetting": {}, + "@autoStartSetting": {}, "appearanceSettingGroup": "Appearance", "@appearanceSettingGroup": {}, + "appearanceSettingGroupDescription": "Set themes, colors and change layout", + "@appearanceSettingGroupDescription": {}, + "nameField": "Name", + "@nameField": {}, + "colorSetting": "Color", + "@colorSetting": {}, + "textColorSetting": "Text", + "@textColorSetting": {}, + "colorSchemeNamePlaceholder": "Color Scheme", + "@colorSchemeNamePlaceholder": {}, + "colorSchemeBackgroundSettingGroup": "Background", + "@colorSchemeBackgroundSettingGroup": {}, + "colorSchemeAccentSettingGroup": "Accent", + "@colorSchemeAccentSettingGroup": {}, + "colorSchemeErrorSettingGroup": "Error", + "@colorSchemeErrorSettingGroup": {}, + "colorSchemeCardSettingGroup": "Card", + "@colorSchemeCardSettingGroup": {}, + "colorSchemeOutlineSettingGroup": "Outline", + "@colorSchemeOutlineSettingGroup": {}, + "colorSchemeShadowSettingGroup": "Shadow", + "@colorSchemeShadowSettingGroup": {}, + "colorSchemeUseAccentAsOutlineSetting": "Use Accent as Outline", + "@colorSchemeUseAccentAsOutlineSetting": {}, + "colorSchemeUseAccentAsShadowSetting": "Use Accent as Shadow", + "@colorSchemeUseAccentAsShadowSetting": {}, + "styleThemeNamePlaceholder": "Style Theme", + "@styleThemeNamePlaceholder": {}, + "styleThemeShadowSettingGroup": "Shadow", + "@styleThemeShadowSettingGroup": {}, + "styleThemeShapeSettingGroup": "Shape", + "@styleThemeShapeSettingGroup": {}, + "styleThemeElevationSetting": "Elevation", + "@styleThemeElevationSetting": {}, + "styleThemeRadiusSetting": "Corner Roundness", + "@styleThemeRadiusSetting": {}, + "styleThemeOpacitySetting": "Opacity", + "@styleThemeOpacitySetting": {}, + "styleThemeBlurSetting": "Blur", + "@styleThemeBlurSetting": {}, + "styleThemeSpreadSetting": "Spread", + "@styleThemeSpreadSetting": {}, + "styleThemeOutlineSettingGroup": "Outline", + "@styleThemeOutlineSetting": {}, + "styleThemeOutlineWidthSetting": "Width", + "@styleThemeOutlineWidthSetting": {}, "accessibilitySettingGroup": "Accessibility", "@accessibilitySettingGroup": {}, "backupSettingGroup": "Backup", "@backupSettingGroup": {}, "developerOptionsSettingGroup": "Developer Options", "@developerOptionsSettingGroup": {}, + "showIstantAlarmButtonSetting": "Show Instant Alarm Button", + "@showIstantAlarmButtonSetting": {}, + "showIstantTimerButtonSetting": "Show Instant Timer Button", + "@showIstantTimerButtonSetting": {}, + "logsSettingGroup": "Logs", + "@logsSettingGroup": {}, + "maxLogsSetting": "Max Logs", + "@maxLogsSetting": {}, + "alarmLogSetting": "Alarm Logs", + "@alarmLogSetting": {}, "aboutSettingGroup": "About", "@aboutSettingGroup": {}, "restoreSettingGroup": "Restore default values", "@restoreSettingGroup": {}, + "resetButton": "Reset", + "@resetButton": {}, + "previewLabel": "Preview", + "@previewLabel": {}, + "cardLabel": "Card", + "@cardLabel": {}, + "accentLabel": "Accent", + "@accentLabel": {}, + "errorLabel": "Error", + "@errorLabel": {}, "displaySettingGroup": "Display", "@displaySettingGroup": {}, "reliabilitySettingGroup": "Reliability", @@ -41,8 +173,16 @@ "@useMaterialYouColorSetting": {}, "materialBrightnessSetting": "Brightness", "@materialBrightnessSetting": {}, + "materialBrightnessSystem": "System", + "@materialBrightnessSystem": {}, + "materialBrightnessLight": "Light", + "@materialBrightnessLight": {}, + "materialBrightnessDark": "Dark", + "@materialBrightnessDark": {}, "overrideAccentSetting": "Override Accent Color", "@overrideAccentSetting": {}, + "accentColorSetting": "Accent Color", + "@accentColorSetting": {}, "useMaterialStyleSetting": "Use Material Style", "@useMaterialStyleSetting": {}, "styleThemeSetting": "Style Theme", @@ -65,6 +205,35 @@ "@appearanceSettingGroupDescription": {}, "backupSettingGroupDescription": "Export or Import your settings locally", "@backupSettingGroupDescription": {}, + "alarmWeekdaysSetting": "Week Days", + "@alarmWeekdaysSetting": {}, + "mondayLetter": "M", + "@mondayLetter": {}, + "tuesdayLetter": "T", + "@tuesdayLetter": {}, + "wednesdayLetter": "W", + "@wednesdayLetter": {}, + "thursdayLetter": "T", + "@thursdayLetter": {}, + "fridayLetter": "F", + "@fridayLetter": {}, + "saturdayLetter": "S", + "@saturdayLetter": {}, + "sundayLetter": "S", + "alarmDatesSetting": "Dates", + "@alarmDatesSetting": {}, + "alarmRangeSetting": "Date Range", + "@alarmRangeSetting": {}, + "alarmIntervalSetting": "Interval", + "@alarmIntervalSetting": {}, + "alarmIntervalDaily": "Daily", + "@alarmIntervalDaily": {}, + "alarmIntervalWeekly": "Weekly", + "@alarmIntervalWeekly": {}, + "alarmDeleteAfterRingingSetting": "Delete After Dismiss", + "@alarmDeleteAfterRingingSetting": {}, + "alarmDeleteAfterFinishingSetting" : "Delete After Finishing", + "@alarmDeleteAfterFinishingSetting": {}, "selectTime": "Select Time", "@selectTime": {}, "cancelButton": "Cancel", @@ -93,15 +262,17 @@ "@scheduleTypeWeek": {}, "scheduleTypeWeekDescription": "Will repeat on the specified week days", "@scheduleTypeWeekDescription": {}, - "scheduleTypeData": "On Specific Dates", - "@scheduleTypeData": {}, + "scheduleTypeDate": "On Specific Dates", + "@scheduleTypeDate": {}, "scheduleTypeRange": "Date Range", "@scheduleTypeRange": {}, "scheduleTypeDateDescription": "Will repeat on the specified dates", "@scheduleTypeDateDescription": {}, "scheduleTypeRangeDescription": "Will repeat during the specified date range", "@scheduleTypeRangeDescription": {}, - "soundSettingGroup": "Sound and Vibration", + "soundAndVibrationSettingGroup": "Sound and Vibration", + "@soundAndVibrationSettingGroup": {}, + "soundSettingGroup": "Sound", "@soundSettingGroup": {}, "settingGroupMore": "More", "@settingGroupMore": {}, @@ -111,22 +282,34 @@ "@vibrationSetting": {}, "audioChannelSetting": "Audio Channel", "@audioChannelSetting": {}, + "audioChannelAlarm": "Alarm", + "@audioChannelAlarm": {}, + "audioChannelNotification": "Notification", + "@audioChannelNotification": {}, + "audioChannelRingtone": "Ringtone", + "@audioChannelRingtone": {}, + "audioChannelMedia": "Media", + "@audioChannelMedia": {}, "volumeSetting": "Volume", "@volumeSetting": {}, "risingVolumeSetting": "Rising Volume", "@risingVolumeSetting": {}, + "timeToFullVolumeSetting": "Time to Full Volume", + "@timeToFullVolumeSetting": {}, "snoozeSettingGroup": "Snooze", "@snoozeSettingGroup": {}, "snoozeEnableSetting": "Enabled", "@snoozeEnableSetting": {}, "snoozeLengthSetting": "Length", "@snoozeLengthSetting": {}, + "maxSnoozesSetting": "Max Snoozes", + "@maxSnoozesSetting": {}, "whileSnoozedSettingGroup": "While Snoozed", "@whileSnoozedSettingGroup": {}, "snoozePreventDisablingSetting": "Prevent Disabling", "@snoozePreventDisablingSetting": {}, - "snoozePreventDeletion": "Prevent Deletion", - "@snoozePreventDeletion": {}, + "snoozePreventDeletionSetting": "Prevent Deletion", + "@snoozePreventDeletionSetting": {}, "settings": "Settings", "@settings": {}, "tasksSetting": "Tasks", @@ -137,6 +320,14 @@ "@chooseTaskTitle": {}, "mathTask": "Math Problems", "@mathTask": {}, + "mathEasyDifficulty": "Easy (X + Y)", + "@mathEasyDifficulty": {}, + "mathMediumDifficulty": "Medium (X × Y)", + "@mathMediumDifficulty": {}, + "mathHardDifficulty": "Hard (X × Y + Z)", + "@mathHardDifficulty": {}, + "mathVeryHardDifficulty": "Very Hard (X × Y × Z)", + "@mathVeryHardDifficulty": {}, "retypeTask": "Retype Text", "@retypeTask": {}, "sequenceTask": "Sequence", @@ -155,6 +346,8 @@ "@sequenceLengthSetting": {}, "sequenceGridSizeSetting": "Grid size", "@sequenceGridSizeSetting": {}, + "numberOfProblemsSetting": "Number of Problems", + "@numberOfProblemsSetting": {}, "saveReminderAlert": "Do you want to leave without saving?", "@saveReminderAlert": {}, "yesButton": "Yes", @@ -205,12 +398,87 @@ "@stopwatchFastest": {}, "alarmDescriptionDays": "On {days}", "@alarmDescriptionDays": {}, - "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly}} from {startDate} to {endDate}", + "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly} other{Other}} from {startDate} to {endDate}", "@alarmDescriptionRange": {}, "stopwatchSlowest": "Slowest", "@stopwatchSlowest": {}, "alarmDescriptionDates": "On {date}{count, plural, =0{} =1{ and 1 other date} other{ and {count} other dates}}", "@alarmDescriptionDates": {}, "stopwatchAverage": "Average", - "@stopwatchAverage": {} + "@stopwatchAverage": {}, + "defaultSettingGroup": "Default Settings", + "@defaultSettingGroup": {}, + "alarmsDefaultSettingGroupDescription": "Set default values for new alarms", + "@alarmsDefaultSettingGroupDescription" : {}, + "timerDefaultSettingGroupDescription": "Set default values for new timers", + "@timerDefaultSettingGroupDescription": {}, + "filtersSettingGroup": "Filters", + "@filtersSettingGroup": {}, + "showFiltersSetting": "Show Filters", + "@showFiltersSetting": {}, + "showSortSetting": "Show Sort", + "@showSortSetting": {}, + "notificationsSettingGroup": "Notifications", + "@notificationsSettingGroup": {}, + "showUpcomingAlarmNotificationSetting": "Show Upcoming Alarm Notifications", + "@showUpcomingAlarmNotificationSetting": {}, + "upcomingLeadTimeSetting": "Upcoming Lead Time", + "@upcomingLeadTimeSetting": {}, + "showSnoozeNotificationSetting": "Show Snooze Notifications", + "showNotificationSetting": "Show Notification", + "presetsSetting": "Presets", + "@presetsSetting": {}, + "newPresetPlaceholder": "New Preset", + "@newPresetPlaceholder": {}, + "dismissActionSetting": "Dismiss Action Type", + "@dismissActionSetting": {}, + "dismissActionSlide": "Slide", + "@dismissActionSlide": {}, + "dismissActionButtons": "Buttons", + "@dismissActionButtons": {}, + "dismissActionAreaButtons": "Area Buttons", + "@dismissActionAreaButtons": {}, + "stopwatchTimeFormatSettingGroup": "Time Format", + "@stopwatchTimeFormatSettingGroup": {}, + "stopwatchShowMillisecondsSetting": "Show Milliseconds", + "@stopwatchShowMillisecondsSetting": {}, + "comparisonLapBarsSettingGroup": "Comparison Lap Bars", + "@comparisonLapBarsSettingGroup": {}, + "showPreviousLapSetting": "Show Previous Lap", + "@showPreviousLapSetting": {}, + "showFastestLapSetting": "Show Fastest Lap", + "@showFastestLapSetting": {}, + "showAverageLapSetting": "Show Average Lap", + "@showAverageLapSetting": {}, + "showSlowestLapSetting": "Show Slowest Lap", + "@showSlowestLapSetting": {}, + "leftHandedSetting": "Left Handed Mode", + "@leftHandedSetting": {}, + "backupSettingGroup": "Settings", + "@backupSettingGroup": {}, + "backupSettingGroupDescription": "Export or Import your settings locally", + "@backupSettingGroupDescription": {}, + "exportSettingsSetting": "Export", + "@exportSettingsSetting": {}, + "exportSettingsSettingDescription": "Export settings to a local file", + "@exportSettingsSettingDescription": {}, + "importSettingsSetting": "Import", + "@importSettingsSetting": {}, + "importSettingsSettingDescription": "Import settings from a local file", + "@importSettingsSettingDescription": {}, + "versionLabel": "Version", + "@versionLabel": {}, + "packageNameLabel": "Package name", + "@packageNameLabel": {}, + "licenseLabel": "License", + "@licenseLabel": {}, + "emailLabel": "Email", + "@emailLabel": {}, + "viewOnGithubLabel": "View on GitHub", + "@viewOnGithubLabel": {}, + "creditsSettingGroup": "Credits", + "@creditsSettingGroup": {}, + "addLengthSetting": "Add Length", + "@addLengthSetting": {} + } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index a5232d33..69fd4a81 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -199,7 +199,7 @@ "@alarmDescriptionDays": {}, "stopwatchSlowest": "La más lenta", "@stopwatchSlowest": {}, - "alarmDescriptionRange": "{interval, select, daily{A diario} weekly{Semanalmente}} desde {startDate} a {endDate}", + "alarmDescriptionRange": "{interval, select, daily{A diario} weekly{Semanalmente} other{Other}} desde {startDate} a {endDate}", "@alarmDescriptionRange": {}, "alarmDescriptionDates": "En {date}{count, plural, =0{} =1{ y otra fecha} other{ y {count} otras fechas}}", "@alarmDescriptionDates": {}, diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index effccdfe..f8368659 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -169,7 +169,7 @@ "@stopwatchFastest": {}, "alarmDescriptionDays": "Le {days}", "@alarmDescriptionDays": {}, - "alarmDescriptionRange": "{interval, select, daily{Tous les jours} weekly{Toutes les semaines}} du {startDate} au {endDate}", + "alarmDescriptionRange": "{interval, select, daily{Tous les jours} weekly{Toutes les semaines} other{Other}} du {startDate} au {endDate}", "@alarmDescriptionRange": {}, "stopwatchSlowest": "Le plus lent", "@stopwatchSlowest": {}, diff --git a/lib/l10n/app_nb_NO.arb b/lib/l10n/app_nb.arb similarity index 100% rename from lib/l10n/app_nb_NO.arb rename to lib/l10n/app_nb.arb diff --git a/lib/l10n/app_ur.arb b/lib/l10n/app_ur.arb deleted file mode 100644 index 0967ef42..00000000 --- a/lib/l10n/app_ur.arb +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/lib/l10n/language_local.dart b/lib/l10n/language_local.dart index f038c080..e1b5349f 100644 --- a/lib/l10n/language_local.dart +++ b/lib/l10n/language_local.dart @@ -125,7 +125,7 @@ "mn": {"name": "Mongolian", "nativeName": "монгол"}, "na": {"name": "Nauru", "nativeName": "Ekakairũ Naoero"}, "nv": {"name": "Navajo, Navaho", "nativeName": "Diné bizaad, Dinékʼehǰí"}, - "nb": {"name": "Norwegian Bokmål", "nativeName": "Norsk bokmål"}, + "nb_NO": {"name": "Norwegian Bokmål", "nativeName": "Norsk bokmål"}, "nd": {"name": "North Ndebele", "nativeName": "isiNdebele"}, "ne": {"name": "Nepali", "nativeName": "नेपाली"}, "ng": {"name": "Ndonga", "nativeName": "Owambo"}, diff --git a/lib/settings/data/accessibility_settings_schema.dart b/lib/settings/data/accessibility_settings_schema.dart index 2ece8449..8acfc0eb 100644 --- a/lib/settings/data/accessibility_settings_schema.dart +++ b/lib/settings/data/accessibility_settings_schema.dart @@ -1,10 +1,15 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; SettingGroup accessibilitySettingsSchema = SettingGroup( "Accessibility", - [SwitchSetting("Left Handed Mode", false)], + (context) => AppLocalizations.of(context)!.accessibilitySettingGroup, + [ + SwitchSetting("Left Handed Mode", + (context) => AppLocalizations.of(context)!.leftHandedSetting, false) + ], icon: Icons.accessibility_new_rounded, showExpandedView: false, ); diff --git a/lib/settings/data/alarm_app_settings_schema.dart b/lib/settings/data/alarm_app_settings_schema.dart index 2fb5591d..1d05e86c 100644 --- a/lib/settings/data/alarm_app_settings_schema.dart +++ b/lib/settings/data/alarm_app_settings_schema.dart @@ -9,70 +9,87 @@ import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; SettingGroup alarmAppSettingsSchema = SettingGroup( "Alarm", + (context) => AppLocalizations.of(context)!.alarmTitle, [ SettingGroup( "Default Settings", + (context) => AppLocalizations.of(context)!.defaultSettingGroup, [...alarmSettingsSchema.settingItems], - description: "Set default settings for new alarms", + getDescription: (context) => + AppLocalizations.of(context)!.alarmsDefaultSettingGroupDescription, icon: Icons.settings, ), - SelectSetting("Dismiss Action Type", searchTags: [ - "action", - "buttons", - "slider", - "slide", - "area" - ], [ - SelectSettingOption( - "Slide", - NotificationAction( - builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => - SlideNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - dismissLabel: dismissLabel, - snoozeLabel: snoozeLabel, + SelectSetting( + "Dismiss Action Type", + (context) => AppLocalizations.of(context)!.dismissActionSetting, + searchTags: [ + "action", + "buttons", + "slider", + "slide", + "area" + ], + [ + SelectSettingOption( + (context) => AppLocalizations.of(context)!.dismissActionSlide, + NotificationAction( + builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => + SlideNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + dismissLabel: dismissLabel, + snoozeLabel: snoozeLabel, + ), + ), ), - ), - ), - SelectSettingOption( - "Buttons", - NotificationAction( - builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => - ButtonsNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - dismissLabel: dismissLabel, - snoozeLabel: snoozeLabel, - ), - ), - ), - SelectSettingOption( - "Area Buttons", - NotificationAction( - builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => - AreaNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - dismissLabel: dismissLabel, - snoozeLabel: snoozeLabel, + SelectSettingOption( + (context) => AppLocalizations.of(context)!.dismissActionButtons, + NotificationAction( + builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => + ButtonsNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + dismissLabel: dismissLabel, + snoozeLabel: snoozeLabel, + ), + ), ), - ), - ) - ]), - SettingGroup("Filters", [ - SwitchSetting("Show Filters", true), - SwitchSetting("Show Sort", true), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.dismissActionAreaButtons, + NotificationAction( + builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => + AreaNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + dismissLabel: dismissLabel, + snoozeLabel: snoozeLabel, + ), + ), + ) + ]), + SettingGroup("Filters", + (context) => AppLocalizations.of(context)!.filtersSettingGroup, [ + SwitchSetting("Show Filters", + (context) => AppLocalizations.of(context)!.showFiltersSetting, true), + SwitchSetting("Show Sort", + (context) => AppLocalizations.of(context)!.showSortSetting, true), ]), SettingGroup( "Notifications", + (context) => AppLocalizations.of(context)!.notificationsSettingGroup, [ - SwitchSetting("Show Upcoming Alarm Notifications", true), + SwitchSetting( + "Show Upcoming Alarm Notifications", + (context) => AppLocalizations.of(context)! + .showUpcomingAlarmNotificationSetting, + true), SliderSetting( "Upcoming Lead Time", + (context) => AppLocalizations.of(context)!.upcomingLeadTimeSetting, 5, 120, 10, @@ -83,7 +100,11 @@ SettingGroup alarmAppSettingsSchema = SettingGroup( ["Show Upcoming Alarm Notifications"], (value) => value), ], ), - SwitchSetting("Show Snooze Notifications", true), + SwitchSetting( + "Show Snooze Notifications", + (context) => + AppLocalizations.of(context)!.showSnoozeNotificationSetting, + true), ], ) ], diff --git a/lib/settings/data/appearance_settings_schema.dart b/lib/settings/data/appearance_settings_schema.dart index a70eec39..b4a8bd38 100644 --- a/lib/settings/data/appearance_settings_schema.dart +++ b/lib/settings/data/appearance_settings_schema.dart @@ -9,6 +9,7 @@ import 'package:clock_app/theme/types/color_scheme.dart'; import 'package:clock_app/theme/types/style_theme.dart'; import 'package:clock_app/theme/utils/color_scheme.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; enum ThemeBrightness { light, dark, system } @@ -16,22 +17,36 @@ enum DarkMode { user, system, nightDay } SettingGroup appearanceSettingsSchema = SettingGroup( "Appearance", + (context) => AppLocalizations.of(context)!.appearanceSettingGroup, [ SettingGroup( "Colors", + (context) => AppLocalizations.of(context)!.colorsSettingGroup, [ SwitchSetting( "Use Material You", + (context) => AppLocalizations.of(context)!.useMaterialYouColorSetting, false, onChange: (context, value) => App.refreshTheme(context), searchTags: ["primary", "color", "material"], ), SelectSetting( "Brightness", + (context) => + AppLocalizations.of(context)!.materialBrightnessSetting, [ - SelectSettingOption("System", ThemeBrightness.system), - SelectSettingOption("Light", ThemeBrightness.light), - SelectSettingOption("Dark", ThemeBrightness.dark), + SelectSettingOption( + (context) => + AppLocalizations.of(context)!.materialBrightnessSystem, + ThemeBrightness.system), + SelectSettingOption( + (context) => + AppLocalizations.of(context)!.materialBrightnessLight, + ThemeBrightness.light), + SelectSettingOption( + (context) => + AppLocalizations.of(context)!.materialBrightnessDark, + ThemeBrightness.dark), ], enableConditions: [ ValueCondition(["Use Material You"], (value) => value == true) @@ -39,6 +54,7 @@ SettingGroup appearanceSettingsSchema = SettingGroup( onChange: (context, index) => {App.refreshTheme(context)}), SwitchSetting( "System Dark Mode", + (context) => AppLocalizations.of(context)!.systemDarkModeSetting, false, enableConditions: [ ValueCondition(["Use Material You"], (value) => value == false) @@ -46,8 +62,10 @@ SettingGroup appearanceSettingsSchema = SettingGroup( onChange: (context, value) => {App.refreshTheme(context)}), CustomSetting( "Color Scheme", - description: - "Select from predefined color schemes or create your own", + (context) => AppLocalizations.of(context)!.colorSchemeSetting, + + // description: + // "Select from predefined color schemes or create your own", defaultColorScheme, (context, setting) => ThemesScreen( saveTag: 'color_schemes', @@ -71,8 +89,9 @@ SettingGroup appearanceSettingsSchema = SettingGroup( ), CustomSetting( "Dark Color Scheme", - description: - "Select from predefined color schemes or create your own", + (context) => AppLocalizations.of(context)!.darkColorSchemeSetting, + // description: + // "Select from predefined color schemes or create your own", defaultDarkColorScheme, (context, setting) => ThemesScreen( saveTag: 'color_schemes', @@ -92,11 +111,12 @@ SettingGroup appearanceSettingsSchema = SettingGroup( searchTags: ["theme", "style", "visual", "dark mode", "night mode"], enableConditions: [ ValueCondition(["Use Material You"], (value) => value == false), - ValueCondition(["System Dark Mode"],(value) => value==true) + ValueCondition(["System Dark Mode"], (value) => value == true) ], ), SwitchSetting( "Override Accent Color", + (context) => AppLocalizations.of(context)!.overrideAccentSetting, false, onChange: (context, value) { App.refreshTheme(context); @@ -106,23 +126,28 @@ SettingGroup appearanceSettingsSchema = SettingGroup( // ValueCondition(["Use Material You"], (value) => value == false) ], ), - ColorSetting("Accent Color", Colors.cyan, onChange: (context, color) { - App.refreshTheme(context); - }, enableConditions: [ - ValueCondition(["Override Accent Color"], (value) => value == true), - // ValueCondition(["Use Material You"], (value) => value == false) - ], searchTags: [ - "primary", - "color", - "material you" - ]), + ColorSetting( + "Accent Color", + (context) => AppLocalizations.of(context)!.accentColorSetting, + Colors.cyan, + onChange: (context, color) { + App.refreshTheme(context); + }, + enableConditions: [ + ValueCondition(["Override Accent Color"], (value) => value == true), + // ValueCondition(["Use Material You"], (value) => value == false) + ], + searchTags: ["primary", "color", "material you"], + ), ], ), SettingGroup( "Style", + (context) => AppLocalizations.of(context)!.styleSettingGroup, [ SwitchSetting( "Use Material Style", + (context) => AppLocalizations.of(context)!.useMaterialStyleSetting, false, onChange: (context, value) => App.refreshTheme(context), searchTags: [ @@ -141,7 +166,8 @@ SettingGroup appearanceSettingsSchema = SettingGroup( ), CustomSetting( "Style Theme", - description: "Change styles like shadows, outlines and opacities", + (context) => AppLocalizations.of(context)!.styleThemeSetting, + // description: "Change styles like shadows, outlines and opacities", defaultStyleTheme, (context, setting) => ThemesScreen( saveTag: 'style_themes', @@ -174,5 +200,6 @@ SettingGroup appearanceSettingsSchema = SettingGroup( ), ], icon: Icons.palette_outlined, - description: "Set themes, colors and change layout", + getDescription: (context) => + AppLocalizations.of(context)!.appearanceSettingGroupDescription, ); diff --git a/lib/settings/data/backup_settings_schema.dart b/lib/settings/data/backup_settings_schema.dart index c10e7d44..0e8c5a10 100644 --- a/lib/settings/data/backup_settings_schema.dart +++ b/lib/settings/data/backup_settings_schema.dart @@ -8,25 +8,32 @@ import 'package:clock_app/settings/types/setting_action.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:flutter/material.dart'; import 'package:pick_or_save/pick_or_save.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; SettingGroup backupSettingsSchema = SettingGroup( "Backup", - description: "Export or Import your settings locally", + (context) => AppLocalizations.of(context)!.backupSettingGroup, + getDescription: (context) => + AppLocalizations.of(context)!.backupSettingGroupDescription, icon: Icons.restore_rounded, [ SettingGroup( "Settings", + (context) => AppLocalizations.of(context)!.backupSettingGroup, [ SettingAction( "Export", + (context) => AppLocalizations.of(context)!.exportSettingsSetting, (context) async { saveBackupFile(json.encode(appSettings.valueToJson()), "settings"); }, searchTags: ["settings", "export", "backup", "save"], - description: "Export settings to a local file", + getDescription: (context) => + AppLocalizations.of(context)!.exportSettingsSettingDescription, ), SettingAction( "Import", + (context) => AppLocalizations.of(context)!.importSettingsSetting, (context) async { loadBackupFile( (data) { @@ -38,7 +45,8 @@ SettingGroup backupSettingsSchema = SettingGroup( ); }, searchTags: ["settings", "import", "backup", "load"], - description: "Import settings from a local file", + getDescription: (context) => + AppLocalizations.of(context)!.importSettingsSettingDescription, ), ], ), diff --git a/lib/settings/data/developer_settings_schema.dart b/lib/settings/data/developer_settings_schema.dart index 0c3dcc97..e32d7770 100644 --- a/lib/settings/data/developer_settings_schema.dart +++ b/lib/settings/data/developer_settings_schema.dart @@ -4,27 +4,37 @@ import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_link.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; SettingGroup developerSettingsSchema = SettingGroup( "Developer Options", + (context) => AppLocalizations.of(context)!.developerOptionsSettingGroup, [ - SettingGroup("Alarm", [ + SettingGroup("Alarm", + (context) => AppLocalizations.of(context)!.alarmTitle, + [ SwitchSetting( "Show Instant Alarm Button", + (context) => AppLocalizations.of(context)!.showIstantAlarmButtonSetting, kDebugMode, - description: - "Show a button on the alarm screen that creates an alarm that rings one second in the future", + // description: + // "Show a button on the alarm screen that creates an alarm that rings one second in the future", ), ]), - SettingGroup("Logs", [ + SettingGroup("Logs", + (context) => AppLocalizations.of(context)!.logsSettingGroup, + [ SliderSetting( "Max logs", + (context) => AppLocalizations.of(context)!.maxLogsSetting, 10, 500, 100, snapLength: 1, ), - SettingPageLink("Alarm Logs", const AlarmEventsScreen()), + SettingPageLink("Alarm Logs", + (context) => AppLocalizations.of(context)!.alarmLogSetting, + const AlarmEventsScreen()), ]), ], icon: Icons.code_rounded, diff --git a/lib/settings/data/general_settings_schema.dart b/lib/settings/data/general_settings_schema.dart index 79a56e37..f596f653 100644 --- a/lib/settings/data/general_settings_schema.dart +++ b/lib/settings/data/general_settings_schema.dart @@ -8,7 +8,6 @@ import 'package:clock_app/common/utils/list_storage.dart'; import 'package:clock_app/common/utils/snackbar.dart'; import 'package:clock_app/common/utils/time_format.dart'; import 'package:clock_app/icons/flux_icons.dart'; -import 'package:clock_app/l10n/language_local.dart'; import 'package:clock_app/settings/screens/ringtones_screen.dart'; import 'package:clock_app/settings/screens/tags_screen.dart'; import 'package:clock_app/settings/types/setting.dart'; @@ -27,10 +26,10 @@ enum TimePickerType { dial, input, spinner } enum DurationPickerType { rings, spinner } - SelectSettingOption _getDateSettingOption(String format) { return SelectSettingOption( - "${DateFormat(format).format(DateTime.now())} ($format)", format); + (context) => "${DateFormat(format).format(DateTime.now())} ($format)", + format); } enum SwipeAction { @@ -39,140 +38,188 @@ enum SwipeAction { } final timeFormatOptions = [ - SelectSettingOption("12 Hours", TimeFormat.h12), - SelectSettingOption("24 Hours", TimeFormat.h24), - SelectSettingOption("Device Settings", TimeFormat.device), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.timeFormat12, TimeFormat.h12), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.timeFormat24, TimeFormat.h24), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.timeFormatDevice, + TimeFormat.device), ]; SettingGroup generalSettingsSchema = SettingGroup( "General", + (context) => AppLocalizations.of(context)!.generalSettingGroup, [ - SelectSetting("Language",[SelectSettingOption("System", Locale(Platform.localeName)), ...AppLocalizations.supportedLocales.map((locale) { - return SelectSettingOption(Locale.fromSubtags( - languageCode: locale.languageCode, scriptCode: locale.scriptCode, countryCode: locale.countryCode).nativeDisplayLanguage, locale); - })], onChange: (context, index) { - App.refreshTheme(context); - }), - SettingGroup("Display", [ - SelectSetting( - "Date Format", - [ - _getDateSettingOption("dd/MM/yyyy"), - _getDateSettingOption("dd-MM-yyyy"), - _getDateSettingOption("d/M/yyyy"), - _getDateSettingOption("d-M-yyyy"), - _getDateSettingOption("MM/dd/yyyy"), - _getDateSettingOption("MM-dd-yyyy"), - _getDateSettingOption("M/d/yy"), - _getDateSettingOption("M-d-yy"), - _getDateSettingOption("M/d/yyyy"), - _getDateSettingOption("M-d-yyyy"), - _getDateSettingOption("yyyy/dd/MM"), - _getDateSettingOption("yyyy-dd-MM"), - _getDateSettingOption("yyyy/MM/dd"), - _getDateSettingOption("yyyy-MM-dd"), - // SelectSettingOption(DateTime.now().toIso8601Date(), "YYYY-MM-DD"), - _getDateSettingOption("d MMM yyyy"), - _getDateSettingOption("d MMMM yyyy"), - ], - description: "How to display the dates", - ), - SelectSetting("Time Format", timeFormatOptions, - description: "12 or 24 hour time", onChange: (context, index) { - saveTextFile("time_format_string", - getTimeFormatString(context, timeFormatOptions[index].value)); - }), - SwitchSetting("Show Seconds", true), - SelectSetting("Time Picker", [ - SelectSettingOption( - "Dial", - TimePickerType.dial, - ), - SelectSettingOption( - "Input", - TimePickerType.input, - ), - SelectSettingOption( - "Spinner", - TimePickerType.spinner, - ), - ], searchTags: [ - "time", - "picker", - "dial", - "input", - "spinner", - ]), - SelectSetting("Duration Picker", [ - SelectSettingOption( - "Rings", - DurationPickerType.rings, + SelectSetting( + "Language", + (context) => AppLocalizations.of(context)!.languageSetting, + [ + SelectSettingOption((context) => AppLocalizations.of(context)!.system, + Locale(Platform.localeName)), + ...AppLocalizations.supportedLocales.map((locale) { + return SelectSettingOption( + (context) => Locale.fromSubtags( + languageCode: locale.languageCode, + scriptCode: locale.scriptCode, + countryCode: locale.countryCode) + .nativeDisplayLanguage, + locale); + }) + ], + onChange: (context, index) { + App.refreshTheme(context); + }, + ), + SettingGroup( + "Display", + (context) => AppLocalizations.of(context)!.displaySettingGroup, + [ + SelectSetting( + "Date Format", + (context) => AppLocalizations.of(context)!.dateFormatSetting, + [ + _getDateSettingOption("dd/MM/yyyy"), + _getDateSettingOption("dd-MM-yyyy"), + _getDateSettingOption("d/M/yyyy"), + _getDateSettingOption("d-M-yyyy"), + _getDateSettingOption("MM/dd/yyyy"), + _getDateSettingOption("MM-dd-yyyy"), + _getDateSettingOption("M/d/yy"), + _getDateSettingOption("M-d-yy"), + _getDateSettingOption("M/d/yyyy"), + _getDateSettingOption("M-d-yyyy"), + _getDateSettingOption("yyyy/dd/MM"), + _getDateSettingOption("yyyy-dd-MM"), + _getDateSettingOption("yyyy/MM/dd"), + _getDateSettingOption("yyyy-MM-dd"), + // SelectSettingOption(DateTime.now().toIso8601Date(), "YYYY-MM-DD"), + _getDateSettingOption("d MMM yyyy"), + _getDateSettingOption("d MMMM yyyy"), + ], + getDescription: (context) => "How to display the dates", ), - SelectSettingOption( - "Spinner", - DurationPickerType.spinner, + SelectSetting( + "Time Format", + (context) => AppLocalizations.of(context)!.timeFormatSetting, + timeFormatOptions, + getDescription: (context) => "12 or 24 hour time", + onChange: (context, index) { + saveTextFile("time_format_string", + getTimeFormatString(context, timeFormatOptions[index].value)); + }, ), - ], searchTags: [ - "duration", - "rings", - "time", - "picker", - "dial", - "input", - "spinner", - ]), - ]), + SwitchSetting( + "Show Seconds", + (context) => AppLocalizations.of(context)!.showSecondsSetting, + true), + SelectSetting("Time Picker", + (context) => AppLocalizations.of(context)!.timePickerSetting, [ + SelectSettingOption( + (context) => AppLocalizations.of(context)!.pickerDial, + TimePickerType.dial, + ), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.pickerInput, + TimePickerType.input, + ), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.pickerSpinner, + TimePickerType.spinner, + ), + ], + searchTags: [ + "time", + "picker", + "dial", + "input", + "spinner", + ]), + SelectSetting("Duration Picker", + (context) => AppLocalizations.of(context)!.durationPickerSetting, [ + SelectSettingOption( + (context) => AppLocalizations.of(context)!.pickerRings, + DurationPickerType.rings, + ), + SelectSettingOption( + (context) => AppLocalizations.of(context)!.pickerSpinner, + DurationPickerType.spinner, + ), + ], + searchTags: [ + "duration", + "rings", + "time", + "picker", + "dial", + "input", + "spinner", + ]), + ], + ), SelectSetting( "Swipe Action", + (context) => AppLocalizations.of(context)!.swipeActionSetting, [ SelectSettingOption( - "Card Actions", + (context) => AppLocalizations.of(context)!.swipActionCardAction, SwipeAction.cardActions, - description: "Swipe cards to delete or duplicate them", + getDescription: (context) => + AppLocalizations.of(context)!.swipeActionCardActionDescription, ), SelectSettingOption( - "Switch Tabs", + (context) => AppLocalizations.of(context)!.swipActionSwitchTabs, SwipeAction.switchTabs, - description: "Swipe from one tab to the next", + getDescription: (context) => + AppLocalizations.of(context)!.swipeActionSwitchTabsDescription, ) ], ), SettingPageLink( "Melodies", + (context) => AppLocalizations.of(context)!.melodiesSetting, const RingtonesScreen(), searchTags: ["ringtones", "music", "audio", "tones", "custom"], icon: Icons.music_note_outlined, ), SettingPageLink( "Tags", + (context) => AppLocalizations.of(context)!.tagsSetting, const TagsScreen(), searchTags: ["tags", "groups", "filter"], icon: Icons.label_outline_rounded, ), - SettingGroup("Reliability", [ + SettingGroup("Reliability", + (context) => AppLocalizations.of(context)!.reliabilitySettingGroup, [ SettingAction( "Vendor Specific", + (context) => AppLocalizations.of(context)!.vendorSetting, (context) => launchUrl(Uri.parse("https://dontkillmyapp.com")), - description: "Manually disable vendor-specific optimizations", + getDescription: (context) => + AppLocalizations.of(context)!.vendorSettingDescription, ), SettingAction( "Disable Battery Optimization", + (context) => AppLocalizations.of(context)!.batteryOptimizationSetting, (context) async { AppSettings.openAppSettings( type: AppSettingsType.batteryOptimization); }, - description: - "Disable battery optimization for this app to prevent alarms from being delayed", + getDescription: (context) => + AppLocalizations.of(context)!.batteryOptimizationSettingDescription, ), SettingAction( "Allow Notifications", + (context) => AppLocalizations.of(context)!.allowNotificationSetting, (context) async { AppSettings.openAppSettings(type: AppSettingsType.notification); }, - description: "Allow lock screen notifications for alarms and timers", + getDescription: (context) => + AppLocalizations.of(context)!.allowNotificationSettingDescription, ), SettingAction( "Auto Start", + (context) => AppLocalizations.of(context)!.autoStartSetting, (context) async { try { //check auto-start availability. @@ -191,13 +238,15 @@ SettingGroup generalSettingsSchema = SettingGroup( if (kDebugMode) print(e.message); } }, - description: - "Some devices require Auto Start to be enabled for alarms to ring while app is closed.", + getDescription: (context) => + AppLocalizations.of(context)!.autoStartSettingDescription, ), ]), - SettingGroup("Animations", [ + SettingGroup("Animations", + (context) => AppLocalizations.of(context)!.animationSettingGroup, [ SliderSetting( "Animation Speed", + (context) => AppLocalizations.of(context)!.animationSpeedSetting, 0.5, 2, 1, @@ -208,9 +257,13 @@ SettingGroup generalSettingsSchema = SettingGroup( // ["Show Upcoming Alarm Notifications"], (value) => value), // ], ), - SwitchSetting("Extra Animations", false), + SwitchSetting( + "Extra Animations", + (context) => AppLocalizations.of(context)!.extraAnimationSetting, + false), ]) ], icon: FluxIcons.settings, - description: "Set app wide settings like time format", + getDescription: (context) => + AppLocalizations.of(context)!.generalSettingGroupDescription, ); diff --git a/lib/settings/data/localized_names.dart b/lib/settings/data/localized_names.dart index f0d199ca..06845ff6 100644 --- a/lib/settings/data/localized_names.dart +++ b/lib/settings/data/localized_names.dart @@ -1,21 +1,29 @@ - import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - - -String getLocalizedSettingName(String name, BuildContext context) { - switch (name) { - case "General": - return AppLocalizations.of(context)!.generalSettingGroup; - case "Appearance": - return AppLocalizations.of(context)!.appearanceSettingGroup; - default: - return name; - } - } - -String getLocalizedSettingDescription(String name, BuildContext context) { - switch (name) { - default: - return name; - } - } +// import 'package:flutter/material.dart'; +// import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +// +// String getLocalizedSettingName(String name, BuildContext context) { +// switch (name) { +// case "General": +// return AppLocalizations.of(context)!.generalSettingGroup; +// case "Appearance": +// return AppLocalizations.of(context)!.appearanceSettingGroup; +// case "Alarm": +// return AppLocalizations.of(context)!.alarmTitle; +// case "Timer": +// return AppLocalizations.of(context)!.timerTitle; +// case "Stopwatch": +// return AppLocalizations.of(context)!.stopwatchTitle; +// case "Clock": +// return AppLocalizations.of(context)!.clockTitle; +// case "Developer Options" +// default: +// return name; +// } +// } +// +// String getLocalizedSettingDescription(String name, BuildContext context) { +// switch (name) { +// default: +// return name; +// } +// } diff --git a/lib/settings/data/settings_schema.dart b/lib/settings/data/settings_schema.dart index c0e09ff9..af203323 100644 --- a/lib/settings/data/settings_schema.dart +++ b/lib/settings/data/settings_schema.dart @@ -9,11 +9,12 @@ import 'package:clock_app/settings/data/timer_app_settings_schema.dart'; import 'package:clock_app/settings/screens/about_screen.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_link.dart'; - -const int settingsSchemaVersion = 3; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +const int settingsSchemaVersion = 4; SettingGroup appSettings = SettingGroup( "Settings", + (context) => AppLocalizations.of(context)!.settings, version: settingsSchemaVersion, isSearchable: true, [ @@ -27,6 +28,7 @@ SettingGroup appSettings = SettingGroup( developerSettingsSchema, SettingPageLink( "About", + (context) => AppLocalizations.of(context)!.aboutSettingGroup, const AboutScreen(), ), ], diff --git a/lib/settings/data/stopwatch_settings_schema.dart b/lib/settings/data/stopwatch_settings_schema.dart index 595c67bc..7e3f5067 100644 --- a/lib/settings/data/stopwatch_settings_schema.dart +++ b/lib/settings/data/stopwatch_settings_schema.dart @@ -3,30 +3,55 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + SettingGroup stopwatchSettingsSchema = SettingGroup( "Stopwatch", + (context) => AppLocalizations.of(context)!.stopwatchTitle, [ SettingGroup( "Time Format", + (context) => + AppLocalizations.of(context)!.stopwatchTimeFormatSettingGroup, [ - SwitchSetting("Show Milliseconds", true), + SwitchSetting( + "Show Milliseconds", + (context) => AppLocalizations.of(context)! + .stopwatchShowMillisecondsSetting, + true), ], - description: "Show comparison laps bars in stopwatch", + // description: "Show comparison laps bars in stopwatch", icon: Icons.settings, searchTags: ["milliseconds"]), SettingGroup( "Comparison Lap Bars", + (context) => AppLocalizations.of(context)!.comparisonLapBarsSettingGroup, [ - SwitchSetting("Show Previous Lap", true), - SwitchSetting("Show Fastest Lap", true), - SwitchSetting("Show Slowest Lap", true), - SwitchSetting("Show Average Lap", true), + SwitchSetting( + "Show Previous Lap", + (context) => AppLocalizations.of(context)!.showPreviousLapSetting, + true), + SwitchSetting( + "Show Fastest Lap", + (context) => AppLocalizations.of(context)!.showFastestLapSetting, + true), + SwitchSetting( + "Show Slowest Lap", + (context) => AppLocalizations.of(context)!.showSlowestLapSetting, + true), + SwitchSetting( + "Show Average Lap", + (context) => AppLocalizations.of(context)!.showAverageLapSetting, + true), ], - description: "Show comparison laps bars in stopwatch", + // description: "Show comparison laps bars in stopwatch", icon: Icons.settings, searchTags: ["fastest", "slowest", "average", "previous"], ), - SwitchSetting("Show Notification", true), + SwitchSetting( + "Show Notification", + (context) => AppLocalizations.of(context)!.showNotificationSetting, + true), ], icon: FluxIcons.stopwatch, ); diff --git a/lib/settings/data/timer_app_settings_schema.dart b/lib/settings/data/timer_app_settings_schema.dart index dfc54a38..d7fbfdb4 100644 --- a/lib/settings/data/timer_app_settings_schema.dart +++ b/lib/settings/data/timer_app_settings_schema.dart @@ -9,66 +9,83 @@ import 'package:clock_app/settings/types/setting_link.dart'; import 'package:clock_app/timer/data/timer_settings_schema.dart'; import 'package:clock_app/timer/screens/presets_screen.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; SettingGroup timerAppSettingsSchema = SettingGroup( "Timer", + (context) => AppLocalizations.of(context)!.timerTitle, [ SettingGroup( "Default Settings", + (context) => AppLocalizations.of(context)!.defaultSettingGroup, [...timerSettingsSchema.settingItems], - description: "Set default settings for new timers", + getDescription: (context) => + AppLocalizations.of(context)!.timerDefaultSettingGroupDescription, icon: Icons.settings, ), - SettingPageLink("Presets", const PresetsScreen()), - SelectSetting("Dismiss Action Type", searchTags: [ - "action", - "buttons", - "slider", - "slide", - "area" - ], [ - SelectSettingOption( - "Area Buttons", - NotificationAction( - builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => - AreaNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - dismissLabel: dismissLabel, - snoozeLabel: snoozeLabel, + SettingPageLink( + "Presets", + (context) => AppLocalizations.of(context)!.presetsSetting, + const PresetsScreen()), + SelectSetting( + "Dismiss Action Type", + (context) => AppLocalizations.of(context)!.dismissActionSetting, + searchTags: [ + "action", + "buttons", + "slider", + "slide", + "area" + ], + [ + SelectSettingOption( + (context) => AppLocalizations.of(context)!.dismissActionSlide, + NotificationAction( + builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => + AreaNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + dismissLabel: dismissLabel, + snoozeLabel: snoozeLabel, + ), + ), ), - ), - ), - SelectSettingOption( - "Slide", - NotificationAction( - builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => - SlideNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - dismissLabel: dismissLabel, - snoozeLabel: snoozeLabel, + SelectSettingOption( + (context) => AppLocalizations.of(context)!.dismissActionButtons, + NotificationAction( + builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => + SlideNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + dismissLabel: dismissLabel, + snoozeLabel: snoozeLabel, + ), + ), ), - ), - ), - SelectSettingOption( - "Buttons", - NotificationAction( - builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => - ButtonsNotificationAction( - onDismiss: onDismiss, - onSnooze: onSnooze, - dismissLabel: dismissLabel, - snoozeLabel: snoozeLabel, + SelectSettingOption( + (context) => AppLocalizations.of(context)!.dismissActionAreaButtons, + NotificationAction( + builder: (onDismiss, onSnooze, dismissLabel, snoozeLabel) => + ButtonsNotificationAction( + onDismiss: onDismiss, + onSnooze: onSnooze, + dismissLabel: dismissLabel, + snoozeLabel: snoozeLabel, + ), + ), ), - ), - ), + ]), + SettingGroup("Filters", + (context) => AppLocalizations.of(context)!.filtersSettingGroup, [ + SwitchSetting("Show Filters", + (context) => AppLocalizations.of(context)!.showFiltersSetting, true), + SwitchSetting("Show Sort", + (context) => AppLocalizations.of(context)!.showSortSetting, true), ]), - SettingGroup("Filters", [ - SwitchSetting("Show Filters", true), - SwitchSetting("Show Sort", true), - ]), - SwitchSetting("Show Notification", true), + SwitchSetting( + "Show Notification", + (context) => AppLocalizations.of(context)!.showNotificationSetting, + true), ], icon: FluxIcons.timer, ); diff --git a/lib/settings/screens/about_screen.dart b/lib/settings/screens/about_screen.dart index c757812a..9d8d58f6 100644 --- a/lib/settings/screens/about_screen.dart +++ b/lib/settings/screens/about_screen.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher_string.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class AboutScreen extends StatelessWidget { const AboutScreen({super.key}); @@ -30,7 +31,12 @@ class AboutScreen extends StatelessWidget { child: Column( children: [ const AboutInfo(), - SettingPageLinkCard(setting: SettingPageLink("Credits", const LicensesScreen())), + SettingPageLinkCard( + setting: SettingPageLink( + "Credits", + (context) => + AppLocalizations.of(context)!.creditsSettingGroup, + const LicensesScreen())), // CardContainer( // child: Padding( // padding: const EdgeInsets.all(16.0), diff --git a/lib/settings/screens/licenses.dart b/lib/settings/screens/licenses.dart index 63a01460..97a4e869 100644 --- a/lib/settings/screens/licenses.dart +++ b/lib/settings/screens/licenses.dart @@ -1,13 +1,9 @@ -import 'package:clock_app/common/data/app_info.dart'; -import 'package:clock_app/common/widgets/card_container.dart'; import 'package:clock_app/navigation/widgets/app_top_bar.dart'; import 'package:clock_app/oss_licenses.dart'; import 'package:clock_app/settings/types/setting_action.dart'; import 'package:clock_app/settings/widgets/setting_action_card.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:url_launcher/url_launcher_string.dart'; class LicensesScreen extends StatelessWidget { const LicensesScreen({super.key}); @@ -30,7 +26,9 @@ class LicensesScreen extends StatelessWidget { child: Column( children: [ ...allDependencies.map((dependency) => SettingActionCard( - setting: SettingAction(dependency.name, (context) async { + setting: SettingAction(dependency.name, + (context) => dependency.name, + (context) async { if (dependency.repository != null) { await launchUrl(Uri.parse(dependency.repository!)); } diff --git a/lib/settings/screens/restore_defaults_screen.dart b/lib/settings/screens/restore_defaults_screen.dart index 27fb1f26..24d52290 100644 --- a/lib/settings/screens/restore_defaults_screen.dart +++ b/lib/settings/screens/restore_defaults_screen.dart @@ -7,11 +7,10 @@ import 'package:flutter/material.dart'; class SettingCheckBox extends StatelessWidget { const SettingCheckBox( - {Key? key, + {super.key, required this.settingItem, required this.isChecked, - required this.onChanged}) - : super(key: key); + required this.onChanged}); final SettingItem settingItem; @@ -29,7 +28,7 @@ class SettingCheckBox extends StatelessWidget { onChanged: onChanged, ), Text( - settingItem.name, + settingItem.displayName(context), style: Theme.of(context).textTheme.headlineMedium, ), ], @@ -114,7 +113,7 @@ class _RestoreDefaultScreenState extends State { }, ), ) - .toList(), + , const SizedBox(height: 16), ], ), diff --git a/lib/settings/screens/settings_group_screen.dart b/lib/settings/screens/settings_group_screen.dart index 544e040b..44e967f2 100644 --- a/lib/settings/screens/settings_group_screen.dart +++ b/lib/settings/screens/settings_group_screen.dart @@ -4,7 +4,7 @@ import 'package:clock_app/settings/screens/restore_defaults_screen.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_item.dart'; import 'package:clock_app/settings/types/setting_link.dart'; - +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:clock_app/settings/widgets/search_setting_card.dart'; import 'package:clock_app/settings/widgets/setting_page_link_card.dart'; import 'package:clock_app/settings/widgets/settings_top_bar.dart'; @@ -66,6 +66,7 @@ class _SettingGroupScreenState extends State { SettingPageLinkCard( setting: SettingPageLink( 'Restore default values', + (context) =>AppLocalizations.of(context)!.restoreSettingGroup, RestoreDefaultScreen( settingGroup: widget.settingGroup, onRestore: () async { diff --git a/lib/settings/types/setting.dart b/lib/settings/types/setting.dart index 93c09d6b..d840855c 100644 --- a/lib/settings/types/setting.dart +++ b/lib/settings/types/setting.dart @@ -4,6 +4,7 @@ import 'package:clock_app/common/utils/json_serialize.dart'; import 'package:clock_app/common/utils/list_item.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_item.dart'; +import 'package:clock_app/settings/utils/description.dart'; import 'package:clock_app/timer/types/time_duration.dart'; import 'package:flutter/material.dart'; @@ -21,7 +22,8 @@ abstract class Setting extends SettingItem { Setting( String name, - String description, + String Function(BuildContext) getLocalizedName, + String Function(BuildContext) description, T defaultValue, this.onChange, List enableConditions, @@ -32,7 +34,8 @@ abstract class Setting extends SettingItem { _defaultValue = valueCopyGetter?.call(defaultValue) ?? defaultValue, changesEnableCondition = false, _valueCopyGetter = valueCopyGetter, - super(name, description, searchTags, enableConditions); + super( + name, getLocalizedName, description, searchTags, enableConditions); void setValue(BuildContext context, T value) { _value = _valueCopyGetter?.call(value) ?? value; @@ -65,7 +68,7 @@ abstract class Setting extends SettingItem { class ListSetting extends Setting> { List possibleItems; - Widget Function(T item, [VoidCallback?,VoidCallback?]) cardBuilder; + Widget Function(T item, [VoidCallback?, VoidCallback?]) cardBuilder; Widget Function(T item) addCardBuilder; Widget Function(T item)? itemPreviewBuilder; // The widget that will be used to display the value of this setting. @@ -74,20 +77,22 @@ class ListSetting extends Setting> { ListSetting( String name, + String Function(BuildContext) getLocalizedName, List defaultValue, this.possibleItems, { required this.cardBuilder, required this.valueDisplayBuilder, required this.addCardBuilder, this.itemPreviewBuilder, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, void Function(BuildContext, List)? onChange, bool isVisual = true, List enableConditions = const [], List searchTags = const [], }) : super( name, - description, + getLocalizedName, + getDescription, copyItemList(defaultValue), onChange, enableConditions, @@ -100,12 +105,13 @@ class ListSetting extends Setting> { ListSetting copy() { return ListSetting( name, + getLocalizedName, _value, possibleItems, valueDisplayBuilder: valueDisplayBuilder, cardBuilder: cardBuilder, addCardBuilder: addCardBuilder, - description: description, + getDescription: getDescription, onChange: onChange, enableConditions: enableConditions, isVisual: isVisual, @@ -122,8 +128,9 @@ class ListSetting extends Setting> { return addCardBuilder(item); } - Widget getItemCard(T item, {VoidCallback? onDelete, VoidCallback? onDuplicate}) { - return cardBuilder(item,onDelete,onDuplicate); + Widget getItemCard(T item, + {VoidCallback? onDelete, VoidCallback? onDuplicate}) { + return cardBuilder(item, onDelete, onDuplicate); } Widget? getPreviewCard(T item) { @@ -151,17 +158,18 @@ class CustomSetting extends Setting { CustomSetting( String name, + String Function(BuildContext) getLocalizedName, T defaultValue, this.screenBuilder, this.valueDisplayBuilder, { - String description = "", + String Function(BuildContext) getDescription = defaultDescription, void Function(BuildContext, T)? onChange, this.copyValue, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual) { + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual) { copyValue ??= (T value) => value; } @@ -177,10 +185,11 @@ class CustomSetting extends Setting { CustomSetting copy() { return CustomSetting( name, + getLocalizedName, copyValue?.call(_value) ?? _value, screenBuilder, valueDisplayBuilder, - description: description, + getDescription: getDescription, onChange: onChange, enableConditions: enableConditions, isVisual: isVisual, @@ -204,22 +213,24 @@ class CustomSetting extends Setting { class SwitchSetting extends Setting { SwitchSetting( String name, + String Function(BuildContext) getLocalizedName, bool defaultValue, { void Function(BuildContext, bool)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual); + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual); @override SwitchSetting copy() { return SwitchSetting( name, + getLocalizedName, _value, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -230,22 +241,24 @@ class SwitchSetting extends Setting { class NumberSetting extends Setting { NumberSetting( String name, + String Function(BuildContext) getLocalizedName, double defaultValue, { void Function(BuildContext, double)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual); + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual); @override NumberSetting copy() { return NumberSetting( name, + getLocalizedName, _value, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -256,14 +269,15 @@ class NumberSetting extends Setting { class ColorSetting extends Setting { ColorSetting( String name, + String Function(BuildContext) getLocalizedName, Color defaultValue, { void Function(BuildContext, Color)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual); + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual); @override dynamic valueToJson() { @@ -280,9 +294,10 @@ class ColorSetting extends Setting { ColorSetting copy() { return ColorSetting( name, + getLocalizedName, _value, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -293,22 +308,24 @@ class ColorSetting extends Setting { class StringSetting extends Setting { StringSetting( String name, + String Function(BuildContext) getLocalizedName, String defaultValue, { void Function(BuildContext, String)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual); + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual); @override StringSetting copy() { return StringSetting( name, + getLocalizedName, _value, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -325,19 +342,20 @@ class SliderSetting extends Setting { SliderSetting( String name, + String Function(BuildContext) getLocalizedName, this.min, this.max, double defaultValue, { void Function(BuildContext context, double)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, this.maxIsInfinity = false, this.snapLength, this.unit = "", List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual); + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual); // @override // dynamic get value => @@ -347,11 +365,12 @@ class SliderSetting extends Setting { SliderSetting copy() { return SliderSetting( name, + getLocalizedName, min, max, _value, onChange: onChange, - description: description, + getDescription: getDescription, snapLength: snapLength, maxIsInfinity: maxIsInfinity, enableConditions: enableConditions, @@ -388,24 +407,26 @@ class SelectSetting extends Setting { SelectSetting( String name, + String Function(BuildContext) getLocalizedName, this._options, { void Function(BuildContext, int)? onChange, int defaultValue = 0, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual); + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual); @override SelectSetting copy() { return SelectSetting( name, + getLocalizedName, _options, defaultValue: _value, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -424,15 +445,16 @@ class DynamicSelectSetting extends Setting { DynamicSelectSetting( String name, + String Function(BuildContext) getLocalizedName, this.optionsGetter, { void Function(BuildContext, int)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, int defaultValue = -1, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual) { + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual) { if (defaultValue != -1) { _value = defaultValue; } @@ -442,10 +464,11 @@ class DynamicSelectSetting extends Setting { DynamicSelectSetting copy() { return DynamicSelectSetting( name, + getLocalizedName, optionsGetter, onChange: onChange, defaultValue: _value, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -521,31 +544,33 @@ class MultiSelectSetting extends Setting> { MultiSelectSetting( String name, + String Function(BuildContext) getLocalizedName, this._options, { void Function(BuildContext, List)? onChange, List defaultValue = const [0], - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual); + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual); @override MultiSelectSetting copy() { return MultiSelectSetting( name, + getLocalizedName, _options, defaultValue: _value, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, ); } - @override + @override dynamic valueToJson() { return _value; } @@ -565,21 +590,25 @@ class DynamicMultiSelectSetting extends Setting> { @override dynamic get value { return selectedIndices.map((index) => options[index].value).toList(); -} - List get selectedIndices => - _value.map((id) => getIndexOfId(id)).where((index)=>index>=0).toList(); + } + + List get selectedIndices => _value + .map((id) => getIndexOfId(id)) + .where((index) => index >= 0) + .toList(); DynamicMultiSelectSetting( String name, + String Function(BuildContext) getLocalizedName, this.optionsGetter, { void Function(BuildContext, List)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, List defaultValue = const [-1], bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual) { + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual) { if (!defaultValue.contains(-1)) { _value = defaultValue; } @@ -587,13 +616,17 @@ class DynamicMultiSelectSetting extends Setting> { @override DynamicMultiSelectSetting copy() { - return DynamicMultiSelectSetting(name, optionsGetter, - onChange: onChange, - defaultValue: _value, - description: description, - enableConditions: enableConditions, - isVisual: isVisual, - searchTags: searchTags); + return DynamicMultiSelectSetting( + name, + getLocalizedName, + optionsGetter, + onChange: onChange, + defaultValue: _value, + getDescription: getDescription, + enableConditions: enableConditions, + isVisual: isVisual, + searchTags: searchTags, + ); } void setIndex(BuildContext context, List indices) { @@ -624,7 +657,6 @@ class DynamicMultiSelectSetting extends Setting> { @override dynamic valueToJson() { return _value; - } @override @@ -652,16 +684,18 @@ class ToggleSetting extends Setting> { ToggleSetting( String name, + String Function(BuildContext) getLocalizedName, this.options, { void Function(BuildContext, List)? onChange, List defaultValue = const [], - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], }) : super( name, - description, + getLocalizedName, + getDescription, defaultValue.length == options.length ? List.from(defaultValue) : List.generate(options.length, (index) => index == 0), @@ -676,10 +710,11 @@ class ToggleSetting extends Setting> { ToggleSetting copy() { return ToggleSetting( name, + getLocalizedName, options, defaultValue: _value, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -711,16 +746,18 @@ class DateTimeSetting extends Setting> { DateTimeSetting( String name, + String Function(BuildContext) getLocalizedName, List defaultValue, { this.rangeOnly = false, void Function(BuildContext, List)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], }) : super( name, - description, + getLocalizedName, + getDescription, defaultValue, onChange, enableConditions, @@ -733,10 +770,11 @@ class DateTimeSetting extends Setting> { DateTimeSetting copy() { return DateTimeSetting( name, + getLocalizedName, _value, rangeOnly: rangeOnly, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -770,22 +808,24 @@ class DateTimeSetting extends Setting> { class DurationSetting extends Setting { DurationSetting( String name, + String Function(BuildContext) getLocalizedName, TimeDuration defaultValue, { void Function(BuildContext, TimeDuration)? onChange, - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, List enableConditions = const [], List searchTags = const [], - }) : super(name, description, defaultValue, onChange, enableConditions, - searchTags, isVisual); + }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, + enableConditions, searchTags, isVisual); @override DurationSetting copy() { return DurationSetting( name, + getLocalizedName, _value, onChange: onChange, - description: description, + getDescription: getDescription, enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, @@ -805,16 +845,17 @@ class DurationSetting extends Setting { } class ToggleSettingOption { - String name; + String Function(BuildContext) getLocalizedName; T value; - ToggleSettingOption(this.name, this.value); + ToggleSettingOption(this.getLocalizedName, this.value); } class SelectSettingOption { - String name; - String description; + String Function(BuildContext) getDescription; + String Function(BuildContext) getLocalizedName; T value; - SelectSettingOption(this.name, this.value, {this.description = ""}); + SelectSettingOption(this.getLocalizedName, this.value, + {this.getDescription = defaultDescription}); } diff --git a/lib/settings/types/setting_action.dart b/lib/settings/types/setting_action.dart index 1a72d67c..bf45f32d 100644 --- a/lib/settings/types/setting_action.dart +++ b/lib/settings/types/setting_action.dart @@ -1,5 +1,6 @@ import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_item.dart'; +import 'package:clock_app/settings/utils/description.dart'; import 'package:flutter/material.dart'; class SettingAction extends SettingItem { @@ -7,18 +8,19 @@ class SettingAction extends SettingItem { SettingAction( String name, + String Function(BuildContext) getLocalizedName, this.action, { - String description = "", + String Function(BuildContext) getDescription = defaultDescription, List searchTags = const [], List enableConditions = const [], - }) : super(name, description, searchTags, enableConditions); + }) : super(name, getLocalizedName, getDescription, searchTags, enableConditions); @override SettingAction copy() { - return SettingAction(name, action, - description: description, + return SettingAction(name, getLocalizedName, action, + getDescription: getDescription, searchTags: searchTags, - enableConditions: enableConditions); + enableConditions: enableConditions,); } @override diff --git a/lib/settings/types/setting_group.dart b/lib/settings/types/setting_group.dart index f2185192..4c982b7e 100644 --- a/lib/settings/types/setting_group.dart +++ b/lib/settings/types/setting_group.dart @@ -7,6 +7,7 @@ import 'package:clock_app/settings/types/setting_action.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_item.dart'; import 'package:clock_app/settings/types/setting_link.dart'; +import 'package:clock_app/settings/utils/description.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:get_storage/get_storage.dart'; @@ -36,12 +37,13 @@ class SettingGroup extends SettingItem { SettingGroup( String name, + String Function(BuildContext) getLocalizedName, this._settingItems, { int? version, IconData? icon, List enableConditions = const [], List summarySettings = const [], - String description = "", + String Function(BuildContext) getDescription = defaultDescription, bool? showExpandedView, bool isSearchable = false, List searchTags = const [], @@ -54,7 +56,8 @@ class SettingGroup extends SettingItem { _settingPageLinks = [], _settingActions = [], _version = version, - super(name, description, searchTags, enableConditions) { + super( + name, getLocalizedName, getDescription, searchTags, enableConditions) { for (SettingItem item in _settingItems) { item.parent = this; if (item is Setting) { @@ -82,6 +85,7 @@ class SettingGroup extends SettingItem { SettingGroup copy() { return SettingGroup( name, + getLocalizedName, _settingItems.map((setting) => setting.copy()).toList(), icon: icon, searchTags: searchTags, @@ -90,7 +94,7 @@ class SettingGroup extends SettingItem { isSearchable: isSearchable, showExpandedView: showExpandedView, summarySettings: _summarySettings, - description: description, + getDescription: getDescription, ); } diff --git a/lib/settings/types/setting_item.dart b/lib/settings/types/setting_item.dart index f5862720..8c34d768 100644 --- a/lib/settings/types/setting_item.dart +++ b/lib/settings/types/setting_item.dart @@ -4,11 +4,10 @@ import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:flutter/material.dart'; - - abstract class SettingItem { String name; - String description; + String Function(BuildContext) getLocalizedName; + String Function(BuildContext) getDescription; String id; SettingGroup? _parent; final List _settingListeners; @@ -20,14 +19,17 @@ abstract class SettingItem { List enableSettings; // List compoundEnableSettings; - String displayName(BuildContext context) => getLocalizedSettingName(name, context); - String displayDescription(BuildContext context) => getLocalizedSettingDescription(description, context); + String displayName(BuildContext context) => + getLocalizedName(context); + + String displayDescription(BuildContext context) => + getDescription(context); bool get isEnabled { for (var enableSetting in enableSettings) { - if(!enableSetting.evaluate()){ - return false; - } + if (!enableSetting.evaluate()) { + return false; + } } return true; @@ -49,8 +51,8 @@ abstract class SettingItem { return path.reversed.toList(); } - SettingItem(this.name, this.description, this.searchTags, - this.enableConditions) + SettingItem( + this.name, this.getLocalizedName, this.getDescription, this.searchTags, this.enableConditions ) : id = name, _settingListeners = [], enableSettings = []; diff --git a/lib/settings/types/setting_link.dart b/lib/settings/types/setting_link.dart index 377042c0..be5d09ec 100644 --- a/lib/settings/types/setting_link.dart +++ b/lib/settings/types/setting_link.dart @@ -1,5 +1,6 @@ import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_item.dart'; +import 'package:clock_app/settings/utils/description.dart'; import 'package:flutter/material.dart'; class SettingPageLink extends SettingItem { @@ -8,20 +9,26 @@ class SettingPageLink extends SettingItem { SettingPageLink( String name, + String Function(BuildContext) getLocalizedName, this.screen, { - String description = "", + String Function(BuildContext) getDescription = defaultDescription, this.icon, List searchTags = const [], List enableConditions = const [], - }) : super(name, description, searchTags, enableConditions); + }) : super(name, getLocalizedName, getDescription, searchTags, + enableConditions); @override SettingPageLink copy() { - return SettingPageLink(name, screen, - icon: icon, - description: description, - searchTags: searchTags, - enableConditions: enableConditions); + return SettingPageLink( + name, + getLocalizedName, + screen, + icon: icon, + getDescription: getDescription, + searchTags: searchTags, + enableConditions: enableConditions, + ); } @override diff --git a/lib/settings/utils/description.dart b/lib/settings/utils/description.dart new file mode 100644 index 00000000..a122f2a0 --- /dev/null +++ b/lib/settings/utils/description.dart @@ -0,0 +1,5 @@ +import 'package:flutter/material.dart'; + +String defaultDescription(BuildContext context) { + return ""; +} diff --git a/lib/settings/widgets/dynamic_multi_select_setting_card.dart b/lib/settings/widgets/dynamic_multi_select_setting_card.dart index 53c2cdca..34bf71b9 100644 --- a/lib/settings/widgets/dynamic_multi_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_multi_select_setting_card.dart @@ -31,9 +31,9 @@ class _DynamicMultiSelectSettingCardState multiSelect: true, choices: widget.setting.options .map((option) => SelectChoice( - name: option.name, + name: option.getLocalizedName(context), value: option.value, - description: option.description)) + description: option.getDescription(context))) .toList(), onChanged: (indices) { setState(() { diff --git a/lib/settings/widgets/dynamic_select_setting_card.dart b/lib/settings/widgets/dynamic_select_setting_card.dart index 753e5b03..a0c5313a 100644 --- a/lib/settings/widgets/dynamic_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_select_setting_card.dart @@ -30,9 +30,9 @@ class _DynamicSelectSettingCardState title: widget.setting.displayName(context), choices: widget.setting.options .map((option) => SelectChoice( - name: option.name, + name: option.getLocalizedName(context), value: option.value, - description: option.description)) + description: option.getDescription(context))) .toList(), onChanged: (indices) { setState(() { diff --git a/lib/settings/widgets/multi_select_setting_card.dart b/lib/settings/widgets/multi_select_setting_card.dart index acc48e56..1b9ee9f5 100644 --- a/lib/settings/widgets/multi_select_setting_card.dart +++ b/lib/settings/widgets/multi_select_setting_card.dart @@ -28,9 +28,9 @@ class _MultiSelectSettingCardState extends State> { multiSelect: true, choices: widget.setting.options .map((option) => SelectChoice( - name: option.name, + name: option.getLocalizedName(context), value: option.value, - description: option.description)) + description: option.getDescription(context))) .toList(), onChanged: (value) { setState(() { diff --git a/lib/settings/widgets/select_setting_card.dart b/lib/settings/widgets/select_setting_card.dart index 8da855ec..9232313b 100644 --- a/lib/settings/widgets/select_setting_card.dart +++ b/lib/settings/widgets/select_setting_card.dart @@ -27,9 +27,9 @@ class _SelectSettingCardState extends State> { title: widget.setting.displayName(context), choices: widget.setting.options .map((option) => SelectChoice( - name: option.name, + name: option.getLocalizedName(context), value: option.value, - description: option.description)) + description: option.getDescription(context))) .toList(), onChanged: (value) { setState(() { diff --git a/lib/settings/widgets/setting_action_card.dart b/lib/settings/widgets/setting_action_card.dart index 72802115..ff4ce716 100644 --- a/lib/settings/widgets/setting_action_card.dart +++ b/lib/settings/widgets/setting_action_card.dart @@ -23,6 +23,8 @@ class _SettingActionCardState extends State { TextTheme textTheme = theme.textTheme; ColorScheme colorScheme = theme.colorScheme; + String description = widget.setting.getDescription(context); + Widget inner = Material( color: Colors.transparent, child: InkWell( @@ -39,10 +41,10 @@ class _SettingActionCardState extends State { widget.setting.displayName(context), style: textTheme.displaySmall, ), - if (widget.setting.description.isNotEmpty) ...[ + if (description.isNotEmpty) ...[ const SizedBox(height: 4), Text( - widget.setting.description, + description, style: textTheme.bodyMedium, ) ] diff --git a/lib/settings/widgets/setting_group_card.dart b/lib/settings/widgets/setting_group_card.dart index 065aac58..c984a223 100644 --- a/lib/settings/widgets/setting_group_card.dart +++ b/lib/settings/widgets/setting_group_card.dart @@ -77,6 +77,7 @@ class _SettingGroupCardState extends State { ), ); + String description = widget.settingGroup.displayDescription(context); CardContainer cardView = CardContainer( onTap: openSettingGroupScreen, child: Padding( @@ -94,10 +95,10 @@ class _SettingGroupCardState extends State { widget.settingGroup.displayName(context), style: textTheme.displaySmall, ), - if (widget.settingGroup.description.isNotEmpty) ...[ + if (description.isNotEmpty) ...[ const SizedBox(height: 4), Text( - widget.settingGroup.displayDescription(context), + description, style: textTheme.bodyMedium, ) ] diff --git a/lib/settings/widgets/setting_page_link_card.dart b/lib/settings/widgets/setting_page_link_card.dart index a8a03b47..373d2c54 100644 --- a/lib/settings/widgets/setting_page_link_card.dart +++ b/lib/settings/widgets/setting_page_link_card.dart @@ -22,6 +22,8 @@ class _SettingPageLinkCardState extends State { ThemeData theme = Theme.of(context); TextTheme textTheme = theme.textTheme; ColorScheme colorScheme = theme.colorScheme; + + String displayName = widget.setting.displayName(context); Widget inner = Material( color: Colors.transparent, child: InkWell( @@ -50,10 +52,10 @@ class _SettingPageLinkCardState extends State { widget.setting.displayName(context), style: textTheme.displaySmall, ), - if (widget.setting.description.isNotEmpty) ...[ + if (displayName.isNotEmpty) ...[ const SizedBox(height: 4), Text( - widget.setting.displayDescription(context), + displayName, style: textTheme.bodyMedium, ) ] diff --git a/lib/settings/widgets/string_setting_card.dart b/lib/settings/widgets/string_setting_card.dart index 1bfff865..8d582395 100644 --- a/lib/settings/widgets/string_setting_card.dart +++ b/lib/settings/widgets/string_setting_card.dart @@ -24,7 +24,7 @@ class _StringSettingCardState extends State { Widget build(BuildContext context) { Widget input = InputField( title: widget.setting.displayName(context), - description: widget.setting.description, + description: widget.setting.displayDescription(context), value: widget.setting.value, onChanged: (value) { setState(() { diff --git a/lib/settings/widgets/toggle_setting_card.dart b/lib/settings/widgets/toggle_setting_card.dart index cefc568d..6bd863b6 100644 --- a/lib/settings/widgets/toggle_setting_card.dart +++ b/lib/settings/widgets/toggle_setting_card.dart @@ -26,7 +26,8 @@ class _ToggleSettingCardState extends State> { description: widget.setting.displayDescription(context), selectedItems: widget.setting.value, options: widget.setting.options - .map((option) => ToggleOption(option.name, option.value)) + .map((option) => + ToggleOption(option.getLocalizedName(context), option.value)) .toList(), onChange: (value) { setState(() { diff --git a/lib/theme/data/color_scheme_settings_schema.dart b/lib/theme/data/color_scheme_settings_schema.dart index 4c443afc..03c3e98f 100644 --- a/lib/theme/data/color_scheme_settings_schema.dart +++ b/lib/theme/data/color_scheme_settings_schema.dart @@ -2,41 +2,108 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const colorSchemeSettingsSchemaVersion = 1; SettingGroup colorSchemeSettingsSchema = SettingGroup( version: colorSchemeSettingsSchemaVersion, "Color Scheme", + (context) => AppLocalizations.of(context)!.colorsSettingGroup, [ - StringSetting("Name", "Color Scheme"), - SettingGroup("Background", [ - ColorSetting("Color", Colors.white), - ColorSetting("Text", Colors.black), - ]), - SettingGroup("Card", [ - ColorSetting("Color", Colors.white), - ColorSetting("Text", Colors.black), - ]), - SettingGroup("Accent", [ - ColorSetting("Color", Colors.cyan), - ColorSetting("Text", Colors.white), - ]), - SettingGroup("Shadow", [ - SwitchSetting("Use Accent as Shadow", false), - ColorSetting("Color", Colors.black, enableConditions: [ - ValueCondition(["Use Accent as Shadow"], (value)=>value==false), - ]), - ]), - SettingGroup("Outline", [ - SwitchSetting("Use Accent as Outline", false), - ColorSetting("Color", Colors.black, enableConditions: [ - ValueCondition(["Use Accent as Outline"], (value)=>value==false), - ]), - ]), - SettingGroup("Error", [ - ColorSetting("Color", Colors.red), - ColorSetting("Text", Colors.white), - ]), + StringSetting("Name", (context) => AppLocalizations.of(context)!.nameField, + "Color Scheme"), + SettingGroup( + "Background", + (context) => + AppLocalizations.of(context)!.colorSchemeBackgroundSettingGroup, + [ + ColorSetting( + "Color", + (context) => AppLocalizations.of(context)!.colorSetting, + Colors.white), + ColorSetting( + "Text", + (context) => AppLocalizations.of(context)!.textColorSetting, + Colors.black), + ]), + SettingGroup( + "Card", + (context) => AppLocalizations.of(context)!.colorSchemeCardSettingGroup, + [ + ColorSetting( + "Color", + (context) => AppLocalizations.of(context)!.colorSetting, + Colors.white), + ColorSetting( + "Text", + (context) => AppLocalizations.of(context)!.textColorSetting, + Colors.black), + ]), + SettingGroup( + "Accent", + (context) => + AppLocalizations.of(context)!.colorSchemeAccentSettingGroup, + [ + ColorSetting( + "Color", + (context) => AppLocalizations.of(context)!.colorSetting, + Colors.cyan), + ColorSetting( + "Text", + (context) => AppLocalizations.of(context)!.textColorSetting, + Colors.white), + ]), + SettingGroup( + "Shadow", + (context) => + AppLocalizations.of(context)!.colorSchemeShadowSettingGroup, + [ + SwitchSetting( + "Use Accent as Shadow", + (context) => AppLocalizations.of(context)! + .colorSchemeUseAccentAsShadowSetting, + false), + ColorSetting( + "Color", + (context) => AppLocalizations.of(context)!.colorSetting, + Colors.black, + enableConditions: [ + ValueCondition( + ["Use Accent as Shadow"], (value) => value == false), + ]), + ]), + SettingGroup( + "Outline", + (context) => + AppLocalizations.of(context)!.colorSchemeOutlineSettingGroup, + [ + SwitchSetting( + "Use Accent as Outline", + (context) => AppLocalizations.of(context)! + .colorSchemeUseAccentAsOutlineSetting, + false), + ColorSetting( + "Color", + (context) => AppLocalizations.of(context)!.colorSetting, + Colors.black, + enableConditions: [ + ValueCondition( + ["Use Accent as Outline"], (value) => value == false), + ]), + ]), + SettingGroup( + "Error", + (context) => AppLocalizations.of(context)!.colorSchemeErrorSettingGroup, + [ + ColorSetting( + "Color", + (context) => AppLocalizations.of(context)!.colorSetting, + Colors.red), + ColorSetting( + "Text", + (context) => AppLocalizations.of(context)!.textColorSetting, + Colors.white), + ]), ], ); diff --git a/lib/theme/data/style_theme_settings_schema.dart b/lib/theme/data/style_theme_settings_schema.dart index f55ef1da..9f45e118 100644 --- a/lib/theme/data/style_theme_settings_schema.dart +++ b/lib/theme/data/style_theme_settings_schema.dart @@ -1,24 +1,72 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const styleThemeSettingsSchemaVersion = 1; SettingGroup styleThemeSettingsSchema = SettingGroup( version: styleThemeSettingsSchemaVersion, "App Style", + (context) => AppLocalizations.of(context)!.styleSettingGroup, [ - StringSetting("Name", "Style Theme"), - SettingGroup("Shape", [ - SliderSetting("Corner Roundness", 0, 36, 16), - ]), - SettingGroup("Shadow", [ - SliderSetting("Elevation", 0, 10, 1), - SliderSetting("Opacity", 0, 100, 20), - SliderSetting("Blur", 0, 16, 1), - SliderSetting("Spread", 0, 8, 0), - ]), - SettingGroup("Outline", [ - SliderSetting("Width", 0, 8, 0), - ]), + StringSetting("Name", (context) => AppLocalizations.of(context)!.nameField, + "Style Theme"), + SettingGroup( + "Shape", + (context) => AppLocalizations.of(context)!.styleThemeShapeSettingGroup, + [ + SliderSetting( + "Corner Roundness", + (context) => + AppLocalizations.of(context)!.styleThemeRadiusSetting, + 0, + 36, + 16), + ]), + SettingGroup( + "Shadow", + (context) => AppLocalizations.of(context)!.styleThemeShadowSettingGroup, + [ + SliderSetting( + "Elevation", + (context) => + AppLocalizations.of(context)!.styleThemeElevationSetting, + 0, + 10, + 1), + SliderSetting( + "Opacity", + (context) => + AppLocalizations.of(context)!.styleThemeOpacitySetting, + 0, + 100, + 20), + SliderSetting( + "Blur", + (context) => AppLocalizations.of(context)!.styleThemeBlurSetting, + 0, + 16, + 1), + SliderSetting( + "Spread", + (context) => + AppLocalizations.of(context)!.styleThemeSpreadSetting, + 0, + 8, + 0), + ]), + SettingGroup( + "Outline", + (context) => + AppLocalizations.of(context)!.styleThemeOutlineSettingGroup, + [ + SliderSetting( + "Width", + (context) => + AppLocalizations.of(context)!.styleThemeOutlineWidthSetting, + 0, + 8, + 0), + ]), ], ); diff --git a/lib/timer/data/timer_settings_schema.dart b/lib/timer/data/timer_settings_schema.dart index 4d6ca647..3ac43a37 100644 --- a/lib/timer/data/timer_settings_schema.dart +++ b/lib/timer/data/timer_settings_schema.dart @@ -8,7 +8,7 @@ import 'package:clock_app/common/utils/ringtones.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_group.dart'; - +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:clock_app/timer/types/time_duration.dart'; import 'package:flutter/material.dart'; @@ -17,16 +17,21 @@ const timerSettingSchemeVersion = 1; SettingGroup timerSettingsSchema = SettingGroup( version: timerSettingSchemeVersion, "Timer Setting", + (context) => "Timer Setting", [ - StringSetting("Label", ""), + StringSetting( + "Label", (context) => AppLocalizations.of(context)!.labelField, ""), SettingGroup( "Sound and Vibration", + (context) => AppLocalizations.of(context)!.soundAndVibrationSettingGroup, [ SettingGroup( "Sound", + (context) => AppLocalizations.of(context)!.soundSettingGroup, [ DynamicSelectSetting( "Melody", + (context) => AppLocalizations.of(context)!.melodySetting, getRingtoneOptions, onChange: (context, index) { RingtonePlayer.stop(); @@ -34,21 +39,36 @@ SettingGroup timerSettingsSchema = SettingGroup( // shouldCloseOnSelect: false, ), SelectSetting( - "Audio Channel", audioChannelOptions, - onChange: (context, index) { + "Audio Channel", + (context) => AppLocalizations.of(context)!.audioChannelSetting, + audioChannelOptions, onChange: (context, index) { RingtonePlayer.stop(); }), - SliderSetting("Volume", 0, 100, 100, unit: "%"), - SwitchSetting("Rising Volume", false, - description: "Gradually increase volume over time"), + SliderSetting( + "Volume", + (context) => AppLocalizations.of(context)!.volumeSetting, + 0, + 100, + 100, + unit: "%"), + SwitchSetting( + "Rising Volume", + (context) => AppLocalizations.of(context)!.risingVolumeSetting, + false, + // description: "Gradually increase volume over time", + ), DurationSetting( - "Time To Full Volume", const TimeDuration(minutes: 1), + "Time To Full Volume", + (context) => + AppLocalizations.of(context)!.timeToFullVolumeSetting, + const TimeDuration(minutes: 1), enableConditions: [ ValueCondition(["Rising Volume"], (value) => value == true) ]), ], ), - SwitchSetting("Vibration", false), + SwitchSetting("Vibration", + (context) => AppLocalizations.of(context)!.vibrationSetting, false), ], icon: Icons.volume_up, summarySettings: [ @@ -56,9 +76,12 @@ SettingGroup timerSettingsSchema = SettingGroup( "Vibration", ], ), - SliderSetting("Add Length", 1, 30, 1, unit: "minutes", snapLength: 1), + SliderSetting("Add Length", + (context) => AppLocalizations.of(context)!.addLengthSetting, 1, 30, 1, + unit: "minutes", snapLength: 1), DynamicMultiSelectSetting( "Tags", + (context) => AppLocalizations.of(context)!.tagsSetting, getTagOptions, defaultValue: [], ), diff --git a/lib/timer/logic/edit_duration_picker_mode.dart b/lib/timer/logic/edit_duration_picker_mode.dart index c81c14f8..ff3ec827 100644 --- a/lib/timer/logic/edit_duration_picker_mode.dart +++ b/lib/timer/logic/edit_duration_picker_mode.dart @@ -5,7 +5,8 @@ import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:flutter/material.dart'; -Future editDurationPickerMode(BuildContext context, VoidCallback onChange) async { +Future editDurationPickerMode( + BuildContext context, VoidCallback onChange) async { SelectSetting setting = appSettings .getGroup("General") .getGroup("Display") @@ -19,12 +20,12 @@ Future editDurationPickerMode(BuildContext context, VoidCallback onChange) // setState(() {}); }, title: setting.name, - description: setting.description, + description: setting.getDescription(context), choices: setting.options .map((option) => SelectChoice( - name: option.name, + name: option.getLocalizedName(context), value: option.value, - description: option.description)) + description: option.getDescription(context))) .toList(), initialSelectedIndices: [setting.selectedIndex], multiSelect: false, diff --git a/lib/timer/types/timer.dart b/lib/timer/types/timer.dart index 22669b1b..1578490c 100644 --- a/lib/timer/types/timer.dart +++ b/lib/timer/types/timer.dart @@ -24,6 +24,7 @@ class ClockTimer extends CustomizableListItem { late int _id; SettingGroup _settings = SettingGroup( "Timer Settings", + (context) => "Timer Settings", appSettings .getGroup("Timer") .getGroup("Default Settings") @@ -225,6 +226,7 @@ class ClockTimer extends CustomizableListItem { _id = json['id'] ?? UniqueKey().hashCode; _settings = SettingGroup( "Timer Settings", + (context) => "Timer Settings", appSettings .getGroup("Timer") .getGroup("Default Settings") From cb8676f1c75592dbc3b8c1851030c8925f5289a8 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Mon, 29 Apr 2024 00:28:57 +0500 Subject: [PATCH 036/112] Add alarm screen text --- lib/alarm/data/alarm_list_filters.dart | 1 - lib/alarm/screens/alarm_screen.dart | 23 ++++---- lib/l10n/app_en.arb | 56 ++++++++++++++++++- lib/settings/data/settings_schema.dart | 3 + .../screens/restore_defaults_screen.dart | 1 - .../widgets/setting_page_link_card.dart | 6 +- lib/timer/screens/presets_screen.dart | 2 +- lib/timer/screens/timer_screen.dart | 3 +- 8 files changed, 75 insertions(+), 20 deletions(-) diff --git a/lib/alarm/data/alarm_list_filters.dart b/lib/alarm/data/alarm_list_filters.dart index 3a132cee..405a02f3 100644 --- a/lib/alarm/data/alarm_list_filters.dart +++ b/lib/alarm/data/alarm_list_filters.dart @@ -6,7 +6,6 @@ import 'package:clock_app/common/utils/list_storage.dart'; final List> alarmListFilters = [ ListFilterSelect("Date", [ - ListFilter( 'Today', (alarm) { diff --git a/lib/alarm/screens/alarm_screen.dart b/lib/alarm/screens/alarm_screen.dart index 28fd8fce..cc96b771 100644 --- a/lib/alarm/screens/alarm_screen.dart +++ b/lib/alarm/screens/alarm_screen.dart @@ -18,6 +18,8 @@ import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:flutter/material.dart'; import 'package:great_list_view/great_list_view.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + typedef AlarmCardBuilder = Widget Function( @@ -124,7 +126,7 @@ class _AlarmScreenState extends State { Future _handleEnableChangeAlarm(Alarm alarm, bool value) async { if (!alarm.canBeDisabledWhenSnoozed && !value && alarm.isSnoozed) { - showSnackBar(context, "Cannot disable alarm while it is snoozed", + showSnackBar(context, AppLocalizations.of(context)!.cannotDisableAlarmWhileSnoozedSnackbar, fab: true, navBar: true); } else { await alarm.setIsEnabled(value, @@ -138,7 +140,7 @@ class _AlarmScreenState extends State { List alarms, bool value) async { for (var alarm in alarms) { if (!alarm.canBeDisabledWhenSnoozed && !value && alarm.isSnoozed) { - showSnackBar(context, "Cannot disable alarm while it is snoozed", + showSnackBar(context, AppLocalizations.of(context)!.cannotDisableAlarmWhileSnoozedSnackbar, fab: true, navBar: true); } else { await alarm.setIsEnabled(value, @@ -178,10 +180,9 @@ class _AlarmScreenState extends State { await showTimePickerDialog( context: context, initialTime: TimeOfDay.now(), - title: "Select Time", - cancelText: "Cancel", -// initialEntryMode: TimePickerEntryMode.dial, - confirmText: "Save", + title: AppLocalizations.of(context)!.selectTime, + cancelText: AppLocalizations.of(context)!.cancelButton, + confirmText: AppLocalizations.of(context)!.saveButton, useSimple: false, ); @@ -218,31 +219,31 @@ class _AlarmScreenState extends State { onDeleteItem: (alarm) async { await alarm.disable(); }, - placeholderText: "No alarms created", + placeholderText: AppLocalizations.of(context)!.noAlarmMessage, reloadOnPop: true, listFilters: _showFilters.value ? alarmListFilters : [], customActions: _showFilters.value ? [ ListFilterCustomAction( - name: "Enable all filtered alarms", + name: AppLocalizations.of(context)!.enableAllFilteredAlarmsAction, icon: Icons.alarm_on_rounded, action: (alarms) { _handleEnableChangeMultiple(alarms, true); }), ListFilterCustomAction( - name: "Disable all filtered alarms", + name: AppLocalizations.of(context)!.disableAllFilteredAlarmsAction, icon: Icons.alarm_off_rounded, action: (alarms) { _handleEnableChangeMultiple(alarms, false); }), ListFilterCustomAction( - name: "Skip all filtered alarms", + name: AppLocalizations.of(context)!.skipAllFilteredAlarmsAction, icon: Icons.skip_next_rounded, action: (alarms) { _handleSkipChangeMultiple(alarms, true); }), ListFilterCustomAction( - name: "Cancel skip all filtered alarms", + name: AppLocalizations.of(context)!.cancelSkipAllFilteredAlarmsAction, icon: Icons.skip_next_rounded, action: (alarms) { _handleSkipChangeMultiple(alarms, false); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 42956a5e..833520ce 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -234,13 +234,15 @@ "@alarmDeleteAfterRingingSetting": {}, "alarmDeleteAfterFinishingSetting" : "Delete After Finishing", "@alarmDeleteAfterFinishingSetting": {}, + "cannotDisableAlarmWhileSnoozedSnackbar": "Cannot disable alarm while it is snoozed", + "@cannotDisableAlarmWhileSnoozedSnackbar": {}, "selectTime": "Select Time", "@selectTime": {}, "cancelButton": "Cancel", "@cancelButton": {}, "customizeButton": "Customize", "@customizeButton": {}, - "saveButton": "Save Button", + "saveButton": "Save", "@saveButton": {}, "labelField": "Label", "@labelField": {}, @@ -354,8 +356,18 @@ "@yesButton": {}, "noButton": "No", "@noButton": {}, - "noItemCreatedMessage": "No {items} created", + "noAlarmMessage": "No alarms created", "@noItemCreatedMessage": {}, + "noTimerMessage": "No timers created", + "@noTimerMessage": {}, + "noStopwatchMessage": "No stopwatches created", + "@noStopwatchMessage": {}, + "noTaskMessage": "No tasks created", + "@noTaskMessage": {}, + "noPresetsMessage": "No presets created", + "@noPresetsMessage": {}, + "noLogsMessage": "No alarm logs", + "@noLogsMessage": {}, "deleteButton": "Delete", "@deleteButton": {}, "duplicateButton": "Duplicate", @@ -364,16 +376,56 @@ "@skipAlarmButton": {}, "allFilter": "All", "@allFilter": {}, + "dateFilterGroup": "Date", + "@dateFilterGroup": {}, "todayFilter": "Today", "@todayFilter": {}, "tomorrowFilter": "Tomorrow", "@tomorrowFilter": {}, + "stateFilterGroup": "State", + "@stateFilterGroup": {}, + "activeFilter": "Active", + "@activeFilter": {}, "snoozedFilter": "Snoozed", "@snoozedFilter": {}, "disabledFilter": "Disabled", "@disabledFilter": {}, "completedFilter": "Completed", "@completedFilter": {}, + "sortGroup": "Sort", + "@sortGroup": {}, + "defaultLabel": "Default", + "@defaultLabel": {}, + "remainingTimeDesc": "Remaining Time Descending", + "@remainingTimeDesc": {}, + "remainingTimeAsc": "Remaining Time Ascending", + "@remainingTimeAsc": {}, + "nameAsc": "Name Ascending", + "@nameAsc": {}, + "nameDesc": "Name Descending", + "@nameDesc": {}, + "dateAsc": "Date Ascending", + "@dateAsc": {}, + "dateDesc": "Date Descending", + "@dateDesc": {}, + "timeOfDayAsc": "Time of Day Ascending", + "@timeOfDayAsc": {}, + "timeOfDayDesc": "Time of Day Descending", + "@timeOfDayDesc": {}, + "filterActions": "Filter Actions", + "@filterActions": {}, + "clearFiltersAction": "Clear all filters", + "@clearFiltersAction": {}, + "enableAllFilteredAlarmsAction": "Enable all filtered alarms", + "@enableAllFilteredAlarmsAction": {}, + "disableAllFilteredAlarmsAction": "Disable all filtered alarms", + "@disableAllFilteredAlarmsAction": {}, + "skipAllFilteredAlarmsAction": "Skip all filtered alarms", + "@skipAllFilteredAlarmsAction": {}, + "cancelSkipAllFilteredAlarmsAction": "Cancel skip all filtered alarms", + "@cancelSkipAllFilteredAlarmsAction": {}, + "deleteAllFilteredAction": "Delete all filtered items", + "@deleteAllFilteredAAction": {}, "skippingDescriptionSuffix": "(skipping next occurrence)", "@skippingDescriptionSuffix": {}, "alarmDescriptionSnooze": "Snoozed until {date}", diff --git a/lib/settings/data/settings_schema.dart b/lib/settings/data/settings_schema.dart index af203323..0a01809b 100644 --- a/lib/settings/data/settings_schema.dart +++ b/lib/settings/data/settings_schema.dart @@ -9,6 +9,7 @@ import 'package:clock_app/settings/data/timer_app_settings_schema.dart'; import 'package:clock_app/settings/screens/about_screen.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_link.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const int settingsSchemaVersion = 4; @@ -30,6 +31,8 @@ SettingGroup appSettings = SettingGroup( "About", (context) => AppLocalizations.of(context)!.aboutSettingGroup, const AboutScreen(), + icon: Icons.info_rounded, + ), ], ); diff --git a/lib/settings/screens/restore_defaults_screen.dart b/lib/settings/screens/restore_defaults_screen.dart index 24d52290..d9ef2b13 100644 --- a/lib/settings/screens/restore_defaults_screen.dart +++ b/lib/settings/screens/restore_defaults_screen.dart @@ -2,7 +2,6 @@ import 'package:clock_app/common/widgets/card_container.dart'; import 'package:clock_app/navigation/widgets/app_top_bar.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_item.dart'; - import 'package:flutter/material.dart'; class SettingCheckBox extends StatelessWidget { diff --git a/lib/settings/widgets/setting_page_link_card.dart b/lib/settings/widgets/setting_page_link_card.dart index 373d2c54..d64e9855 100644 --- a/lib/settings/widgets/setting_page_link_card.dart +++ b/lib/settings/widgets/setting_page_link_card.dart @@ -23,7 +23,7 @@ class _SettingPageLinkCardState extends State { TextTheme textTheme = theme.textTheme; ColorScheme colorScheme = theme.colorScheme; - String displayName = widget.setting.displayName(context); + String description = widget.setting.getDescription(context); Widget inner = Material( color: Colors.transparent, child: InkWell( @@ -52,10 +52,10 @@ class _SettingPageLinkCardState extends State { widget.setting.displayName(context), style: textTheme.displaySmall, ), - if (displayName.isNotEmpty) ...[ + if (description.isNotEmpty) ...[ const SizedBox(height: 4), Text( - displayName, + description, style: textTheme.bodyMedium, ) ] diff --git a/lib/timer/screens/presets_screen.dart b/lib/timer/screens/presets_screen.dart index 5d63941d..f0d75f9e 100644 --- a/lib/timer/screens/presets_screen.dart +++ b/lib/timer/screens/presets_screen.dart @@ -48,7 +48,7 @@ class _PresetsScreenState extends State { _listController.changeItems((presets) {}); }, // onDeleteItem: _handleDeleteTimer, - placeholderText: "No timers created", + placeholderText: "No presets created", reloadOnPop: true, ), ), diff --git a/lib/timer/screens/timer_screen.dart b/lib/timer/screens/timer_screen.dart index baeb8884..71f7e56e 100644 --- a/lib/timer/screens/timer_screen.dart +++ b/lib/timer/screens/timer_screen.dart @@ -22,6 +22,7 @@ import 'package:clock_app/common/widgets/fab.dart'; import 'package:clock_app/common/widgets/list/persistent_list_view.dart'; import 'package:clock_app/timer/types/timer.dart'; import 'package:clock_app/timer/widgets/timer_card.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; typedef TimerCardBuilder = Widget Function( BuildContext context, @@ -242,7 +243,7 @@ class _TimerScreenState extends State { // _listController.changeItems((item) {}); }, onDeleteItem: _onDeleteTimer, - placeholderText: "No timers created", + placeholderText: AppLocalizations.of(context)!.noTimerMessage, reloadOnPop: true, listFilters: _showFilters.value ? timerListFilters : [], sortOptions: _showSort.value ? timerSortOptions : [], From 22b92a15c8cf7d2512d15cd2125a9cd0583c51a9 Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Tue, 9 Apr 2024 23:50:50 +0000 Subject: [PATCH 037/112] Translated using Weblate (Portuguese) Currently translated at 100.0% (103 of 103 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 5d8ce9df..019bbfc9 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -180,5 +180,37 @@ "noItemMessage": "Ainda não adicionou {items}", "@noItemMessage": {}, "noItemCreatedMessage": "{items} não criadas", - "@noItemCreatedMessage": {} + "@noItemCreatedMessage": {}, + "skippingDescriptionSuffix": "(ignorar próxima ocorrência)", + "@skippingDescriptionSuffix": {}, + "alarmDescriptionSnooze": "Silenciado até {date}", + "@alarmDescriptionSnooze": {}, + "alarmDescriptionFinished": "Não existem mais alarmes", + "@alarmDescriptionFinished": {}, + "alarmDescriptionNotScheduled": "Não agendado", + "@alarmDescriptionNotScheduled": {}, + "alarmDescriptionToday": "Apenas hoje", + "@alarmDescriptionToday": {}, + "alarmDescriptionTomorrow": "Apenas amanhã", + "@alarmDescriptionTomorrow": {}, + "alarmDescriptionEveryDay": "Todos os dias", + "@alarmDescriptionEveryDay": {}, + "alarmDescriptionWeekend": "Todas as semanas", + "@alarmDescriptionWeekend": {}, + "stopwatchPrevious": "Anterior", + "@stopwatchPrevious": {}, + "alarmDescriptionWeekday": "Todos os dias da semana", + "@alarmDescriptionWeekday": {}, + "stopwatchFastest": "Mais rápida", + "@stopwatchFastest": {}, + "alarmDescriptionDays": "{days}", + "@alarmDescriptionDays": {}, + "alarmDescriptionRange": "{interval, select, daily{Diariamente} weekly{Semanalmente}} entre {startDate} e {endDate}", + "@alarmDescriptionRange": {}, + "stopwatchSlowest": "Mais lenta", + "@stopwatchSlowest": {}, + "alarmDescriptionDates": "Em {date}{count, plural, =0{} =1{ e mais 1 data} other{ e mais {count} datas}}", + "@alarmDescriptionDates": {}, + "stopwatchAverage": "Média", + "@stopwatchAverage": {} } From 9b874a831e2318238f05765dabe3f9a8dabafbcb Mon Sep 17 00:00:00 2001 From: Muha Aliss Date: Fri, 12 Apr 2024 17:00:02 +0200 Subject: [PATCH 038/112] Added translation using Weblate (Turkish) --- lib/l10n/app_tr.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_tr.arb diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_tr.arb @@ -0,0 +1 @@ +{} From 735f3a45f234360b668e48c156d923be7dc29094 Mon Sep 17 00:00:00 2001 From: Muha Aliss Date: Fri, 12 Apr 2024 15:00:48 +0000 Subject: [PATCH 039/112] Translated using Weblate (Turkish) Currently translated at 100.0% (103 of 103 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/tr/ --- lib/l10n/app_tr.arb | 213 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 212 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 0967ef42..93366125 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -1 +1,212 @@ -{} +{ + "clockTitle": "Saat", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "alarmTitle": "Alarm", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "timerTitle": "Zamanlayıcı", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "stopwatchTitle": "Kronometre", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "generalSettingGroup": "Genel", + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Görünüm", + "@appearanceSettingGroup": {}, + "backupSettingGroup": "Yedekleme", + "@backupSettingGroup": {}, + "aboutSettingGroup": "Hakkında", + "@aboutSettingGroup": {}, + "restoreSettingGroup": "Varsayılan değerlere geri yükle", + "@restoreSettingGroup": {}, + "displaySettingGroup": "Görünüm", + "@displaySettingGroup": {}, + "reliabilitySettingGroup": "Güvenlik", + "@reliabilitySettingGroup": {}, + "colorsSettingGroup": "Renkler", + "@colorsSettingGroup": {}, + "styleSettingGroup": "Tarz", + "@styleSettingGroup": {}, + "useMaterialYouColorSetting": "Material You kullan", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "Görünüm", + "@materialBrightnessSetting": {}, + "overrideAccentSetting": "Vurgu rengini geçersiz kıl", + "@overrideAccentSetting": {}, + "developerOptionsSettingGroup": "Geliştirici seçenekleri", + "@developerOptionsSettingGroup": {}, + "useMaterialStyleSetting": "Material tarzını kullan", + "@useMaterialStyleSetting": {}, + "styleThemeSetting": "Tarz teması", + "@styleThemeSetting": {}, + "systemDarkModeSetting": "Sistem karanlık biçemi", + "@systemDarkModeSetting": {}, + "colorSchemeSetting": "Renk uyumu", + "@colorSchemeSetting": {}, + "darkColorSchemeSetting": "Koyu renk tarzı", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "Saat", + "@clockSettingGroup": {}, + "timerSettingGroup": "Zamanlayıcı", + "@timerSettingGroup": {}, + "stopwatchSettingGroup": "Kronometre", + "@stopwatchSettingGroup": {}, + "generalSettingGroupDescription": "Saat biçimi gibi uygulama genelindeki ayarları belirle", + "@generalSettingGroupDescription": {}, + "selectTime": "Zaman seç", + "@selectTime": {}, + "alarmScheduleSettingGroup": "Zamanlama", + "@alarmScheduleSettingGroup": {}, + "scheduleTypeField": "Tip", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "Bir kere", + "@scheduleTypeOnce": {}, + "scheduleTypeDaily": "Günlük", + "@scheduleTypeDaily": {}, + "scheduleTypeOnceDescription": "Bir sonraki seferde çalacak", + "@scheduleTypeOnceDescription": {}, + "scheduleTypeDailyDescription": "Her gün çalacak", + "@scheduleTypeDailyDescription": {}, + "scheduleTypeWeek": "Haftanın belirlenen günlerinde", + "@scheduleTypeWeek": {}, + "scheduleTypeWeekDescription": "Hafta içi belirlenen günlerde tekrarlanacak", + "@scheduleTypeWeekDescription": {}, + "scheduleTypeData": "Belirli tarihlerde", + "@scheduleTypeData": {}, + "scheduleTypeRange": "Tarih aralığı", + "@scheduleTypeRange": {}, + "scheduleTypeDateDescription": "Belirlenen tarihlerde tekrarlanacak", + "@scheduleTypeDateDescription": {}, + "scheduleTypeRangeDescription": "Belirlenen tarih aralığında tekrarlanacak", + "@scheduleTypeRangeDescription": {}, + "settingGroupMore": "Daha fazla", + "@settingGroupMore": {}, + "melodySetting": "Melodi", + "@melodySetting": {}, + "vibrationSetting": "Titreşim", + "@vibrationSetting": {}, + "audioChannelSetting": "Ses kanalı", + "@audioChannelSetting": {}, + "volumeSetting": "Ses", + "@volumeSetting": {}, + "risingVolumeSetting": "Yükselen ses", + "@risingVolumeSetting": {}, + "snoozeSettingGroup": "Ertele", + "@snoozeSettingGroup": {}, + "snoozeEnableSetting": "Aktif", + "@snoozeEnableSetting": {}, + "snoozeLengthSetting": "Süre", + "@snoozeLengthSetting": {}, + "whileSnoozedSettingGroup": "Ertelenmişken", + "@whileSnoozedSettingGroup": {}, + "snoozePreventDisablingSetting": "Devre dışı bırakmayı önle", + "@snoozePreventDisablingSetting": {}, + "snoozePreventDeletion": "Silinmeyi önle", + "@snoozePreventDeletion": {}, + "settings": "Ayarlar", + "@settings": {}, + "tasksSetting": "Görevler", + "@tasksSetting": {}, + "noItemMessage": "Henüz {items} eklenmedi", + "@noItemMessage": {}, + "chooseTaskTitle": "Eklenecek görevi seç", + "@chooseTaskTitle": {}, + "mathTask": "Matematik problemleri", + "@mathTask": {}, + "sequenceTask": "Sekans", + "@sequenceTask": {}, + "mathTaskDifficultySetting": "Zorluk", + "@mathTaskDifficultySetting": {}, + "retypeNumberChars": "Karakter sayısı", + "@retypeNumberChars": {}, + "retypeIncludeNumSetting": "Sayıları dahil et", + "@retypeIncludeNumSetting": {}, + "retypeLowercaseSetting": "Küçük harfleri dahil et", + "@retypeLowercaseSetting": {}, + "sequenceLengthSetting": "Sekans uzunluğu", + "@sequenceLengthSetting": {}, + "sequenceGridSizeSetting": "Izgara boyutu", + "@sequenceGridSizeSetting": {}, + "saveReminderAlert": "Kaydetmeden ayrılmak istiyor musun?", + "@saveReminderAlert": {}, + "yesButton": "Evet", + "@yesButton": {}, + "noItemCreatedMessage": "{items} oluşturulmadı", + "@noItemCreatedMessage": {}, + "deleteButton": "Sil", + "@deleteButton": {}, + "alarmDescriptionNotScheduled": "Planlanmadı", + "@alarmDescriptionNotScheduled": {}, + "alarmDescriptionToday": "Sadece bugün", + "@alarmDescriptionToday": {}, + "alarmDescriptionTomorrow": "Sadece yarın", + "@alarmDescriptionTomorrow": {}, + "alarmDescriptionEveryDay": "Her gün", + "@alarmDescriptionEveryDay": {}, + "alarmDescriptionDays": "{days} tarihinde", + "@alarmDescriptionDays": {}, + "alarmDescriptionDates": "{date}{count, plural, =0{} =1{ ve 1 başka tarih} diğer{ ve {count} diğer tarih}}", + "@alarmDescriptionDates": {}, + "stopwatchAverage": "Ortalama", + "@stopwatchAverage": {}, + "accessibilitySettingGroup": "Erişilebilirlik", + "@accessibilitySettingGroup": {}, + "saveButton": "Kaydet düğmesi", + "@saveButton": {}, + "labelField": "Etiket", + "@labelField": {}, + "appearanceSettingGroupDescription": "Temaları, renkleri ayarla ve düzeni değiştir", + "@appearanceSettingGroupDescription": {}, + "labelFieldPlaceholder": "Bir etiket ekle", + "@labelFieldPlaceholder": {}, + "backupSettingGroupDescription": "Ayarları yerel olarak dışa veya içe aktar", + "@backupSettingGroupDescription": {}, + "cancelButton": "İptal", + "@cancelButton": {}, + "customizeButton": "Özelleştir", + "@customizeButton": {}, + "soundSettingGroup": "Ses ve Titreşim", + "@soundSettingGroup": {}, + "retypeTask": "Metni yeniden yaz", + "@retypeTask": {}, + "noButton": "Hayır", + "@noButton": {}, + "todayFilter": "Bugün", + "@todayFilter": {}, + "duplicateButton": "Çoğalt", + "@duplicateButton": {}, + "skipAlarmButton": "Sonraki alarmı atla", + "@skipAlarmButton": {}, + "allFilter": "Tümü", + "@allFilter": {}, + "tomorrowFilter": "Yarın", + "@tomorrowFilter": {}, + "snoozedFilter": "Ertelendi", + "@snoozedFilter": {}, + "disabledFilter": "Engellendi", + "@disabledFilter": {}, + "completedFilter": "Tamamlandı", + "@completedFilter": {}, + "alarmDescriptionSnooze": "{date} tarihine kadar ertelendi", + "@alarmDescriptionSnooze": {}, + "alarmDescriptionFinished": "Sonraki tarih yok", + "@alarmDescriptionFinished": {}, + "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly}} - {startDate} - {endDate} arası", + "@alarmDescriptionRange": {}, + "alarmDescriptionWeekend": "Her hafta sonu", + "@alarmDescriptionWeekend": {}, + "stopwatchPrevious": "Önceki", + "@stopwatchPrevious": {}, + "stopwatchSlowest": "En yavaş", + "@stopwatchSlowest": {}, + "alarmDescriptionWeekday": "Hafta içi her gün", + "@alarmDescriptionWeekday": {}, + "stopwatchFastest": "En hızlı", + "@stopwatchFastest": {} +} From 452140fe3547504d866bc72af58c4d4b4b99c566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Fri, 12 Apr 2024 18:26:25 +0000 Subject: [PATCH 040/112] Translated using Weblate (Turkish) Currently translated at 100.0% (103 of 103 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/tr/ --- lib/l10n/app_tr.arb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 93366125..629fa78c 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -208,5 +208,9 @@ "alarmDescriptionWeekday": "Hafta içi her gün", "@alarmDescriptionWeekday": {}, "stopwatchFastest": "En hızlı", - "@stopwatchFastest": {} + "@stopwatchFastest": {}, + "taskTryButton": "Dene", + "@taskTryButton": {}, + "skippingDescriptionSuffix": "(sonraki atlanacak)", + "@skippingDescriptionSuffix": {} } From 637f02e698d675bfce31ca68732fecf095f30d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Fri, 12 Apr 2024 18:30:44 +0000 Subject: [PATCH 041/112] Translated using Weblate (Turkish) Currently translated at 100.0% (103 of 103 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/tr/ --- lib/l10n/app_tr.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 629fa78c..8a14fb7c 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -197,7 +197,7 @@ "@alarmDescriptionSnooze": {}, "alarmDescriptionFinished": "Sonraki tarih yok", "@alarmDescriptionFinished": {}, - "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly}} - {startDate} - {endDate} arası", + "alarmDescriptionRange": "{interval, select, daily{Günlük} weekly{Haftalık}} - {startDate} - {endDate} arası", "@alarmDescriptionRange": {}, "alarmDescriptionWeekend": "Her hafta sonu", "@alarmDescriptionWeekend": {}, From 74e992bb19814e40ac940f3e6f223dfa5b40532c Mon Sep 17 00:00:00 2001 From: UngoIiant Date: Sat, 13 Apr 2024 22:48:00 +0000 Subject: [PATCH 042/112] Translated using Weblate (German) Currently translated at 88.2% (75 of 85 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/de/ --- lib/l10n/app_de.arb | 175 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 0967ef42..58885052 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1 +1,174 @@ -{} +{ + "reliabilitySettingGroup": "Zuverlässigkeit", + "@reliabilitySettingGroup": {}, + "developerOptionsSettingGroup": "Entwickleroptionen", + "@developerOptionsSettingGroup": {}, + "colorsSettingGroup": "Farben", + "@colorsSettingGroup": {}, + "overrideAccentSetting": "Akzentfarbe überschreiben", + "@overrideAccentSetting": {}, + "appearanceSettingGroupDescription": "Setze Themes, Farben und ändere das Layout", + "@appearanceSettingGroupDescription": {}, + "scheduleTypeDateDescription": "Wird an den angegebenen Daten wiederholt", + "@scheduleTypeDateDescription": {}, + "scheduleTypeRangeDescription": "Wird während des angegebenen Datumsbereichs wiederholt", + "@scheduleTypeRangeDescription": {}, + "melodySetting": "Melodie", + "@melodySetting": {}, + "whileSnoozedSettingGroup": "Während Schlummern", + "@whileSnoozedSettingGroup": {}, + "tasksSetting": "Aufgaben", + "@tasksSetting": {}, + "noItemMessage": "Noch keine {items} hinzugefügt", + "@noItemMessage": {}, + "chooseTaskTitle": "Aufgabe auswählen", + "@chooseTaskTitle": {}, + "mathTask": "Matheaufgaben", + "@mathTask": {}, + "taskTryButton": "Ausprobieren", + "@taskTryButton": {}, + "retypeTask": "Text neu eingeben", + "@retypeTask": {}, + "sequenceTask": "Sequenz", + "@sequenceTask": {}, + "clockTitle": "Uhr", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "alarmTitle": "Wecker", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "timerTitle": "Timer", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "stopwatchTitle": "Stoppuhr", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "generalSettingGroup": "Allgemein", + "@generalSettingGroup": {}, + "accessibilitySettingGroup": "Barrierefreiheit", + "@accessibilitySettingGroup": {}, + "backupSettingGroup": "Sicherung", + "@backupSettingGroup": {}, + "aboutSettingGroup": "Über", + "@aboutSettingGroup": {}, + "restoreSettingGroup": "Einstellungen zurücksetzten", + "@restoreSettingGroup": {}, + "appearanceSettingGroup": "Design", + "@appearanceSettingGroup": {}, + "displaySettingGroup": "Darstellung", + "@displaySettingGroup": {}, + "styleSettingGroup": "Design", + "@styleSettingGroup": {}, + "useMaterialYouColorSetting": "Nutze Material You", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "Helligkeit", + "@materialBrightnessSetting": {}, + "useMaterialStyleSetting": "Nutze Material Design", + "@useMaterialStyleSetting": {}, + "systemDarkModeSetting": "System-Dunkelmodus", + "@systemDarkModeSetting": {}, + "colorSchemeSetting": "Farbschema", + "@colorSchemeSetting": {}, + "darkColorSchemeSetting": "Dunkles Farbschema", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "Uhr", + "@clockSettingGroup": {}, + "timerSettingGroup": "Timer", + "@timerSettingGroup": {}, + "stopwatchSettingGroup": "Stoppuhr", + "@stopwatchSettingGroup": {}, + "generalSettingGroupDescription": "Setze App-weite Einstellungen wie das Zeitformat", + "@generalSettingGroupDescription": {}, + "backupSettingGroupDescription": "Exportiere oder importiere deine Einstellungen lokal", + "@backupSettingGroupDescription": {}, + "selectTime": "Zeit auswählen", + "@selectTime": {}, + "cancelButton": "Abbrechen", + "@cancelButton": {}, + "customizeButton": "Anpassen", + "@customizeButton": {}, + "saveButton": "Speichern Button", + "@saveButton": {}, + "labelField": "Bezeichnung", + "@labelField": {}, + "labelFieldPlaceholder": "Füge eine Bezeichnung hinzu", + "@labelFieldPlaceholder": {}, + "scheduleTypeField": "Typ", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "Einmal", + "@scheduleTypeOnce": {}, + "alarmScheduleSettingGroup": "Zeitplan", + "@alarmScheduleSettingGroup": {}, + "scheduleTypeDaily": "Täglich", + "@scheduleTypeDaily": {}, + "scheduleTypeOnceDescription": "Wird beim nächsten Auftreten der Zeit klingeln", + "@scheduleTypeOnceDescription": {}, + "scheduleTypeDailyDescription": "Wird jeden Tag klingeln", + "@scheduleTypeDailyDescription": {}, + "scheduleTypeWeek": "An bestimmten Wochentagen", + "@scheduleTypeWeek": {}, + "scheduleTypeWeekDescription": "Wird an den bestimmten Wochentagen wiederholt", + "@scheduleTypeWeekDescription": {}, + "scheduleTypeData": "An bestimmten Daten", + "@scheduleTypeData": {}, + "scheduleTypeRange": "Datumsbereich", + "@scheduleTypeRange": {}, + "settingGroupMore": "Mehr", + "@settingGroupMore": {}, + "soundSettingGroup": "Ton und Vibration", + "@soundSettingGroup": {}, + "vibrationSetting": "Vibration", + "@vibrationSetting": {}, + "audioChannelSetting": "Audio-Kanal", + "@audioChannelSetting": {}, + "volumeSetting": "Lautstärke", + "@volumeSetting": {}, + "risingVolumeSetting": "Ansteigende Lautstärke", + "@risingVolumeSetting": {}, + "snoozeSettingGroup": "Schlummern", + "@snoozeSettingGroup": {}, + "snoozeEnableSetting": "Aktiviert", + "@snoozeEnableSetting": {}, + "snoozeLengthSetting": "Dauer", + "@snoozeLengthSetting": {}, + "settings": "Einstellungen", + "@settings": {}, + "mathTaskDifficultySetting": "Schwierigkeit", + "@mathTaskDifficultySetting": {}, + "skippingDescriptionSuffix": "(Nächstes Mal überspringen)", + "@skippingDescriptionSuffix": {}, + "alarmDescriptionSnooze": "Schlummern bis {date}", + "@alarmDescriptionSnooze": {}, + "alarmDescriptionFinished": "Keine zukünftigen Daten", + "@alarmDescriptionFinished": {}, + "alarmDescriptionNotScheduled": "Nicht geplant", + "@alarmDescriptionNotScheduled": {}, + "alarmDescriptionToday": "Nur heute", + "@alarmDescriptionToday": {}, + "alarmDescriptionTomorrow": "Nur morgen", + "@alarmDescriptionTomorrow": {}, + "alarmDescriptionEveryDay": "Jeden Tag", + "@alarmDescriptionEveryDay": {}, + "alarmDescriptionWeekend": "Jedes Wochenende", + "@alarmDescriptionWeekend": {}, + "stopwatchPrevious": "Vorherige", + "@stopwatchPrevious": {}, + "alarmDescriptionWeekday": "Jeden Wochentag", + "@alarmDescriptionWeekday": {}, + "stopwatchFastest": "Schnellste", + "@stopwatchFastest": {}, + "alarmDescriptionDays": "An {days}", + "@alarmDescriptionDays": {}, + "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly}} von {startDate} bis {endDate}", + "@alarmDescriptionRange": {}, + "stopwatchSlowest": "Langsamste", + "@stopwatchSlowest": {}, + "alarmDescriptionDates": "Am {date}{count, plural, =0{} =1{ and 1 other date} other{ und {count} anderen Daten}}", + "@alarmDescriptionDates": {}, + "stopwatchAverage": "Durchschnitt", + "@stopwatchAverage": {} +} From e81854a36b9d84b01347a51b10aa17861aa70752 Mon Sep 17 00:00:00 2001 From: Stzyxh Date: Sun, 14 Apr 2024 07:31:33 +0000 Subject: [PATCH 043/112] Translated using Weblate (German) Currently translated at 96.4% (82 of 85 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/de/ --- lib/l10n/app_de.arb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 58885052..1a45b207 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -9,7 +9,7 @@ "@overrideAccentSetting": {}, "appearanceSettingGroupDescription": "Setze Themes, Farben und ändere das Layout", "@appearanceSettingGroupDescription": {}, - "scheduleTypeDateDescription": "Wird an den angegebenen Daten wiederholt", + "scheduleTypeDateDescription": "Wird an den angegebenen Tagen wiederholt", "@scheduleTypeDateDescription": {}, "scheduleTypeRangeDescription": "Wird während des angegebenen Datumsbereichs wiederholt", "@scheduleTypeRangeDescription": {}, @@ -113,7 +113,7 @@ "@scheduleTypeWeek": {}, "scheduleTypeWeekDescription": "Wird an den bestimmten Wochentagen wiederholt", "@scheduleTypeWeekDescription": {}, - "scheduleTypeData": "An bestimmten Daten", + "scheduleTypeData": "An bestimmten Tagen", "@scheduleTypeData": {}, "scheduleTypeRange": "Datumsbereich", "@scheduleTypeRange": {}, @@ -143,7 +143,7 @@ "@skippingDescriptionSuffix": {}, "alarmDescriptionSnooze": "Schlummern bis {date}", "@alarmDescriptionSnooze": {}, - "alarmDescriptionFinished": "Keine zukünftigen Daten", + "alarmDescriptionFinished": "Keine zukünftigen Tagen", "@alarmDescriptionFinished": {}, "alarmDescriptionNotScheduled": "Nicht geplant", "@alarmDescriptionNotScheduled": {}, @@ -170,5 +170,11 @@ "alarmDescriptionDates": "Am {date}{count, plural, =0{} =1{ and 1 other date} other{ und {count} anderen Daten}}", "@alarmDescriptionDates": {}, "stopwatchAverage": "Durchschnitt", - "@stopwatchAverage": {} + "@stopwatchAverage": {}, + "styleThemeSetting": "Thema Stil", + "@styleThemeSetting": {}, + "snoozePreventDisablingSetting": "Deaktivierung verhindern", + "@snoozePreventDisablingSetting": {}, + "snoozePreventDeletion": "Löschung verhindern", + "@snoozePreventDeletion": {} } From adcf821c712e93818dc3ee4f1b2fe8b34b620027 Mon Sep 17 00:00:00 2001 From: UngoIiant Date: Sun, 14 Apr 2024 13:31:19 +0000 Subject: [PATCH 044/112] Translated using Weblate (German) Currently translated at 100.0% (85 of 85 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/de/ --- lib/l10n/app_de.arb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 1a45b207..e3b8650f 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -57,7 +57,7 @@ "@aboutSettingGroup": {}, "restoreSettingGroup": "Einstellungen zurücksetzten", "@restoreSettingGroup": {}, - "appearanceSettingGroup": "Design", + "appearanceSettingGroup": "Darstellung", "@appearanceSettingGroup": {}, "displaySettingGroup": "Darstellung", "@displaySettingGroup": {}, @@ -163,7 +163,7 @@ "@stopwatchFastest": {}, "alarmDescriptionDays": "An {days}", "@alarmDescriptionDays": {}, - "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly}} von {startDate} bis {endDate}", + "alarmDescriptionRange": "{interval, select, daily{Täglich} weekly{Wöchentlich}} von {startDate} bis {endDate}", "@alarmDescriptionRange": {}, "stopwatchSlowest": "Langsamste", "@stopwatchSlowest": {}, @@ -171,10 +171,10 @@ "@alarmDescriptionDates": {}, "stopwatchAverage": "Durchschnitt", "@stopwatchAverage": {}, - "styleThemeSetting": "Thema Stil", + "styleThemeSetting": "Designauswahl", "@styleThemeSetting": {}, "snoozePreventDisablingSetting": "Deaktivierung verhindern", "@snoozePreventDisablingSetting": {}, - "snoozePreventDeletion": "Löschung verhindern", + "snoozePreventDeletion": "Löschung verhindern", "@snoozePreventDeletion": {} } From 2e51286cdcc48371e6e8a953380474ed3d2975bb Mon Sep 17 00:00:00 2001 From: ngocanhtve Date: Thu, 18 Apr 2024 04:59:50 +0200 Subject: [PATCH 045/112] Added translation using Weblate (Vietnamese) --- lib/l10n/app_vi.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_vi.arb diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_vi.arb @@ -0,0 +1 @@ +{} From cc4a757d5104754d11f275caa3d2f29768686283 Mon Sep 17 00:00:00 2001 From: ngocanhtve Date: Thu, 18 Apr 2024 13:09:57 +0000 Subject: [PATCH 046/112] Translated using Weblate (Vietnamese) Currently translated at 100.0% (103 of 103 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/vi/ --- lib/l10n/app_vi.arb | 217 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 216 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 0967ef42..c29b8ff5 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -1 +1,216 @@ -{} +{ + "sequenceGridSizeSetting": "Kích thước lưới", + "@sequenceGridSizeSetting": {}, + "scheduleTypeWeekDescription": "Sẽ lặp lại vào các ngày trong tuần được chỉ định", + "@scheduleTypeWeekDescription": {}, + "soundSettingGroup": "Âm thanh và Rung", + "@soundSettingGroup": {}, + "saveReminderAlert": "Bạn có muốn rời đi mà không lưu?", + "@saveReminderAlert": {}, + "scheduleTypeData": "Vào những ngày cụ thể", + "@scheduleTypeData": {}, + "scheduleTypeDaily": "Hằng ngày", + "@scheduleTypeDaily": {}, + "yesButton": "Có", + "@yesButton": {}, + "scheduleTypeDateDescription": "Sẽ lặp lại vào những ngày được chỉ định", + "@scheduleTypeDateDescription": {}, + "scheduleTypeRangeDescription": "Sẽ lặp lại trong phạm vi ngày được chỉ định", + "@scheduleTypeRangeDescription": {}, + "settingGroupMore": "Nhiều hơn", + "@settingGroupMore": {}, + "scheduleTypeRange": "Phạm vi ngày", + "@scheduleTypeRange": {}, + "selectTime": "Chọn thời gian", + "@selectTime": {}, + "cancelButton": "Hủy", + "@cancelButton": {}, + "customizeButton": "Tùy chỉnh", + "@customizeButton": {}, + "alarmDescriptionToday": "Chỉ hôm nay", + "@alarmDescriptionToday": {}, + "snoozedFilter": "Đã hoãn", + "@snoozedFilter": {}, + "stopwatchSettingGroup": "Bấm giờ", + "@stopwatchSettingGroup": {}, + "scheduleTypeOnceDescription": "Sẽ đổ chuông vào lần xuất hiện tiếp theo của thời điểm", + "@scheduleTypeOnceDescription": {}, + "scheduleTypeWeek": "Vào Ngày trong tuần được chỉ định", + "@scheduleTypeWeek": {}, + "melodySetting": "Giai điệu", + "@melodySetting": {}, + "scheduleTypeField": "Loại", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "Một lần", + "@scheduleTypeOnce": {}, + "vibrationSetting": "Rung", + "@vibrationSetting": {}, + "alarmTitle": "Báo thức", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "timerTitle": "Hẹn giờ", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "stopwatchTitle": "Bấm giờ", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "generalSettingGroup": "Tổng quan", + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Diện mạo", + "@appearanceSettingGroup": {}, + "aboutSettingGroup": "Giới thiệu", + "@aboutSettingGroup": {}, + "restoreSettingGroup": "Khôi phục giá trị mặc định", + "@restoreSettingGroup": {}, + "displaySettingGroup": "Hiển thị", + "@displaySettingGroup": {}, + "reliabilitySettingGroup": "Độ tin cậy", + "@reliabilitySettingGroup": {}, + "colorsSettingGroup": "Màu sắc", + "@colorsSettingGroup": {}, + "styleSettingGroup": "Phong cách", + "@styleSettingGroup": {}, + "useMaterialYouColorSetting": "Sử dụng Material You", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "Độ sáng", + "@materialBrightnessSetting": {}, + "overrideAccentSetting": "Ghi đè màu nhấn", + "@overrideAccentSetting": {}, + "useMaterialStyleSetting": "Sử dụng phong cách Material", + "@useMaterialStyleSetting": {}, + "styleThemeSetting": "Chủ đề phong cách", + "@styleThemeSetting": {}, + "systemDarkModeSetting": "Chế độ tối của hệ thống", + "@systemDarkModeSetting": {}, + "darkColorSchemeSetting": "Phối màu tối", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "Đồng hồ", + "@clockSettingGroup": {}, + "timerSettingGroup": "Hẹn giờ", + "@timerSettingGroup": {}, + "generalSettingGroupDescription": "Đặt cài đặt trên toàn ứng dụng như định dạng thời gian", + "@generalSettingGroupDescription": {}, + "appearanceSettingGroupDescription": "Đặt chủ đề, màu sắc và thay đổi bố cục", + "@appearanceSettingGroupDescription": {}, + "backupSettingGroupDescription": "Xuất hoặc nhập thiết đặt của bạn cục bộ", + "@backupSettingGroupDescription": {}, + "saveButton": "Nút lưu", + "@saveButton": {}, + "labelField": "Nhãn", + "@labelField": {}, + "labelFieldPlaceholder": "Thêm nhãn", + "@labelFieldPlaceholder": {}, + "alarmScheduleSettingGroup": "Lịch trình", + "@alarmScheduleSettingGroup": {}, + "audioChannelSetting": "Kênh âm thanh", + "@audioChannelSetting": {}, + "volumeSetting": "Âm lượng", + "@volumeSetting": {}, + "risingVolumeSetting": "Tăng âm lượng", + "@risingVolumeSetting": {}, + "snoozeSettingGroup": "Hoãn", + "@snoozeSettingGroup": {}, + "snoozeEnableSetting": "Đã bật", + "@snoozeEnableSetting": {}, + "snoozeLengthSetting": "Thời lượng", + "@snoozeLengthSetting": {}, + "whileSnoozedSettingGroup": "Trong khi hoãn", + "@whileSnoozedSettingGroup": {}, + "snoozePreventDisablingSetting": "Ngăn chặn việc vô hiệu hóa", + "@snoozePreventDisablingSetting": {}, + "snoozePreventDeletion": "Ngăn chặn xóa", + "@snoozePreventDeletion": {}, + "settings": "Thiết đặt", + "@settings": {}, + "noItemMessage": "Chưa có {items} nào được thêm vào", + "@noItemMessage": {}, + "chooseTaskTitle": "Chọn nhiệm vụ để thêm", + "@chooseTaskTitle": {}, + "mathTask": "Bài toán", + "@mathTask": {}, + "retypeTask": "Nhập lại văn bản", + "@retypeTask": {}, + "mathTaskDifficultySetting": "Độ khó", + "@mathTaskDifficultySetting": {}, + "retypeNumberChars": "Số ký tự", + "@retypeNumberChars": {}, + "retypeIncludeNumSetting": "Bao gồm số", + "@retypeIncludeNumSetting": {}, + "retypeLowercaseSetting": "Bao gồm chữ thường", + "@retypeLowercaseSetting": {}, + "noButton": "Không", + "@noButton": {}, + "noItemCreatedMessage": "Chưa tạo {items} nào", + "@noItemCreatedMessage": {}, + "deleteButton": "Xóa", + "@deleteButton": {}, + "duplicateButton": "Nhân đôi", + "@duplicateButton": {}, + "skipAlarmButton": "Bỏ qua báo thức tiếp theo", + "@skipAlarmButton": {}, + "allFilter": "Tất cả", + "@allFilter": {}, + "todayFilter": "Hôm nay", + "@todayFilter": {}, + "tomorrowFilter": "Ngày mai", + "@tomorrowFilter": {}, + "disabledFilter": "Đã tắt", + "@disabledFilter": {}, + "completedFilter": "Hoàn thành", + "@completedFilter": {}, + "skippingDescriptionSuffix": "(bỏ qua lần xuất hiện tiếp theo)", + "@skippingDescriptionSuffix": {}, + "alarmDescriptionSnooze": "Đã hoãn cho đến {date}", + "@alarmDescriptionSnooze": {}, + "alarmDescriptionFinished": "Không có ngày trong tương lai", + "@alarmDescriptionFinished": {}, + "alarmDescriptionNotScheduled": "Chưa lên lịch", + "@alarmDescriptionNotScheduled": {}, + "sequenceTask": "Dãy", + "@sequenceTask": {}, + "taskTryButton": "Dùng thử", + "@taskTryButton": {}, + "sequenceLengthSetting": "Chiều dài dãy", + "@sequenceLengthSetting": {}, + "stopwatchPrevious": "Trước đó", + "@stopwatchPrevious": {}, + "stopwatchFastest": "Nhanh nhất", + "@stopwatchFastest": {}, + "stopwatchSlowest": "Chậm nhất", + "@stopwatchSlowest": {}, + "stopwatchAverage": "Trung bình", + "@stopwatchAverage": {}, + "alarmDescriptionTomorrow": "Chỉ ngày mai", + "@alarmDescriptionTomorrow": {}, + "alarmDescriptionEveryDay": "Hằng ngày", + "@alarmDescriptionEveryDay": {}, + "alarmDescriptionWeekend": "Mỗi cuối tuần", + "@alarmDescriptionWeekend": {}, + "alarmDescriptionWeekday": "Mỗi ngày trong tuần", + "@alarmDescriptionWeekday": {}, + "alarmDescriptionDays": "Vào {days}", + "@alarmDescriptionDays": {}, + "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly}} từ {startDate} tới {endDate}", + "@alarmDescriptionRange": {}, + "alarmDescriptionDates": "Vào {date}{count, plural, =0{} =1{ and 1 other date} other{ and {count} other dates}}", + "@alarmDescriptionDates": {}, + "clockTitle": "Đồng hồ", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "accessibilitySettingGroup": "Khả năng tiếp cận", + "@accessibilitySettingGroup": {}, + "backupSettingGroup": "Sao lưu", + "@backupSettingGroup": {}, + "developerOptionsSettingGroup": "Tùy chọn nhà phát triển", + "@developerOptionsSettingGroup": {}, + "tasksSetting": "Nhiệm vụ", + "@tasksSetting": {}, + "colorSchemeSetting": "Phối màu", + "@colorSchemeSetting": {}, + "scheduleTypeDailyDescription": "Sẽ đổ chuông mỗi ngày", + "@scheduleTypeDailyDescription": {} +} From ba9266be9eb6631cda2b19cb63cf775b365a38e8 Mon Sep 17 00:00:00 2001 From: Nie Pytany Date: Fri, 26 Apr 2024 19:34:54 +0200 Subject: [PATCH 047/112] Added translation using Weblate (Polish) --- lib/l10n/app_pl.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_pl.arb diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_pl.arb @@ -0,0 +1 @@ +{} From 4db3e2511a0c01e18dae5b759721bdd42064a4ea Mon Sep 17 00:00:00 2001 From: Eryk Michalak Date: Sat, 27 Apr 2024 02:05:37 +0000 Subject: [PATCH 048/112] Translated using Weblate (Polish) Currently translated at 48.5% (50 of 103 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pl/ --- lib/l10n/app_pl.arb | 109 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 0967ef42..c442eb66 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1 +1,108 @@ -{} +{ + "restoreSettingGroup": "Przywróć domyślne wartości", + "@restoreSettingGroup": {}, + "colorsSettingGroup": "Kolory", + "@colorsSettingGroup": {}, + "styleSettingGroup": "Styl", + "@styleSettingGroup": {}, + "useMaterialYouColorSetting": "Użyj Material You", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "Jasność", + "@materialBrightnessSetting": {}, + "colorSchemeSetting": "Paleta kolorów", + "@colorSchemeSetting": {}, + "cancelButton": "Anuluj", + "@cancelButton": {}, + "customizeButton": "Dostosuj", + "@customizeButton": {}, + "yesButton": "Tak", + "@yesButton": {}, + "stopwatchPrevious": "Poprzedni", + "@stopwatchPrevious": {}, + "stopwatchFastest": "Najszybszy", + "@stopwatchFastest": {}, + "stopwatchSlowest": "Najwolniejszy", + "@stopwatchSlowest": {}, + "clockTitle": "Zegar", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "alarmTitle": "Alarm", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "aboutSettingGroup": "O aplikacji", + "@aboutSettingGroup": {}, + "overrideAccentSetting": "Nadpisz kolor akcentu", + "@overrideAccentSetting": {}, + "timerTitle": "Czasomierz", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "useMaterialStyleSetting": "Użyj stylu Material", + "@useMaterialStyleSetting": {}, + "generalSettingGroup": "Ogólne", + "@generalSettingGroup": {}, + "appearanceSettingGroup": "Wygląd", + "@appearanceSettingGroup": {}, + "accessibilitySettingGroup": "Dostępność", + "@accessibilitySettingGroup": {}, + "backupSettingGroup": "Kopia zapasowa", + "@backupSettingGroup": {}, + "developerOptionsSettingGroup": "Opcje programistyczne", + "@developerOptionsSettingGroup": {}, + "styleThemeSetting": "Motyw", + "@styleThemeSetting": {}, + "clockSettingGroup": "Zegar", + "@clockSettingGroup": {}, + "labelField": "Etykieta", + "@labelField": {}, + "alarmScheduleSettingGroup": "Kolejka", + "@alarmScheduleSettingGroup": {}, + "settingGroupMore": "Więcej", + "@settingGroupMore": {}, + "vibrationSetting": "Wibracje", + "@vibrationSetting": {}, + "snoozeEnableSetting": "Włączono", + "@snoozeEnableSetting": {}, + "tasksSetting": "Zadania", + "@tasksSetting": {}, + "stopwatchAverage": "Średnia", + "@stopwatchAverage": {}, + "scheduleTypeField": "Typ", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "Raz", + "@scheduleTypeOnce": {}, + "melodySetting": "Melodia", + "@melodySetting": {}, + "volumeSetting": "Głośność", + "@volumeSetting": {}, + "snoozeLengthSetting": "Długość", + "@snoozeLengthSetting": {}, + "noButton": "Nie", + "@noButton": {}, + "timerSettingGroup": "Czasomierz", + "@timerSettingGroup": {}, + "scheduleTypeDaily": "Codziennie", + "@scheduleTypeDaily": {}, + "settings": "Ustawienia", + "@settings": {}, + "selectTime": "Wybierz czas", + "@selectTime": {}, + "mathTaskDifficultySetting": "Poziom trudności", + "@mathTaskDifficultySetting": {}, + "deleteButton": "Usuń", + "@deleteButton": {}, + "duplicateButton": "Duplikuj", + "@duplicateButton": {}, + "allFilter": "Wszystko", + "@allFilter": {}, + "todayFilter": "Dzisiaj", + "@todayFilter": {}, + "tomorrowFilter": "Jutro", + "@tomorrowFilter": {}, + "disabledFilter": "Wyłączono", + "@disabledFilter": {}, + "completedFilter": "Zakończone", + "@completedFilter": {} +} From c60bb95545ece7340ed67996993035ba7b4b5ecb Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sun, 28 Apr 2024 15:30:33 +0200 Subject: [PATCH 049/112] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/ --- lib/l10n/app_de.arb | 6 +----- lib/l10n/app_es.arb | 4 ---- lib/l10n/app_fr.arb | 4 ---- lib/l10n/app_pt.arb | 4 ---- lib/l10n/app_tr.arb | 4 ---- lib/l10n/app_vi.arb | 4 ---- 6 files changed, 1 insertion(+), 25 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index e3b8650f..9f2967df 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -113,8 +113,6 @@ "@scheduleTypeWeek": {}, "scheduleTypeWeekDescription": "Wird an den bestimmten Wochentagen wiederholt", "@scheduleTypeWeekDescription": {}, - "scheduleTypeData": "An bestimmten Tagen", - "@scheduleTypeData": {}, "scheduleTypeRange": "Datumsbereich", "@scheduleTypeRange": {}, "settingGroupMore": "Mehr", @@ -174,7 +172,5 @@ "styleThemeSetting": "Designauswahl", "@styleThemeSetting": {}, "snoozePreventDisablingSetting": "Deaktivierung verhindern", - "@snoozePreventDisablingSetting": {}, - "snoozePreventDeletion": "Löschung verhindern", - "@snoozePreventDeletion": {} + "@snoozePreventDisablingSetting": {} } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 69fd4a81..c8cc0ea4 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -85,8 +85,6 @@ "@scheduleTypeWeek": {}, "scheduleTypeWeekDescription": "Se repetirá los días de la semana especificados", "@scheduleTypeWeekDescription": {}, - "scheduleTypeData": "En fechas concretas", - "@scheduleTypeData": {}, "scheduleTypeRange": "Intervalo de fechas", "@scheduleTypeRange": {}, "scheduleTypeDateDescription": "Se repetirá en las fechas especificadas", @@ -115,8 +113,6 @@ "@snoozeLengthSetting": {}, "snoozePreventDisablingSetting": "Evitar la desactivación", "@snoozePreventDisablingSetting": {}, - "snoozePreventDeletion": "Evitar la eliminación", - "@snoozePreventDeletion": {}, "settings": "Ajustes", "@settings": {}, "tasksSetting": "Tareas", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index f8368659..046b5f6c 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -91,8 +91,6 @@ "@scheduleTypeOnceDescription": {}, "scheduleTypeWeek": "À des jours spécifiques", "@scheduleTypeWeek": {}, - "scheduleTypeData": "À des dates spécifiques", - "@scheduleTypeData": {}, "scheduleTypeRange": "Période", "@scheduleTypeRange": {}, "scheduleTypeDateDescription": "Se répétera aux dates spécifiées", @@ -123,8 +121,6 @@ "@whileSnoozedSettingGroup": {}, "snoozePreventDisablingSetting": "Empêcher la désactivation", "@snoozePreventDisablingSetting": {}, - "snoozePreventDeletion": "Empêcher la suppression", - "@snoozePreventDeletion": {}, "settings": "Paramètres", "@settings": {}, "tasksSetting": "Tâches", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 019bbfc9..bc2ce95c 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -73,8 +73,6 @@ "@selectTime": {}, "scheduleTypeOnceDescription": "Será ativado na próxima ocorrência de hora", "@scheduleTypeOnceDescription": {}, - "scheduleTypeData": "Datas específicas", - "@scheduleTypeData": {}, "settingGroupMore": "Mais", "@settingGroupMore": {}, "melodySetting": "Melodia", @@ -99,8 +97,6 @@ "@snoozeLengthSetting": {}, "snoozePreventDisablingSetting": "Impedir desativação", "@snoozePreventDisablingSetting": {}, - "snoozePreventDeletion": "Impedir eliminação", - "@snoozePreventDeletion": {}, "chooseTaskTitle": "Escolha o tipo de tarefa", "@chooseTaskTitle": {}, "mathTask": "Matemática", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 8a14fb7c..5a09a92d 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -77,8 +77,6 @@ "@scheduleTypeWeek": {}, "scheduleTypeWeekDescription": "Hafta içi belirlenen günlerde tekrarlanacak", "@scheduleTypeWeekDescription": {}, - "scheduleTypeData": "Belirli tarihlerde", - "@scheduleTypeData": {}, "scheduleTypeRange": "Tarih aralığı", "@scheduleTypeRange": {}, "scheduleTypeDateDescription": "Belirlenen tarihlerde tekrarlanacak", @@ -107,8 +105,6 @@ "@whileSnoozedSettingGroup": {}, "snoozePreventDisablingSetting": "Devre dışı bırakmayı önle", "@snoozePreventDisablingSetting": {}, - "snoozePreventDeletion": "Silinmeyi önle", - "@snoozePreventDeletion": {}, "settings": "Ayarlar", "@settings": {}, "tasksSetting": "Görevler", diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index c29b8ff5..c324e181 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -7,8 +7,6 @@ "@soundSettingGroup": {}, "saveReminderAlert": "Bạn có muốn rời đi mà không lưu?", "@saveReminderAlert": {}, - "scheduleTypeData": "Vào những ngày cụ thể", - "@scheduleTypeData": {}, "scheduleTypeDaily": "Hằng ngày", "@scheduleTypeDaily": {}, "yesButton": "Có", @@ -121,8 +119,6 @@ "@whileSnoozedSettingGroup": {}, "snoozePreventDisablingSetting": "Ngăn chặn việc vô hiệu hóa", "@snoozePreventDisablingSetting": {}, - "snoozePreventDeletion": "Ngăn chặn xóa", - "@snoozePreventDeletion": {}, "settings": "Thiết đặt", "@settings": {}, "noItemMessage": "Chưa có {items} nào được thêm vào", From 0e28597de7312da6d2eb80f6c5409f2a6784bcd0 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 28 Apr 2024 15:49:27 +0000 Subject: [PATCH 050/112] Translated using Weblate (Spanish) Currently translated at 99.1% (232 of 234 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 268 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 265 insertions(+), 3 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index c8cc0ea4..cd92ce31 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -13,7 +13,7 @@ "@appearanceSettingGroup": {}, "accessibilitySettingGroup": "Accesibilidad", "@accessibilitySettingGroup": {}, - "backupSettingGroup": "Copia de seguridad", + "backupSettingGroup": "Ajustes", "@backupSettingGroup": {}, "developerOptionsSettingGroup": "Opciones de desarrollador", "@developerOptionsSettingGroup": {}, @@ -91,7 +91,7 @@ "@scheduleTypeDateDescription": {}, "scheduleTypeRangeDescription": "Se repetirá durante el intervalo de fechas especificado", "@scheduleTypeRangeDescription": {}, - "soundSettingGroup": "Sonido y vibración", + "soundSettingGroup": "Sonido", "@soundSettingGroup": {}, "settingGroupMore": "Más", "@settingGroupMore": {}, @@ -200,5 +200,267 @@ "alarmDescriptionDates": "En {date}{count, plural, =0{} =1{ y otra fecha} other{ y {count} otras fechas}}", "@alarmDescriptionDates": {}, "stopwatchAverage": "Promedio", - "@stopwatchAverage": {} + "@stopwatchAverage": {}, + "system": "Sistema", + "@system": {}, + "timeFormatSetting": "Formato de la hora", + "@timeFormatSetting": {}, + "timeFormat12": "12 horas", + "@timeFormat12": {}, + "timeFormat24": "24 horas", + "@timeFormat24": {}, + "timeFormatDevice": "Ajustes del dispositivo", + "@timeFormatDevice": {}, + "showSecondsSetting": "Mostrar los segundos", + "@showSecondsSetting": {}, + "timePickerSetting": "Selector de tiempo", + "@timePickerSetting": {}, + "pickerDial": "Marcar", + "@pickerDial": {}, + "pickerInput": "Entrada", + "@pickerInput": {}, + "pickerSpinner": "Spinner", + "@pickerSpinner": {}, + "durationPickerSetting": "Selector de duración", + "@durationPickerSetting": {}, + "pickerRings": "Tonos", + "@pickerRings": {}, + "swipeActionCardActionDescription": "Desliza el dedo a izquierda o derecha en la tarjeta para realizar acciones", + "@swipeActionCardActionDescription": {}, + "swipActionSwitchTabs": "Cambiar pestañas", + "@swipActionSwitchTabs": {}, + "swipeActionSwitchTabsDescription": "Pasar de una pestaña a otra", + "@swipeActionSwitchTabsDescription": {}, + "melodiesSetting": "Melodías", + "@melodiesSetting": {}, + "tagsSetting": "Etiquetas", + "@tagsSetting": {}, + "vendorSetting": "Ajustes del proveedor", + "@vendorSetting": {}, + "vendorSettingDescription": "Desactivar manualmente las optimizaciones específicas del proveedor", + "@vendorSettingDescription": {}, + "batteryOptimizationSetting": "Desactivar la optimización de la batería", + "@batteryOptimizationSetting": {}, + "allowNotificationSetting": "Permitir notificaciones", + "@allowNotificationSetting": {}, + "autoStartSetting": "Inicio automático", + "@autoStartSetting": {}, + "animationSettingGroup": "Animaciones", + "@animationSettingGroup": {}, + "animationSpeedSetting": "Velocidad de las animaciones", + "@animationSpeedSetting": {}, + "extraAnimationSetting": "Animaciones adicionales", + "@extraAnimationSetting": {}, + "nameField": "Nombre", + "@nameField": {}, + "colorSetting": "Color", + "@colorSetting": {}, + "textColorSetting": "Texto", + "@textColorSetting": {}, + "colorSchemeNamePlaceholder": "Esquema de colores", + "@colorSchemeNamePlaceholder": {}, + "colorSchemeBackgroundSettingGroup": "Fondo", + "@colorSchemeBackgroundSettingGroup": {}, + "colorSchemeAccentSettingGroup": "Acentuar", + "@colorSchemeAccentSettingGroup": {}, + "colorSchemeErrorSettingGroup": "Error", + "@colorSchemeErrorSettingGroup": {}, + "colorSchemeCardSettingGroup": "Tarjeta", + "@colorSchemeCardSettingGroup": {}, + "colorSchemeOutlineSettingGroup": "Descripción", + "@colorSchemeOutlineSettingGroup": {}, + "colorSchemeShadowSettingGroup": "Sombra", + "@colorSchemeShadowSettingGroup": {}, + "styleThemeNamePlaceholder": "Estilo del tema", + "@styleThemeNamePlaceholder": {}, + "styleThemeShadowSettingGroup": "Sombra", + "@styleThemeShadowSettingGroup": {}, + "styleThemeShapeSettingGroup": "Forma", + "@styleThemeShapeSettingGroup": {}, + "styleThemeElevationSetting": "Elevación", + "@styleThemeElevationSetting": {}, + "styleThemeRadiusSetting": "Redondez de las esquinas", + "@styleThemeRadiusSetting": {}, + "styleThemeOpacitySetting": "Opacidad", + "@styleThemeOpacitySetting": {}, + "styleThemeBlurSetting": "Difuminar", + "@styleThemeBlurSetting": {}, + "styleThemeSpreadSetting": "Envergadura", + "@styleThemeSpreadSetting": {}, + "styleThemeOutlineSettingGroup": "Descripción", + "@styleThemeOutlineSettingGroup": {}, + "styleThemeOutlineWidthSetting": "Ancho", + "@styleThemeOutlineWidthSetting": {}, + "showIstantAlarmButtonSetting": "Mostrar botón de alarma instantánea", + "@showIstantAlarmButtonSetting": {}, + "showIstantTimerButtonSetting": "Mostrar botón de temporizador instantáneo", + "@showIstantTimerButtonSetting": {}, + "maxLogsSetting": "Registros máximos", + "@maxLogsSetting": {}, + "alarmLogSetting": "Registros de alarmas", + "@alarmLogSetting": {}, + "resetButton": "Restablecer", + "@resetButton": {}, + "previewLabel": "Vista previa", + "@previewLabel": {}, + "errorLabel": "Error", + "@errorLabel": {}, + "materialBrightnessSystem": "Sistema", + "@materialBrightnessSystem": {}, + "materialBrightnessLight": "Claro", + "@materialBrightnessLight": {}, + "materialBrightnessDark": "Oscuro", + "@materialBrightnessDark": {}, + "accentColorSetting": "Acentuar el color", + "@accentColorSetting": {}, + "alarmWeekdaysSetting": "Días de la semana", + "@alarmWeekdaysSetting": {}, + "mondayLetter": "L", + "@mondayLetter": {}, + "tuesdayLetter": "M", + "@tuesdayLetter": {}, + "colorSchemeUseAccentAsShadowSetting": "Usar acento como sombra", + "@colorSchemeUseAccentAsShadowSetting": {}, + "thursdayLetter": "J", + "@thursdayLetter": {}, + "fridayLetter": "V", + "@fridayLetter": {}, + "saturdayLetter": "S", + "@saturdayLetter": {}, + "sundayLetter": "D", + "@sundayLetter": {}, + "alarmDatesSetting": "Fechas", + "@alarmDatesSetting": {}, + "alarmRangeSetting": "Rango de fechas", + "@alarmRangeSetting": {}, + "alarmIntervalSetting": "Intervalo", + "@alarmIntervalSetting": {}, + "alarmIntervalDaily": "A diario", + "@alarmIntervalDaily": {}, + "alarmIntervalWeekly": "Semanalmente", + "@alarmIntervalWeekly": {}, + "soundAndVibrationSettingGroup": "Sonido y vibración", + "@soundAndVibrationSettingGroup": {}, + "audioChannelAlarm": "Alarma", + "@audioChannelAlarm": {}, + "audioChannelNotification": "Notificación", + "@audioChannelNotification": {}, + "audioChannelRingtone": "Tono de llamada", + "@audioChannelRingtone": {}, + "audioChannelMedia": "Medio", + "@audioChannelMedia": {}, + "maxSnoozesSetting": "Máximo de repeticiones", + "@maxSnoozesSetting": {}, + "snoozePreventDeletionSetting": "Prevenir la eliminación", + "@snoozePreventDeletionSetting": {}, + "mathEasyDifficulty": "Fácil (X+Y)", + "@mathEasyDifficulty": {}, + "mathMediumDifficulty": "Medio (X × Y)", + "@mathMediumDifficulty": {}, + "mathHardDifficulty": "Difícil (X × Y + Z)", + "@mathHardDifficulty": {}, + "mathVeryHardDifficulty": "Muy difícil (X × Y × Z)", + "@mathVeryHardDifficulty": {}, + "numberOfProblemsSetting": "Número de problemas", + "@numberOfProblemsSetting": {}, + "defaultSettingGroup": "Ajustes por defecto", + "@defaultSettingGroup": {}, + "alarmsDefaultSettingGroupDescription": "Establecer valores predeterminados para nuevas alarmas", + "@alarmsDefaultSettingGroupDescription": {}, + "timerDefaultSettingGroupDescription": "Establecer valores predeterminados para nuevos temporizadores", + "@timerDefaultSettingGroupDescription": {}, + "filtersSettingGroup": "Filtros", + "@filtersSettingGroup": {}, + "showSortSetting": "Mostrar ordenar", + "@showSortSetting": {}, + "notificationsSettingGroup": "Notificaciones", + "@notificationsSettingGroup": {}, + "upcomingLeadTimeSetting": "Próximo plazo", + "@upcomingLeadTimeSetting": {}, + "showSnoozeNotificationSetting": "Mostrar notificaciones de repetición", + "@showSnoozeNotificationSetting": {}, + "showNotificationSetting": "Mostrar la notificación", + "@showNotificationSetting": {}, + "presetsSetting": "Ajustes preestablecidos", + "@presetsSetting": {}, + "newPresetPlaceholder": "Nuevos ajustes preestablecidos", + "@newPresetPlaceholder": {}, + "dismissActionButtons": "Botones", + "@dismissActionButtons": {}, + "stopwatchTimeFormatSettingGroup": "Formato de la hora", + "@stopwatchTimeFormatSettingGroup": {}, + "stopwatchShowMillisecondsSetting": "Mostrar milisegundos", + "@stopwatchShowMillisecondsSetting": {}, + "showFastestLapSetting": "Mostrar vuelta más rápida", + "@showFastestLapSetting": {}, + "showPreviousLapSetting": "Mostrar vuelta anterior", + "@showPreviousLapSetting": {}, + "comparisonLapBarsSettingGroup": "Comparar las vueltas", + "@comparisonLapBarsSettingGroup": {}, + "showAverageLapSetting": "Mostrar vuelta promedio", + "@showAverageLapSetting": {}, + "showSlowestLapSetting": "Mostrar vuelta más lenta", + "@showSlowestLapSetting": {}, + "leftHandedSetting": "Modo para zurdos", + "@leftHandedSetting": {}, + "exportSettingsSetting": "Exportar", + "@exportSettingsSetting": {}, + "exportSettingsSettingDescription": "Exportar ajustes a un archivo local", + "@exportSettingsSettingDescription": {}, + "importSettingsSetting": "Importar", + "@importSettingsSetting": {}, + "importSettingsSettingDescription": "Importar ajustes desde un archivo local", + "@importSettingsSettingDescription": {}, + "versionLabel": "Versión", + "@versionLabel": {}, + "packageNameLabel": "Nombre del paquete", + "@packageNameLabel": {}, + "licenseLabel": "Licencia", + "@licenseLabel": {}, + "viewOnGithubLabel": "Ver en GitHub", + "@viewOnGithubLabel": {}, + "creditsSettingGroup": "Créditos", + "@creditsSettingGroup": {}, + "addLengthSetting": "Agregar longitud", + "@addLengthSetting": {}, + "dismissActionAreaButtons": "Zona de controles", + "@dismissActionAreaButtons": {}, + "languageSetting": "Idioma", + "@languageSetting": {}, + "dateFormatSetting": "Formato de la fecha", + "@dateFormatSetting": {}, + "swipeActionSetting": "Acción de deslizar", + "@swipeActionSetting": {}, + "swipActionCardAction": "Acciones con tarjetas", + "@swipActionCardAction": {}, + "batteryOptimizationSettingDescription": "Desactiva la optimización de la batería de esta aplicación para evitar que las alarmas se retrasen", + "@batteryOptimizationSettingDescription": {}, + "alarmDeleteAfterRingingSetting": "Eliminar después de descartar", + "@alarmDeleteAfterRingingSetting": {}, + "timeToFullVolumeSetting": "Tiempo hasta el volumen máximo", + "@timeToFullVolumeSetting": {}, + "logsSettingGroup": "Registros", + "@logsSettingGroup": {}, + "scheduleTypeDate": "En fechas específicas", + "@scheduleTypeDate": {}, + "showUpcomingAlarmNotificationSetting": "Mostrar próximas notificaciones de alarma", + "@showUpcomingAlarmNotificationSetting": {}, + "showFiltersSetting": "Mostrar los filtros", + "@showFiltersSetting": {}, + "allowNotificationSettingDescription": "Permitir notificaciones en la pantalla de bloqueo para alarmas y temporizadores", + "@allowNotificationSettingDescription": {}, + "autoStartSettingDescription": "Algunos dispositivos requieren que el inicio automático esté activado para que las alarmas suenen mientras la aplicación está cerrada", + "@autoStartSettingDescription": {}, + "cardLabel": "Tarjeta", + "@cardLabel": {}, + "wednesdayLetter": "X", + "@wednesdayLetter": {}, + "alarmDeleteAfterFinishingSetting": "Eliminar después de terminar", + "@alarmDeleteAfterFinishingSetting": {}, + "dismissActionSetting": "Descartar tipo de acción", + "@dismissActionSetting": {}, + "dismissActionSlide": "Deslizar", + "@dismissActionSlide": {}, + "emailLabel": "Correo electrónico", + "@emailLabel": {} } From 3bb658a12944b611d0352670f0679c688837736d Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sun, 28 Apr 2024 21:29:20 +0200 Subject: [PATCH 051/112] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/ --- lib/l10n/app_es.arb | 2 -- lib/l10n/app_nb.arb | 2 -- lib/l10n/app_pt.arb | 2 -- lib/l10n/app_tr.arb | 2 -- lib/l10n/app_vi.arb | 2 -- 5 files changed, 10 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index cd92ce31..0830c7b2 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -145,8 +145,6 @@ "@yesButton": {}, "noButton": "No", "@noButton": {}, - "noItemCreatedMessage": "No se han creado {items}", - "@noItemCreatedMessage": {}, "deleteButton": "Borrar", "@deleteButton": {}, "duplicateButton": "Duplicar", diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index 496a261f..630e16ed 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -57,8 +57,6 @@ "@selectTime": {}, "cancelButton": "Avbryt", "@cancelButton": {}, - "snoozePreventDeletion": "Forhindre sletting", - "@snoozePreventDeletion": {}, "customizeButton": "Tilpass", "@customizeButton": {}, "labelField": "Etikett", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index bc2ce95c..87327951 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -175,8 +175,6 @@ "@scheduleTypeRangeDescription": {}, "noItemMessage": "Ainda não adicionou {items}", "@noItemMessage": {}, - "noItemCreatedMessage": "{items} não criadas", - "@noItemCreatedMessage": {}, "skippingDescriptionSuffix": "(ignorar próxima ocorrência)", "@skippingDescriptionSuffix": {}, "alarmDescriptionSnooze": "Silenciado até {date}", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 5a09a92d..03a5fa93 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -133,8 +133,6 @@ "@saveReminderAlert": {}, "yesButton": "Evet", "@yesButton": {}, - "noItemCreatedMessage": "{items} oluşturulmadı", - "@noItemCreatedMessage": {}, "deleteButton": "Sil", "@deleteButton": {}, "alarmDescriptionNotScheduled": "Planlanmadı", diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index c324e181..a71d1c16 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -139,8 +139,6 @@ "@retypeLowercaseSetting": {}, "noButton": "Không", "@noButton": {}, - "noItemCreatedMessage": "Chưa tạo {items} nào", - "@noItemCreatedMessage": {}, "deleteButton": "Xóa", "@deleteButton": {}, "duplicateButton": "Nhân đôi", From c5434ba132b3bf54a15c9f3872919062452db005 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 28 Apr 2024 20:10:58 +0000 Subject: [PATCH 052/112] Translated using Weblate (Spanish) Currently translated at 99.2% (258 of 260 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 58 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 0830c7b2..07d892a6 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -63,7 +63,7 @@ "@cancelButton": {}, "customizeButton": "Personalizar", "@customizeButton": {}, - "saveButton": "Botón guardar", + "saveButton": "Guardar", "@saveButton": {}, "labelField": "Etiqueta", "@labelField": {}, @@ -460,5 +460,59 @@ "dismissActionSlide": "Deslizar", "@dismissActionSlide": {}, "emailLabel": "Correo electrónico", - "@emailLabel": {} + "@emailLabel": {}, + "cannotDisableAlarmWhileSnoozedSnackbar": "No se puede desactivar la alarma mientras está pospuesta", + "@cannotDisableAlarmWhileSnoozedSnackbar": {}, + "noTimerMessage": "No se crearon temporizadores", + "@noTimerMessage": {}, + "noTaskMessage": "No se crearon tareas", + "@noTaskMessage": {}, + "timeOfDayAsc": "Hora del día ascendente", + "@timeOfDayAsc": {}, + "disableAllFilteredAlarmsAction": "Deshabilitar todas las alarmas filtradas", + "@disableAllFilteredAlarmsAction": {}, + "noAlarmMessage": "No se crearon alarmas", + "@noAlarmMessage": {}, + "noStopwatchMessage": "No se crearon cronómetros", + "@noStopwatchMessage": {}, + "noPresetsMessage": "No se han creado ajustes preestablecidos", + "@noPresetsMessage": {}, + "noLogsMessage": "Sin registros de alarma", + "@noLogsMessage": {}, + "dateFilterGroup": "Fecha", + "@dateFilterGroup": {}, + "stateFilterGroup": "Estado", + "@stateFilterGroup": {}, + "activeFilter": "Activa", + "@activeFilter": {}, + "sortGroup": "Ordenar", + "@sortGroup": {}, + "defaultLabel": "Por defecto", + "@defaultLabel": {}, + "remainingTimeDesc": "Tiempo restante descendente", + "@remainingTimeDesc": {}, + "remainingTimeAsc": "Tiempo restante ascendente", + "@remainingTimeAsc": {}, + "nameAsc": "Nombre ascendente", + "@nameAsc": {}, + "nameDesc": "Nombre descendente", + "@nameDesc": {}, + "dateAsc": "Fecha ascendente", + "@dateAsc": {}, + "dateDesc": "Fecha descendente", + "@dateDesc": {}, + "timeOfDayDesc": "Hora del día descendente", + "@timeOfDayDesc": {}, + "filterActions": "Filtrar acciones", + "@filterActions": {}, + "clearFiltersAction": "Limpiar todos los filtros", + "@clearFiltersAction": {}, + "enableAllFilteredAlarmsAction": "Habilitar todas las alarmas filtradas", + "@enableAllFilteredAlarmsAction": {}, + "cancelSkipAllFilteredAlarmsAction": "No omitir todas las alarmas filtradas", + "@cancelSkipAllFilteredAlarmsAction": {}, + "skipAllFilteredAlarmsAction": "Omitir todas las alarmas filtradas", + "@skipAllFilteredAlarmsAction": {}, + "deleteAllFilteredAction": "Eliminar todos los elementos filtrados", + "@deleteAllFilteredAction": {} } From 02afd9bf8a78fe5efeecf7258f8e95e68ae71d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC=D0=B8=D0=B9=20=D0=9B=D0=B0?= =?UTF-8?q?=D0=B7=D0=B0=D1=80=D0=B5=D0=B2=20=28BurnBird=29?= Date: Mon, 29 Apr 2024 05:37:47 +0000 Subject: [PATCH 053/112] Translated using Weblate (Russian) Currently translated at 26.5% (69 of 260 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/ru/ --- lib/l10n/app_ru.arb | 102 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 004a4e62..1ced906a 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -60,5 +60,105 @@ "saveButton": "Сохранить", "@saveButton": {}, "vibrationSetting": "Вибрация", - "@vibrationSetting": {} + "@vibrationSetting": {}, + "backupSettingGroup": "Настройки", + "@backupSettingGroup": {}, + "systemDarkModeSetting": "Тёмная тема системы", + "@systemDarkModeSetting": {}, + "system": "Система", + "@system": {}, + "languageSetting": "Язык", + "@languageSetting": {}, + "dateFormatSetting": "Формат даты", + "@dateFormatSetting": {}, + "timeFormatSetting": "Формат времени", + "@timeFormatSetting": {}, + "timeFormat12": "12 часов", + "@timeFormat12": {}, + "timeFormat24": "24 часа", + "@timeFormat24": {}, + "timeFormatDevice": "Настройки устройства", + "@timeFormatDevice": {}, + "showSecondsSetting": "Показать секунды", + "@showSecondsSetting": {}, + "swipeActionCardActionDescription": "Смахните карточку влево или вправо, чтобы выполнить действие", + "@swipeActionCardActionDescription": {}, + "batteryOptimizationSetting": "Отключить оптимизацию батареи", + "@batteryOptimizationSetting": {}, + "batteryOptimizationSettingDescription": "Отключить оптимизацию батареи для этого приложения, чтобы избежать откладывания будильника", + "@batteryOptimizationSettingDescription": {}, + "allowNotificationSetting": "Разрешить уведомления", + "@allowNotificationSetting": {}, + "autoStartSetting": "Автозапуск", + "@autoStartSetting": {}, + "animationSettingGroup": "Анимации", + "@animationSettingGroup": {}, + "animationSpeedSetting": "Скорость анимации", + "@animationSpeedSetting": {}, + "extraAnimationSetting": "Дополнительные анимации", + "@extraAnimationSetting": {}, + "nameField": "Имя", + "@nameField": {}, + "colorSetting": "Цвет", + "@colorSetting": {}, + "swipeActionSetting": "Смахивание", + "@swipeActionSetting": {}, + "swipActionCardAction": "Действия карточки", + "@swipActionCardAction": {}, + "swipActionSwitchTabs": "Сменить вкладу", + "@swipActionSwitchTabs": {}, + "melodiesSetting": "Мелодии", + "@melodiesSetting": {}, + "tagsSetting": "Ярлыки", + "@tagsSetting": {}, + "colorSchemeBackgroundSettingGroup": "Фон", + "@colorSchemeBackgroundSettingGroup": {}, + "colorSchemeAccentSettingGroup": "Акцент", + "@colorSchemeAccentSettingGroup": {}, + "colorSchemeCardSettingGroup": "Карточка", + "@colorSchemeCardSettingGroup": {}, + "colorSchemeOutlineSettingGroup": "Граница", + "@colorSchemeOutlineSettingGroup": {}, + "colorSchemeShadowSettingGroup": "Тень", + "@colorSchemeShadowSettingGroup": {}, + "colorSchemeUseAccentAsOutlineSetting": "Использовать акцент для границ", + "@colorSchemeUseAccentAsOutlineSetting": {}, + "colorSchemeUseAccentAsShadowSetting": "Использовать акцент для теней", + "@colorSchemeUseAccentAsShadowSetting": {}, + "styleThemeShadowSettingGroup": "Тень", + "@styleThemeShadowSettingGroup": {}, + "styleThemeShapeSettingGroup": "Форма", + "@styleThemeShapeSettingGroup": {}, + "styleThemeRadiusSetting": "Скругление углов", + "@styleThemeRadiusSetting": {}, + "styleThemeBlurSetting": "Размытие", + "@styleThemeBlurSetting": {}, + "styleThemeOutlineSettingGroup": "Граница", + "@styleThemeOutlineSettingGroup": {}, + "styleThemeOutlineWidthSetting": "Ширина", + "@styleThemeOutlineWidthSetting": {}, + "resetButton": "Сбросить", + "@resetButton": {}, + "cardLabel": "Карточка", + "@cardLabel": {}, + "accentLabel": "Акцент", + "@accentLabel": {}, + "errorLabel": "Ошибка", + "@errorLabel": {}, + "materialBrightnessSystem": "Система", + "@materialBrightnessSystem": {}, + "materialBrightnessLight": "Светлая", + "@materialBrightnessLight": {}, + "materialBrightnessDark": "Тёмная", + "@materialBrightnessDark": {}, + "accentColorSetting": "Цвет акцента", + "@accentColorSetting": {}, + "textColorSetting": "Текст", + "@textColorSetting": {}, + "colorSchemeErrorSettingGroup": "Ошибка", + "@colorSchemeErrorSettingGroup": {}, + "styleThemeOpacitySetting": "Прозрачность", + "@styleThemeOpacitySetting": {}, + "colorSchemeNamePlaceholder": "Цветовая схема", + "@colorSchemeNamePlaceholder": {} } From 61e05d7fb2429e8aa77b78c7d538d2962030778c Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Mon, 29 Apr 2024 08:06:03 +0000 Subject: [PATCH 054/112] Translated using Weblate (German) Currently translated at 30.7% (80 of 260 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/de/ --- lib/l10n/app_de.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9f2967df..39e83eeb 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -161,7 +161,7 @@ "@stopwatchFastest": {}, "alarmDescriptionDays": "An {days}", "@alarmDescriptionDays": {}, - "alarmDescriptionRange": "{interval, select, daily{Täglich} weekly{Wöchentlich}} von {startDate} bis {endDate}", + "alarmDescriptionRange": "{interval, select, daily{Täglich} weekly{Wöchentlich} other{Other}} von {startDate} bis {endDate}", "@alarmDescriptionRange": {}, "stopwatchSlowest": "Langsamste", "@stopwatchSlowest": {}, From 296a130404d74f1d3c28177f899895f85d68545e Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Mon, 29 Apr 2024 08:06:23 +0000 Subject: [PATCH 055/112] Translated using Weblate (Portuguese) Currently translated at 37.3% (97 of 260 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 87327951..8f4f490b 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -199,7 +199,7 @@ "@stopwatchFastest": {}, "alarmDescriptionDays": "{days}", "@alarmDescriptionDays": {}, - "alarmDescriptionRange": "{interval, select, daily{Diariamente} weekly{Semanalmente}} entre {startDate} e {endDate}", + "alarmDescriptionRange": "{interval, select, daily{Diariamente} weekly{Semanalmente} other{Other}} entre {startDate} e {endDate}", "@alarmDescriptionRange": {}, "stopwatchSlowest": "Mais lenta", "@stopwatchSlowest": {}, From 380d19a96a63a78ccfb8036beb6f1806041161d4 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Mon, 29 Apr 2024 08:05:33 +0000 Subject: [PATCH 056/112] Translated using Weblate (Turkish) Currently translated at 37.3% (97 of 260 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/tr/ --- lib/l10n/app_tr.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 03a5fa93..60be61ac 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -191,7 +191,7 @@ "@alarmDescriptionSnooze": {}, "alarmDescriptionFinished": "Sonraki tarih yok", "@alarmDescriptionFinished": {}, - "alarmDescriptionRange": "{interval, select, daily{Günlük} weekly{Haftalık}} - {startDate} - {endDate} arası", + "alarmDescriptionRange": "{interval, select, daily{Günlük} weekly{Haftalık} other{Other}} - {startDate} - {endDate} arası", "@alarmDescriptionRange": {}, "alarmDescriptionWeekend": "Her hafta sonu", "@alarmDescriptionWeekend": {}, From 0b46a43296a2c5681e334998a05c697fbe24dad1 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Mon, 29 Apr 2024 08:05:44 +0000 Subject: [PATCH 057/112] Translated using Weblate (Vietnamese) Currently translated at 37.3% (97 of 260 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/vi/ --- lib/l10n/app_vi.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index a71d1c16..35f6d96d 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -187,7 +187,7 @@ "@alarmDescriptionWeekday": {}, "alarmDescriptionDays": "Vào {days}", "@alarmDescriptionDays": {}, - "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly}} từ {startDate} tới {endDate}", + "alarmDescriptionRange": "{interval, select, daily{Daily} weekly{Weekly} other{Other}} từ {startDate} tới {endDate}", "@alarmDescriptionRange": {}, "alarmDescriptionDates": "Vào {date}{count, plural, =0{} =1{ and 1 other date} other{ and {count} other dates}}", "@alarmDescriptionDates": {}, From b08eccfec1539534bd4925ea286abf097a75edc5 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Mon, 29 Apr 2024 08:31:06 +0000 Subject: [PATCH 058/112] Translated using Weblate (Turkish) Currently translated at 37.3% (97 of 260 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/tr/ --- lib/l10n/app_tr.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 60be61ac..6255255e 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -145,7 +145,7 @@ "@alarmDescriptionEveryDay": {}, "alarmDescriptionDays": "{days} tarihinde", "@alarmDescriptionDays": {}, - "alarmDescriptionDates": "{date}{count, plural, =0{} =1{ ve 1 başka tarih} diğer{ ve {count} diğer tarih}}", + "alarmDescriptionDates": "{date}{count, plural, =0{} =1{ ve 1 başka tarih} other{ ve {count} diğer tarih}}", "@alarmDescriptionDates": {}, "stopwatchAverage": "Ortalama", "@stopwatchAverage": {}, From 99b5ae5d85ca461237b9635b557baefe36cb6a6e Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Mon, 29 Apr 2024 17:51:49 +0500 Subject: [PATCH 059/112] Localize filters and sort --- lib/alarm/data/alarm_events_list_filters.dart | 36 ++ lib/alarm/data/alarm_list_filters.dart | 60 +-- lib/alarm/data/alarm_sort_options.dart | 22 +- lib/alarm/screens/alarm_events_screen.dart | 23 +- lib/app.dart | 7 + lib/common/types/list_filter.dart | 53 ++- lib/common/widgets/list/custom_list_view.dart | 16 +- lib/common/widgets/list/list_filter_chip.dart | 29 +- lib/common/widgets/time_picker.dart | 8 +- lib/l10n/app_en.arb | 36 +- lib/l10n/language_local.dart | 440 +++++++++--------- .../data/general_settings_schema.dart | 13 +- lib/settings/data/settings_schema.dart | 4 +- lib/timer/data/timer_list_filters.dart | 15 +- lib/timer/data/timer_sort_options.dart | 17 +- 15 files changed, 422 insertions(+), 357 deletions(-) create mode 100644 lib/alarm/data/alarm_events_list_filters.dart diff --git a/lib/alarm/data/alarm_events_list_filters.dart b/lib/alarm/data/alarm_events_list_filters.dart new file mode 100644 index 00000000..79687dfe --- /dev/null +++ b/lib/alarm/data/alarm_events_list_filters.dart @@ -0,0 +1,36 @@ +import 'package:clock_app/alarm/types/alarm_event.dart'; +import 'package:clock_app/common/types/list_filter.dart'; +import 'package:clock_app/common/types/notification_type.dart'; +import 'package:clock_app/common/utils/date_time.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +final List> alarmEventsListFilters = [ + ListFilterSelect( + (context) => AppLocalizations.of(context)!.stateFilterGroup, [ + ListFilter((context) => AppLocalizations.of(context)!.activeFilter, + (event) => event.isActive), + ListFilter((context) => AppLocalizations.of(context)!.inactiveFilter, + (event) => !event.isActive), + ]), + ListFilterSelect( + (context) => AppLocalizations.of(context)!.scheduleDateFilterGroup, [ + ListFilter((context) => AppLocalizations.of(context)!.todayFilter, + (event) => event.startDate.isToday()), + ListFilter((context) => AppLocalizations.of(context)!.tomorrowFilter, + (event) => event.startDate.isTomorrow()), + ]), + ListFilterSelect( + (context) => AppLocalizations.of(context)!.logTypeFilterGroup, [ + ListFilter((context) => AppLocalizations.of(context)!.alarmTitle, + (event) => event.notificationType == ScheduledNotificationType.alarm), + ListFilter((context) => AppLocalizations.of(context)!.timerTitle, + (event) => event.notificationType == ScheduledNotificationType.timer), + ]), + ListFilterSelect( + (context) => AppLocalizations.of(context)!.createdDateFilterGroup, [ + ListFilter((context) => AppLocalizations.of(context)!.todayFilter, + (event) => event.eventTime.isToday()), + ListFilter((context) => AppLocalizations.of(context)!.tomorrowFilter, + (event) => event.eventTime.isTomorrow()), + ]), +]; diff --git a/lib/alarm/data/alarm_list_filters.dart b/lib/alarm/data/alarm_list_filters.dart index 405a02f3..8392cb44 100644 --- a/lib/alarm/data/alarm_list_filters.dart +++ b/lib/alarm/data/alarm_list_filters.dart @@ -3,49 +3,55 @@ import 'package:clock_app/common/types/list_filter.dart'; import 'package:clock_app/common/types/tag.dart'; import 'package:clock_app/common/utils/date_time.dart'; import 'package:clock_app/common/utils/list_storage.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; final List> alarmListFilters = [ - ListFilterSelect("Date", [ - ListFilter( - 'Today', - (alarm) { + ListFilterSelect( + (context) => AppLocalizations.of(context)!.dateFilterGroup, + [ + ListFilter( + (context) => AppLocalizations.of(context)!.todayFilter, + (alarm) { + if (alarm.currentScheduleDateTime == null) return false; + return alarm.currentScheduleDateTime!.isToday(); + }, + ), + ListFilter((context) => AppLocalizations.of(context)!.tomorrowFilter, + (alarm) { if (alarm.currentScheduleDateTime == null) return false; - return alarm.currentScheduleDateTime!.isToday(); - }, - ), - ListFilter('Tomorrow', (alarm) { - if (alarm.currentScheduleDateTime == null) return false; - return alarm.currentScheduleDateTime!.isTomorrow(); - }), - ]), - ListFilterSelect("State", [ - + return alarm.currentScheduleDateTime!.isTomorrow(); + }), + ], + ), + ListFilterSelect( + (context) => AppLocalizations.of(context)!.stateFilterGroup, [ ListFilter( - 'Active', + (context) => AppLocalizations.of(context)!.activeFilter, (alarm) => alarm.isEnabled && !alarm.isFinished, ), ListFilter( - 'Snoozed', + (context) => AppLocalizations.of(context)!.snoozedFilter, (alarm) => alarm.isSnoozed, ), ListFilter( - 'Disabled', + (context) => AppLocalizations.of(context)!.disabledFilter, (alarm) => !alarm.isEnabled, ), ListFilter( - 'Completed', + (context) => AppLocalizations.of(context)!.completedFilter, (alarm) => alarm.isFinished, ), ]), - // - DynamicListFilterMultiSelect("Tags", () { + // + DynamicListFilterMultiSelect( + (context) => AppLocalizations.of(context)!.tagsSetting, () { final tags = loadListSync("tags"); return tags.map((tag) { - return ListFilter( - tag.name, - (alarm) => alarm.tags.any((element) => element.id == tag.id), - id: tag.id, - ); - }).toList(); + return ListFilter( + (context) => tag.name, + (alarm) => alarm.tags.any((element) => element.id == tag.id), + id: tag.id, + ); + }).toList(); }), - ]; +]; diff --git a/lib/alarm/data/alarm_sort_options.dart b/lib/alarm/data/alarm_sort_options.dart index 3c9387e0..90d972cc 100644 --- a/lib/alarm/data/alarm_sort_options.dart +++ b/lib/alarm/data/alarm_sort_options.dart @@ -1,17 +1,17 @@ import 'package:clock_app/alarm/types/alarm.dart'; import 'package:clock_app/common/types/list_filter.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -const List> alarmSortOptions = [ - ListSortOption( - "Remaining Time Descending", "9-1", sortRemainingTimeDescending), - ListSortOption("Remaining Time Ascending", "1-9", sortRemainingTimeAscending), - ListSortOption("Date Descending", "30-1", sortDateDescending), - ListSortOption("Date Ascending", "1-30", sortDateAscending), - ListSortOption("Name Ascending", "A-Z", sortNameAscending), - ListSortOption("Name Descending", "Z-A", sortNameDescending), - ListSortOption("Time of Day Ascending", "0:00-12:00", sortTimeOfDayAscending), - ListSortOption( - "Time of Day Descending", "12:00-0:00", sortTimeOfDayDescending), + +final List> alarmSortOptions = [ + ListSortOption((context) => AppLocalizations.of(context)!.remainingTimeDesc, sortRemainingTimeDescending), + ListSortOption((context) => AppLocalizations.of(context)!.remainingTimeAsc, sortRemainingTimeAscending), + // ListSortOption("Date Descending", "30-1", sortDateDescending), + // ListSortOption("Date Ascending", "1-30", sortDateAscending), + ListSortOption((context) => AppLocalizations.of(context)!.nameAsc, sortNameAscending), + ListSortOption((context) => AppLocalizations.of(context)!.nameDesc, sortNameDescending), + ListSortOption((context) => AppLocalizations.of(context)!.timeOfDayAsc, sortTimeOfDayAscending), + ListSortOption((context) => AppLocalizations.of(context)!.timeOfDayDesc, sortTimeOfDayDescending), ]; int sortRemainingTimeDescending(Alarm a, Alarm b) { diff --git a/lib/alarm/screens/alarm_events_screen.dart b/lib/alarm/screens/alarm_events_screen.dart index c0f39141..3222f224 100644 --- a/lib/alarm/screens/alarm_events_screen.dart +++ b/lib/alarm/screens/alarm_events_screen.dart @@ -2,11 +2,9 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; +import 'package:clock_app/alarm/data/alarm_events_list_filters.dart'; import 'package:clock_app/alarm/types/alarm_event.dart'; import 'package:clock_app/alarm/widgets/alarm_event_card.dart'; -import 'package:clock_app/common/types/list_filter.dart'; -import 'package:clock_app/common/types/notification_type.dart'; -import 'package:clock_app/common/utils/date_time.dart'; import 'package:clock_app/common/utils/json_serialize.dart'; import 'package:clock_app/common/utils/list_storage.dart'; import 'package:clock_app/common/widgets/fab.dart'; @@ -25,27 +23,8 @@ class AlarmEventsScreen extends StatefulWidget { State createState() => _AlarmEventsScreenState(); } -final List> alarmEventsListFilters = [ - ListFilterSelect("State", [ - ListFilter('Active', (event) => event.isActive), - ListFilter('Inactive', (event) => !event.isActive), - ]), - ListFilterSelect("Schedule Date", [ - ListFilter('Today', (event) => event.startDate.isToday()), - ListFilter('Tomorrow', (event) => event.startDate.isTomorrow()), - ]), - ListFilterSelect("Type", [ - ListFilter('Alarm', (event) => event.notificationType == ScheduledNotificationType.alarm), - ListFilter('Timer', (event) => event.notificationType == ScheduledNotificationType.timer), - ]), - ListFilterSelect("Created Date", [ - ListFilter('Today', (event) => event.eventTime.isToday()), - ListFilter('Tomorrow', (event) => event.eventTime.isTomorrow()), - ]), -]; - class _AlarmEventsScreenState extends State { final _listController = PersistentListController(); List searchedItems = []; diff --git a/lib/app.dart b/lib/app.dart index 38356c4e..b1caa69f 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,6 +1,7 @@ import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:clock_app/alarm/screens/alarm_notification_screen.dart'; import 'package:clock_app/common/data/app_info.dart'; +import 'package:clock_app/l10n/language_local.dart'; import 'package:clock_app/navigation/data/route_observer.dart'; import 'package:clock_app/navigation/screens/nav_scaffold.dart'; import 'package:clock_app/navigation/types/routes.dart'; @@ -160,6 +161,12 @@ class _AppState extends State { ThemeBrightness themeBrightness = _colorSettings.getSetting("Brightness").value; Locale locale = _generalSettings.getSetting("Language").value; + // if(!AppLocalizations.supportedLocales.contains(locale)){ + // + // } + // + // print("locaaaaaaaale $locale"); + // print(getLocaleOptions().map((e) => e.value).toList()); return MaterialApp( scaffoldMessengerKey: _messangerKey, diff --git a/lib/common/types/list_filter.dart b/lib/common/types/list_filter.dart index f0d04e66..7b7abe59 100644 --- a/lib/common/types/list_filter.dart +++ b/lib/common/types/list_filter.dart @@ -1,25 +1,29 @@ import 'package:clock_app/common/types/list_item.dart'; import 'package:clock_app/common/utils/debug.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class ListSortOption { - final String name; - final String abbreviation; + final String Function(BuildContext) getLocalizedName; + // final String abbreviation; final int Function(Item, Item) sortFunction; - const ListSortOption(this.name, this.abbreviation, this.sortFunction); + String Function(BuildContext) get displayName => getLocalizedName; + + const ListSortOption( + this.getLocalizedName, this.sortFunction); } abstract class ListFilterItem { bool Function(Item) get filterFunction; - String get displayName; + String Function(BuildContext) get displayName; bool get isActive; void reset(); } ListFilter defaultFilter() { return ListFilter( - 'All', + (context) => AppLocalizations.of(context)!.allFilter, (item) => true, id: -1, ); @@ -27,11 +31,12 @@ ListFilter defaultFilter() { class ListFilter extends ListFilterItem { final int _id; - final String name; + final String Function(BuildContext) getLocalizedName; bool isSelected = false; final bool Function(Item) _filterFunction; - ListFilter(this.name, bool Function(Item) filterFunction, {int? id}) + ListFilter(this.getLocalizedName, bool Function(Item) filterFunction, + {int? id}) : _id = id ?? UniqueKey().hashCode, _filterFunction = filterFunction; @@ -44,7 +49,7 @@ class ListFilter extends ListFilterItem { } @override - String get displayName => name; + String Function(BuildContext) get displayName => getLocalizedName; @override bool get isActive => isSelected; @@ -56,7 +61,7 @@ class ListFilter extends ListFilterItem { } class ListFilterSearch extends ListFilterItem { - final String name; + final String Function(BuildContext) getLocalizedName; String searchText = ''; @override bool Function(Item) get filterFunction { @@ -66,9 +71,9 @@ class ListFilterSearch extends ListFilterItem { // return (Item item) => item.searchText.contains(searchText); } - ListFilterSearch(this.name); + ListFilterSearch(this.getLocalizedName); @override - String get displayName => name; + String Function(BuildContext) get displayName => getLocalizedName; @override bool get isActive => false; @@ -98,10 +103,10 @@ abstract class FilterMultiSelect class ListFilterMultiSelect extends FilterMultiSelect { - final String name; + final String Function(BuildContext) getLocalizedName; @override final List> filters; - ListFilterMultiSelect(this.name, this.filters); + ListFilterMultiSelect(this.getLocalizedName, this.filters); @override List get selectedIndices => filters @@ -121,7 +126,7 @@ class ListFilterMultiSelect } @override - String get displayName => name; + String Function(BuildContext) get displayName => getLocalizedName; @override bool get isActive => filters.any((filter) => filter.isSelected); @@ -136,13 +141,14 @@ class ListFilterMultiSelect class DynamicListFilterMultiSelect extends FilterMultiSelect { - final String name; + final String Function(BuildContext) getLocalizedName; final List> Function() getFilters; List selectedIds; - DynamicListFilterMultiSelect(this.name, this.getFilters) : selectedIds = []; + DynamicListFilterMultiSelect(this.getLocalizedName, this.getFilters) + : selectedIds = []; @override @override - String get displayName => name; + String Function(BuildContext) get displayName => getLocalizedName; @override List> get selectedFilters => @@ -199,10 +205,10 @@ abstract class FilterSelect } class ListFilterSelect extends FilterSelect { - final String name; + final String Function(BuildContext) getLocalizedName; @override final List> filters; - ListFilterSelect(this.name, this.filters) { + ListFilterSelect(this.getLocalizedName, this.filters) { filters.insert(0, defaultFilter()); if (filters.isNotEmpty) { filters[0].isSelected = true; @@ -227,7 +233,7 @@ class ListFilterSelect extends FilterSelect { } @override - String get displayName => name; + String Function(BuildContext) get displayName => getLocalizedName; @override bool get isActive => !filters[0].isSelected; @@ -240,10 +246,11 @@ class ListFilterSelect extends FilterSelect { class DynamicListFilterSelect extends FilterSelect { - final String name; + final String Function(BuildContext) getLocalizedName; final List> Function() getFilters; int selectedId; - DynamicListFilterSelect(this.name, this.getFilters) : selectedId = -1; + DynamicListFilterSelect(this.getLocalizedName, this.getFilters) + : selectedId = -1; @override List> get filters { @@ -281,7 +288,7 @@ class DynamicListFilterSelect } @override - String get displayName => name; + String Function(BuildContext) get displayName => getLocalizedName; @override bool get isActive => selectedIndex != 0; diff --git a/lib/common/widgets/list/custom_list_view.dart b/lib/common/widgets/list/custom_list_view.dart index c84e61df..9e4f3fe2 100644 --- a/lib/common/widgets/list/custom_list_view.dart +++ b/lib/common/widgets/list/custom_list_view.dart @@ -2,7 +2,6 @@ import 'package:clock_app/common/logic/get_list_filter_chips.dart'; import 'package:clock_app/common/types/list_controller.dart'; import 'package:clock_app/common/types/list_filter.dart'; import 'package:clock_app/common/types/list_item.dart'; -import 'package:clock_app/common/utils/json_serialize.dart'; import 'package:clock_app/common/utils/reorderable_list_decorator.dart'; import 'package:clock_app/common/widgets/list/delete_alert_dialogue.dart'; import 'package:clock_app/common/widgets/list/list_filter_chip.dart'; @@ -10,6 +9,7 @@ import 'package:clock_app/common/widgets/list/list_item_card.dart'; import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:great_list_view/great_list_view.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; typedef ItemCardBuilder = Widget Function( BuildContext context, @@ -169,10 +169,12 @@ class _CustomListViewState }); final deletedItems = List.from(initialList - .where((element) => currentList.where((e) => e.id == element.id).isEmpty) + .where( + (element) => currentList.where((e) => e.id == element.id).isEmpty) .toList()); final addedItems = List.from(currentList - .where((element) => initialList.where((e) => e.id == element.id).isEmpty) + .where( + (element) => initialList.where((e) => e.id == element.id).isEmpty) .toList()); for (var deletedItem in deletedItems) { @@ -333,7 +335,7 @@ class _CustomListViewState widgets.add(ListFilterActionChip( actions: [ ListFilterAction( - name: "Clear all filters", + name: AppLocalizations.of(context)!.clearFiltersAction, icon: Icons.clear_rounded, action: () { for (var filter in widget.listFilters) { @@ -351,7 +353,7 @@ class _CustomListViewState .toList()), )), ListFilterAction( - name: "Delete all filtered items", + name: AppLocalizations.of(context)!.deleteAllFilteredAction, icon: Icons.delete_rounded, color: colorScheme.error, action: () async { @@ -378,7 +380,9 @@ class _CustomListViewState ListSortChip( selectedIndex: selectedSortIndex, sortOptions: [ - ListSortOption("Default", "", (a, b) => 0), + ListSortOption( + (context) => AppLocalizations.of(context)!.defaultLabel, + (a, b) => 0), ...widget.sortOptions, ], onChange: (index) => setState(() { diff --git a/lib/common/widgets/list/list_filter_chip.dart b/lib/common/widgets/list/list_filter_chip.dart index 8a3307df..d0fb92ec 100644 --- a/lib/common/widgets/list/list_filter_chip.dart +++ b/lib/common/widgets/list/list_filter_chip.dart @@ -3,9 +3,10 @@ import 'package:clock_app/common/types/list_filter.dart'; import 'package:clock_app/common/types/list_item.dart'; import 'package:clock_app/common/types/select_choice.dart'; import 'package:clock_app/common/widgets/card_container.dart'; -import 'package:clock_app/common/widgets/card_edit_menu.dart'; import 'package:clock_app/common/widgets/list/action_bottom_sheet.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class ListFilterChip extends StatelessWidget { const ListFilterChip({ @@ -32,7 +33,7 @@ class ListFilterChip extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: Text( - listFilter.name, + listFilter.displayName(context), style: textTheme.headlineSmall?.copyWith( color: listFilter.isSelected ? colorScheme.onPrimary @@ -61,7 +62,7 @@ class ListFilterActionChip extends StatelessWidget { enableDrag: true, builder: (BuildContext context) { return ActionBottomSheet( - title: "Filter Actions", + title: AppLocalizations.of(context)!.filterActions, actions: actions, // description: description, ); @@ -130,10 +131,10 @@ class ListFilterSelectChip extends StatelessWidget { selectedIndices?[0] ?? listFilter.selectedIndex; onChange(); }, - title: listFilter.displayName, + title: listFilter.displayName(context), description: "", choices: listFilter.filters - .map((e) => SelectChoice(name: e.name, value: e.id)) + .map((e) => SelectChoice(name: e.displayName(context), value: e.id)) .toList(), initialSelectedIndices: [listFilter.selectedIndex], multiSelect: false); @@ -149,8 +150,8 @@ class ListFilterSelectChip extends StatelessWidget { top: 8.0, bottom: 8.0, left: 16.0, right: 2.0), child: Text( isFirstSelected - ? listFilter.displayName - : listFilter.selectedFilter.name, + ? listFilter.displayName(context) + : listFilter.selectedFilter.displayName(context), style: textTheme.headlineSmall?.copyWith( color: isFirstSelected ? colorScheme.onSurface @@ -196,10 +197,10 @@ class ListFilterMultiSelectChip extends StatelessWidget { newSelectedIndices ?? listFilter.selectedIndices; onChange(); }, - title: listFilter.displayName, + title: listFilter.displayName(context), description: "", choices: listFilter.filters - .map((e) => SelectChoice(name: e.name, value: e.id)) + .map((e) => SelectChoice(name: e.displayName(context), value: e.id)) .toList(), initialSelectedIndices: selectedIndices, multiSelect: true); @@ -215,9 +216,9 @@ class ListFilterMultiSelectChip extends StatelessWidget { top: 8.0, bottom: 8.0, left: 16.0, right: 2.0), child: Text( !isSelected - ? listFilter.displayName + ? listFilter.displayName(context) : listFilter.selectedIndices.length == 1 - ? listFilter.selectedFilters[0].name + ? listFilter.selectedFilters[0].displayName(context) : "${listFilter.selectedIndices.length} selected", style: textTheme.headlineSmall?.copyWith( color: isSelected @@ -262,10 +263,10 @@ class ListSortChip extends StatelessWidget { showSelectBottomSheet(context, (List? selectedIndices) { onChange(selectedIndices?[0] ?? selectedIndex); }, - title: "Sort by", + title: AppLocalizations.of(context)!.sortGroup, description: "", choices: sortOptions - .map((e) => SelectChoice(name: e.name, value: e.name)) + .map((e) => SelectChoice(name: e.displayName(context), value: e.getLocalizedName)) .toList(), initialSelectedIndices: [selectedIndex], multiSelect: false); @@ -280,7 +281,7 @@ class ListSortChip extends StatelessWidget { padding: const EdgeInsets.only( top: 8.0, bottom: 8.0, left: 16.0, right: 2.0), child: Text( - "Sort${isFirstSelected ? "" : ": ${sortOptions[selectedIndex].abbreviation}"}", + "${AppLocalizations.of(context)!.sortGroup}${isFirstSelected ? "" : ": ${sortOptions[selectedIndex].displayName(context)}"}", style: textTheme.headlineSmall?.copyWith( color: colorScheme.onSurface ), diff --git a/lib/common/widgets/time_picker.dart b/lib/common/widgets/time_picker.dart index 07874ce1..2af00c74 100644 --- a/lib/common/widgets/time_picker.dart +++ b/lib/common/widgets/time_picker.dart @@ -18,6 +18,8 @@ import 'package:clock_app/theme/border.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + // Examples can assume: // late BuildContext context; @@ -318,7 +320,7 @@ class _TitleBar extends StatelessWidget { appSettings.save(); }, child: Text( - "Mode", + AppLocalizations.of(context)!.timePickerModeButton, style: Theme.of(context).textTheme.titleSmall?.copyWith( color: Theme.of(context).colorScheme.primary, ), @@ -2401,7 +2403,7 @@ class _TimePickerDialogState extends State ), onPressed: _handleCancel, child: Text( - "Cancel", + AppLocalizations.of(context)!.cancelButton, style: Theme.of(context).textTheme.labelMedium?.copyWith( color: Theme.of(context) .colorScheme @@ -2422,7 +2424,7 @@ class _TimePickerDialogState extends State TextButton( onPressed: () => _handleOk(type, isCustomize: true), child: Text( - "Customize", + AppLocalizations.of(context)!.customizeButton, style: Theme.of(context).textTheme.labelMedium?.copyWith( color: Theme.of(context).colorScheme.primary), ), diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 833520ce..2819755b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -238,6 +238,8 @@ "@cannotDisableAlarmWhileSnoozedSnackbar": {}, "selectTime": "Select Time", "@selectTime": {}, + "timePickerModeButton": "Mode", + "@timePickerModeButton": {}, "cancelButton": "Cancel", "@cancelButton": {}, "customizeButton": "Customize", @@ -378,6 +380,12 @@ "@allFilter": {}, "dateFilterGroup": "Date", "@dateFilterGroup": {}, + "scheduleDateFilterGroup": "Schedule Date", + "@scheduleDateFilterGroup" : {}, + "logTypeFilterGroup" : "Type", + "@logTypeFilterGroup" : {}, + "createdDateFilterGroup": "Created Date", + "@createdDateFilterGroup" : {}, "todayFilter": "Today", "@todayFilter": {}, "tomorrowFilter": "Tomorrow", @@ -386,31 +394,39 @@ "@stateFilterGroup": {}, "activeFilter": "Active", "@activeFilter": {}, + "inactiveFilter": "Inactive", + "@inactiveFilter": {}, "snoozedFilter": "Snoozed", "@snoozedFilter": {}, "disabledFilter": "Disabled", "@disabledFilter": {}, "completedFilter": "Completed", "@completedFilter": {}, + "runningTimerFilter": "Running", + "@runningTimerFilter": {}, + "pausedTimerFilter": "Paused", + "@pausedTimerFilter": {}, + "stoppedTimerFilter": "Stopped", + "@stoppedTimerFilter": {}, "sortGroup": "Sort", "@sortGroup": {}, "defaultLabel": "Default", "@defaultLabel": {}, - "remainingTimeDesc": "Remaining Time Descending", + "remainingTimeDesc": "Least time left", "@remainingTimeDesc": {}, - "remainingTimeAsc": "Remaining Time Ascending", + "remainingTimeAsc": "Most time left", "@remainingTimeAsc": {}, - "nameAsc": "Name Ascending", + "durationAsc": "Shortest", + "@durationAsc": {}, + "durationDesc": "Longest", + "@durationDesc": {}, + "nameAsc": "Label A-Z", "@nameAsc": {}, - "nameDesc": "Name Descending", + "nameDesc": "Label Z-A", "@nameDesc": {}, - "dateAsc": "Date Ascending", - "@dateAsc": {}, - "dateDesc": "Date Descending", - "@dateDesc": {}, - "timeOfDayAsc": "Time of Day Ascending", + "timeOfDayAsc": "Early hours first", "@timeOfDayAsc": {}, - "timeOfDayDesc": "Time of Day Descending", + "timeOfDayDesc": "Late hours first", "@timeOfDayDesc": {}, "filterActions": "Filter Actions", "@filterActions": {}, diff --git a/lib/l10n/language_local.dart b/lib/l10n/language_local.dart index e1b5349f..488c8cd4 100644 --- a/lib/l10n/language_local.dart +++ b/lib/l10n/language_local.dart @@ -1,218 +1,228 @@ - final isoLangs = { - "ab": {"name": "Abkhaz", "nativeName": "аҧсуа"}, - "aa": {"name": "Afar", "nativeName": "Afaraf"}, - "af": {"name": "Afrikaans", "nativeName": "Afrikaans"}, - "ak": {"name": "Akan", "nativeName": "Akan"}, - "sq": {"name": "Albanian", "nativeName": "Shqip"}, - "am": {"name": "Amharic", "nativeName": "አማርኛ"}, - "ar": {"name": "Arabic", "nativeName": "العربية"}, - "an": {"name": "Aragonese", "nativeName": "Aragonés"}, - "hy": {"name": "Armenian", "nativeName": "Հայերեն"}, - "as": {"name": "Assamese", "nativeName": "অসমীয়া"}, - "av": {"name": "Avaric", "nativeName": "авар мацӀ, магӀарул мацӀ"}, - "ae": {"name": "Avestan", "nativeName": "avesta"}, - "ay": {"name": "Aymara", "nativeName": "aymar aru"}, - "az": {"name": "Azerbaijani", "nativeName": "azərbaycan dili"}, - "bm": {"name": "Bambara", "nativeName": "bamanankan"}, - "ba": {"name": "Bashkir", "nativeName": "башҡорт теле"}, - "eu": {"name": "Basque", "nativeName": "euskara, euskera"}, - "be": {"name": "Belarusian", "nativeName": "Беларуская"}, - "bn": {"name": "Bengali", "nativeName": "বাংলা"}, - "bh": {"name": "Bihari", "nativeName": "भोजपुरी"}, - "bi": {"name": "Bislama", "nativeName": "Bislama"}, - "bs": {"name": "Bosnian", "nativeName": "bosanski jezik"}, - "br": {"name": "Breton", "nativeName": "brezhoneg"}, - "bg": {"name": "Bulgarian", "nativeName": "български език"}, - "my": {"name": "Burmese", "nativeName": "ဗမာစာ"}, - "ca": {"name": "Catalan; Valencian", "nativeName": "Català"}, - "ch": {"name": "Chamorro", "nativeName": "Chamoru"}, - "ce": {"name": "Chechen", "nativeName": "нохчийн мотт"}, - "ny": { - "name": "Chichewa; Chewa; Nyanja", - "nativeName": "chiCheŵa, chinyanja" - }, - "zh": {"name": "Chinese", "nativeName": "中文 (Zhōngwén), 汉语, 漢語"}, - "cv": {"name": "Chuvash", "nativeName": "чӑваш чӗлхи"}, - "kw": {"name": "Cornish", "nativeName": "Kernewek"}, - "co": {"name": "Corsican", "nativeName": "corsu, lingua corsa"}, - "cr": {"name": "Cree", "nativeName": "ᓀᐦᐃᔭᐍᐏᐣ"}, - "hr": {"name": "Croatian", "nativeName": "hrvatski"}, - "cs": {"name": "Czech", "nativeName": "česky, čeština"}, - "da": {"name": "Danish", "nativeName": "dansk"}, - "dv": {"name": "Divehi; Dhivehi; Maldivian;", "nativeName": "ދިވެހި"}, - "nl": {"name": "Dutch", "nativeName": "Nederlands, Vlaams"}, - "en": {"name": "English", "nativeName": "English"}, - "eo": {"name": "Esperanto", "nativeName": "Esperanto"}, - "et": {"name": "Estonian", "nativeName": "eesti, eesti keel"}, - "ee": {"name": "Ewe", "nativeName": "Eʋegbe"}, - "fo": {"name": "Faroese", "nativeName": "føroyskt"}, - "fj": {"name": "Fijian", "nativeName": "vosa Vakaviti"}, - "fi": {"name": "Finnish", "nativeName": "suomi, suomen kieli"}, - "fr": {"name": "French", "nativeName": "français, langue française"}, - "ff": { - "name": "Fula; Fulah; Pulaar; Pular", - "nativeName": "Fulfulde, Pulaar, Pular" - }, - "gl": {"name": "Galician", "nativeName": "Galego"}, - "ka": {"name": "Georgian", "nativeName": "ქართული"}, - "de": {"name": "German", "nativeName": "Deutsch"}, - "el": {"name": "Greek, Modern", "nativeName": "Ελληνικά"}, - "gn": {"name": "Guaraní", "nativeName": "Avañeẽ"}, - "gu": {"name": "Gujarati", "nativeName": "ગુજરાતી"}, - "ht": {"name": "Haitian; Haitian Creole", "nativeName": "Kreyòl ayisyen"}, - "ha": {"name": "Hausa", "nativeName": "Hausa, هَوُسَ"}, - "he": {"name": "Hebrew (modern)", "nativeName": "עברית"}, - "hz": {"name": "Herero", "nativeName": "Otjiherero"}, - "hi": {"name": "Hindi", "nativeName": "हिन्दी, हिंदी"}, - "ho": {"name": "Hiri Motu", "nativeName": "Hiri Motu"}, - "hu": {"name": "Hungarian", "nativeName": "Magyar"}, - "ia": {"name": "Interlingua", "nativeName": "Interlingua"}, - "id": {"name": "Indonesian", "nativeName": "Bahasa Indonesia"}, - "ie": { - "name": "Interlingue", - "nativeName": "Originally called Occidental; then Interlingue after WWII" - }, - "ga": {"name": "Irish", "nativeName": "Gaeilge"}, - "ig": {"name": "Igbo", "nativeName": "Asụsụ Igbo"}, - "ik": {"name": "Inupiaq", "nativeName": "Iñupiaq, Iñupiatun"}, - "io": {"name": "Ido", "nativeName": "Ido"}, - "is": {"name": "Icelandic", "nativeName": "Íslenska"}, - "it": {"name": "Italian", "nativeName": "Italiano"}, - "iu": {"name": "Inuktitut", "nativeName": "ᐃᓄᒃᑎᑐᑦ"}, - "ja": {"name": "Japanese", "nativeName": "日本語 (にほんご/にっぽんご)"}, - "jv": {"name": "Javanese", "nativeName": "basa Jawa"}, - "kl": { - "name": "Kalaallisut, Greenlandic", - "nativeName": "kalaallisut, kalaallit oqaasii" - }, - "kn": {"name": "Kannada", "nativeName": "ಕನ್ನಡ"}, - "kr": {"name": "Kanuri", "nativeName": "Kanuri"}, - "ks": {"name": "Kashmiri", "nativeName": "कश्मीरी, كشميري‎"}, - "kk": {"name": "Kazakh", "nativeName": "Қазақ тілі"}, - "km": {"name": "Khmer", "nativeName": "ភាសាខ្មែរ"}, - "ki": {"name": "Kikuyu, Gikuyu", "nativeName": "Gĩkũyũ"}, - "rw": {"name": "Kinyarwanda", "nativeName": "Ikinyarwanda"}, - "ky": {"name": "Kirghiz, Kyrgyz", "nativeName": "кыргыз тили"}, - "kv": {"name": "Komi", "nativeName": "коми кыв"}, - "kg": {"name": "Kongo", "nativeName": "KiKongo"}, - "ko": {"name": "Korean", "nativeName": "한국어 (韓國語), 조선말 (朝鮮語)"}, - "ku": {"name": "Kurdish", "nativeName": "Kurdî, كوردی‎"}, - "kj": {"name": "Kwanyama, Kuanyama", "nativeName": "Kuanyama"}, - "la": {"name": "Latin", "nativeName": "latine, lingua latina"}, - "lb": { - "name": "Luxembourgish, Letzeburgesch", - "nativeName": "Lëtzebuergesch" - }, - "lg": {"name": "Luganda", "nativeName": "Luganda"}, - "li": { - "name": "Limburgish, Limburgan, Limburger", - "nativeName": "Limburgs" - }, - "ln": {"name": "Lingala", "nativeName": "Lingála"}, - "lo": {"name": "Lao", "nativeName": "ພາສາລາວ"}, - "lt": {"name": "Lithuanian", "nativeName": "lietuvių kalba"}, - "lu": {"name": "Luba-Katanga", "nativeName": ""}, - "lv": {"name": "Latvian", "nativeName": "latviešu valoda"}, - "gv": {"name": "Manx", "nativeName": "Gaelg, Gailck"}, - "mk": {"name": "Macedonian", "nativeName": "македонски јазик"}, - "mg": {"name": "Malagasy", "nativeName": "Malagasy fiteny"}, - "ms": {"name": "Malay", "nativeName": "bahasa Melayu, بهاس ملايو‎"}, - "ml": {"name": "Malayalam", "nativeName": "മലയാളം"}, - "mt": {"name": "Maltese", "nativeName": "Malti"}, - "mi": {"name": "Māori", "nativeName": "te reo Māori"}, - "mr": {"name": "Marathi (Marāṭhī)", "nativeName": "मराठी"}, - "mh": {"name": "Marshallese", "nativeName": "Kajin M̧ajeļ"}, - "mn": {"name": "Mongolian", "nativeName": "монгол"}, - "na": {"name": "Nauru", "nativeName": "Ekakairũ Naoero"}, - "nv": {"name": "Navajo, Navaho", "nativeName": "Diné bizaad, Dinékʼehǰí"}, - "nb_NO": {"name": "Norwegian Bokmål", "nativeName": "Norsk bokmål"}, - "nd": {"name": "North Ndebele", "nativeName": "isiNdebele"}, - "ne": {"name": "Nepali", "nativeName": "नेपाली"}, - "ng": {"name": "Ndonga", "nativeName": "Owambo"}, - "nn": {"name": "Norwegian Nynorsk", "nativeName": "Norsk nynorsk"}, - "no": {"name": "Norwegian", "nativeName": "Norsk"}, - "ii": {"name": "Nuosu", "nativeName": "ꆈꌠ꒿ Nuosuhxop"}, - "nr": {"name": "South Ndebele", "nativeName": "isiNdebele"}, - "oc": {"name": "Occitan", "nativeName": "Occitan"}, - "oj": {"name": "Ojibwe, Ojibwa", "nativeName": "ᐊᓂᔑᓈᐯᒧᐎᓐ"}, - "cu": { - "name": - "Old Church Slavonic, Church Slavic, Church Slavonic, Old Bulgarian, Old Slavonic", - "nativeName": "ѩзыкъ словѣньскъ" - }, - "om": {"name": "Oromo", "nativeName": "Afaan Oromoo"}, - "or": {"name": "Oriya", "nativeName": "ଓଡ଼ିଆ"}, - "os": {"name": "Ossetian, Ossetic", "nativeName": "ирон æвзаг"}, - "pa": {"name": "Panjabi, Punjabi", "nativeName": "ਪੰਜਾਬੀ, پنجابی‎"}, - "pi": {"name": "Pāli", "nativeName": "पाऴि"}, - "fa": {"name": "Persian", "nativeName": "فارسی"}, - "pl": {"name": "Polish", "nativeName": "polski"}, - "ps": {"name": "Pashto, Pushto", "nativeName": "پښتو"}, - "pt": {"name": "Portuguese", "nativeName": "Português"}, - "qu": {"name": "Quechua", "nativeName": "Runa Simi, Kichwa"}, - "rm": {"name": "Romansh", "nativeName": "rumantsch grischun"}, - "rn": {"name": "Kirundi", "nativeName": "kiRundi"}, - "ro": {"name": "Romanian, Moldavian, Moldovan", "nativeName": "română"}, - "ru": {"name": "Russian", "nativeName": "русский язык"}, - "sa": {"name": "Sanskrit (Saṁskṛta)", "nativeName": "संस्कृतम्"}, - "sc": {"name": "Sardinian", "nativeName": "sardu"}, - "sd": {"name": "Sindhi", "nativeName": "सिन्धी, سنڌي، سندھی‎"}, - "se": {"name": "Northern Sami", "nativeName": "Davvisámegiella"}, - "sm": {"name": "Samoan", "nativeName": "gagana faa Samoa"}, - "sg": {"name": "Sango", "nativeName": "yângâ tî sängö"}, - "sr": {"name": "Serbian", "nativeName": "српски језик"}, - "gd": {"name": "Scottish Gaelic; Gaelic", "nativeName": "Gàidhlig"}, - "sn": {"name": "Shona", "nativeName": "chiShona"}, - "si": {"name": "Sinhala, Sinhalese", "nativeName": "සිංහල"}, - "sk": {"name": "Slovak", "nativeName": "slovenčina"}, - "sl": {"name": "Slovene", "nativeName": "slovenščina"}, - "so": {"name": "Somali", "nativeName": "Soomaaliga, af Soomaali"}, - "st": {"name": "Southern Sotho", "nativeName": "Sesotho"}, - "es": {"name": "Spanish; Castilian", "nativeName": "español, castellano"}, - "su": {"name": "Sundanese", "nativeName": "Basa Sunda"}, - "sw": {"name": "Swahili", "nativeName": "Kiswahili"}, - "ss": {"name": "Swati", "nativeName": "SiSwati"}, - "sv": {"name": "Swedish", "nativeName": "svenska"}, - "ta": {"name": "Tamil", "nativeName": "தமிழ்"}, - "te": {"name": "Telugu", "nativeName": "తెలుగు"}, - "tg": {"name": "Tajik", "nativeName": "тоҷикӣ, toğikī, تاجیکی‎"}, - "th": {"name": "Thai", "nativeName": "ไทย"}, - "ti": {"name": "Tigrinya", "nativeName": "ትግርኛ"}, - "bo": { - "name": "Tibetan Standard, Tibetan, Central", - "nativeName": "བོད་ཡིག" - }, - "tk": {"name": "Turkmen", "nativeName": "Türkmen, Түркмен"}, - "tl": {"name": "Tagalog", "nativeName": "Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔"}, - "tn": {"name": "Tswana", "nativeName": "Setswana"}, - "to": {"name": "Tonga (Tonga Islands)", "nativeName": "faka Tonga"}, - "tr": {"name": "Turkish", "nativeName": "Türkçe"}, - "ts": {"name": "Tsonga", "nativeName": "Xitsonga"}, - "tt": {"name": "Tatar", "nativeName": "татарча, tatarça, تاتارچا‎"}, - "tw": {"name": "Twi", "nativeName": "Twi"}, - "ty": {"name": "Tahitian", "nativeName": "Reo Tahiti"}, - "ug": {"name": "Uighur, Uyghur", "nativeName": "Uyƣurqə, ئۇيغۇرچە‎"}, - "uk": {"name": "Ukrainian", "nativeName": "українська"}, - "ur": {"name": "Urdu", "nativeName": "اردو"}, - "uz": {"name": "Uzbek", "nativeName": "zbek, Ўзбек, أۇزبېك‎"}, - "ve": {"name": "Venda", "nativeName": "Tshivenḓa"}, - "vi": {"name": "Vietnamese", "nativeName": "Tiếng Việt"}, - "vo": {"name": "Volapük", "nativeName": "Volapük"}, - "wa": {"name": "Walloon", "nativeName": "Walon"}, - "cy": {"name": "Welsh", "nativeName": "Cymraeg"}, - "wo": {"name": "Wolof", "nativeName": "Wollof"}, - "fy": {"name": "Western Frisian", "nativeName": "Frysk"}, - "xh": {"name": "Xhosa", "nativeName": "isiXhosa"}, - "yi": {"name": "Yiddish", "nativeName": "ייִדיש"}, - "yo": {"name": "Yoruba", "nativeName": "Yorùbá"}, - "za": {"name": "Zhuang, Chuang", "nativeName": "Saɯ cueŋƅ, Saw cuengh"} - }; +import 'package:clock_app/settings/types/setting.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:locale_names/locale_names.dart'; +List getLocaleOptions() { + return AppLocalizations.supportedLocales.map((locale) { + return SelectSettingOption( + (context) => Locale.fromSubtags( + languageCode: locale.languageCode, + scriptCode: locale.scriptCode, + countryCode: locale.countryCode) + .nativeDisplayLanguage, + locale); + }).toList(); +} - Map? getlanguageDisplayName(String key) { - if (isoLangs.containsKey(key)) { - return isoLangs[key]; - } else { - throw Exception("Language key incorrect"); - } +final isoLangs = { + "ab": {"name": "Abkhaz", "nativeName": "аҧсуа"}, + "aa": {"name": "Afar", "nativeName": "Afaraf"}, + "af": {"name": "Afrikaans", "nativeName": "Afrikaans"}, + "ak": {"name": "Akan", "nativeName": "Akan"}, + "sq": {"name": "Albanian", "nativeName": "Shqip"}, + "am": {"name": "Amharic", "nativeName": "አማርኛ"}, + "ar": {"name": "Arabic", "nativeName": "العربية"}, + "an": {"name": "Aragonese", "nativeName": "Aragonés"}, + "hy": {"name": "Armenian", "nativeName": "Հայերեն"}, + "as": {"name": "Assamese", "nativeName": "অসমীয়া"}, + "av": {"name": "Avaric", "nativeName": "авар мацӀ, магӀарул мацӀ"}, + "ae": {"name": "Avestan", "nativeName": "avesta"}, + "ay": {"name": "Aymara", "nativeName": "aymar aru"}, + "az": {"name": "Azerbaijani", "nativeName": "azərbaycan dili"}, + "bm": {"name": "Bambara", "nativeName": "bamanankan"}, + "ba": {"name": "Bashkir", "nativeName": "башҡорт теле"}, + "eu": {"name": "Basque", "nativeName": "euskara, euskera"}, + "be": {"name": "Belarusian", "nativeName": "Беларуская"}, + "bn": {"name": "Bengali", "nativeName": "বাংলা"}, + "bh": {"name": "Bihari", "nativeName": "भोजपुरी"}, + "bi": {"name": "Bislama", "nativeName": "Bislama"}, + "bs": {"name": "Bosnian", "nativeName": "bosanski jezik"}, + "br": {"name": "Breton", "nativeName": "brezhoneg"}, + "bg": {"name": "Bulgarian", "nativeName": "български език"}, + "my": {"name": "Burmese", "nativeName": "ဗမာစာ"}, + "ca": {"name": "Catalan; Valencian", "nativeName": "Català"}, + "ch": {"name": "Chamorro", "nativeName": "Chamoru"}, + "ce": {"name": "Chechen", "nativeName": "нохчийн мотт"}, + "ny": { + "name": "Chichewa; Chewa; Nyanja", + "nativeName": "chiCheŵa, chinyanja" + }, + "zh": {"name": "Chinese", "nativeName": "中文 (Zhōngwén), 汉语, 漢語"}, + "cv": {"name": "Chuvash", "nativeName": "чӑваш чӗлхи"}, + "kw": {"name": "Cornish", "nativeName": "Kernewek"}, + "co": {"name": "Corsican", "nativeName": "corsu, lingua corsa"}, + "cr": {"name": "Cree", "nativeName": "ᓀᐦᐃᔭᐍᐏᐣ"}, + "hr": {"name": "Croatian", "nativeName": "hrvatski"}, + "cs": {"name": "Czech", "nativeName": "česky, čeština"}, + "da": {"name": "Danish", "nativeName": "dansk"}, + "dv": {"name": "Divehi; Dhivehi; Maldivian;", "nativeName": "ދިވެހި"}, + "nl": {"name": "Dutch", "nativeName": "Nederlands, Vlaams"}, + "en": {"name": "English", "nativeName": "English"}, + "eo": {"name": "Esperanto", "nativeName": "Esperanto"}, + "et": {"name": "Estonian", "nativeName": "eesti, eesti keel"}, + "ee": {"name": "Ewe", "nativeName": "Eʋegbe"}, + "fo": {"name": "Faroese", "nativeName": "føroyskt"}, + "fj": {"name": "Fijian", "nativeName": "vosa Vakaviti"}, + "fi": {"name": "Finnish", "nativeName": "suomi, suomen kieli"}, + "fr": {"name": "French", "nativeName": "français, langue française"}, + "ff": { + "name": "Fula; Fulah; Pulaar; Pular", + "nativeName": "Fulfulde, Pulaar, Pular" + }, + "gl": {"name": "Galician", "nativeName": "Galego"}, + "ka": {"name": "Georgian", "nativeName": "ქართული"}, + "de": {"name": "German", "nativeName": "Deutsch"}, + "el": {"name": "Greek, Modern", "nativeName": "Ελληνικά"}, + "gn": {"name": "Guaraní", "nativeName": "Avañeẽ"}, + "gu": {"name": "Gujarati", "nativeName": "ગુજરાતી"}, + "ht": {"name": "Haitian; Haitian Creole", "nativeName": "Kreyòl ayisyen"}, + "ha": {"name": "Hausa", "nativeName": "Hausa, هَوُسَ"}, + "he": {"name": "Hebrew (modern)", "nativeName": "עברית"}, + "hz": {"name": "Herero", "nativeName": "Otjiherero"}, + "hi": {"name": "Hindi", "nativeName": "हिन्दी, हिंदी"}, + "ho": {"name": "Hiri Motu", "nativeName": "Hiri Motu"}, + "hu": {"name": "Hungarian", "nativeName": "Magyar"}, + "ia": {"name": "Interlingua", "nativeName": "Interlingua"}, + "id": {"name": "Indonesian", "nativeName": "Bahasa Indonesia"}, + "ie": { + "name": "Interlingue", + "nativeName": "Originally called Occidental; then Interlingue after WWII" + }, + "ga": {"name": "Irish", "nativeName": "Gaeilge"}, + "ig": {"name": "Igbo", "nativeName": "Asụsụ Igbo"}, + "ik": {"name": "Inupiaq", "nativeName": "Iñupiaq, Iñupiatun"}, + "io": {"name": "Ido", "nativeName": "Ido"}, + "is": {"name": "Icelandic", "nativeName": "Íslenska"}, + "it": {"name": "Italian", "nativeName": "Italiano"}, + "iu": {"name": "Inuktitut", "nativeName": "ᐃᓄᒃᑎᑐᑦ"}, + "ja": {"name": "Japanese", "nativeName": "日本語 (にほんご/にっぽんご)"}, + "jv": {"name": "Javanese", "nativeName": "basa Jawa"}, + "kl": { + "name": "Kalaallisut, Greenlandic", + "nativeName": "kalaallisut, kalaallit oqaasii" + }, + "kn": {"name": "Kannada", "nativeName": "ಕನ್ನಡ"}, + "kr": {"name": "Kanuri", "nativeName": "Kanuri"}, + "ks": {"name": "Kashmiri", "nativeName": "कश्मीरी, كشميري‎"}, + "kk": {"name": "Kazakh", "nativeName": "Қазақ тілі"}, + "km": {"name": "Khmer", "nativeName": "ភាសាខ្មែរ"}, + "ki": {"name": "Kikuyu, Gikuyu", "nativeName": "Gĩkũyũ"}, + "rw": {"name": "Kinyarwanda", "nativeName": "Ikinyarwanda"}, + "ky": {"name": "Kirghiz, Kyrgyz", "nativeName": "кыргыз тили"}, + "kv": {"name": "Komi", "nativeName": "коми кыв"}, + "kg": {"name": "Kongo", "nativeName": "KiKongo"}, + "ko": {"name": "Korean", "nativeName": "한국어 (韓國語), 조선말 (朝鮮語)"}, + "ku": {"name": "Kurdish", "nativeName": "Kurdî, كوردی‎"}, + "kj": {"name": "Kwanyama, Kuanyama", "nativeName": "Kuanyama"}, + "la": {"name": "Latin", "nativeName": "latine, lingua latina"}, + "lb": { + "name": "Luxembourgish, Letzeburgesch", + "nativeName": "Lëtzebuergesch" + }, + "lg": {"name": "Luganda", "nativeName": "Luganda"}, + "li": {"name": "Limburgish, Limburgan, Limburger", "nativeName": "Limburgs"}, + "ln": {"name": "Lingala", "nativeName": "Lingála"}, + "lo": {"name": "Lao", "nativeName": "ພາສາລາວ"}, + "lt": {"name": "Lithuanian", "nativeName": "lietuvių kalba"}, + "lu": {"name": "Luba-Katanga", "nativeName": ""}, + "lv": {"name": "Latvian", "nativeName": "latviešu valoda"}, + "gv": {"name": "Manx", "nativeName": "Gaelg, Gailck"}, + "mk": {"name": "Macedonian", "nativeName": "македонски јазик"}, + "mg": {"name": "Malagasy", "nativeName": "Malagasy fiteny"}, + "ms": {"name": "Malay", "nativeName": "bahasa Melayu, بهاس ملايو‎"}, + "ml": {"name": "Malayalam", "nativeName": "മലയാളം"}, + "mt": {"name": "Maltese", "nativeName": "Malti"}, + "mi": {"name": "Māori", "nativeName": "te reo Māori"}, + "mr": {"name": "Marathi (Marāṭhī)", "nativeName": "मराठी"}, + "mh": {"name": "Marshallese", "nativeName": "Kajin M̧ajeļ"}, + "mn": {"name": "Mongolian", "nativeName": "монгол"}, + "na": {"name": "Nauru", "nativeName": "Ekakairũ Naoero"}, + "nv": {"name": "Navajo, Navaho", "nativeName": "Diné bizaad, Dinékʼehǰí"}, + "nb_NO": {"name": "Norwegian Bokmål", "nativeName": "Norsk bokmål"}, + "nd": {"name": "North Ndebele", "nativeName": "isiNdebele"}, + "ne": {"name": "Nepali", "nativeName": "नेपाली"}, + "ng": {"name": "Ndonga", "nativeName": "Owambo"}, + "nn": {"name": "Norwegian Nynorsk", "nativeName": "Norsk nynorsk"}, + "no": {"name": "Norwegian", "nativeName": "Norsk"}, + "ii": {"name": "Nuosu", "nativeName": "ꆈꌠ꒿ Nuosuhxop"}, + "nr": {"name": "South Ndebele", "nativeName": "isiNdebele"}, + "oc": {"name": "Occitan", "nativeName": "Occitan"}, + "oj": {"name": "Ojibwe, Ojibwa", "nativeName": "ᐊᓂᔑᓈᐯᒧᐎᓐ"}, + "cu": { + "name": + "Old Church Slavonic, Church Slavic, Church Slavonic, Old Bulgarian, Old Slavonic", + "nativeName": "ѩзыкъ словѣньскъ" + }, + "om": {"name": "Oromo", "nativeName": "Afaan Oromoo"}, + "or": {"name": "Oriya", "nativeName": "ଓଡ଼ିଆ"}, + "os": {"name": "Ossetian, Ossetic", "nativeName": "ирон æвзаг"}, + "pa": {"name": "Panjabi, Punjabi", "nativeName": "ਪੰਜਾਬੀ, پنجابی‎"}, + "pi": {"name": "Pāli", "nativeName": "पाऴि"}, + "fa": {"name": "Persian", "nativeName": "فارسی"}, + "pl": {"name": "Polish", "nativeName": "polski"}, + "ps": {"name": "Pashto, Pushto", "nativeName": "پښتو"}, + "pt": {"name": "Portuguese", "nativeName": "Português"}, + "qu": {"name": "Quechua", "nativeName": "Runa Simi, Kichwa"}, + "rm": {"name": "Romansh", "nativeName": "rumantsch grischun"}, + "rn": {"name": "Kirundi", "nativeName": "kiRundi"}, + "ro": {"name": "Romanian, Moldavian, Moldovan", "nativeName": "română"}, + "ru": {"name": "Russian", "nativeName": "русский язык"}, + "sa": {"name": "Sanskrit (Saṁskṛta)", "nativeName": "संस्कृतम्"}, + "sc": {"name": "Sardinian", "nativeName": "sardu"}, + "sd": {"name": "Sindhi", "nativeName": "सिन्धी, سنڌي، سندھی‎"}, + "se": {"name": "Northern Sami", "nativeName": "Davvisámegiella"}, + "sm": {"name": "Samoan", "nativeName": "gagana faa Samoa"}, + "sg": {"name": "Sango", "nativeName": "yângâ tî sängö"}, + "sr": {"name": "Serbian", "nativeName": "српски језик"}, + "gd": {"name": "Scottish Gaelic; Gaelic", "nativeName": "Gàidhlig"}, + "sn": {"name": "Shona", "nativeName": "chiShona"}, + "si": {"name": "Sinhala, Sinhalese", "nativeName": "සිංහල"}, + "sk": {"name": "Slovak", "nativeName": "slovenčina"}, + "sl": {"name": "Slovene", "nativeName": "slovenščina"}, + "so": {"name": "Somali", "nativeName": "Soomaaliga, af Soomaali"}, + "st": {"name": "Southern Sotho", "nativeName": "Sesotho"}, + "es": {"name": "Spanish; Castilian", "nativeName": "español, castellano"}, + "su": {"name": "Sundanese", "nativeName": "Basa Sunda"}, + "sw": {"name": "Swahili", "nativeName": "Kiswahili"}, + "ss": {"name": "Swati", "nativeName": "SiSwati"}, + "sv": {"name": "Swedish", "nativeName": "svenska"}, + "ta": {"name": "Tamil", "nativeName": "தமிழ்"}, + "te": {"name": "Telugu", "nativeName": "తెలుగు"}, + "tg": {"name": "Tajik", "nativeName": "тоҷикӣ, toğikī, تاجیکی‎"}, + "th": {"name": "Thai", "nativeName": "ไทย"}, + "ti": {"name": "Tigrinya", "nativeName": "ትግርኛ"}, + "bo": {"name": "Tibetan Standard, Tibetan, Central", "nativeName": "བོད་ཡིག"}, + "tk": {"name": "Turkmen", "nativeName": "Türkmen, Түркмен"}, + "tl": {"name": "Tagalog", "nativeName": "Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔"}, + "tn": {"name": "Tswana", "nativeName": "Setswana"}, + "to": {"name": "Tonga (Tonga Islands)", "nativeName": "faka Tonga"}, + "tr": {"name": "Turkish", "nativeName": "Türkçe"}, + "ts": {"name": "Tsonga", "nativeName": "Xitsonga"}, + "tt": {"name": "Tatar", "nativeName": "татарча, tatarça, تاتارچا‎"}, + "tw": {"name": "Twi", "nativeName": "Twi"}, + "ty": {"name": "Tahitian", "nativeName": "Reo Tahiti"}, + "ug": {"name": "Uighur, Uyghur", "nativeName": "Uyƣurqə, ئۇيغۇرچە‎"}, + "uk": {"name": "Ukrainian", "nativeName": "українська"}, + "ur": {"name": "Urdu", "nativeName": "اردو"}, + "uz": {"name": "Uzbek", "nativeName": "zbek, Ўзбек, أۇزبېك‎"}, + "ve": {"name": "Venda", "nativeName": "Tshivenḓa"}, + "vi": {"name": "Vietnamese", "nativeName": "Tiếng Việt"}, + "vo": {"name": "Volapük", "nativeName": "Volapük"}, + "wa": {"name": "Walloon", "nativeName": "Walon"}, + "cy": {"name": "Welsh", "nativeName": "Cymraeg"}, + "wo": {"name": "Wolof", "nativeName": "Wollof"}, + "fy": {"name": "Western Frisian", "nativeName": "Frysk"}, + "xh": {"name": "Xhosa", "nativeName": "isiXhosa"}, + "yi": {"name": "Yiddish", "nativeName": "ייִדיש"}, + "yo": {"name": "Yoruba", "nativeName": "Yorùbá"}, + "za": {"name": "Zhuang, Chuang", "nativeName": "Saɯ cueŋƅ, Saw cuengh"} +}; + +Map? getlanguageDisplayName(String key) { + if (isoLangs.containsKey(key)) { + return isoLangs[key]; + } else { + throw Exception("Language key incorrect"); } +} diff --git a/lib/settings/data/general_settings_schema.dart b/lib/settings/data/general_settings_schema.dart index f596f653..4802b2ca 100644 --- a/lib/settings/data/general_settings_schema.dart +++ b/lib/settings/data/general_settings_schema.dart @@ -8,6 +8,7 @@ import 'package:clock_app/common/utils/list_storage.dart'; import 'package:clock_app/common/utils/snackbar.dart'; import 'package:clock_app/common/utils/time_format.dart'; import 'package:clock_app/icons/flux_icons.dart'; +import 'package:clock_app/l10n/language_local.dart'; import 'package:clock_app/settings/screens/ringtones_screen.dart'; import 'package:clock_app/settings/screens/tags_screen.dart'; import 'package:clock_app/settings/types/setting.dart'; @@ -56,16 +57,8 @@ SettingGroup generalSettingsSchema = SettingGroup( (context) => AppLocalizations.of(context)!.languageSetting, [ SelectSettingOption((context) => AppLocalizations.of(context)!.system, - Locale(Platform.localeName)), - ...AppLocalizations.supportedLocales.map((locale) { - return SelectSettingOption( - (context) => Locale.fromSubtags( - languageCode: locale.languageCode, - scriptCode: locale.scriptCode, - countryCode: locale.countryCode) - .nativeDisplayLanguage, - locale); - }) + Locale(Platform.localeName.split("_").first)), + ...getLocaleOptions() ], onChange: (context, index) { App.refreshTheme(context); diff --git a/lib/settings/data/settings_schema.dart b/lib/settings/data/settings_schema.dart index 0a01809b..fd700233 100644 --- a/lib/settings/data/settings_schema.dart +++ b/lib/settings/data/settings_schema.dart @@ -11,6 +11,7 @@ import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_link.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + const int settingsSchemaVersion = 4; SettingGroup appSettings = SettingGroup( @@ -31,8 +32,7 @@ SettingGroup appSettings = SettingGroup( "About", (context) => AppLocalizations.of(context)!.aboutSettingGroup, const AboutScreen(), - icon: Icons.info_rounded, - + icon: Icons.info_outline_rounded, ), ], ); diff --git a/lib/timer/data/timer_list_filters.dart b/lib/timer/data/timer_list_filters.dart index 391b2669..e53548f7 100644 --- a/lib/timer/data/timer_list_filters.dart +++ b/lib/timer/data/timer_list_filters.dart @@ -2,28 +2,31 @@ import 'package:clock_app/common/types/list_filter.dart'; import 'package:clock_app/common/types/tag.dart'; import 'package:clock_app/common/utils/list_storage.dart'; import 'package:clock_app/timer/types/timer.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; final List> timerListFilters = [ - ListFilterSelect("State", [ + ListFilterSelect( + (context) => AppLocalizations.of(context)!.stateFilterGroup, [ ListFilter( - 'Running', + (context) => AppLocalizations.of(context)!.runningTimerFilter, (timer) => timer.isRunning, ), ListFilter( - 'Paused', + (context) => AppLocalizations.of(context)!.pausedTimerFilter, (timer) => timer.isPaused, ), ListFilter( - 'Stopped', + (context) => AppLocalizations.of(context)!.stoppedTimerFilter, (timer) => timer.isStopped, ), ]), // - DynamicListFilterMultiSelect("Tags", () { + DynamicListFilterMultiSelect( + (context) => AppLocalizations.of(context)!.tagsSetting, () { final tags = loadListSync("tags"); return tags.map((tag) { return ListFilter( - tag.name, + (context) => tag.name, (timer) => timer.tags.any((element) => element.id == tag.id), id: tag.id, ); diff --git a/lib/timer/data/timer_sort_options.dart b/lib/timer/data/timer_sort_options.dart index 5bdb89a6..d5c8caa8 100644 --- a/lib/timer/data/timer_sort_options.dart +++ b/lib/timer/data/timer_sort_options.dart @@ -1,13 +1,14 @@ import 'package:clock_app/common/types/list_filter.dart'; import 'package:clock_app/timer/types/timer.dart'; - -const List> timerSortOptions = [ - ListSortOption("Remaining Time Descending", "9-1", sortRemainingTimeDescending), - ListSortOption("Remaining Time Ascending", "1-9", sortRemainingTimeAscending), - ListSortOption("Duration Descending", "5:00-1:00", sortTotalDurationDescending), - ListSortOption("Duration Ascending", "1:00-5:00", sortTotalDurationAscending), - ListSortOption("Name Ascending", "A-Z", sortNameAscending), - ListSortOption("Name Descending", "Z-A", sortNameDescending), +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +final List> timerSortOptions = [ + ListSortOption((context) => AppLocalizations.of(context)!.remainingTimeDesc, sortRemainingTimeDescending), + ListSortOption((context) => AppLocalizations.of(context)!.remainingTimeAsc, sortRemainingTimeAscending), + ListSortOption((context) => AppLocalizations.of(context)!.durationAsc, sortTotalDurationAscending), + ListSortOption((context) => AppLocalizations.of(context)!.durationDesc, sortTotalDurationDescending), + ListSortOption((context) => AppLocalizations.of(context)!.nameAsc, sortNameAscending), + ListSortOption((context) => AppLocalizations.of(context)!.nameDesc, sortNameDescending), ]; From 66cde11e97f29b95c7f8d72b0e6e128d189040b3 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 2 May 2024 17:07:30 +0200 Subject: [PATCH 060/112] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Hosted Weblate Translate-URL: https://hosted.weblate.org/projects/chrono/app/ Translation: Chrono/App --- lib/l10n/app_es.arb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 07d892a6..3d900b01 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -497,10 +497,6 @@ "@nameAsc": {}, "nameDesc": "Nombre descendente", "@nameDesc": {}, - "dateAsc": "Fecha ascendente", - "@dateAsc": {}, - "dateDesc": "Fecha descendente", - "@dateDesc": {}, "timeOfDayDesc": "Hora del día descendente", "@timeOfDayDesc": {}, "filterActions": "Filtrar acciones", From 7b2c3ab6d15ac6c2525d294b801fb46936ff4931 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Thu, 2 May 2024 17:07:31 +0200 Subject: [PATCH 061/112] Translated using Weblate (Spanish) Currently translated at 100.0% (268 of 268 strings) Co-authored-by: gallegonovato Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ Translation: Chrono/App --- lib/l10n/app_es.arb | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 3d900b01..e53dfb39 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -467,7 +467,7 @@ "@noTimerMessage": {}, "noTaskMessage": "No se crearon tareas", "@noTaskMessage": {}, - "timeOfDayAsc": "Hora del día ascendente", + "timeOfDayAsc": "Primero las primeras horas", "@timeOfDayAsc": {}, "disableAllFilteredAlarmsAction": "Deshabilitar todas las alarmas filtradas", "@disableAllFilteredAlarmsAction": {}, @@ -489,15 +489,15 @@ "@sortGroup": {}, "defaultLabel": "Por defecto", "@defaultLabel": {}, - "remainingTimeDesc": "Tiempo restante descendente", + "remainingTimeDesc": "Queda menos tiempo", "@remainingTimeDesc": {}, - "remainingTimeAsc": "Tiempo restante ascendente", + "remainingTimeAsc": "Queda más tiempo", "@remainingTimeAsc": {}, - "nameAsc": "Nombre ascendente", + "nameAsc": "Nombre A-Z", "@nameAsc": {}, - "nameDesc": "Nombre descendente", + "nameDesc": "Nombre Z-A", "@nameDesc": {}, - "timeOfDayDesc": "Hora del día descendente", + "timeOfDayDesc": "Primero las últimas horas", "@timeOfDayDesc": {}, "filterActions": "Filtrar acciones", "@filterActions": {}, @@ -510,5 +510,29 @@ "skipAllFilteredAlarmsAction": "Omitir todas las alarmas filtradas", "@skipAllFilteredAlarmsAction": {}, "deleteAllFilteredAction": "Eliminar todos los elementos filtrados", - "@deleteAllFilteredAction": {} + "@deleteAllFilteredAction": {}, + "timePickerModeButton": "Modo", + "@timePickerModeButton": {}, + "colorSchemeUseAccentAsOutlineSetting": "Utilice énfasis para los bordes", + "@colorSchemeUseAccentAsOutlineSetting": {}, + "accentLabel": "Acentuar", + "@accentLabel": {}, + "scheduleDateFilterGroup": "Fecha de programacion", + "@scheduleDateFilterGroup": {}, + "logTypeFilterGroup": "Tipo", + "@logTypeFilterGroup": {}, + "createdDateFilterGroup": "Fecha de creación", + "@createdDateFilterGroup": {}, + "inactiveFilter": "Inactivo", + "@inactiveFilter": {}, + "runningTimerFilter": "Ejecutándose", + "@runningTimerFilter": {}, + "pausedTimerFilter": "Pausado", + "@pausedTimerFilter": {}, + "stoppedTimerFilter": "Detenido", + "@stoppedTimerFilter": {}, + "durationAsc": "Más corto", + "@durationAsc": {}, + "durationDesc": "Más largo", + "@durationDesc": {} } From 1504b41c438d3e249a67d18174f9a680d559eeee Mon Sep 17 00:00:00 2001 From: Matsukky Date: Thu, 2 May 2024 17:07:32 +0200 Subject: [PATCH 062/112] Translated using Weblate (French) Currently translated at 33.5% (90 of 268 strings) Co-authored-by: Matsukky Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ Translation: Chrono/App --- lib/l10n/app_fr.arb | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 046b5f6c..55c6f4de 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -172,5 +172,29 @@ "alarmDescriptionDates": "Le {date}{count, plural, =0{} =1{ et 1 autre date} other{ et {count} autres dates}}", "@alarmDescriptionDates": {}, "stopwatchAverage": "Moyenne", - "@stopwatchAverage": {} + "@stopwatchAverage": {}, + "system": "Système", + "@system": {}, + "languageSetting": "Langue", + "@languageSetting": {}, + "dateFormatSetting": "Format des dates", + "@dateFormatSetting": {}, + "timeFormatSetting": "Format de l'heure", + "@timeFormatSetting": {}, + "timeFormat12": "12 heures", + "@timeFormat12": {}, + "timeFormat24": "24 heures", + "@timeFormat24": {}, + "timeFormatDevice": "Paramètre de l'appareil", + "@timeFormatDevice": {}, + "showSecondsSetting": "Montrez les secondes", + "@showSecondsSetting": {}, + "timePickerSetting": "Sélectionneur d'heure", + "@timePickerSetting": {}, + "pickerDial": "Cadran", + "@pickerDial": {}, + "pickerInput": "Entrée", + "@pickerInput": {}, + "durationPickerSetting": "Sélection de la durée", + "@durationPickerSetting": {} } From ee1e531c43eef75d046dbacba3745d05751271c1 Mon Sep 17 00:00:00 2001 From: Sinan Date: Thu, 2 May 2024 17:07:34 +0200 Subject: [PATCH 063/112] Translated using Weblate (Turkish) Currently translated at 39.5% (106 of 268 strings) Co-authored-by: Sinan Translate-URL: https://hosted.weblate.org/projects/chrono/app/tr/ Translation: Chrono/App --- lib/l10n/app_tr.arb | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 6255255e..f6fe9b38 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -206,5 +206,23 @@ "taskTryButton": "Dene", "@taskTryButton": {}, "skippingDescriptionSuffix": "(sonraki atlanacak)", - "@skippingDescriptionSuffix": {} + "@skippingDescriptionSuffix": {}, + "system": "Dizge", + "@system": {}, + "languageSetting": "Dil", + "@languageSetting": {}, + "dateFormatSetting": "Tarih Biçimi", + "@dateFormatSetting": {}, + "timeFormatSetting": "Saat Biçimi", + "@timeFormatSetting": {}, + "timeFormat12": "12 saat", + "@timeFormat12": {}, + "timeFormat24": "24 saat", + "@timeFormat24": {}, + "timeFormatDevice": "Cihaz Ayarları", + "@timeFormatDevice": {}, + "showSecondsSetting": "Saniye Göster", + "@showSecondsSetting": {}, + "pickerInput": "Girdi", + "@pickerInput": {} } From edb4313f1abe34dc38351e512ffd5fb11d4c823a Mon Sep 17 00:00:00 2001 From: Raf Date: Thu, 2 May 2024 17:07:36 +0200 Subject: [PATCH 064/112] Translated using Weblate (Bengali) Currently translated at 21.2% (57 of 268 strings) Added translation using Weblate (Bengali) Co-authored-by: Raf Translate-URL: https://hosted.weblate.org/projects/chrono/app/bn/ Translation: Chrono/App --- lib/l10n/app_bn.arb | 124 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 lib/l10n/app_bn.arb diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb new file mode 100644 index 00000000..122bfb0c --- /dev/null +++ b/lib/l10n/app_bn.arb @@ -0,0 +1,124 @@ +{ + "pickerRings": "রিং", + "@pickerRings": {}, + "pickerDial": "ডায়াল", + "@pickerDial": {}, + "swipeActionCardActionDescription": "কাজ সম্পাদন করতে কার্ডের বাম বা ডানদিকে সোয়াইপ করুন", + "@swipeActionCardActionDescription": {}, + "vendorSettingDescription": "ম্যানুয়ালি কোম্পানি-নির্দিষ্ট সীমাবদ্ধতা বন্ধ করুন", + "@vendorSettingDescription": {}, + "batteryOptimizationSettingDescription": "অ্যালার্ম দেরি হওয়া থেকে আটকাতে এই অ্যাপের জন্য ব্যাটারি সীমাবদ্ধতা বন্ধ করুন", + "@batteryOptimizationSettingDescription": {}, + "animationSettingGroup": "অ্যানিমেশন", + "@animationSettingGroup": {}, + "animationSpeedSetting": "অ্যানিমেশনের গতি", + "@animationSpeedSetting": {}, + "autoStartSetting": "অটোমেটিক শুরু", + "@autoStartSetting": {}, + "colorSchemeUseAccentAsOutlineSetting": "আউটলাইনের রঙ হিসাবে পরিপূরক রঙ ব্যবহার করুন", + "@colorSchemeUseAccentAsOutlineSetting": {}, + "styleThemeNamePlaceholder": "স্টাইল থিম", + "@styleThemeNamePlaceholder": {}, + "timerTitle": "টাইমার", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "stopwatchTitle": "স্টপওয়াচ", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "system": "পদ্ধতি", + "@system": {}, + "generalSettingGroup": "সাধারণ", + "@generalSettingGroup": {}, + "dateFormatSetting": "তারিখ বিন্যাস", + "@dateFormatSetting": {}, + "generalSettingGroupDescription": "সময় বিন্যাসের মতো অ্যাপ ওয়াইড সেটিংস সেট করুন", + "@generalSettingGroupDescription": {}, + "timeFormatSetting": "সময়ের বিন্যাস", + "@timeFormatSetting": {}, + "timeFormat12": "১২ ঘণ্টা", + "@timeFormat12": {}, + "timeFormat24": "২৪ ঘন্টা", + "@timeFormat24": {}, + "timeFormatDevice": "ডিভাইস সেটিংস", + "@timeFormatDevice": {}, + "showSecondsSetting": "সেকেন্ড দেখান", + "@showSecondsSetting": {}, + "timePickerSetting": "সময় বাছাইকারী", + "@timePickerSetting": {}, + "pickerInput": "নির্দেশ", + "@pickerInput": {}, + "pickerSpinner": "ঘূর্ণন", + "@pickerSpinner": {}, + "durationPickerSetting": "সময়কাল বাছাইকারী", + "@durationPickerSetting": {}, + "swipeActionSetting": "সোয়াইপ করুন", + "@swipeActionSetting": {}, + "swipActionCardAction": "কার্ড কর্ম", + "@swipActionCardAction": {}, + "swipActionSwitchTabs": "ট্যাব পরিবর্তন করুন", + "@swipActionSwitchTabs": {}, + "swipeActionSwitchTabsDescription": "ট্যাবের মধ্যে সোয়াইপ করুন", + "@swipeActionSwitchTabsDescription": {}, + "melodiesSetting": "শব্দ", + "@melodiesSetting": {}, + "tagsSetting": "চিহ্ন", + "@tagsSetting": {}, + "vendorSetting": "কোম্পানির সেটিং", + "@vendorSetting": {}, + "batteryOptimizationSetting": "ব্যাটারি সীমাবদ্ধতা বন্ধ করুন", + "@batteryOptimizationSetting": {}, + "allowNotificationSettingDescription": "অ্যালার্ম এবং টাইমারগুলির জন্য লক স্ক্রীন নোটিফিকেশন অনুমতি দিন", + "@allowNotificationSettingDescription": {}, + "autoStartSettingDescription": "অ্যাপ বন্ধ থাকা অবস্থায় অ্যালার্ম বাজানোর জন্য কিছু ডিভাইসে অটোমেটিক শুরু হওয়া করা প্রয়োজন", + "@autoStartSettingDescription": {}, + "allowNotificationSetting": "নোটিফিকেশন অনুমতি দিন", + "@allowNotificationSetting": {}, + "extraAnimationSetting": "অতিরিক্ত অ্যানিমেশন", + "@extraAnimationSetting": {}, + "appearanceSettingGroup": "উপস্থিতি", + "@appearanceSettingGroup": {}, + "appearanceSettingGroupDescription": "থিম, রং সেট করুন এবং লেআউট পরিবর্তন করুন", + "@appearanceSettingGroupDescription": {}, + "nameField": "নাম", + "@nameField": {}, + "colorSetting": "রঙ", + "@colorSetting": {}, + "textColorSetting": "লেখা", + "@textColorSetting": {}, + "colorSchemeNamePlaceholder": "রঙের পরিকল্পনা", + "@colorSchemeNamePlaceholder": {}, + "colorSchemeBackgroundSettingGroup": "ব্যাকগ্রাউন্ড", + "@colorSchemeBackgroundSettingGroup": {}, + "colorSchemeAccentSettingGroup": "পরিপূরক রঙ", + "@colorSchemeAccentSettingGroup": {}, + "colorSchemeErrorSettingGroup": "ত্রুটি", + "@colorSchemeErrorSettingGroup": {}, + "colorSchemeCardSettingGroup": "কার্ড", + "@colorSchemeCardSettingGroup": {}, + "colorSchemeShadowSettingGroup": "ছায়া", + "@colorSchemeShadowSettingGroup": {}, + "colorSchemeOutlineSettingGroup": "আউটলাইন", + "@colorSchemeOutlineSettingGroup": {}, + "colorSchemeUseAccentAsShadowSetting": "ছায়া হিসাবে পরিপূরক রঙ ব্যবহার করুন", + "@colorSchemeUseAccentAsShadowSetting": {}, + "styleThemeShadowSettingGroup": "ছায়া", + "@styleThemeShadowSettingGroup": {}, + "styleThemeShapeSettingGroup": "আকৃতি", + "@styleThemeShapeSettingGroup": {}, + "styleThemeElevationSetting": "উচ্চতা", + "@styleThemeElevationSetting": {}, + "styleThemeRadiusSetting": "কোণার গোলাকারতা", + "@styleThemeRadiusSetting": {}, + "clockTitle": "ঘড়ি", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "alarmTitle": "এলার্ম", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "languageSetting": "ভাষা", + "@languageSetting": {} +} From 9506683104ea32fe94106f075650cdb235eace37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC=D0=B8=D0=B9=20=D0=9B=D0=B0?= =?UTF-8?q?=D0=B7=D0=B0=D1=80=D0=B5=D0=B2=20=28BurnBird=29?= Date: Thu, 2 May 2024 17:07:37 +0200 Subject: [PATCH 065/112] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 26.1% (70 of 268 strings) Co-authored-by: Артемий Лазарев (BurnBird) Translate-URL: https://hosted.weblate.org/projects/chrono/app/ru/ Translation: Chrono/App --- lib/l10n/app_ru.arb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 1ced906a..bea50b18 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -160,5 +160,7 @@ "styleThemeOpacitySetting": "Прозрачность", "@styleThemeOpacitySetting": {}, "colorSchemeNamePlaceholder": "Цветовая схема", - "@colorSchemeNamePlaceholder": {} + "@colorSchemeNamePlaceholder": {}, + "vendorSetting": "Настройки производителя", + "@vendorSetting": {} } From a9fcefa56fb63cddefd61d1f15f4a07fb058a7e6 Mon Sep 17 00:00:00 2001 From: "Brice dOliveira ([#]b-do)" Date: Thu, 2 May 2024 17:07:39 +0200 Subject: [PATCH 066/112] Translated using Weblate (French) Currently translated at 33.5% (90 of 268 strings) Co-authored-by: Brice dOliveira ([#]b-do) Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ Translation: Chrono/App --- lib/l10n/app_fr.arb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 55c6f4de..a382ae11 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -93,9 +93,9 @@ "@scheduleTypeWeek": {}, "scheduleTypeRange": "Période", "@scheduleTypeRange": {}, - "scheduleTypeDateDescription": "Se répétera aux dates spécifiées", + "scheduleTypeDateDescription": "Se répétera aux dates définies", "@scheduleTypeDateDescription": {}, - "scheduleTypeWeekDescription": "Se répétera aux jours de la semaine spécifiés", + "scheduleTypeWeekDescription": "Se répétera aux jours définis de la semaine", "@scheduleTypeWeekDescription": {}, "reliabilitySettingGroup": "Fiabilité", "@reliabilitySettingGroup": {}, @@ -103,7 +103,7 @@ "@alarmScheduleSettingGroup": {}, "soundSettingGroup": "Son et vibration", "@soundSettingGroup": {}, - "settingGroupMore": "Plus", + "settingGroupMore": "Paramètres supplémentaires", "@settingGroupMore": {}, "melodySetting": "Mélodie", "@melodySetting": {}, @@ -139,7 +139,7 @@ "@taskTryButton": {}, "mathTaskDifficultySetting": "Difficulté", "@mathTaskDifficultySetting": {}, - "scheduleTypeRangeDescription": "Se répétera pendant la période spécifiée", + "scheduleTypeRangeDescription": "Se répétera pendant la période définie", "@scheduleTypeRangeDescription": {}, "skippingDescriptionSuffix": "(prochaine alarme ignorée)", "@skippingDescriptionSuffix": {}, @@ -159,11 +159,11 @@ "@alarmDescriptionWeekend": {}, "stopwatchPrevious": "Précedent", "@stopwatchPrevious": {}, - "alarmDescriptionWeekday": "Tous les jours de la semaine", + "alarmDescriptionWeekday": "Tous les jours", "@alarmDescriptionWeekday": {}, "stopwatchFastest": "Le plus rapide", "@stopwatchFastest": {}, - "alarmDescriptionDays": "Le {days}", + "alarmDescriptionDays": "Tous les {days}", "@alarmDescriptionDays": {}, "alarmDescriptionRange": "{interval, select, daily{Tous les jours} weekly{Toutes les semaines} other{Other}} du {startDate} au {endDate}", "@alarmDescriptionRange": {}, @@ -189,11 +189,11 @@ "@timeFormatDevice": {}, "showSecondsSetting": "Montrez les secondes", "@showSecondsSetting": {}, - "timePickerSetting": "Sélectionneur d'heure", + "timePickerSetting": "Réglage de l’heure", "@timePickerSetting": {}, "pickerDial": "Cadran", "@pickerDial": {}, - "pickerInput": "Entrée", + "pickerInput": "Clavier", "@pickerInput": {}, "durationPickerSetting": "Sélection de la durée", "@durationPickerSetting": {} From 419283f327bcead0e9dabc534f645f4998c29e51 Mon Sep 17 00:00:00 2001 From: ngocanhtve Date: Thu, 2 May 2024 17:07:41 +0200 Subject: [PATCH 067/112] Translated using Weblate (Vietnamese) Currently translated at 44.0% (118 of 268 strings) Co-authored-by: ngocanhtve Translate-URL: https://hosted.weblate.org/projects/chrono/app/vi/ Translation: Chrono/App --- lib/l10n/app_vi.arb | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 35f6d96d..d4f09934 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -206,5 +206,47 @@ "colorSchemeSetting": "Phối màu", "@colorSchemeSetting": {}, "scheduleTypeDailyDescription": "Sẽ đổ chuông mỗi ngày", - "@scheduleTypeDailyDescription": {} + "@scheduleTypeDailyDescription": {}, + "swipeActionCardActionDescription": "Vuốt sang trái hoặc phải trên thẻ để thực hiện hành động", + "@swipeActionCardActionDescription": {}, + "batteryOptimizationSetting": "Tắt tối ưu hóa pin", + "@batteryOptimizationSetting": {}, + "system": "Hệ thống", + "@system": {}, + "languageSetting": "Ngôn ngữ", + "@languageSetting": {}, + "dateFormatSetting": "Định dạng ngày tháng", + "@dateFormatSetting": {}, + "timeFormatSetting": "Định dạng thời gian", + "@timeFormatSetting": {}, + "timeFormat12": "12 giờ", + "@timeFormat12": {}, + "timeFormat24": "24 giờ", + "@timeFormat24": {}, + "timeFormatDevice": "Thiết đặt thiết bị", + "@timeFormatDevice": {}, + "showSecondsSetting": "Hiển thị giây", + "@showSecondsSetting": {}, + "timePickerSetting": "Bộ chọn thời gian", + "@timePickerSetting": {}, + "pickerDial": "Quay số", + "@pickerDial": {}, + "durationPickerSetting": "Bộ chọn thời lượng", + "@durationPickerSetting": {}, + "pickerRings": "Chuông", + "@pickerRings": {}, + "swipeActionSetting": "Hành động vuốt", + "@swipeActionSetting": {}, + "swipActionCardAction": "Hành động thẻ", + "@swipActionCardAction": {}, + "swipActionSwitchTabs": "Chuyển tab", + "@swipActionSwitchTabs": {}, + "swipeActionSwitchTabsDescription": "Vuốt giữa các tab", + "@swipeActionSwitchTabsDescription": {}, + "melodiesSetting": "Giai điệu", + "@melodiesSetting": {}, + "vendorSetting": "Thiết đặt nhà cung cấp", + "@vendorSetting": {}, + "vendorSettingDescription": "Tắt thủ công các tối ưu hóa dành riêng cho nhà cung cấp", + "@vendorSettingDescription": {} } From 6bd5e27cb26d715e590acf21c62cfa26dbc7a9d5 Mon Sep 17 00:00:00 2001 From: Lorenzo Vainigli Date: Thu, 2 May 2024 20:00:37 +0000 Subject: [PATCH 068/112] Translated using Weblate (Italian) Currently translated at 5.2% (14 of 268 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/it/ --- lib/l10n/app_it.arb | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 0967ef42..d3645022 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1 +1,38 @@ -{} +{ + "languageSetting": "Lingua", + "@languageSetting": {}, + "dateFormatSetting": "Formato data", + "@dateFormatSetting": {}, + "timeFormatSetting": "Formato ora", + "@timeFormatSetting": {}, + "timeFormat12": "12 ore", + "@timeFormat12": {}, + "timeFormat24": "24 ore", + "@timeFormat24": {}, + "timeFormatDevice": "Impostazioni dispositivo", + "@timeFormatDevice": {}, + "showSecondsSetting": "Mostra secondi", + "@showSecondsSetting": {}, + "clockTitle": "Orologio", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "alarmTitle": "Sveglia", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "timerTitle": "Timer", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "stopwatchTitle": "Cronometro", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "generalSettingGroup": "Generali", + "@generalSettingGroup": {}, + "system": "Sistema", + "@system": {}, + "melodiesSetting": "Melodie", + "@melodiesSetting": {} +} From bdebbf04cc918323f888ff80727bec4ce4fab413 Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Thu, 2 May 2024 22:28:05 +0000 Subject: [PATCH 069/112] Translated using Weblate (Portuguese) Currently translated at 44.7% (120 of 268 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 48 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 8f4f490b..b8246140 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -206,5 +206,51 @@ "alarmDescriptionDates": "Em {date}{count, plural, =0{} =1{ e mais 1 data} other{ e mais {count} datas}}", "@alarmDescriptionDates": {}, "stopwatchAverage": "Média", - "@stopwatchAverage": {} + "@stopwatchAverage": {}, + "pickerSpinner": "Spinner", + "@pickerSpinner": {}, + "durationPickerSetting": "Seletor de duração", + "@durationPickerSetting": {}, + "pickerRings": "Anéis", + "@pickerRings": {}, + "swipeActionSetting": "Ação de deslizae", + "@swipeActionSetting": {}, + "system": "Sistema", + "@system": {}, + "languageSetting": "Idioma", + "@languageSetting": {}, + "dateFormatSetting": "Formato da data", + "@dateFormatSetting": {}, + "timeFormatSetting": "Formato das horas", + "@timeFormatSetting": {}, + "timeFormat12": "12 horas", + "@timeFormat12": {}, + "timeFormat24": "24 horas", + "@timeFormat24": {}, + "timeFormatDevice": "Definições do dispositivo", + "@timeFormatDevice": {}, + "showSecondsSetting": "Mostrar segundos", + "@showSecondsSetting": {}, + "timePickerSetting": "Seletor de horas", + "@timePickerSetting": {}, + "pickerDial": "Marcador", + "@pickerDial": {}, + "pickerInput": "Introdução", + "@pickerInput": {}, + "swipActionCardAction": "Ações em cartões", + "@swipActionCardAction": {}, + "swipeActionCardActionDescription": "Deslizar para os lados no cartão para executar ações", + "@swipeActionCardActionDescription": {}, + "swipActionSwitchTabs": "Troca de separadores", + "@swipActionSwitchTabs": {}, + "swipeActionSwitchTabsDescription": "Deslizar entre separadores", + "@swipeActionSwitchTabsDescription": {}, + "melodiesSetting": "Melodias", + "@melodiesSetting": {}, + "tagsSetting": "Etiquetas", + "@tagsSetting": {}, + "vendorSetting": "Definição d fornecedor", + "@vendorSetting": {}, + "batteryOptimizationSetting": "Desativar otimização de bateria", + "@batteryOptimizationSetting": {} } From 3c9f28e9b446a75871ba39cd518a0dcb10a78f2e Mon Sep 17 00:00:00 2001 From: o101010 Date: Sun, 5 May 2024 19:01:36 +0000 Subject: [PATCH 070/112] Translated using Weblate (French) Currently translated at 39.5% (106 of 268 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index a382ae11..eb949d74 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -196,5 +196,39 @@ "pickerInput": "Clavier", "@pickerInput": {}, "durationPickerSetting": "Sélection de la durée", - "@durationPickerSetting": {} + "@durationPickerSetting": {}, + "autoStartSettingDescription": "Certains appareils nécessitent que le démarrage automatique ne soit activé pour que les alarmes sonnent malgré que l'application ne soit fermée", + "@autoStartSettingDescription": {}, + "pickerRings": "Sonneries", + "@pickerRings": {}, + "swipeActionSetting": "Action de balayage", + "@swipeActionSetting": {}, + "pickerSpinner": "Tourniquet", + "@pickerSpinner": {}, + "swipActionSwitchTabs": "Changer d'onglet", + "@swipActionSwitchTabs": {}, + "swipeActionSwitchTabsDescription": "Balayer entre les onglets", + "@swipeActionSwitchTabsDescription": {}, + "swipeActionCardActionDescription": "Balayer à gauche ou à droite pour effectuer une action", + "@swipeActionCardActionDescription": {}, + "melodiesSetting": "Mélodies", + "@melodiesSetting": {}, + "tagsSetting": "Étiquettes", + "@tagsSetting": {}, + "vendorSetting": "Paramètre du vendeur", + "@vendorSetting": {}, + "vendorSettingDescription": "Désactiver manuellement les optimisations spécifiques au vendeur", + "@vendorSettingDescription": {}, + "batteryOptimizationSetting": "Désactiver l'optimisation de la batterie", + "@batteryOptimizationSetting": {}, + "batteryOptimizationSettingDescription": "Désactiver l'optimisation de la batterie pour cette application afin d'éviter que l'alarme ne soit retardée", + "@batteryOptimizationSettingDescription": {}, + "allowNotificationSettingDescription": "Autoriser les notifications sur l'écran de verrouillage pour les alarmes et le chronomètre", + "@allowNotificationSettingDescription": {}, + "allowNotificationSetting": "Autoriser les notifications", + "@allowNotificationSetting": {}, + "autoStartSetting": "Démarrage automatique", + "@autoStartSetting": {}, + "animationSettingGroup": "Animations", + "@animationSettingGroup": {} } From cb76a71e1ac90a4b4a9fde29c279e222e072c9a6 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Tue, 7 May 2024 16:30:42 +0500 Subject: [PATCH 071/112] Localize weekdays --- lib/alarm/data/alarm_settings_schema.dart | 21 +- lib/alarm/logic/schedule_description.dart | 41 ++-- lib/alarm/widgets/alarm_card.dart | 9 +- lib/alarm/widgets/alarm_task_card.dart | 2 +- lib/audio/logic/audio_session.dart | 1 + lib/audio/types/audio.dart | 47 ---- lib/audio/types/ringtone_manager.dart | 25 +-- lib/audio/types/ringtone_player.dart | 6 - lib/common/data/weekdays.dart | 24 ++- lib/common/types/weekday.dart | 8 +- lib/common/utils/popup_action.dart | 8 +- lib/common/utils/weekday_utils.dart | 8 +- lib/common/widgets/action_pane.dart | 6 +- .../select_field/select_bottom_sheet.dart | 4 +- lib/common/widgets/popup_menu.dart | 202 ------------------ lib/common/widgets/spinner_time_picker.dart | 2 + lib/l10n/app_en.arb | 78 +++++-- lib/settings/widgets/tag_card.dart | 2 +- lib/stopwatch/screens/stopwatch_screen.dart | 9 +- lib/stopwatch/widgets/lap_card.dart | 4 +- lib/stopwatch/widgets/stopwatch_ticker.dart | 10 +- lib/theme/widgets/theme_card.dart | 2 +- lib/timer/widgets/timer_card.dart | 2 +- lib/timer/widgets/timer_preset_card.dart | 2 +- 24 files changed, 155 insertions(+), 368 deletions(-) delete mode 100644 lib/audio/types/audio.dart delete mode 100644 lib/common/widgets/popup_menu.dart diff --git a/lib/alarm/data/alarm_settings_schema.dart b/lib/alarm/data/alarm_settings_schema.dart index baf93c0c..3ce22a6d 100644 --- a/lib/alarm/data/alarm_settings_schema.dart +++ b/lib/alarm/data/alarm_settings_schema.dart @@ -11,6 +11,7 @@ import 'package:clock_app/alarm/widgets/alarm_task_card.dart'; import 'package:clock_app/alarm/widgets/try_alarm_task_button.dart'; import 'package:clock_app/audio/audio_channels.dart'; import 'package:clock_app/audio/types/ringtone_player.dart'; +import 'package:clock_app/common/data/weekdays.dart'; import 'package:clock_app/common/logic/tags.dart'; import 'package:clock_app/common/types/file_item.dart'; import 'package:clock_app/common/types/tag.dart'; @@ -74,22 +75,10 @@ SettingGroup alarmSettingsSchema = SettingGroup( ToggleSetting( "Week Days", (context) => AppLocalizations.of(context)!.alarmWeekdaysSetting, - [ - ToggleSettingOption( - (context) => AppLocalizations.of(context)!.mondayLetter, 1), - ToggleSettingOption( - (context) => AppLocalizations.of(context)!.tuesdayLetter, 2), - ToggleSettingOption( - (context) => AppLocalizations.of(context)!.wednesdayLetter, 3), - ToggleSettingOption( - (context) => AppLocalizations.of(context)!.thursdayLetter, 4), - ToggleSettingOption( - (context) => AppLocalizations.of(context)!.fridayLetter, 5), - ToggleSettingOption( - (context) => AppLocalizations.of(context)!.saturdayLetter, 6), - ToggleSettingOption( - (context) => AppLocalizations.of(context)!.sundayLetter, 7), - ], + weekdays + .map((weekday) => ToggleSettingOption( + (context) => weekday.getAbbreviation(context), weekday.id)) + .toList(), enableConditions: [ ValueCondition(["Type"], (value) => value == WeeklyAlarmSchedule) ], diff --git a/lib/alarm/logic/schedule_description.dart b/lib/alarm/logic/schedule_description.dart index 811bd92d..8e3f95db 100644 --- a/lib/alarm/logic/schedule_description.dart +++ b/lib/alarm/logic/schedule_description.dart @@ -13,45 +13,52 @@ import 'package:clock_app/common/utils/time_format.dart'; import 'package:clock_app/common/utils/weekday_utils.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; String getAlarmScheduleDescription(BuildContext context, Alarm alarm, String dateFormat, TimeFormat timeFormat) { String suffix = ''; if (alarm.shouldSkipNextAlarm) { - suffix = ' (skipping next occurence)'; + suffix = ' ${AppLocalizations.of(context)!.skippingDescriptionSuffix}'; } if (alarm.isSnoozed) { - return 'Snoozed until ${DateFormat(getTimeFormatString(context, timeFormat)).format(alarm.snoozeTime!)}'; + return AppLocalizations.of(context)!.alarmDescriptionSnooze( + DateFormat(getTimeFormatString(context, timeFormat)) + .format(alarm.snoozeTime!)); } if (alarm.isFinished) { - return 'No future dates'; + return AppLocalizations.of(context)!.alarmDescriptionFinished; } if (!alarm.isEnabled) { - return 'Not scheduled'; + return AppLocalizations.of(context)!.alarmDescriptionNotScheduled; } switch (alarm.scheduleType) { case OnceAlarmSchedule: - return 'Just ${alarm.time.toHours() > DateTime.now().toHours() ? 'today' : 'tomorrow'}$suffix'; + return '${alarm.time.toHours() > DateTime.now().toHours() ? AppLocalizations.of(context)!.alarmDescriptionToday : AppLocalizations.of(context)!.alarmDescriptionTomorrow}$suffix'; case DailyAlarmSchedule: - return 'Every day$suffix'; + return '${AppLocalizations.of(context)!.alarmDescriptionEveryDay}$suffix'; case WeeklyAlarmSchedule: List alarmWeekdays = alarm.weekdays; if (alarmWeekdays.length == 7) { - return 'Every day$suffix'; + return '${AppLocalizations.of(context)!.alarmDescriptionEveryDay}$suffix'; } if (alarmWeekdays.length == 2 && - weekdaysContainsAll(alarmWeekdays, ['Sat', 'Sun'])) { - return 'Every weekend$suffix'; + weekdaysContainsAll(alarmWeekdays, [6, 7])) { + return '${AppLocalizations.of(context)!.alarmDescriptionWeekend}$suffix'; } if (alarmWeekdays.length == 5 && - weekdaysContainsAll( - alarmWeekdays, ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])) { - return 'Every weekday$suffix'; + weekdaysContainsAll(alarmWeekdays, [1, 2, 3, 4, 5])) { + return '${AppLocalizations.of(context)!.alarmDescriptionWeekday}$suffix'; } - return 'Every ${weekdays.where((weekday) => alarmWeekdays.contains(weekday)).map((weekday) => weekday.displayName).join(', ')}$suffix'; + final weekdaysString = weekdays + .where((weekday) => alarmWeekdays.contains(weekday)) + .map((weekday) => weekday.getDisplayName(context)) + .join(', '); + return '${AppLocalizations.of(context)!.alarmDescriptionWeekly(weekdaysString)}$suffix'; case DatesAlarmSchedule: List dates = alarm.dates; - return 'On ${DateFormat(dateFormat).format(dates[0])}${dates.length > 1 ? ' and ${dates.length - 1} other date${dates.length > 2 ? 's' : ''} ' : ''}$suffix'; + return '${AppLocalizations.of(context)!.alarmDescriptionDates(dates.length - 1, DateFormat(dateFormat).format(dates[0]))}$suffix'; + /* return 'On ${DateFormat(dateFormat).format(dates[0])}${dates.length > 1 ? ' and ${dates.length - 1} other date${dates.length > 2 ? 's' : ''} ' : ''}$suffix'; */ case RangeAlarmSchedule: DateTime rangeStart = alarm.startDate; DateTime rangeEnd = alarm.endDate; @@ -72,9 +79,9 @@ String getAlarmScheduleDescription(BuildContext context, Alarm alarm, endString = DateFormat('d MMM').format(rangeEnd); } } - - return '${interval == RangeInterval.daily ? "Daily" : "Weekly"} from $startString to $endString$suffix'; + return '${AppLocalizations.of(context)!.alarmDescriptionRange(endString, interval == RangeInterval.daily ? "daily" : "weekly", startString)}$suffix'; + // return '${interval == RangeInterval.daily ? "Daily" : "Weekly"} from $startString to $endString$suffix'; default: - return 'Not scheduled'; + return AppLocalizations.of(context)!.alarmDescriptionNotScheduled; } } diff --git a/lib/alarm/widgets/alarm_card.dart b/lib/alarm/widgets/alarm_card.dart index 6e637a94..3b71298a 100644 --- a/lib/alarm/widgets/alarm_card.dart +++ b/lib/alarm/widgets/alarm_card.dart @@ -11,6 +11,7 @@ import 'package:clock_app/common/widgets/clock/clock_display.dart'; import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class AlarmCard extends StatefulWidget { const AlarmCard({ @@ -109,7 +110,7 @@ class _AlarmCardState extends State { ); } return TextButton( - child: Text("Dismiss", + child: Text(AppLocalizations.of(context)!.dismissAlarmButton, maxLines: 1, style: textTheme.labelLarge?.copyWith(color: colorScheme.primary)), onPressed: () async { @@ -204,12 +205,12 @@ class _AlarmCardState extends State { CardEditMenu(actions: [ if (widget.alarm.isDeletable) getDeletePopupAction(context, widget.onPressDelete), - getDuplicatePopupAction(widget.onPressDuplicate), + getDuplicatePopupAction(context, widget.onPressDuplicate), if (widget.alarm.canBeSkipped) PopupAction( widget.alarm.shouldSkipNextAlarm - ? "Cancel Skip" - : "Skip Next Alarm", + ? AppLocalizations.of(context)!.cancelSkipAlarmButton + : AppLocalizations.of(context)!.skipAlarmButton, () { if (widget.alarm.shouldSkipNextAlarm) { widget.onSkipChange(false); diff --git a/lib/alarm/widgets/alarm_task_card.dart b/lib/alarm/widgets/alarm_task_card.dart index 07b7aacd..8db45cfc 100644 --- a/lib/alarm/widgets/alarm_task_card.dart +++ b/lib/alarm/widgets/alarm_task_card.dart @@ -48,7 +48,7 @@ class AlarmTaskCard extends StatelessWidget { if (onPressDelete != null) getDeletePopupAction(context, onPressDelete!), if (onPressDuplicate != null) - getDuplicatePopupAction(onPressDuplicate!), + getDuplicatePopupAction(context, onPressDuplicate!), ]), if (!isAddCard) Icon(FluxIcons.settings, color: colorScheme.onSurface), diff --git a/lib/audio/logic/audio_session.dart b/lib/audio/logic/audio_session.dart index bd7a9912..35abc10c 100644 --- a/lib/audio/logic/audio_session.dart +++ b/lib/audio/logic/audio_session.dart @@ -7,6 +7,7 @@ Future initializeAudioSession( androidAudioAttributes: AndroidAudioAttributes( usage: usage, contentType: AndroidAudioContentType.music, + ), )); } diff --git a/lib/audio/types/audio.dart b/lib/audio/types/audio.dart deleted file mode 100644 index 2d950589..00000000 --- a/lib/audio/types/audio.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'dart:convert'; - -import 'package:clock_app/common/types/json.dart'; - -// class Audio { -// final String id; -// final String title; -// final String uri; - -// const Audio({ -// required this.id, -// required this.title, -// required this.uri, -// }); - -// factory Audio.fromJson(Json json) => Audio( -// id: json != null ? json['id'] ?? '' : '', -// title: json != null ? json['title'] ?? 'Unknown' : 'Unknown', -// uri: json != null ? json['uri'] ?? '' : '', -// ); - -// Json toJson() => { -// 'id': id, -// 'title': title, -// 'uri': uri, -// }; - -// factory Audio.fromEncodedJson(String encodedJson) => -// Audio.fromJson(json.decode(encodedJson)); -// String toEncodedJson() => json.encode(toJson()); -// @override -// String toString() { -// return 'Ringtone{id: $id, title: $title, uri: $uri}'; -// } - -// Audio copyWith({ -// String? id, -// String? title, -// String? uri, -// }) { -// return Audio( -// id: id ?? this.id, -// title: title ?? this.title, -// uri: uri ?? this.uri, -// ); -// } -// } diff --git a/lib/audio/types/ringtone_manager.dart b/lib/audio/types/ringtone_manager.dart index af7edbd4..03fb34f6 100644 --- a/lib/audio/types/ringtone_manager.dart +++ b/lib/audio/types/ringtone_manager.dart @@ -1,18 +1,8 @@ -import 'package:clock_app/audio/types/audio.dart'; -import 'package:clock_app/common/types/file_item.dart'; -import 'package:clock_app/common/utils/list_storage.dart'; -import 'package:clock_app/settings/data/settings_schema.dart'; -import 'package:flutter_system_ringtones/flutter_system_ringtones.dart'; - class RingtoneManager { - // static List _ringtones = []; - // static List _customRingtones = []; - static String _lastPlayedRingtoneUri = ""; + static String _lastPlayedRingtoneUri = ""; static final List _listeners = []; - // static List get ringtones => _ringtones; - // static List get customRingtones => _customRingtones; static List get listeners => _listeners; static String get lastPlayedRingtoneUri => _lastPlayedRingtoneUri; static set lastPlayedRingtoneUri(String uri) { @@ -29,17 +19,4 @@ class RingtoneManager { static void removeListener(void Function() listener) { _listeners.remove(listener); } - - // static Future updateCustomRingtones() async { - // _customRingtones = await loadList('ringtones'); - // } - - // static Future initialize() async { - // if (_ringtones.isEmpty) { - // _ringtones = await getSystemRingtones(); - // } - // if (_customRingtones.isEmpty) { - // _customRingtones = await loadList('ringtones'); - // } - // } } diff --git a/lib/audio/types/ringtone_player.dart b/lib/audio/types/ringtone_player.dart index bfb3db6c..fd8430e3 100644 --- a/lib/audio/types/ringtone_player.dart +++ b/lib/audio/types/ringtone_player.dart @@ -1,15 +1,9 @@ -import 'dart:io'; -import 'dart:math'; - import 'package:audio_session/audio_session.dart'; import 'package:clock_app/alarm/types/alarm.dart'; import 'package:clock_app/audio/logic/audio_session.dart'; import 'package:clock_app/audio/types/ringtone_manager.dart'; -import 'package:clock_app/common/types/file_item.dart'; -import 'package:clock_app/common/utils/list_storage.dart'; import 'package:clock_app/timer/types/timer.dart'; import 'package:just_audio/just_audio.dart'; -import 'package:pick_or_save/pick_or_save.dart'; import 'package:vibration/vibration.dart'; class RingtonePlayer { diff --git a/lib/common/data/weekdays.dart b/lib/common/data/weekdays.dart index 746fe87a..7d507263 100644 --- a/lib/common/data/weekdays.dart +++ b/lib/common/data/weekdays.dart @@ -1,11 +1,19 @@ import 'package:clock_app/common/types/weekday.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -const List weekdays = [ - Weekday(1, 'M', 'Mon'), - Weekday(2, 'T', 'Tue'), - Weekday(3, 'W', 'Wed'), - Weekday(4, 'T', 'Thu'), - Weekday(5, 'F', 'Fri'), - Weekday(6, 'S', 'Sat'), - Weekday(7, 'S', 'Sun'), +List weekdays = [ + Weekday(1, (context) => AppLocalizations.of(context)!.mondayLetter, + (context) => AppLocalizations.of(context)!.mondayShort), + Weekday(2, (context) => AppLocalizations.of(context)!.tuesdayLetter, + (context) => AppLocalizations.of(context)!.tuesdayShort), + Weekday(3, (context) => AppLocalizations.of(context)!.wednesdayLetter, + (context) => AppLocalizations.of(context)!.wednesdayShort), + Weekday(4, (context) => AppLocalizations.of(context)!.thursdayLetter, + (context) => AppLocalizations.of(context)!.thursdayShort), + Weekday(5, (context) => AppLocalizations.of(context)!.fridayLetter, + (context) => AppLocalizations.of(context)!.fridayShort), + Weekday(6, (context) => AppLocalizations.of(context)!.saturdayLetter, + (context) => AppLocalizations.of(context)!.saturdayShort), + Weekday(7, (context) => AppLocalizations.of(context)!.sundayLetter, + (context) => AppLocalizations.of(context)!.sundayShort), ]; diff --git a/lib/common/types/weekday.dart b/lib/common/types/weekday.dart index 1ca08af0..06160441 100644 --- a/lib/common/types/weekday.dart +++ b/lib/common/types/weekday.dart @@ -1,7 +1,9 @@ +import 'package:flutter/material.dart'; + class Weekday { final int id; - final String abbreviation; - final String displayName; + final String Function(BuildContext) getAbbreviation; + final String Function(BuildContext) getDisplayName; - const Weekday(this.id, this.abbreviation, this.displayName); + const Weekday(this.id, this.getAbbreviation, this.getDisplayName); } diff --git a/lib/common/utils/popup_action.dart b/lib/common/utils/popup_action.dart index 32c321c9..7e166c8f 100644 --- a/lib/common/utils/popup_action.dart +++ b/lib/common/utils/popup_action.dart @@ -1,11 +1,13 @@ import 'package:clock_app/common/types/popup_action.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + PopupAction getDeletePopupAction(BuildContext context, Function callback) { - return PopupAction("Delete", callback, Icons.delete_rounded, + return PopupAction(AppLocalizations.of(context)!.deleteButton, callback, Icons.delete_rounded, Theme.of(context).colorScheme.error); } -PopupAction getDuplicatePopupAction(Function callback) { - return PopupAction("Duplicate", callback, Icons.copy_rounded); +PopupAction getDuplicatePopupAction(BuildContext context, Function callback) { + return PopupAction(AppLocalizations.of(context)!.duplicateButton, callback, Icons.copy_rounded); } diff --git a/lib/common/utils/weekday_utils.dart b/lib/common/utils/weekday_utils.dart index 24c1996a..66eaac36 100644 --- a/lib/common/utils/weekday_utils.dart +++ b/lib/common/utils/weekday_utils.dart @@ -1,12 +1,12 @@ import 'package:clock_app/common/data/weekdays.dart'; import 'package:clock_app/common/types/weekday.dart'; -bool weekdaysContains(List alarmWeekdays, String name) { +bool weekdaysContains(List alarmWeekdays, int id) { Weekday weekday = - weekdays.firstWhere((weekday) => weekday.displayName == name); + weekdays.firstWhere((weekday) => weekday.id == id); return alarmWeekdays.contains(weekday); } -bool weekdaysContainsAll(List alarmWeekdays, List names) { - return names.every((name) => weekdaysContains(alarmWeekdays, name)); +bool weekdaysContainsAll(List alarmWeekdays, List ids) { + return ids.every((id) => weekdaysContains(alarmWeekdays, id)); } diff --git a/lib/common/widgets/action_pane.dart b/lib/common/widgets/action_pane.dart index b428218d..2773c304 100644 --- a/lib/common/widgets/action_pane.dart +++ b/lib/common/widgets/action_pane.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + ActionPane getDeleteActionPane(VoidCallback onDelete, BuildContext context) { final theme = Theme.of(context); @@ -18,7 +20,7 @@ ActionPane getDeleteActionPane(VoidCallback onDelete, BuildContext context) { children: [ Icon(Icons.delete, color: colorScheme.onError), const SizedBox(height: 4), - Text('Delete', + Text(AppLocalizations.of(context)!.deleteButton, style: textTheme.titleSmall?.copyWith( color: colorScheme.onError, )), @@ -49,7 +51,7 @@ ActionPane getDuplicateActionPane( children: [ Icon(Icons.copy_rounded, color: colorScheme.onPrimary), const SizedBox(height: 4), - Text('Duplicate', + Text(AppLocalizations.of(context)!.duplicateButton, style: textTheme.titleSmall?.copyWith( color: colorScheme.onPrimary, )), diff --git a/lib/common/widgets/fields/select_field/select_bottom_sheet.dart b/lib/common/widgets/fields/select_field/select_bottom_sheet.dart index 6228479d..f9491d9f 100644 --- a/lib/common/widgets/fields/select_field/select_bottom_sheet.dart +++ b/lib/common/widgets/fields/select_field/select_bottom_sheet.dart @@ -4,6 +4,8 @@ import 'package:clock_app/common/widgets/fields/select_field/option_cards/audio_ import 'package:clock_app/common/widgets/fields/select_field/option_cards/color_option_card.dart'; import 'package:clock_app/common/widgets/fields/select_field/option_cards/text_option_card.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class SelectBottomSheet extends StatelessWidget { const SelectBottomSheet({ @@ -147,7 +149,7 @@ class SelectBottomSheet extends StatelessWidget { ), TextButton(onPressed: (){ Navigator.of(context).pop(); - }, child: Text('Save', + }, child: Text(AppLocalizations.of(context)!.saveButton, style: textTheme.labelMedium?.copyWith( color:colorScheme.primary))), ]), diff --git a/lib/common/widgets/popup_menu.dart b/lib/common/widgets/popup_menu.dart deleted file mode 100644 index 913465b5..00000000 --- a/lib/common/widgets/popup_menu.dart +++ /dev/null @@ -1,202 +0,0 @@ -// import 'dart:core'; -// import 'dart:ui'; - -// import 'package:flutter/material.dart'; -// import 'package:popup_menu/src/grid_menu_layout.dart'; -// import 'package:popup_menu/src/list_menu_layout.dart'; -// import 'package:popup_menu/src/menu_config.dart'; -// import 'package:popup_menu/src/menu_layout.dart'; -// import 'package:popup_menu/src/triangle_painter.dart'; -// import 'package:popup_menu/src/utils.dart'; - -// enum MenuType { -// /// 格子 -// grid, - -// /// 单列 -// list -// } - -// typedef MenuClickCallback = void Function(MenuItemProvider item); - -// class CustomPopupMenu { -// OverlayEntry? _entry; -// late List items; - -// /// callback -// final VoidCallback? onDismiss; -// final MenuClickCallback? onClickMenu; -// final VoidCallback? onShow; - -// /// Cannot be null -// BuildContext context; - -// /// It's showing or not. -// bool _isShow = false; -// bool get isShow => _isShow; - -// final MenuConfig config; -// final Size _screenSize = window.physicalSize / window.devicePixelRatio; - -// CustomPopupMenu({ -// required this.context, -// required this.items, -// this.config = const MenuConfig(), -// this.onClickMenu, -// this.onDismiss, -// this.onShow, -// }); - -// MenuLayout? menuLayout; - -// void show({ -// Rect? rect, -// GlobalKey? widgetKey, -// }) { -// assert(rect != null || widgetKey != null, -// "'rect' and 'key' can't be both null"); - -// final attachRect = rect ?? getWidgetGlobalRect(widgetKey!); - -// if (config.type == MenuType.grid) { -// menuLayout = GridMenuLayout( -// config: config, -// items: items, -// onDismiss: dismiss, -// context: context, -// onClickMenu: onClickMenu, -// ); -// } else if (config.type == MenuType.list) { -// menuLayout = ListMenuLayout( -// config: config, -// items: items, -// onDismiss: dismiss, -// context: context, -// onClickMenu: onClickMenu, -// ); -// } - -// _LayoutP layoutp = _calculateOffset( -// context, -// attachRect, -// menuLayout!.width, -// menuLayout!.height, -// ); - -// _entry = OverlayEntry(builder: (context) { -// return build(layoutp, menuLayout!); -// }); - -// Overlay.of(context)!.insert(_entry!); -// _isShow = true; -// onShow?.call(); -// } - -// Widget build(_LayoutP layoutp, MenuLayout menu) { -// return GestureDetector( -// behavior: HitTestBehavior.translucent, -// onTap: () { -// dismiss(); -// }, -// onVerticalDragStart: (DragStartDetails details) { -// dismiss(); -// }, -// onHorizontalDragStart: (DragStartDetails details) { -// dismiss(); -// }, -// child: Material( -// color: Colors.transparent, -// elevation: 2, -// child: Stack( -// children: [ -// // triangle arrow -// Positioned( -// left: layoutp.attachRect.left + -// layoutp.attachRect.width / 2.0 - -// 7.5, -// top: layoutp.isDown -// ? layoutp.offset.dy + layoutp.height -// : layoutp.offset.dy - config.arrowHeight, -// child: CustomPaint( -// size: Size(15.0, config.arrowHeight), -// painter: TrianglePainter( -// isDown: layoutp.isDown, color: config.backgroundColor), -// ), -// ), -// // menu content -// Positioned( -// left: layoutp.offset.dx, -// top: layoutp.offset.dy, -// child: menu.build(), -// ) -// ], -// )), -// ); -// } - -// /// 计算布局位置 -// _LayoutP _calculateOffset( -// BuildContext context, -// Rect attachRect, -// double contentWidth, -// double contentHeight, -// ) { -// double dx = attachRect.left + attachRect.width / 2.0 - contentWidth / 2.0; -// if (dx < 10.0) { -// dx = 10.0; -// } - -// if (dx + contentWidth > _screenSize.width && dx > 10.0) { -// double tempDx = _screenSize.width - contentWidth - 10; -// if (tempDx > 10) { -// dx = tempDx; -// } -// } - -// double dy = attachRect.top - contentHeight; -// bool isDown = false; -// if (dy <= MediaQuery.of(context).padding.top + 10) { -// // The have not enough space above, show menu under the widget. -// dy = config.arrowHeight + attachRect.height + attachRect.top; -// isDown = false; -// } else { -// dy -= config.arrowHeight; -// isDown = true; -// } - -// return _LayoutP( -// width: contentWidth, -// height: contentHeight, -// attachRect: attachRect, -// offset: Offset(dx, dy), -// isDown: isDown, -// ); -// } - -// void dismiss() { -// if (!_isShow) { -// // Remove method should only be called once -// return; -// } - -// _entry?.remove(); -// _isShow = false; -// onDismiss?.call(); -// } -// } - -// class _LayoutP { -// double width; -// double height; -// Offset offset; -// Rect attachRect; -// bool isDown; - -// _LayoutP({ -// required this.width, -// required this.height, -// required this.offset, -// required this.attachRect, -// required this.isDown, -// }); -// } diff --git a/lib/common/widgets/spinner_time_picker.dart b/lib/common/widgets/spinner_time_picker.dart index 5f119da2..5ba2d64b 100644 --- a/lib/common/widgets/spinner_time_picker.dart +++ b/lib/common/widgets/spinner_time_picker.dart @@ -312,6 +312,8 @@ class _TimePickerSpinnerState extends State { @override Widget build(BuildContext context) { + + List contents = [ SizedBox( width: _getItemWidth(), diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2819755b..16b52fd1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -207,19 +207,6 @@ "@backupSettingGroupDescription": {}, "alarmWeekdaysSetting": "Week Days", "@alarmWeekdaysSetting": {}, - "mondayLetter": "M", - "@mondayLetter": {}, - "tuesdayLetter": "T", - "@tuesdayLetter": {}, - "wednesdayLetter": "W", - "@wednesdayLetter": {}, - "thursdayLetter": "T", - "@thursdayLetter": {}, - "fridayLetter": "F", - "@fridayLetter": {}, - "saturdayLetter": "S", - "@saturdayLetter": {}, - "sundayLetter": "S", "alarmDatesSetting": "Dates", "@alarmDatesSetting": {}, "alarmRangeSetting": "Date Range", @@ -376,6 +363,10 @@ "@duplicateButton": {}, "skipAlarmButton": "Skip Next Alarm", "@skipAlarmButton": {}, + "cancelSkipAlarmButton": "Cancel Skip", + "@cancelSkipAlarmButton": {}, + "dismissAlarmButton": "Dismiss", + "@dismissAlarmButton": {}, "allFilter": "All", "@allFilter": {}, "dateFilterGroup": "Date", @@ -462,6 +453,8 @@ "@stopwatchPrevious": {}, "alarmDescriptionWeekday": "Every weekday", "@alarmDescriptionWeekday": {}, + "alarmDescriptionWeekly": "Every {days}", + "@alarmDescriptionWeekly": {}, "stopwatchFastest": "Fastest", "@stopwatchFastest": {}, "alarmDescriptionDays": "On {days}", @@ -547,6 +540,61 @@ "creditsSettingGroup": "Credits", "@creditsSettingGroup": {}, "addLengthSetting": "Add Length", - "@addLengthSetting": {} - + "@addLengthSetting": {}, + "relativeTime": "{hours}h {relative, select, ahead{ahead} behind{behind} other{Other}}", + "@relativeTime": {}, + "sameTime": "Same time", + "@sameTime": {}, + "searchCityPlaceholder": "Search for a city", + "@searchCityPlaceholder": {}, + "durationPickerTitle": "Choose Duration", + "@durationPickerTitle": {}, + "editButton": "Edit", + "@editButton": {}, + "noLapsMessage": "No laps yet", + "@noLapsMessage": {}, + "elapsedTime": "Elapsed Time", + "@elapsedTime": {}, + "mondayFull": "Monday", + "@mondayFull": {}, + "tuesdayFull": "Tuesday", + "@tuesdayFull": {}, + "wednesdayFull": "Wednesday", + "@wednesdayFull": {}, + "thursdayFull": "Thursday", + "@thursdayFull": {}, + "fridayFull": "Friday", + "@fridayFull": {}, + "saturdayFull": "Saturday", + "@saturdayFull": {}, + "sundayFull": "Sunday", + "@sundayFull": {}, + "mondayShort": "Mon", + "@mondayShort": {}, + "tuesdayShort": "Tue", + "@tuesdayShort": {}, + "wednesdayShort": "Wed", + "@wednesdayShort": {}, + "thursdayShort": "Thu", + "@thursdayShort": {}, + "fridayShort": "Fri", + "@fridayShort": {}, + "saturdayShort": "Sat", + "@saturdayShort": {}, + "sundayShort": "Sun", + "@sundayShort": {}, + "mondayLetter": "M", + "@mondayLetter": {}, + "tuesdayLetter": "T", + "@tuesdayLetter": {}, + "wednesdayLetter": "W", + "@wednesdayLetter": {}, + "thursdayLetter": "T", + "@thursdayLetter": {}, + "fridayLetter": "F", + "@fridayLetter": {}, + "saturdayLetter": "S", + "@saturdayLetter": {}, + "sundayLetter": "S", + "@sundayLetter": {} } diff --git a/lib/settings/widgets/tag_card.dart b/lib/settings/widgets/tag_card.dart index c7a8a9da..7c3de9bf 100644 --- a/lib/settings/widgets/tag_card.dart +++ b/lib/settings/widgets/tag_card.dart @@ -43,7 +43,7 @@ class _TagCardState extends State { ), CardEditMenu(actions: [ getDeletePopupAction(context, widget.onPressDelete), - getDuplicatePopupAction(widget.onPressDuplicate), + getDuplicatePopupAction(context, widget.onPressDuplicate), ]), ], )); diff --git a/lib/stopwatch/screens/stopwatch_screen.dart b/lib/stopwatch/screens/stopwatch_screen.dart index 6ab7f3c2..a4645316 100644 --- a/lib/stopwatch/screens/stopwatch_screen.dart +++ b/lib/stopwatch/screens/stopwatch_screen.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:clock_app/common/types/list_controller.dart'; import 'package:clock_app/common/utils/list_storage.dart'; -import 'package:clock_app/common/widgets/linear_progress_bar.dart'; import 'package:clock_app/common/widgets/list/custom_list_view.dart'; import 'package:clock_app/common/widgets/fab.dart'; import 'package:clock_app/notifications/data/notification_channel.dart'; @@ -10,16 +9,14 @@ import 'package:clock_app/notifications/data/update_notification_intervals.dart' import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/settings/types/listener_manager.dart'; import 'package:clock_app/settings/types/setting.dart'; -import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/stopwatch/logic/stopwatch_notification.dart'; import 'package:clock_app/stopwatch/types/lap.dart'; import 'package:clock_app/stopwatch/types/stopwatch.dart'; import 'package:clock_app/stopwatch/widgets/lap_card.dart'; import 'package:clock_app/stopwatch/widgets/stopwatch_ticker.dart'; -import 'package:clock_app/timer/types/time_duration.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:timer_builder/timer_builder.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class StopwatchScreen extends StatefulWidget { @@ -150,7 +147,7 @@ class _StopwatchScreenState extends State { key: ValueKey(lap), lap: lap, ), - placeholderText: "No laps yet", + placeholderText: AppLocalizations.of(context)!.noLapsMessage, isDeleteEnabled: false, isDuplicateEnabled: false, isReorderable: false, diff --git a/lib/stopwatch/widgets/lap_card.dart b/lib/stopwatch/widgets/lap_card.dart index 5207d70a..5ce040a5 100644 --- a/lib/stopwatch/widgets/lap_card.dart +++ b/lib/stopwatch/widgets/lap_card.dart @@ -1,5 +1,7 @@ import 'package:clock_app/stopwatch/types/lap.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class LapCard extends StatefulWidget { const LapCard({super.key, required this.lap, this.onInit}); @@ -32,7 +34,7 @@ class _LapCardState extends State { Text(widget.lap.lapTime.toTimeString(showMilliseconds: true), style: Theme.of(context).textTheme.displaySmall), Text( - 'Elapsed Time: ${widget.lap.elapsedTime.toTimeString(showMilliseconds: true)}'), + '${AppLocalizations.of(context)!.elapsedTime}: ${widget.lap.elapsedTime.toTimeString(showMilliseconds: true)}'), ], ), ], diff --git a/lib/stopwatch/widgets/stopwatch_ticker.dart b/lib/stopwatch/widgets/stopwatch_ticker.dart index b542e065..5a3bae65 100644 --- a/lib/stopwatch/widgets/stopwatch_ticker.dart +++ b/lib/stopwatch/widgets/stopwatch_ticker.dart @@ -6,6 +6,8 @@ import 'package:clock_app/stopwatch/widgets/lap_comparer.dart'; import 'package:clock_app/timer/types/time_duration.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class StopwatchTicker extends StatefulWidget { const StopwatchTicker({super.key, required this.stopwatch}); @@ -106,7 +108,7 @@ class _StopwatchTickerState extends State { LapComparer( stopwatch: widget.stopwatch, comparisonLap: widget.stopwatch.previousLap, - label: "Previous", + label: AppLocalizations.of(context)!.stopwatchPrevious, color: Colors.blue, ), ], @@ -115,7 +117,7 @@ class _StopwatchTickerState extends State { LapComparer( stopwatch: widget.stopwatch, comparisonLap: widget.stopwatch.fastestLap, - label: "Fastest", + label: AppLocalizations.of(context)!.stopwatchFastest, color: Colors.red, ), ], @@ -124,7 +126,7 @@ class _StopwatchTickerState extends State { LapComparer( stopwatch: widget.stopwatch, comparisonLap: widget.stopwatch.slowestLap, - label: "Slowest", + label: AppLocalizations.of(context)!.stopwatchSlowest, color: Colors.orange, ), ], @@ -133,7 +135,7 @@ class _StopwatchTickerState extends State { LapComparer( stopwatch: widget.stopwatch, comparisonLap: widget.stopwatch.averageLap, - label: "Average", + label: AppLocalizations.of(context)!.stopwatchAverage, color: Colors.green, showLapNumber: false, ), diff --git a/lib/theme/widgets/theme_card.dart b/lib/theme/widgets/theme_card.dart index bfa0aebb..ca5bc643 100644 --- a/lib/theme/widgets/theme_card.dart +++ b/lib/theme/widgets/theme_card.dart @@ -74,7 +74,7 @@ class ThemeCard extends StatelessWidget { CardEditMenu(actions: [ if (themeItem.isDeletable) getDeletePopupAction(context, onPressDelete), - getDuplicatePopupAction(onPressDuplicate), + getDuplicatePopupAction(context,onPressDuplicate), ]), ], ), diff --git a/lib/timer/widgets/timer_card.dart b/lib/timer/widgets/timer_card.dart index 1fc64f7e..82f3e9d5 100644 --- a/lib/timer/widgets/timer_card.dart +++ b/lib/timer/widgets/timer_card.dart @@ -138,7 +138,7 @@ class _TimerCardState extends State { const Spacer(), CardEditMenu(actions: [ getDeletePopupAction(context, widget.onPressDelete), - getDuplicatePopupAction(widget.onPressDuplicate), + getDuplicatePopupAction(context, widget.onPressDuplicate), if (!widget.timer.isStopped) PopupAction( "Reset", diff --git a/lib/timer/widgets/timer_preset_card.dart b/lib/timer/widgets/timer_preset_card.dart index 92007e1c..192b618c 100644 --- a/lib/timer/widgets/timer_preset_card.dart +++ b/lib/timer/widgets/timer_preset_card.dart @@ -50,7 +50,7 @@ class _TimerPresetCardState extends State { ), CardEditMenu(actions: [ getDeletePopupAction(context, widget.onPressDelete), - getDuplicatePopupAction(widget.onPressDuplicate), + getDuplicatePopupAction(context, widget.onPressDuplicate), ]), ], )); From 34828c5282db4bbff32982e4ce47f7b8b2c6df14 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Tue, 7 May 2024 16:50:00 +0500 Subject: [PATCH 072/112] Localize clock screen --- lib/alarm/widgets/alarm_event_card.dart | 41 ++++++++++++--------- lib/clock/screens/search_city_screen.dart | 5 +-- lib/clock/widgets/timezone_card.dart | 15 +++++--- lib/clock/widgets/timezone_search_card.dart | 14 ++++++- lib/l10n/app_en.arb | 2 + 5 files changed, 50 insertions(+), 27 deletions(-) diff --git a/lib/alarm/widgets/alarm_event_card.dart b/lib/alarm/widgets/alarm_event_card.dart index 0134d4be..64b6076d 100644 --- a/lib/alarm/widgets/alarm_event_card.dart +++ b/lib/alarm/widgets/alarm_event_card.dart @@ -1,7 +1,5 @@ - import 'package:clock_app/alarm/types/alarm_event.dart'; import 'package:clock_app/common/types/notification_type.dart'; -import 'package:clock_app/common/widgets/clock/clock_display.dart'; import 'package:flutter/material.dart'; class AlarmEventCard extends StatelessWidget { @@ -18,25 +16,34 @@ class AlarmEventCard extends StatelessWidget { Color textColor = colorScheme.onSurface.withOpacity(0.8); return Column( - children: [ + children: [ Padding( padding: const EdgeInsets.only( - left: 16.0, - right: 16.0, - top: 8.0 , - bottom: 8.0), + left: 16.0, right: 16.0, top: 8.0, bottom: 8.0), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, children: [ - Text(event.isActive ? "Active" : "Inactive", style: textTheme.labelMedium?.copyWith(color: event.isActive ? colorScheme.primary : colorScheme.onSurface)), - Text('Scheduled for: ${event.startDate}', style: textTheme.labelMedium?.copyWith(color: textColor)), - Text('Type: ${event.notificationType == ScheduledNotificationType.alarm ? "Alarm" : "Timer"}', style: textTheme.labelMedium?.copyWith(color:textColor)), - Text('Created at: ${event.eventTime}', style: textTheme.labelMedium?.copyWith(color: textColor)), - Text('Description: ${event.description}', style: textTheme.labelMedium?.copyWith(color: textColor),maxLines: 5,), - Text('Schedule Id: ${event.scheduleId}', style: textTheme.labelMedium?.copyWith(color: textColor)), - - ], + Text(event.isActive ? "Active" : "Inactive", + style: textTheme.labelMedium?.copyWith( + color: event.isActive + ? colorScheme.primary + : colorScheme.onSurface)), + Text('Scheduled for: ${event.startDate}', + style: textTheme.labelMedium?.copyWith(color: textColor)), + Text( + 'Type: ${event.notificationType == ScheduledNotificationType.alarm ? "Alarm" : "Timer"}', + style: textTheme.labelMedium?.copyWith(color: textColor)), + Text('Created at: ${event.eventTime}', + style: textTheme.labelMedium?.copyWith(color: textColor)), + Text( + 'Description: ${event.description}', + style: textTheme.labelMedium?.copyWith(color: textColor), + maxLines: 5, + ), + Text('Schedule Id: ${event.scheduleId}', + style: textTheme.labelMedium?.copyWith(color: textColor)), + ], ), ), ], diff --git a/lib/clock/screens/search_city_screen.dart b/lib/clock/screens/search_city_screen.dart index b7bd7a76..db172c7f 100644 --- a/lib/clock/screens/search_city_screen.dart +++ b/lib/clock/screens/search_city_screen.dart @@ -1,8 +1,7 @@ import 'package:clock_app/navigation/widgets/app_top_bar.dart'; import 'package:flutter/material.dart'; - import 'package:sqflite/sqflite.dart'; - +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:clock_app/common/utils/list_storage.dart'; import 'package:clock_app/common/data/paths.dart'; import 'package:clock_app/clock/widgets/timezone_search_card.dart'; @@ -77,7 +76,7 @@ class _SearchCityScreenState extends State { focusedBorder: const OutlineInputBorder(borderSide: BorderSide.none), fillColor: Colors.transparent, - hintText: 'Search for a city', + hintText: AppLocalizations.of(context)!.searchCityPlaceholder, hintStyle: Theme.of(context).textTheme.bodyLarge, ), textAlignVertical: TextAlignVertical.center, diff --git a/lib/clock/widgets/timezone_card.dart b/lib/clock/widgets/timezone_card.dart index 6851d53e..f06be9d5 100644 --- a/lib/clock/widgets/timezone_card.dart +++ b/lib/clock/widgets/timezone_card.dart @@ -1,11 +1,11 @@ import 'package:clock_app/clock/types/city.dart'; -import 'package:clock_app/clock/widgets/timezone_card_content.dart'; import 'package:clock_app/common/utils/popup_action.dart'; import 'package:clock_app/common/widgets/card_edit_menu.dart'; import 'package:clock_app/common/widgets/clock/clock.dart'; import 'package:flutter/material.dart'; import 'package:timer_builder/timer_builder.dart'; import 'package:timezone/timezone.dart' as timezone; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class TimeZoneCard extends StatelessWidget { TimeZoneCard({ @@ -28,15 +28,18 @@ class TimeZoneCard extends StatelessWidget { return n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 1); } - String _getOffsetDescription() { + String _getOffsetDescription(BuildContext context) { DateTime currentTime = DateTime.now(); DateTime cityTime = timezone.TZDateTime.now(_timezoneLocation); String hourDifference = _formatTimeOffset(_offset.abs()); - String hourLabel = _offset == 1 ? 'h' : 'h'; String relativeLabel = _offset < 0 ? 'behind' : 'ahead'; - String differentOffsetLabel = '$hourDifference$hourLabel $relativeLabel'; - String offsetLabel = _offset != 0 ? differentOffsetLabel : 'Same time'; + String differentOffsetLabel = AppLocalizations.of(context)! + .relativeTime(hourDifference, relativeLabel); + // '$hourDifference$hourLabel $relativeLabel'; + String offsetLabel = _offset != 0 + ? differentOffsetLabel + : AppLocalizations.of(context)!.sameTime; String differentDayLabel = currentTime.day < cityTime.day ? ' (next day)' @@ -89,7 +92,7 @@ class TimeZoneCard extends StatelessWidget { const Duration(seconds: 1), builder: (context) { return Text( - _getOffsetDescription(), + _getOffsetDescription(context), style: textTheme.bodyMedium?.copyWith( height: 0.5, color: colorScheme.onSurface.withOpacity(0.8)), diff --git a/lib/clock/widgets/timezone_search_card.dart b/lib/clock/widgets/timezone_search_card.dart index 6510f82e..5cbe33f9 100644 --- a/lib/clock/widgets/timezone_search_card.dart +++ b/lib/clock/widgets/timezone_search_card.dart @@ -6,6 +6,7 @@ import 'package:clock_app/common/widgets/clock/clock.dart'; import 'package:flutter/material.dart'; import 'package:timer_builder/timer_builder.dart'; import 'package:timezone/timezone.dart' as timezone; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class TimeZoneSearchCard extends StatelessWidget { TimeZoneSearchCard( @@ -23,6 +24,9 @@ class TimeZoneSearchCard extends StatelessWidget { @override Widget build(BuildContext context) { + final gmtOffset = timezoneLocation.currentTimeZone.offset; + final gmtOffsetHour = gmtOffset / 3600000; + final gmtOffsetMinutes = (gmtOffset % 3600000) / 60000; Color? textColor = disabled ? Theme.of(context).colorScheme.onBackground.withOpacity(0.6) : null; @@ -34,7 +38,8 @@ class TimeZoneSearchCard extends StatelessWidget { ScaffoldMessenger.of(context).removeCurrentSnackBar(); if (disabled) { - showSnackBar(context, 'This city is already in your favorites.'); + showSnackBar( + context, AppLocalizations.of(context)!.cityAlreadyInFavorites); } else { onTap(); } @@ -83,6 +88,13 @@ class TimeZoneSearchCard extends StatelessWidget { scale: 0.3, color: textColor, ), + const SizedBox(height: 4), + Text( + 'GMT ${gmtOffset > 0 ? '+' : '-'}${gmtOffsetHour.abs().toStringAsFixed(0).padLeft(2, '0')}:${gmtOffsetMinutes.toStringAsFixed(0).padLeft(2, '0')}', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: textColor, + ), + ), ], ), ], diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 16b52fd1..017616c7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -547,6 +547,8 @@ "@sameTime": {}, "searchCityPlaceholder": "Search for a city", "@searchCityPlaceholder": {}, + "cityAlreadyInFavorites": "This city is already in your favorites", + "@cityAlreadyInFavorites": {}, "durationPickerTitle": "Choose Duration", "@durationPickerTitle": {}, "editButton": "Edit", From f426c78e0eeaa1c7dba9c41fa2b41f679fef387f Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Tue, 7 May 2024 17:03:56 +0500 Subject: [PATCH 073/112] Localize timer screen --- lib/common/widgets/customize_screen.dart | 13 +++++++------ lib/common/widgets/modal.dart | 6 ++++-- lib/settings/widgets/string_setting_card.dart | 4 +++- lib/timer/screens/timer_fullscreen.dart | 5 ++--- lib/timer/widgets/duration_picker.dart | 6 ++++-- lib/timer/widgets/timer_picker.dart | 14 +++++++++----- 6 files changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/common/widgets/customize_screen.dart b/lib/common/widgets/customize_screen.dart index 394efe82..ec581693 100644 --- a/lib/common/widgets/customize_screen.dart +++ b/lib/common/widgets/customize_screen.dart @@ -1,6 +1,7 @@ import 'package:clock_app/common/types/list_item.dart'; import 'package:clock_app/navigation/widgets/app_top_bar.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class CustomizeState { bool isSaved = false; @@ -47,7 +48,7 @@ class _CustomizeScreenState Navigator.pop(context); }, child: Text( - "Cancel", + AppLocalizations.of(context)!.cancelButton, style: TextStyle( color: colorScheme.onSurface.withOpacity(0.6), ), @@ -61,7 +62,7 @@ class _CustomizeScreenState _isSaved = true; Navigator.pop(context, _item); }, - child: const Text("Save"), + child: Text(AppLocalizations.of(context)!.saveButton), ), ) ]), @@ -76,21 +77,21 @@ class _CustomizeScreenState builder: (buildContext) { return AlertDialog( actionsPadding: const EdgeInsets.only(bottom: 6, right: 10), - content: const Text("Do you want to leave without saving?"), + content: Text(AppLocalizations.of(context)!.saveReminderAlert), actions: [ TextButton( onPressed: () { Navigator.pop(context, false); }, - child: Text("No", + child: Text(AppLocalizations.of(context)!.noButton, style: TextStyle(color: colorScheme.primary)), ), TextButton( onPressed: () { Navigator.pop(context, true); }, - child: - Text("Yes", style: TextStyle(color: colorScheme.error)), + child: Text(AppLocalizations.of(context)!.yesButton, + style: TextStyle(color: colorScheme.error)), ), ], ); diff --git a/lib/common/widgets/modal.dart b/lib/common/widgets/modal.dart index 5ca669a4..1f66b09c 100644 --- a/lib/common/widgets/modal.dart +++ b/lib/common/widgets/modal.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class ModalAction { final String title; @@ -53,7 +55,7 @@ class Modal extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( - child: Text('Cancel', + child: Text(AppLocalizations.of(context)!.cancelButton, style: textTheme.labelMedium?.copyWith( color: colorScheme.onBackground.withOpacity(0.6))), onPressed: () { @@ -74,7 +76,7 @@ class Modal extends StatelessWidget { ], TextButton( child: Text( - 'Save', + AppLocalizations.of(context)!.saveButton, style: textTheme.labelMedium?.copyWith( color: isSaveEnabled ? colorScheme.primary diff --git a/lib/settings/widgets/string_setting_card.dart b/lib/settings/widgets/string_setting_card.dart index 8d582395..53aa5d1b 100644 --- a/lib/settings/widgets/string_setting_card.dart +++ b/lib/settings/widgets/string_setting_card.dart @@ -2,6 +2,8 @@ import 'package:clock_app/common/widgets/card_container.dart'; import 'package:clock_app/common/widgets/fields/input_field.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class StringSettingCard extends StatefulWidget { final StringSetting setting; @@ -32,7 +34,7 @@ class _StringSettingCardState extends State { }); widget.onChanged?.call(widget.setting.value); }, - hintText: "Add a label", + hintText: AppLocalizations.of(context)!.labelFieldPlaceholder, ); return widget.showAsCard ? CardContainer(child: input) : input; diff --git a/lib/timer/screens/timer_fullscreen.dart b/lib/timer/screens/timer_fullscreen.dart index 4e088667..ea6a0a5d 100644 --- a/lib/timer/screens/timer_fullscreen.dart +++ b/lib/timer/screens/timer_fullscreen.dart @@ -9,6 +9,7 @@ import 'package:clock_app/timer/types/timer.dart'; import 'package:clock_app/timer/utils/timer_id.dart'; import 'package:clock_app/timer/widgets/timer_progress_bar.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class TimerFullscreen extends StatefulWidget { const TimerFullscreen({ @@ -80,7 +81,7 @@ class _TimerFullscreenState extends State { }); } }, - child: const Text("Edit")) + child: Text(AppLocalizations.of(context)!.editButton)) ]), body: OrientationBuilder(builder: (context, orientation) { double buttonSize = orientation == Orientation.portrait ? 32 : 32; @@ -88,8 +89,6 @@ class _TimerFullscreenState extends State { double width = MediaQuery.of(context).size.width - 64; double height = MediaQuery.of(context).size.height - 136; - print('$width $height'); - return SizedBox( width: orientation == Orientation.portrait ? double.infinity : null, height: orientation == Orientation.landscape ? double.infinity : null, diff --git a/lib/timer/widgets/duration_picker.dart b/lib/timer/widgets/duration_picker.dart index a6157313..ddc71e1c 100644 --- a/lib/timer/widgets/duration_picker.dart +++ b/lib/timer/widgets/duration_picker.dart @@ -3,6 +3,8 @@ import 'package:clock_app/timer/logic/edit_duration_picker_mode.dart'; import 'package:clock_app/timer/logic/get_duration_picker.dart'; import 'package:clock_app/timer/types/time_duration.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + Future showDurationPicker( BuildContext context, { @@ -32,7 +34,7 @@ Future showDurationPicker( children: [ // const SizedBox(width: 8), Text( - "Choose Duration", + AppLocalizations.of(context)!.durationPickerTitle, style: TimePickerTheme.of(context).helpTextStyle ?? Theme.of(context).textTheme.labelSmall, ), @@ -41,7 +43,7 @@ Future showDurationPicker( onPressed: () => editDurationPickerMode( context, () => setState(() {})), child: Text( - "Mode", + AppLocalizations.of(context)!.timePickerModeButton, style: Theme.of(context) .textTheme .titleSmall diff --git a/lib/timer/widgets/timer_picker.dart b/lib/timer/widgets/timer_picker.dart index c5bc0718..32f54f37 100644 --- a/lib/timer/widgets/timer_picker.dart +++ b/lib/timer/widgets/timer_picker.dart @@ -9,6 +9,8 @@ import 'package:clock_app/timer/types/time_duration.dart'; import 'package:clock_app/timer/types/timer.dart'; import 'package:clock_app/timer/types/timer_preset.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + Future?> showTimerPicker( BuildContext context, { @@ -37,7 +39,7 @@ Future?> showTimerPicker( isSaveEnabled: timer.duration.inSeconds > 0, // title: "Choose Duration", additionalAction: ModalAction( - title: "Customize", + title: AppLocalizations.of(context)!.customizeButton, onPressed: () async { Navigator.of(context).pop(PickerResult(timer, true)); }, @@ -52,7 +54,9 @@ Future?> showTimerPicker( Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text("Presets", style: textTheme.labelMedium), + Text(AppLocalizations.of(context)!.presetsSetting, + + style: textTheme.labelMedium), const Spacer(), TextButton( style: TextButton.styleFrom( @@ -79,7 +83,7 @@ Future?> showTimerPicker( }); }, child: Text( - "Edit", + AppLocalizations.of(context)!.editButton, style: textTheme.labelSmall ?.copyWith(color: colorScheme.primary), ), @@ -128,7 +132,7 @@ Future?> showTimerPicker( Widget title() => Row( children: [ Text( - "Choose Duration", + AppLocalizations.of(context)!.durationPickerTitle, style: TimePickerTheme.of(context).helpTextStyle ?? Theme.of(context).textTheme.labelSmall, ), @@ -137,7 +141,7 @@ Future?> showTimerPicker( onPressed: () => editDurationPickerMode( context, () => setState(() {})), child: Text( - "Mode", + AppLocalizations.of(context)!.timePickerModeButton, style: Theme.of(context) .textTheme .titleSmall From d99dbd6d0bfff1e96f739aca3a62070fbb03ae68 Mon Sep 17 00:00:00 2001 From: Potato Cinna Date: Tue, 7 May 2024 10:15:58 +0000 Subject: [PATCH 074/112] Translated using Weblate (French) Currently translated at 94.7% (254 of 268 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 314 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 306 insertions(+), 8 deletions(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index eb949d74..6007b4c0 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -35,7 +35,7 @@ "@appearanceSettingGroup": {}, "accessibilitySettingGroup": "Accessibilité", "@accessibilitySettingGroup": {}, - "backupSettingGroup": "Sauvegarde", + "backupSettingGroup": "Paramètres", "@backupSettingGroup": {}, "developerOptionsSettingGroup": "Options pour les développeurs", "@developerOptionsSettingGroup": {}, @@ -75,11 +75,11 @@ "@selectTime": {}, "cancelButton": "Annuler", "@cancelButton": {}, - "saveButton": "Bouton d'enregistrement", + "saveButton": "Enregistrer", "@saveButton": {}, - "labelField": "Nom", + "labelField": "Libellé", "@labelField": {}, - "labelFieldPlaceholder": "Ajouter un nom", + "labelFieldPlaceholder": "Ajouter un libellé", "@labelFieldPlaceholder": {}, "scheduleTypeField": "Type", "@scheduleTypeField": {}, @@ -101,7 +101,7 @@ "@reliabilitySettingGroup": {}, "alarmScheduleSettingGroup": "Planifier", "@alarmScheduleSettingGroup": {}, - "soundSettingGroup": "Son et vibration", + "soundSettingGroup": "Son", "@soundSettingGroup": {}, "settingGroupMore": "Paramètres supplémentaires", "@settingGroupMore": {}, @@ -157,7 +157,7 @@ "@alarmDescriptionEveryDay": {}, "alarmDescriptionWeekend": "Tous les weekends", "@alarmDescriptionWeekend": {}, - "stopwatchPrevious": "Précedent", + "stopwatchPrevious": "Précédent", "@stopwatchPrevious": {}, "alarmDescriptionWeekday": "Tous les jours", "@alarmDescriptionWeekday": {}, @@ -201,7 +201,7 @@ "@autoStartSettingDescription": {}, "pickerRings": "Sonneries", "@pickerRings": {}, - "swipeActionSetting": "Action de balayage", + "swipeActionSetting": "Action de glisser", "@swipeActionSetting": {}, "pickerSpinner": "Tourniquet", "@pickerSpinner": {}, @@ -230,5 +230,303 @@ "autoStartSetting": "Démarrage automatique", "@autoStartSetting": {}, "animationSettingGroup": "Animations", - "@animationSettingGroup": {} + "@animationSettingGroup": {}, + "defaultLabel": "Défaut", + "@defaultLabel": {}, + "versionLabel": "Version", + "@versionLabel": {}, + "licenseLabel": "Licence", + "@licenseLabel": {}, + "emailLabel": "Adresse mail", + "@emailLabel": {}, + "viewOnGithubLabel": "Afficher sur GitHub", + "@viewOnGithubLabel": {}, + "scheduleTypeDate": "Sur des dates spécifiques", + "@scheduleTypeDate": {}, + "soundAndVibrationSettingGroup": "Son et Vibration", + "@soundAndVibrationSettingGroup": {}, + "audioChannelAlarm": "Alarme", + "@audioChannelAlarm": {}, + "audioChannelNotification": "Notification", + "@audioChannelNotification": {}, + "mathEasyDifficulty": "Facile (X + Y)", + "@mathEasyDifficulty": {}, + "mathMediumDifficulty": "Intermédiaire (X × Y)", + "@mathMediumDifficulty": {}, + "mathHardDifficulty": "Difficile (X × Y + Z)", + "@mathHardDifficulty": {}, + "mathVeryHardDifficulty": "Très difficile (X × Y × Z)", + "@mathVeryHardDifficulty": {}, + "numberOfProblemsSetting": "Nombre de problèmes", + "@numberOfProblemsSetting": {}, + "tomorrowFilter": "Demain", + "@tomorrowFilter": {}, + "stateFilterGroup": "État", + "@stateFilterGroup": {}, + "timeOfDayAsc": "Les heures les plus tôt en premier", + "@timeOfDayAsc": {}, + "disableAllFilteredAlarmsAction": "Désactiver toutes les alarmes filtrées", + "@disableAllFilteredAlarmsAction": {}, + "skipAllFilteredAlarmsAction": "Ignorer toutes les alarmes filtrées", + "@skipAllFilteredAlarmsAction": {}, + "filtersSettingGroup": "Filtres", + "@filtersSettingGroup": {}, + "showFiltersSetting": "Montrer les filtres", + "@showFiltersSetting": {}, + "timerDefaultSettingGroupDescription": "Définir des valeurs par défaut pour les nouveaux minuteurs", + "@timerDefaultSettingGroupDescription": {}, + "stopwatchTimeFormatSettingGroup": "Format de l'heure", + "@stopwatchTimeFormatSettingGroup": {}, + "stopwatchShowMillisecondsSetting": "Afficher les millisecondes", + "@stopwatchShowMillisecondsSetting": {}, + "swipActionCardAction": "Actions des cartes", + "@swipActionCardAction": {}, + "animationSpeedSetting": "Vitesse de l'animation", + "@animationSpeedSetting": {}, + "extraAnimationSetting": "Animations supplémentaires", + "@extraAnimationSetting": {}, + "nameField": "Nom", + "@nameField": {}, + "previewLabel": "Aperçu", + "@previewLabel": {}, + "colorSetting": "Couleur", + "@colorSetting": {}, + "textColorSetting": "Texte", + "@textColorSetting": {}, + "colorSchemeNamePlaceholder": "Palette de couleurs", + "@colorSchemeNamePlaceholder": {}, + "colorSchemeBackgroundSettingGroup": "Arrière-plan", + "@colorSchemeBackgroundSettingGroup": {}, + "colorSchemeAccentSettingGroup": "Couleur d'accentuation", + "@colorSchemeAccentSettingGroup": {}, + "colorSchemeErrorSettingGroup": "Erreur", + "@colorSchemeErrorSettingGroup": {}, + "colorSchemeCardSettingGroup": "Carte", + "@colorSchemeCardSettingGroup": {}, + "colorSchemeOutlineSettingGroup": "Contour", + "@colorSchemeOutlineSettingGroup": {}, + "colorSchemeShadowSettingGroup": "Ombre", + "@colorSchemeShadowSettingGroup": {}, + "colorSchemeUseAccentAsOutlineSetting": "Utiliser la couleur accentuée comme contour", + "@colorSchemeUseAccentAsOutlineSetting": {}, + "colorSchemeUseAccentAsShadowSetting": "Utiliser la couleur accentuée comme ombre", + "@colorSchemeUseAccentAsShadowSetting": {}, + "styleThemeNamePlaceholder": "Style de thème", + "@styleThemeNamePlaceholder": {}, + "styleThemeShadowSettingGroup": "Ombre", + "@styleThemeShadowSettingGroup": {}, + "styleThemeShapeSettingGroup": "Forme", + "@styleThemeShapeSettingGroup": {}, + "styleThemeRadiusSetting": "Arrondi des angles", + "@styleThemeRadiusSetting": {}, + "styleThemeOpacitySetting": "Opacité", + "@styleThemeOpacitySetting": {}, + "styleThemeBlurSetting": "Flou", + "@styleThemeBlurSetting": {}, + "styleThemeSpreadSetting": "Réglage de propagation du style de thème", + "@styleThemeSpreadSetting": {}, + "styleThemeOutlineSettingGroup": "Contour", + "@styleThemeOutlineSettingGroup": {}, + "styleThemeOutlineWidthSetting": "Largeur", + "@styleThemeOutlineWidthSetting": {}, + "showIstantAlarmButtonSetting": "Afficher le bouton d'alarme instantanée", + "@showIstantAlarmButtonSetting": {}, + "showIstantTimerButtonSetting": "Afficher le bouton de minuterie instantanée", + "@showIstantTimerButtonSetting": {}, + "logsSettingGroup": "Logs", + "@logsSettingGroup": {}, + "alarmLogSetting": "Logs des alarmes", + "@alarmLogSetting": {}, + "resetButton": "Remettre à zéro", + "@resetButton": {}, + "cardLabel": "Carte", + "@cardLabel": {}, + "accentLabel": "Thème", + "@accentLabel": {}, + "errorLabel": "Erreur", + "@errorLabel": {}, + "materialBrightnessSystem": "Système", + "@materialBrightnessSystem": {}, + "materialBrightnessLight": "Lumière", + "@materialBrightnessLight": {}, + "materialBrightnessDark": "Sombre", + "@materialBrightnessDark": {}, + "accentColorSetting": "Couleur accentuée", + "@accentColorSetting": {}, + "alarmWeekdaysSetting": "Jours de la semaine", + "@alarmWeekdaysSetting": {}, + "mondayLetter": "L", + "@mondayLetter": {}, + "tuesdayLetter": "M", + "@tuesdayLetter": {}, + "wednesdayLetter": "Me", + "@wednesdayLetter": {}, + "thursdayLetter": "J", + "@thursdayLetter": {}, + "fridayLetter": "V", + "@fridayLetter": {}, + "saturdayLetter": "S", + "@saturdayLetter": {}, + "sundayLetter": "D", + "@sundayLetter": {}, + "alarmDatesSetting": "Dates", + "@alarmDatesSetting": {}, + "alarmRangeSetting": "Intervalle de dates", + "@alarmRangeSetting": {}, + "alarmIntervalSetting": "Intervalle", + "@alarmIntervalSetting": {}, + "alarmIntervalDaily": "Tous les jours", + "@alarmIntervalDaily": {}, + "alarmIntervalWeekly": "Chaque semaine", + "@alarmIntervalWeekly": {}, + "alarmDeleteAfterRingingSetting": "Supprimer après avoir été arrêté", + "@alarmDeleteAfterRingingSetting": {}, + "alarmDeleteAfterFinishingSetting": "Supprimer après avoir terminé", + "@alarmDeleteAfterFinishingSetting": {}, + "yesButton": "Oui", + "@yesButton": {}, + "cannotDisableAlarmWhileSnoozedSnackbar": "Impossible de désactiver l'alarme tant qu'elle est en mode répétition", + "@cannotDisableAlarmWhileSnoozedSnackbar": {}, + "completedFilter": "Terminée", + "@completedFilter": {}, + "sortGroup": "Trier", + "@sortGroup": {}, + "timePickerModeButton": "Mode", + "@timePickerModeButton": {}, + "audioChannelRingtone": "Sonnerie", + "@audioChannelRingtone": {}, + "timeToFullVolumeSetting": "Temps jusqu'au volume maximal", + "@timeToFullVolumeSetting": {}, + "maxSnoozesSetting": "Nombre maximum de répétitions", + "@maxSnoozesSetting": {}, + "snoozePreventDeletionSetting": "Empêcher la suppression", + "@snoozePreventDeletionSetting": {}, + "nameAsc": "Libellé A-Z", + "@nameAsc": {}, + "retypeNumberChars": "Nombre de charactères", + "@retypeNumberChars": {}, + "retypeIncludeNumSetting": "Inclure des chiffres", + "@retypeIncludeNumSetting": {}, + "retypeLowercaseSetting": "Inclure des lettres en minuscules", + "@retypeLowercaseSetting": {}, + "sequenceLengthSetting": "Longueur de la séquence", + "@sequenceLengthSetting": {}, + "sequenceGridSizeSetting": "Taille de la grille", + "@sequenceGridSizeSetting": {}, + "saveReminderAlert": "Voulez-vous quitter le menu sans sauvegarder ?", + "@saveReminderAlert": {}, + "noButton": "Non", + "@noButton": {}, + "noAlarmMessage": "Aucune alarme", + "@noAlarmMessage": {}, + "noTimerMessage": "Aucun minuteur", + "@noTimerMessage": {}, + "noStopwatchMessage": "Aucun chronomètre", + "@noStopwatchMessage": {}, + "noTaskMessage": "Aucune tâche", + "@noTaskMessage": {}, + "noPresetsMessage": "Aucun préréglage", + "@noPresetsMessage": {}, + "noLogsMessage": "Aucun log d'alarme", + "@noLogsMessage": {}, + "deleteButton": "Supprimer", + "@deleteButton": {}, + "duplicateButton": "Dupliquer", + "@duplicateButton": {}, + "skipAlarmButton": "Ignorer l'alarme suivante", + "@skipAlarmButton": {}, + "allFilter": "Tous", + "@allFilter": {}, + "dateFilterGroup": "Date", + "@dateFilterGroup": {}, + "logTypeFilterGroup": "Type", + "@logTypeFilterGroup": {}, + "todayFilter": "Aujourd'hui", + "@todayFilter": {}, + "createdDateFilterGroup": "Date de création", + "@createdDateFilterGroup": {}, + "activeFilter": "Active", + "@activeFilter": {}, + "inactiveFilter": "Inactive", + "@inactiveFilter": {}, + "snoozedFilter": "Ignorée", + "@snoozedFilter": {}, + "disabledFilter": "Désactivée", + "@disabledFilter": {}, + "runningTimerFilter": "En cours", + "@runningTimerFilter": {}, + "pausedTimerFilter": "En pause", + "@pausedTimerFilter": {}, + "stoppedTimerFilter": "Arrêté", + "@stoppedTimerFilter": {}, + "remainingTimeDesc": "Temps restant le plus court", + "@remainingTimeDesc": {}, + "remainingTimeAsc": "Temps restant le plus long", + "@remainingTimeAsc": {}, + "durationAsc": "Le plus court", + "@durationAsc": {}, + "durationDesc": "Le plus long", + "@durationDesc": {}, + "timeOfDayDesc": "Les heures les plus tard en premier", + "@timeOfDayDesc": {}, + "filterActions": "Trier les actions", + "@filterActions": {}, + "clearFiltersAction": "Effacer tous les filtres", + "@clearFiltersAction": {}, + "enableAllFilteredAlarmsAction": "Activer toutes les alarmes filtrées", + "@enableAllFilteredAlarmsAction": {}, + "packageNameLabel": "Nom du package", + "@packageNameLabel": {}, + "cancelSkipAllFilteredAlarmsAction": "Annuler d'ignorer toutes les alarmes filtrées", + "@cancelSkipAllFilteredAlarmsAction": {}, + "deleteAllFilteredAction": "Supprimer toutes les alarmes filtrées", + "@deleteAllFilteredAction": {}, + "defaultSettingGroup": "Paramètres par défaut", + "@defaultSettingGroup": {}, + "alarmsDefaultSettingGroupDescription": "Définir des valeurs par défaut pour les nouvelles alarmes", + "@alarmsDefaultSettingGroupDescription": {}, + "notificationsSettingGroup": "Notifications", + "@notificationsSettingGroup": {}, + "showUpcomingAlarmNotificationSetting": "Afficher les notifications des prochaines alarmes", + "@showUpcomingAlarmNotificationSetting": {}, + "upcomingLeadTimeSetting": "Temps avant l'alarme pour afficher une notification de rappel", + "@upcomingLeadTimeSetting": {}, + "showSnoozeNotificationSetting": "Afficher une notification lorsque l'alarme est repoussée", + "@showSnoozeNotificationSetting": {}, + "presetsSetting": "Préréglages", + "@presetsSetting": {}, + "newPresetPlaceholder": "Nouveau préréglage", + "@newPresetPlaceholder": {}, + "dismissActionSetting": "Type d'action pour arrêter l'alarme", + "@dismissActionSetting": {}, + "dismissActionSlide": "Glisser", + "@dismissActionSlide": {}, + "dismissActionButtons": "Boutons", + "@dismissActionButtons": {}, + "dismissActionAreaButtons": "Boutons larges", + "@dismissActionAreaButtons": {}, + "comparisonLapBarsSettingGroup": "Comparaison des tours", + "@comparisonLapBarsSettingGroup": {}, + "showPreviousLapSetting": "Afficher le tour précédent", + "@showPreviousLapSetting": {}, + "showFastestLapSetting": "Afficher le tour le plus rapide", + "@showFastestLapSetting": {}, + "showAverageLapSetting": "Afficher le tour moyen", + "@showAverageLapSetting": {}, + "showSlowestLapSetting": "Afficher le tour le plus lent", + "@showSlowestLapSetting": {}, + "leftHandedSetting": "Mode gaucher", + "@leftHandedSetting": {}, + "exportSettingsSetting": "Exporter", + "@exportSettingsSetting": {}, + "exportSettingsSettingDescription": "Exporter les paramètres vers un fichier local", + "@exportSettingsSettingDescription": {}, + "importSettingsSetting": "Importer", + "@importSettingsSetting": {}, + "importSettingsSettingDescription": "Importer les paramètres à partir d'un fichier local", + "@importSettingsSettingDescription": {}, + "creditsSettingGroup": "Crédits", + "@creditsSettingGroup": {}, + "addLengthSetting": "Ajouter du temps supplémentaire", + "@addLengthSetting": {} } From 53d4430423bf3229d10838f0146c778cd97ff649 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Tue, 7 May 2024 13:16:02 +0000 Subject: [PATCH 075/112] Translated using Weblate (English) Currently translated at 100.0% (293 of 293 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 017616c7..861a89b0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -22,7 +22,7 @@ "generalSettingGroupDescription": "Set app wide settings like time format", "@generalSettingGroupDescription": {}, "languageSetting": "Language", - "@languageSettingG": {}, + "@languageSetting": {}, "dateFormatSetting": "Date Format", "@dateFormatSetting": {}, "timeFormatSetting": "Time Format", @@ -44,7 +44,7 @@ "pickerSpinner": "Spinner", "@pickerSpinner": {}, "durationPickerSetting": "Duration Picker", - "@timePickerSetting": {}, + "@durationPickerSetting": {}, "pickerRings": "Rings", "@pickerRings": {}, "swipeActionSetting": "Swipe Action", @@ -61,7 +61,7 @@ "@melodiesSetting": {}, "tagsSetting": "Tags", "@tagsSetting": {}, - "vendorSetting": "Vendor Setting", + "vendorSetting": "Vendor Settings", "@vendorSetting": {}, "vendorSettingDescription": "Manually disable vendor-specific optimizations", "@vendorSettingDescription": {}, @@ -76,13 +76,13 @@ "allowNotificationSetting": "Allow Notifications", "@allowNotificationSetting": {}, "autoStartSetting": "Auto Start", + "@autoStartSetting": {}, "animationSettingGroup": "Animations", "@animationSettingGroup": {}, "animationSpeedSetting": "Animation Speed", "@animationSpeedSetting": {}, "extraAnimationSetting": "Extra Animations", "@extraAnimationSetting": {}, - "@autoStartSetting": {}, "appearanceSettingGroup": "Appearance", "@appearanceSettingGroup": {}, "appearanceSettingGroupDescription": "Set themes, colors and change layout", @@ -128,12 +128,12 @@ "styleThemeSpreadSetting": "Spread", "@styleThemeSpreadSetting": {}, "styleThemeOutlineSettingGroup": "Outline", - "@styleThemeOutlineSetting": {}, + "@styleThemeOutlineSettingGroup": {}, "styleThemeOutlineWidthSetting": "Width", "@styleThemeOutlineWidthSetting": {}, "accessibilitySettingGroup": "Accessibility", "@accessibilitySettingGroup": {}, - "backupSettingGroup": "Backup", + "backupSettingGroup": "Settings", "@backupSettingGroup": {}, "developerOptionsSettingGroup": "Developer Options", "@developerOptionsSettingGroup": {}, @@ -199,10 +199,6 @@ "@timerSettingGroup": {}, "stopwatchSettingGroup": "Stopwatch", "@stopwatchSettingGroup": {}, - "generalSettingGroupDescription": "Set app wide settings like time format", - "@generalSettingGroupDescription": {}, - "appearanceSettingGroupDescription": "Set themes, colors and change layout", - "@appearanceSettingGroupDescription": {}, "backupSettingGroupDescription": "Export or Import your settings locally", "@backupSettingGroupDescription": {}, "alarmWeekdaysSetting": "Week Days", @@ -219,7 +215,7 @@ "@alarmIntervalWeekly": {}, "alarmDeleteAfterRingingSetting": "Delete After Dismiss", "@alarmDeleteAfterRingingSetting": {}, - "alarmDeleteAfterFinishingSetting" : "Delete After Finishing", + "alarmDeleteAfterFinishingSetting": "Delete After Finishing", "@alarmDeleteAfterFinishingSetting": {}, "cannotDisableAlarmWhileSnoozedSnackbar": "Cannot disable alarm while it is snoozed", "@cannotDisableAlarmWhileSnoozedSnackbar": {}, @@ -346,7 +342,7 @@ "noButton": "No", "@noButton": {}, "noAlarmMessage": "No alarms created", - "@noItemCreatedMessage": {}, + "@noAlarmMessage": {}, "noTimerMessage": "No timers created", "@noTimerMessage": {}, "noStopwatchMessage": "No stopwatches created", @@ -372,11 +368,11 @@ "dateFilterGroup": "Date", "@dateFilterGroup": {}, "scheduleDateFilterGroup": "Schedule Date", - "@scheduleDateFilterGroup" : {}, - "logTypeFilterGroup" : "Type", - "@logTypeFilterGroup" : {}, + "@scheduleDateFilterGroup": {}, + "logTypeFilterGroup": "Type", + "@logTypeFilterGroup": {}, "createdDateFilterGroup": "Created Date", - "@createdDateFilterGroup" : {}, + "@createdDateFilterGroup": {}, "todayFilter": "Today", "@todayFilter": {}, "tomorrowFilter": "Tomorrow", @@ -432,7 +428,7 @@ "cancelSkipAllFilteredAlarmsAction": "Cancel skip all filtered alarms", "@cancelSkipAllFilteredAlarmsAction": {}, "deleteAllFilteredAction": "Delete all filtered items", - "@deleteAllFilteredAAction": {}, + "@deleteAllFilteredAction": {}, "skippingDescriptionSuffix": "(skipping next occurrence)", "@skippingDescriptionSuffix": {}, "alarmDescriptionSnooze": "Snoozed until {date}", @@ -470,7 +466,7 @@ "defaultSettingGroup": "Default Settings", "@defaultSettingGroup": {}, "alarmsDefaultSettingGroupDescription": "Set default values for new alarms", - "@alarmsDefaultSettingGroupDescription" : {}, + "@alarmsDefaultSettingGroupDescription": {}, "timerDefaultSettingGroupDescription": "Set default values for new timers", "@timerDefaultSettingGroupDescription": {}, "filtersSettingGroup": "Filters", @@ -486,7 +482,9 @@ "upcomingLeadTimeSetting": "Upcoming Lead Time", "@upcomingLeadTimeSetting": {}, "showSnoozeNotificationSetting": "Show Snooze Notifications", + "@showSnoozeNotificationSetting": {}, "showNotificationSetting": "Show Notification", + "@showNotificationSetting": {}, "presetsSetting": "Presets", "@presetsSetting": {}, "newPresetPlaceholder": "New Preset", @@ -515,10 +513,6 @@ "@showSlowestLapSetting": {}, "leftHandedSetting": "Left Handed Mode", "@leftHandedSetting": {}, - "backupSettingGroup": "Settings", - "@backupSettingGroup": {}, - "backupSettingGroupDescription": "Export or Import your settings locally", - "@backupSettingGroupDescription": {}, "exportSettingsSetting": "Export", "@exportSettingsSetting": {}, "exportSettingsSettingDescription": "Export settings to a local file", From 2e5f3a31b4ec31d1272c6f6c3deddbe8f192b85e Mon Sep 17 00:00:00 2001 From: "Brice dOliveira ([#]b-do)" Date: Tue, 7 May 2024 12:48:15 +0000 Subject: [PATCH 076/112] Translated using Weblate (French) Currently translated at 100.0% (293 of 293 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 70 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 6007b4c0..78035b0e 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -341,7 +341,7 @@ "@resetButton": {}, "cardLabel": "Carte", "@cardLabel": {}, - "accentLabel": "Thème", + "accentLabel": "Couleur primaire & d’accent", "@accentLabel": {}, "errorLabel": "Erreur", "@errorLabel": {}, @@ -401,7 +401,7 @@ "@maxSnoozesSetting": {}, "snoozePreventDeletionSetting": "Empêcher la suppression", "@snoozePreventDeletionSetting": {}, - "nameAsc": "Libellé A-Z", + "nameAsc": "Noms A-z", "@nameAsc": {}, "retypeNumberChars": "Nombre de charactères", "@retypeNumberChars": {}, @@ -528,5 +528,69 @@ "creditsSettingGroup": "Crédits", "@creditsSettingGroup": {}, "addLengthSetting": "Ajouter du temps supplémentaire", - "@addLengthSetting": {} + "@addLengthSetting": {}, + "audioChannelMedia": "Média", + "@audioChannelMedia": {}, + "cancelSkipAlarmButton": "Annuler", + "@cancelSkipAlarmButton": {}, + "dismissAlarmButton": "Rejeter", + "@dismissAlarmButton": {}, + "scheduleDateFilterGroup": "Date prévue", + "@scheduleDateFilterGroup": {}, + "showSortSetting": "Afficher le tri", + "@showSortSetting": {}, + "showNotificationSetting": "Afficher une notification", + "@showNotificationSetting": {}, + "sameTime": "En même temps", + "@sameTime": {}, + "searchCityPlaceholder": "Rechercher une ville", + "@searchCityPlaceholder": {}, + "relativeTime": "{hours}h {relative, select, ahead{ahead} behind{behind} other{Other}}", + "@relativeTime": {}, + "cityAlreadyInFavorites": "Cette ville est déjà dans vos favoris", + "@cityAlreadyInFavorites": {}, + "durationPickerTitle": "Définir la durée", + "@durationPickerTitle": {}, + "editButton": "Modifier", + "@editButton": {}, + "noLapsMessage": "Pas de temps au tour", + "@noLapsMessage": {}, + "elapsedTime": "Temps écoulé", + "@elapsedTime": {}, + "mondayFull": "Lundi", + "@mondayFull": {}, + "fridayFull": "Vendredi", + "@fridayFull": {}, + "saturdayFull": "Samedi", + "@saturdayFull": {}, + "sundayFull": "Dimanche", + "@sundayFull": {}, + "mondayShort": "Lun", + "@mondayShort": {}, + "tuesdayShort": "Mar", + "@tuesdayShort": {}, + "wednesdayShort": "Mer", + "@wednesdayShort": {}, + "thursdayShort": "Jeu", + "@thursdayShort": {}, + "fridayShort": "Ven", + "@fridayShort": {}, + "saturdayShort": "Sam", + "@saturdayShort": {}, + "sundayShort": "Dim", + "@sundayShort": {}, + "nameDesc": "Noms Z-a", + "@nameDesc": {}, + "alarmDescriptionWeekly": "Tous les {days}", + "@alarmDescriptionWeekly": {}, + "tuesdayFull": "Mardi", + "@tuesdayFull": {}, + "wednesdayFull": "Mercredi", + "@wednesdayFull": {}, + "thursdayFull": "Jeudi", + "@thursdayFull": {}, + "maxLogsSetting": "Nombres de journaux", + "@maxLogsSetting": {}, + "styleThemeElevationSetting": "Élévation", + "@styleThemeElevationSetting": {} } From cab429b7a32bb599558bc31bee9e95c9d6be1be4 Mon Sep 17 00:00:00 2001 From: "Brice dOliveira ([#]b-do)" Date: Tue, 7 May 2024 13:16:36 +0000 Subject: [PATCH 077/112] Translated using Weblate (French) Currently translated at 100.0% (293 of 293 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 78035b0e..e57345b9 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -333,7 +333,7 @@ "@showIstantAlarmButtonSetting": {}, "showIstantTimerButtonSetting": "Afficher le bouton de minuterie instantanée", "@showIstantTimerButtonSetting": {}, - "logsSettingGroup": "Logs", + "logsSettingGroup": "Journaux", "@logsSettingGroup": {}, "alarmLogSetting": "Logs des alarmes", "@alarmLogSetting": {}, @@ -373,7 +373,7 @@ "@alarmDatesSetting": {}, "alarmRangeSetting": "Intervalle de dates", "@alarmRangeSetting": {}, - "alarmIntervalSetting": "Intervalle", + "alarmIntervalSetting": "Interval", "@alarmIntervalSetting": {}, "alarmIntervalDaily": "Tous les jours", "@alarmIntervalDaily": {}, @@ -447,11 +447,11 @@ "@createdDateFilterGroup": {}, "activeFilter": "Active", "@activeFilter": {}, - "inactiveFilter": "Inactive", + "inactiveFilter": "Inactif", "@inactiveFilter": {}, "snoozedFilter": "Ignorée", "@snoozedFilter": {}, - "disabledFilter": "Désactivée", + "disabledFilter": "Désactiver", "@disabledFilter": {}, "runningTimerFilter": "En cours", "@runningTimerFilter": {}, From 0b91ad3c7e82dfc7bfa146617393ed256f50ebda Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Tue, 7 May 2024 20:25:26 +0500 Subject: [PATCH 078/112] Add some remaining strings --- lib/l10n/app_en.arb | 6 ++++-- lib/settings/data/general_settings_schema.dart | 1 - lib/settings/widgets/setting_group_card.dart | 4 +++- lib/settings/widgets/settings_top_bar.dart | 4 +++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 017616c7..2ff68abd 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -56,12 +56,12 @@ "swipActionSwitchTabs": "Switch Tabs", "@swipActionSwitchTabs": {}, "swipeActionSwitchTabsDescription": "Swipe between tabs", - "@swipeActionSwitchTabsDescription": {}, + "@swipeActionSwitchTabsDesc/iption": {}, "melodiesSetting": "Melodies", "@melodiesSetting": {}, "tagsSetting": "Tags", "@tagsSetting": {}, - "vendorSetting": "Vendor Setting", + "vendorSetting": "Vendor Settings", "@vendorSetting": {}, "vendorSettingDescription": "Manually disable vendor-specific optimizations", "@vendorSettingDescription": {}, @@ -545,6 +545,8 @@ "@relativeTime": {}, "sameTime": "Same time", "@sameTime": {}, + "searchSettingPlaceholder" : "Search for a setting", + "@searchCityPlaceholder": {}, "searchCityPlaceholder": "Search for a city", "@searchCityPlaceholder": {}, "cityAlreadyInFavorites": "This city is already in your favorites", diff --git a/lib/settings/data/general_settings_schema.dart b/lib/settings/data/general_settings_schema.dart index 4802b2ca..9f46b98c 100644 --- a/lib/settings/data/general_settings_schema.dart +++ b/lib/settings/data/general_settings_schema.dart @@ -21,7 +21,6 @@ import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:locale_names/locale_names.dart'; enum TimePickerType { dial, input, spinner } diff --git a/lib/settings/widgets/setting_group_card.dart b/lib/settings/widgets/setting_group_card.dart index c984a223..3ae8873b 100644 --- a/lib/settings/widgets/setting_group_card.dart +++ b/lib/settings/widgets/setting_group_card.dart @@ -4,6 +4,8 @@ import 'package:clock_app/settings/screens/settings_group_screen.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_item.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class SettingGroupCard extends StatefulWidget { final SettingGroup settingGroup; @@ -158,7 +160,7 @@ class SettingGroupHeader extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 6.0), child: Text( - "More", + AppLocalizations.of(context)!.settingGroupMore, style: textTheme.titleSmall?.copyWith( color: colorScheme.primary, ), diff --git a/lib/settings/widgets/settings_top_bar.dart b/lib/settings/widgets/settings_top_bar.dart index ef5a9050..1c25ac23 100644 --- a/lib/settings/widgets/settings_top_bar.dart +++ b/lib/settings/widgets/settings_top_bar.dart @@ -3,6 +3,8 @@ import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/settings/types/setting_item.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + class SettingsTopBar extends StatefulWidget implements PreferredSizeWidget { @override @@ -61,7 +63,7 @@ class _SettingsTopBarState extends State { focusedBorder: const OutlineInputBorder(borderSide: BorderSide.none), fillColor: Colors.transparent, - hintText: 'Search for a setting', + hintText: AppLocalizations.of(context)!.searchSettingPlaceholder, hintStyle: Theme.of(context).textTheme.bodyLarge, ), textAlignVertical: TextAlignVertical.center, From db4068891e4011063273bc007be7e93b8a80dc2d Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Tue, 7 May 2024 16:44:53 +0000 Subject: [PATCH 079/112] Translated using Weblate (English) Currently translated at 100.0% (294 of 294 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1179ad75..9c4736d0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -56,7 +56,7 @@ "swipActionSwitchTabs": "Switch Tabs", "@swipActionSwitchTabs": {}, "swipeActionSwitchTabsDescription": "Swipe between tabs", - "@swipeActionSwitchTabsDesc/iption": {}, + "@swipeActionSwitchTabsDescription": {}, "melodiesSetting": "Melodies", "@melodiesSetting": {}, "tagsSetting": "Tags", @@ -531,7 +531,7 @@ "@emailLabel": {}, "viewOnGithubLabel": "View on GitHub", "@viewOnGithubLabel": {}, - "creditsSettingGroup": "Credits", + "creditsSettingGroup": "Open Source Licenses", "@creditsSettingGroup": {}, "addLengthSetting": "Add Length", "@addLengthSetting": {}, @@ -539,8 +539,8 @@ "@relativeTime": {}, "sameTime": "Same time", "@sameTime": {}, - "searchSettingPlaceholder" : "Search for a setting", - "@searchCityPlaceholder": {}, + "searchSettingPlaceholder": "Search for a setting", + "@searchSettingPlaceholder": {}, "searchCityPlaceholder": "Search for a city", "@searchCityPlaceholder": {}, "cityAlreadyInFavorites": "This city is already in your favorites", From af9f635803e51726825f311db512430076a81a5a Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Tue, 7 May 2024 18:47:06 +0200 Subject: [PATCH 080/112] Translated using Weblate (Spanish) Currently translated at 90.4% (266 of 294 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index e53dfb39..6dcbd2e6 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -417,8 +417,6 @@ "@licenseLabel": {}, "viewOnGithubLabel": "Ver en GitHub", "@viewOnGithubLabel": {}, - "creditsSettingGroup": "Créditos", - "@creditsSettingGroup": {}, "addLengthSetting": "Agregar longitud", "@addLengthSetting": {}, "dismissActionAreaButtons": "Zona de controles", From c67160cce110ae32c1f454251c4b286f0de05cca Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Tue, 7 May 2024 18:47:06 +0200 Subject: [PATCH 081/112] Translated using Weblate (French) Currently translated at 98.9% (291 of 294 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index e57345b9..e2824689 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -525,8 +525,6 @@ "@importSettingsSetting": {}, "importSettingsSettingDescription": "Importer les paramètres à partir d'un fichier local", "@importSettingsSettingDescription": {}, - "creditsSettingGroup": "Crédits", - "@creditsSettingGroup": {}, "addLengthSetting": "Ajouter du temps supplémentaire", "@addLengthSetting": {}, "audioChannelMedia": "Média", From 1731141741276b3572ade364378a5c9776a70067 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Tue, 7 May 2024 18:47:06 +0200 Subject: [PATCH 082/112] Translated using Weblate (English) Currently translated at 100.0% (294 of 294 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9c4736d0..ea9e3ecd 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -531,8 +531,6 @@ "@emailLabel": {}, "viewOnGithubLabel": "View on GitHub", "@viewOnGithubLabel": {}, - "creditsSettingGroup": "Open Source Licenses", - "@creditsSettingGroup": {}, "addLengthSetting": "Add Length", "@addLengthSetting": {}, "relativeTime": "{hours}h {relative, select, ahead{ahead} behind{behind} other{Other}}", From d301e3a0ac562fdec75e35c62225ed2983a48f5a Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Tue, 7 May 2024 22:59:38 +0000 Subject: [PATCH 083/112] Translated using Weblate (Spanish) Currently translated at 100.0% (293 of 293 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 54 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 6dcbd2e6..3c7e5d1e 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -532,5 +532,57 @@ "durationAsc": "Más corto", "@durationAsc": {}, "durationDesc": "Más largo", - "@durationDesc": {} + "@durationDesc": {}, + "cancelSkipAlarmButton": "Cancelar omitir", + "@cancelSkipAlarmButton": {}, + "dismissAlarmButton": "Descartar", + "@dismissAlarmButton": {}, + "sameTime": "Al mismo tiempo", + "@sameTime": {}, + "searchCityPlaceholder": "Buscar una ciudad", + "@searchCityPlaceholder": {}, + "durationPickerTitle": "Elige la duración", + "@durationPickerTitle": {}, + "relativeTime": "{hours}h {relativo, seleccionar, adelante{ahead} detrás{behind} otros{Other}}", + "@relativeTime": {}, + "thursdayFull": "Jueves", + "@thursdayFull": {}, + "elapsedTime": "Tiempo transcurrido", + "@elapsedTime": {}, + "wednesdayFull": "Miércoles", + "@wednesdayFull": {}, + "mondayShort": "LU", + "@mondayShort": {}, + "thursdayShort": "JU", + "@thursdayShort": {}, + "fridayShort": "VI", + "@fridayShort": {}, + "sundayShort": "DO", + "@sundayShort": {}, + "editButton": "Editar", + "@editButton": {}, + "noLapsMessage": "Aún no hay vueltas", + "@noLapsMessage": {}, + "tuesdayFull": "Martes", + "@tuesdayFull": {}, + "fridayFull": "Viernes", + "@fridayFull": {}, + "saturdayFull": "Sábado", + "@saturdayFull": {}, + "sundayFull": "Domingo", + "@sundayFull": {}, + "tuesdayShort": "MA", + "@tuesdayShort": {}, + "wednesdayShort": "MI", + "@wednesdayShort": {}, + "saturdayShort": "SA", + "@saturdayShort": {}, + "alarmDescriptionWeekly": "Cada {days}", + "@alarmDescriptionWeekly": {}, + "searchSettingPlaceholder": "Buscar un ajuste", + "@searchSettingPlaceholder": {}, + "cityAlreadyInFavorites": "Esta ciudad ya está en tus favoritos", + "@cityAlreadyInFavorites": {}, + "mondayFull": "Lunes", + "@mondayFull": {} } From 9c22aa6d04efe4831bf6ad1011c80540c0724d81 Mon Sep 17 00:00:00 2001 From: "Brice dOliveira ([#]b-do)" Date: Wed, 8 May 2024 06:34:03 +0000 Subject: [PATCH 084/112] Translated using Weblate (French) Currently translated at 100.0% (293 of 293 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index e2824689..ae43bfb1 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -590,5 +590,7 @@ "maxLogsSetting": "Nombres de journaux", "@maxLogsSetting": {}, "styleThemeElevationSetting": "Élévation", - "@styleThemeElevationSetting": {} + "@styleThemeElevationSetting": {}, + "searchSettingPlaceholder": "Rechercher", + "@searchSettingPlaceholder": {} } From c7e1d3461115e97631d2d9bcb3e8653b315ff94c Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Wed, 8 May 2024 13:37:54 +0500 Subject: [PATCH 085/112] Add more sections to about page --- assets/contributors.json | 65 -------------- assets/contributors/avatars/41967492?v=4.jpg | Bin 0 -> 29966 bytes assets/contributors/avatars/75314629?v=4.jpg | Bin 0 -> 1563 bytes assets/contributors/avatars/84540569?v=4.jpg | Bin 0 -> 10792 bytes assets/contributors/git.json | 17 ++++ assets/patreons/patreons.json | 12 +++ .../field_cards/text_field_card.dart | 35 +++++--- .../select_field/select_bottom_sheet.dart | 1 + lib/l10n/app_en.arb | 19 +++- lib/settings/screens/about_screen.dart | 60 ++++++++----- lib/settings/screens/contributors.dart | 85 ++++++++++++++++++ lib/settings/screens/donors.dart | 84 +++++++++++++++++ lib/settings/screens/licenses.dart | 3 +- lib/theme/widgets/theme_preview_card.dart | 9 +- patreons.csv | 4 + pubspec.yaml | 4 +- scripts/contributors.py | 44 +++++++++ scripts/patreons.py | 26 ++++++ 18 files changed, 356 insertions(+), 112 deletions(-) delete mode 100644 assets/contributors.json create mode 100644 assets/contributors/avatars/41967492?v=4.jpg create mode 100644 assets/contributors/avatars/75314629?v=4.jpg create mode 100644 assets/contributors/avatars/84540569?v=4.jpg create mode 100644 assets/contributors/git.json create mode 100644 assets/patreons/patreons.json create mode 100644 lib/settings/screens/contributors.dart create mode 100644 lib/settings/screens/donors.dart create mode 100644 patreons.csv create mode 100644 scripts/contributors.py create mode 100644 scripts/patreons.py diff --git a/assets/contributors.json b/assets/contributors.json deleted file mode 100644 index 085bd7e0..00000000 --- a/assets/contributors.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "login": "AhsanSarwar45", - "id": 41967492, - "node_id": "MDQ6VXNlcjQxOTY3NDky", - "avatar_url": "https://avatars.githubusercontent.com/u/41967492?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/AhsanSarwar45", - "html_url": "https://github.com/AhsanSarwar45", - "followers_url": "https://api.github.com/users/AhsanSarwar45/followers", - "following_url": "https://api.github.com/users/AhsanSarwar45/following{/other_user}", - "gists_url": "https://api.github.com/users/AhsanSarwar45/gists{/gist_id}", - "starred_url": "https://api.github.com/users/AhsanSarwar45/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/AhsanSarwar45/subscriptions", - "organizations_url": "https://api.github.com/users/AhsanSarwar45/orgs", - "repos_url": "https://api.github.com/users/AhsanSarwar45/repos", - "events_url": "https://api.github.com/users/AhsanSarwar45/events{/privacy}", - "received_events_url": "https://api.github.com/users/AhsanSarwar45/received_events", - "type": "User", - "site_admin": false, - "contributions": 428 - }, - { - "login": "azeem-io", - "id": 84540569, - "node_id": "MDQ6VXNlcjg0NTQwNTY5", - "avatar_url": "https://avatars.githubusercontent.com/u/84540569?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/azeem-io", - "html_url": "https://github.com/azeem-io", - "followers_url": "https://api.github.com/users/azeem-io/followers", - "following_url": "https://api.github.com/users/azeem-io/following{/other_user}", - "gists_url": "https://api.github.com/users/azeem-io/gists{/gist_id}", - "starred_url": "https://api.github.com/users/azeem-io/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/azeem-io/subscriptions", - "organizations_url": "https://api.github.com/users/azeem-io/orgs", - "repos_url": "https://api.github.com/users/azeem-io/repos", - "events_url": "https://api.github.com/users/azeem-io/events{/privacy}", - "received_events_url": "https://api.github.com/users/azeem-io/received_events", - "type": "User", - "site_admin": false, - "contributions": 11 - }, - { - "login": "inson1", - "id": 75314629, - "node_id": "MDQ6VXNlcjc1MzE0NjI5", - "avatar_url": "https://avatars.githubusercontent.com/u/75314629?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/inson1", - "html_url": "https://github.com/inson1", - "followers_url": "https://api.github.com/users/inson1/followers", - "following_url": "https://api.github.com/users/inson1/following{/other_user}", - "gists_url": "https://api.github.com/users/inson1/gists{/gist_id}", - "starred_url": "https://api.github.com/users/inson1/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/inson1/subscriptions", - "organizations_url": "https://api.github.com/users/inson1/orgs", - "repos_url": "https://api.github.com/users/inson1/repos", - "events_url": "https://api.github.com/users/inson1/events{/privacy}", - "received_events_url": "https://api.github.com/users/inson1/received_events", - "type": "User", - "site_admin": false, - "contributions": 3 - } -] diff --git a/assets/contributors/avatars/41967492?v=4.jpg b/assets/contributors/avatars/41967492?v=4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b71cad748f7b79b8251d9e0dc00d4ba6f070384f GIT binary patch literal 29966 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 AI{*Lx literal 0 HcmV?d00001 diff --git a/assets/contributors/avatars/75314629?v=4.jpg b/assets/contributors/avatars/75314629?v=4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4245dbde8b4e142a70ed84570e3bdbe21034bee1 GIT binary patch literal 1563 zcmeAS@N?(olHy`uVBq!ia0y~yU|a&i985rwk9xQeL6owMbiyN&Lnn~4%rC` zWezmvoPNV7|HfkdP2qRj^IyN=EdS*8=lLdPp(A`A0@ezSZyH!O4nNMcHg^Uz3&e1weKeX>17?hLC})=t>Jvxoa=8m&2Min{nlc= z_kH6Jv+49mZS+dj*zGxVT_X7#TZ8RhVw56k q-!X~J<_v!<=$MK>=rb_<|Id9y>0$CVI~QP~&*16m=d#Wzp$Pz^y9S^D literal 0 HcmV?d00001 diff --git a/assets/contributors/avatars/84540569?v=4.jpg b/assets/contributors/avatars/84540569?v=4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bff7da9d4dc2c36b0c06f569f8afca4aa1008617 GIT binary patch literal 10792 zcmbVxdpwi<8~+@K9EvIAeB4NdP0o=vHiv9;$kGY1O$l?H4i2Ffau{V;Gn+Yk5=Es) zGN&4uQAwVnoJ&Hdr>B0mp6B~~zkmLIzx(z2?B4y_&Fj8C*ZX>3@9Ta4eD?DN=mJPa zS{f`ZB?AV7Wo2dLNX-E2}6$v@~?IwKOy}bq#l#=<4q<(A0$Pf$i9B0f)nN zOl%!(EFE@Q!7asPWo6|z$*URJ9jA3r-mTV%u@i#?VQ(+7!f5tG;=_On}z z4FZWtiTyf2{~TiC5|UEVU>RAtO`AdDViFSKk`huAtdxfSU8bHro_g@CnP3O(=TLXW?j5QD=4HF6<@tp!eCc&xK+IBn%d@@Ev>h1 zx3%Btdf3hH>Fw(u5RQmO$DTfWKK^=Y`pw&!*}3_Jm5-}y>z_V<`T9)^B=L7Rz~|oq z{ZBkwfOy0uB_$-m8}W#VCjd)gi=>pEg|xB@7JNKfMc*=22C^@|;>H7611sDI)!>+6 zxvhrq*G4NFA^nQz|1O}k|F4Mt4d~x^evX6WCB%S)No)b_1-+`7rXAxc5gxB?eg&Jl z2GaV%Yw&<6;lFA`Iqq$+h>>#8CT-11&khHVm316wu%M3g5|DbYR@Q68X4paa2lGAz zBQPy-$qK933Z0+Kch66prX|i!vcXzj?p7&eb++-*yW>nnndN0{_-%6jfinr!C)j@9 zOYs=9e-SN?voIxQ z#>7h_77y6~KDnd$pO@i2v3*&0Vh0D=X^%ZKW zXq{Z!no7FGr#hT%_*T+>6nP@-W^kU;Pmtf?T$jU}!?oP6PCNLrR{gO2gE)nFd{M5g zKGwriy3FjprI-3;q&mCa1qtyH^MrFmkOMDcB6A;aEU3mDf2j`N*(u(0fR0BTQ1 zy8FFU+WEIwTH?F!wSn&R5Juu(rU+a32OvX6T3N>rsH*j8ooo5vUPElb+;272c3eSebj~ZaD4m>Y??~<~ zd|b83`k9?_!;3}Q>&Mxv>Y>4d-e||g-<48NPgY;qrILd^(=y~I{9)W1D``oPsS3$Z zFafXdV=pyK_HEl*>vrD!lEK={J#Dl@*Y=dNcb_8JU+((+X0h+RafXuIU(xHli=8BD z=<${Q`vhKVV8p|Wl2H8ecFiAtareAPk<8FsYvy&c&>w1zJ74grXZaV4U&)kYfqt`f z>V3M1Z)_3TT|W)xv-?TUHbgEBOC`4`)8jaP!~J z)}C%_+6P%kM&QieB*j%67`M?unMKx!H7281REujOja%Dk?nC<;2#c}hFVEYJsSfws z;VwVB%?KJj?hj*xhSL7O4o5dM|X%|bTEjM{jByQ z+N%K5V0dr6F;HZk;fQ)2sa44zLSQGB2nKfN?u~`cHjoA*cAh)m{q(SvY>Dvm0|D-81|mL^r|Acy zYPY_Wpd}X>sx3aKU9#}s-Vi`JY+)O^@1?236jStYtOd2>S}YImhDjiM-gubmtu0Ew zPja5(5Th2ob*K#3!?AqgSsTh2!}cd=5r5UVP(xd3`haFgdo|x?3m+Ytc73EwbZqs2 z+B|N+RmALAz>e?`TS>3Jg>g6-PRdyY%sr-iwaYsJrsJlMV2dduFB+?u#?h(`Bo^6D zKk*%i2L5lgN^i8`pe!= zz18fn>DIy|t38t^LvJ*i1U`L_K%WaUQ~R^ljC?T3YyL+6MSf4g=t8WRTKpAhm>-h1jOBwR{!OXo(GoACc71wSbX`LH+xX+I17!)*H)fESqa3f>p zY>`7;(3@{KTyBe)WspEaZ44#j9Y34>muVOI=}HkS!Sda9)KdpJUiL^*P1NO=5T4OZ z&BG;^g3*9@AWku0q-O!|Bj>cCB8R;;L_>4gKc6st|9sl`g)$|5z1{$Iw6ElR8cKcd z0m26Y)gGyTr@UU#Rk5dS@zv`9ze+n&a8PV<^*8@h!L~*g%SMpMb=AV3AX&uy(uPBv z0MMa{^pDaL6U)o0G1$hN%YGE>CqrLGJqCca*~d)X}c!!RMpt!Mr1_8UV{5hC_I^t61v zn)X!10MUolELojc;!Sq(X>#zr z{6*9}Y)Sn#BL5&P*ZP6sY@ydAMCT}`Qxwkl1FLLRn4<1HPs3(esbb1#vjihK(0i(H z|E_lF8%vEBZq#Wiqg+f_b=&q_I;}m`scg^a=TG+3lAmtFjTQ`B*EKN`)ops)8_&%K z=1yA6T9#}#(fxR!rZL&~esby4C_epzVzQrdcP{nmDF;)ub&}tT@KkldM9`yXy`-QU z4u#BCF{ib2@FGzGrf;?M)XU3ANJ*96^Ge8sFt?=>I*){aSWlAR^mfi}cCIKaMUh1D znz_2dlImw!eAaHEhfJpIyk9{*P?u7rqDI+7&?@ku`s-7j#3nEBT!I zkGPrno!y-hPAzZqE2Dg;6M_QFPdboMFSLAbD5u~5>{J@~nPuD8O9(*+ollG7iDIGt zsK>uG_8PADQs+Gyj^=vQ&5b5(VBKM*Y=XB~WZK2tR>?Gm^53pDKP zhkw;c_vIE!n5b!0)7qaD<@Iyc5ZA5N5%6X|SZL$5{evf)tX{3x;(nLZ8LTS$O9_EN z^&y^1#tiPabc!*pyG0H>#BB9@ah*J$W*gc!F-=RYMIkn6rbWb3+(RhX878TSZ5g`g z4Tg9BWs2?RJaV?9#Tmn>RNrD7ipL1U*$s2V!nyYf2I~d>ool0kRMc*Hz2LQ5BdP~x z+329%vW`&OTV$`FHw<;6e@LpPuhoE0lQRjStdR$^>eZ=J%+?((o;+3k>#MX3_Z~Y@ zipa9ia9n0N@J?&i`1F8kV8HtV>Yp0-1-Tde9p64WJa}sA)Q###ZH`J@843wn z{KD|spo7I1^L9sx&A|`~sEFUrJXL!y<$pihFejJE>%iJdsPA<>oS#Nz`qmDb zW81XVCptd-t}M!^y)}ghcQ64v(x8)}N%fJ);zFyg%zATh zI`bGM$i(Wh$5XCeF632W)j9Y|Kc~mtZk?CjtGaoHX~P-V&swVyTL;hkq`&BJSE6PT zjPTxuAqcfs+PlfyOTM=qN-x8;4nz*T*|TR(wda8P_eJ$49FzdxUiR_OEpicmWME0w zX2^5&{O-Esr=GBbtK{JARHc%V_L!JtUvMMr{p(sQ5#zZ*f%g;^LxLJAK(NkWGL)UN zwU7&G0nuCNKH@Xk!|p^eB4>@ul3eyc8iCB!*)))qz}yJZ1GV7}88A-iU_4dqk8WDn zzJ>KNzirFV$$-$C#x{i}_mv1Me@0w-XQN`=NHR%PZS%_V=mTJvG-6uxIr^41#+GcPhttb;nZGx z6!PKPB+3v*+9r%?H*?MM0471ZC3CM0{M$v!7iP=SsynAY^}XFln_$0UfcDylC=>}& zV#*jA)j4_Cs!%lgB-zgkrT;0HrR?0t)#Bq{hZ`Rle75YWOdUB?Y)o5nI5v;=7%#Y% zMuT$1+^9gI(EeT$5G>=rg|zGf>^Q*+&47xXYr(~HS>oAKxkMH?^MQ6zaL-ZG(-wy! zV12bEQ*;Y|$#^dG<-zKK!P#UIOZn;u?IUj!nv+al zptx8RSX(h_my{5OIrEGrgXFRN{obyI=g3>h6pf6b-!bFRF3*VFpBJ%v8f=)O>NBk< zuZsuZBQ6ejbRFu{#RCvJ9?i;M(MBG=LaW?LUJJ<<^^KM6=5nx4g!vKZJGFQKg@ew}f7-Wx2P*Dv<%Gr*P&C|O?9 zX#&z1&9oY;oe(_meC3xata;fPy08EG5tt!tPe@t&C3aD&W*A$#X<%syw~sPESu>F8 z4ceO%XHxOjDp6sX0BuLvUSDY@%Mxyqz*c@a^oZxFX3A#qmt@|Z940_&r_QVe9_xvpWRoBXXP_$n?;CHi@1P zGgD^el~-~+6k&??6XVrUF#MWr=`$Sv^;+_}X{%RGrGB3+ge7twNqvJew{%AC`hs_v zp@(Y7Y1^HJi3Z!bKS6S?uHS;o?D1mD7^fDRwk@2s%KQTpnY1zEJ7~zjC$cr7`qVj= zu&GJbF@MEMHQHfT2yO0*33Ift?)kkefwPRJHu=@kAoat&$m}B`tdKV6@PSRUf3mT! zYVp9wW-K74fF%!LRPrAj>t#T&p5hy95zx|MJ?(ctSNJjkt=IXg?3^Fk_okE>I*Pd{Nt;$x4`{TUe1Z0oTLYPaR?5}S-w=x>v({&d{i&a8#8hR} z)Ru7)?!!uu_iMx6kgXZo^o}1b9H(HutG2P$XoUwk9K9%PvXuD?Fe^_=v#AC zJWO~4vhL<=i?OH50sYCsyrCG9UjV%KsdybGxZ%^X}CfEH+R~zRH(qc3on;OIG$<_{I{hA+-Gr~x+ zRg60ITlVlSqCgL^|1x^45MILCSIF1n2#krUee*6HNb7z%TP_E}&g0L}H-^eg?;^X{ z+IfFvZmBapt_JI|8H~s7a`4YclQ2FI!rxzBG)RlSdjoF0oqqbH%KZLsu{Th{3MGxd zmg2DQ&AdRHMjD)qU+7N1HIby!WrMA)|Cg`mo)J=o!>@MXV?nf3Ie?eUNyU4{p3gR z?7{Gc$fJi^E{0~8cgEarz38Hle#kZC@|Kk#40IVuq+~!s{*jeHY5dLKY0w^+yp%Zv z58^JsEHDZZDiGYTvy5p(;=MmFzSimKJlCok_}fp=l`mF*tzZsWJV@?ai-1lw-^`WC z6t7m*{4AO7D;V3>NN&0LCd4tK$LG|`>&^>C+x5}2=6^6M;3b@b$a|yVXP$cM#&~nP z6Ka>+{&|qiqWS>T{z575zG^Lx9lW@?H!lfU#?$! z;ng2$ObSmr_^}ru<`9j&Iz&Bwa(eQPa`TOT*ijs=Gp_n_47#dt8AJWk$2B-}ru=S$ z+ax`%%B&!hmpQ|hF3u-i2^(NMZ1XV;S%^5^|12h{p7g?U3p2ANH6tNLGdRVPB=XOK zUcl0VqR}*vCvNI0gyJlNG`8W1(O?;wz-4f8%5U^G2$l~dBiaKAk}hm8-(WE{mQ+ps zPtf#7gSk5;6)(vjlFH`LN8 z>0(;2G9Bpt=C&mI`a5@Go<@AM7i0l-(TDV+)=A{E%}8nafU+-y#qfu@Uq6T3N!A=m zn#z*$q84zw02cux`;CJHArCbS7X>SuG6)o$)4BGK> z(ePt8v#S2(qmH!n&f3uy)%+pNPkKbJzo$$|%?dVqlkAq=6G1{X8h@igm_5PCQFv zZmabP=t6eepo}1FVXKF-Y=ykRpN+gPhraI}LeR-oOA&TEP3L%wb7X~Q2*_=c{s+O914bAR z{zYtCvg**97mXi-;DkP68ybECXGS0xhXruBk#uq1g=HiJuhz~kNEZUa4vp(7ee=zy zi(g0lohvuwce{mPRU5YDm)@C(BxN-?&`x1@U|cZ(%J=!4CBl95U`Qh< zONyQ9;oMU;OpAv}iK{^H-?Dwf8+IQ@N;KF8m`E@{r$8emG6L(AXHgEcm%?eel*l`7_r2#ryzTFb%~3s(ljaFIw%hih&iSL& zb+vnx=;=NSlzI)#VVke-wfv;*Vf}j_tv1<}U2pNyE+X>0Cf>M7->UEXC|VIV?{+j@ zFY3g$=KeuBl7oy*YB|iT>Jvjz(&v2+-#H(4SXK?BlKt5}OI7~!4HuY94hW|_X~skXo+7G3ju#X-f#(y#(=NL0kY+pE@hnUw|Dkq~<< z()3UpB5#&yhWR%A#=tSc=(=r_H!WVYYSvF7N|(BO8ArtCCSPWFGGJETT_=Nv8J@%A zd1>X&yx@FyB5%Z*=d+t{4C^XL+0Inh%_Q+j9K2E5#|ZDS9mmqs18W}ok5D9Jc$k=^2#fdlCGKiu&)Md-1SI1W71t(Ca89k%( zjfX1Xif)Mbfmbh_qKkSB5EzdC)E&dd`k1bu#<@9zvEx@1-dO3xcm8EtYnNML{=IHT zcj(S1px4f8wPJViCrX?pgg0`aJpt}>^pV%o%U4=b1h0RtlVkXn2s=Ge3lIhZXw zMZ%2=Oa~wglq>f*s*({P);?2+h&FHg`i+rxFi@#_og2Gn>%|(Rk-6o*yE<9SZ9gVQ z??1JX9_Sw}KX|_WT!q_h%1_YKMn}K0ci4hN@%tGcavDn`UPriacN48={D&T&(2X>o zqZ~OGPKd2`@_Ig+QN`Pv_#$2^saNv{;^B7}n(Z30=*As&G5q?gr$^1SUFO%DtiEJ4 z^y+z8Z+&DCNzd)ol>7Sqj!IGDi>leCfMQ5#{sVgo_UZ$H=H{wb`IHiD8!Y*jg-*xsO91!#@d0`kp z@qmPNF5RFr1?EDr3M^S1kzDi?d z4K%~XEOnckry{4E51#1LviCprSYUlP*F$rLtt?OZidX-vIjvfDj4d$n>sJs+ePTpd z+xhNaJ*4@r0A8OwRoPz&#~$nG0_+7BKz-Y?B;eR|6riJuvwg(F=o%J4J14+kL{KM( zg?j>mJ%@~oRY^2MIqcL-;*VH-zI;yVSK;x93(+mP5T%BrxkfoCFdV7e)23Eqw#Tfr zYpWV5JE=ya06K+z(I^6$ z7wmL;ZWgt(Za6NSPz6k-qFdIH_W~Lwxtb?MwGuQ)9a!5#!`x^W8B_o} z^Lxc&fM2S*mf0RI8p2hy*C=ibGC8GQ!LY(+Nrt!XB%eGL-OGrC3bd#`dTlc~?Y!y9 zTv5;ttJCvd2y;}|h3;YXD(#j}RT`DnCJ+r6>>>epp$}^300SbZD(_b>KqXb_vI{nV zY31Q82TTFG$gXmL#u2j*Z$)`~Is7%A%P`6?CK0Rj?1#sT|2A{%H_{DQ5_w&@YrjV2 zb&eS0m-%B3SeI%XClTOl0&PZX-pj}wWCT%ckptn;Ze%+j$tQij?;I5ZrK{y`t1Jg; zx9$)s&w22n3nUi)j));mG^Qzlc9N}m+AU)&&zxGzBpxH2T4@cTcg({sDnP=rXHw+6 z*V;IMnMAV#W=N9`X%0j)nT`ahb2%Fj+*t42$j2aYTnJ9gG&#<8 zh@28P(`alhAIlk_iO!Ko9dp$PEryl59hM1I`yCU3o5}k~x|E;K-%ZOCZYJgR&GELN zX`#Lb}SlEkhIE`eB zVwr1-pLSsxx!We%9FcofzGp7nq*=tqvLGWA{i9|}7@B#e2Ixv}lu@ZdS58Gi9bqYLl^rG+E9Vr3OL1WX=24=3B~P z2>Pf+E`HI~#x-mGpE>|){vYWGoR9esITmhQ>4K{@ERg2rvt}4u30-AXtPZ#*?a zJGGOzDGQDZ%YL$LTPpCNGv;53PM4G>}XhLj!$rz6?*JytKP+jrf#i% zb>UTxwOn8KYdGAnuX94>7*G?H9pF|7C;@Q!{+ou4VHNt$9Yq4hL*Omi2Hb#U0uVTm zGznn=Kx@F;BX>KYP%V>l;q}E&)dEvZn~JoF7A43l61$l7ENGYsYp;Y$@r?^@I78HZ zXXj~CBVN0xp24XyMDC(Xl^&Gk0}$SvcsA~dI96b;2E4DE_W=A^D0kUy+F2F_6o?cT zLa*ea_X&r`=zu!KM`s#LHqvT#cW0I*7$?iKX{L|=0seomBKYr?|5EMF|M}rR=Zzbj zXHqjH8X!JWtqw}uov{2e7H{n2=t(0Zdtf65Nzr`itHM+nFdR4R87zjTMZa@lNlyW~ zQ4)fi0+b0(F3#jv1%l`}2Id&hao?exvv8l-#heNkE@arlxz{h^%6+GzVAl2OZzG2a z9WPRVy(8Sz<#6Bqg9#tvuLlC&UAeG)0DBreS^VFE_*EFJC%=kfycp;;zra-~Om|l4 zLQVL#N;)o_8 + AppLocalizations.of(context)!.donateDescription, + (context) => AppLocalizations.of(context)!.donateButton, + (context) => + launchUrl(Uri.parse("https://www.patreon.com/vicolo"))), + ), + SettingPageLinkCard( + setting: SettingPageLink( + "Donors", + getDescription: (context) => + AppLocalizations.of(context)!.donorsDescription, + (context) => AppLocalizations.of(context)!.donorsSetting, + DonorsScreen())), SettingPageLinkCard( setting: SettingPageLink( - "Credits", + "Contributors", + getDescription: (context) => + AppLocalizations.of(context)!.contributorsDescription, (context) => - AppLocalizations.of(context)!.creditsSettingGroup, + AppLocalizations.of(context)!.contributorsSetting, + ContributorsScreen())), + SettingPageLinkCard( + setting: SettingPageLink( + "Open Source Licenses", + (context) => AppLocalizations.of(context)! + .openSourceLicensesSetting, const LicensesScreen())), - // CardContainer( - // child: Padding( - // padding: const EdgeInsets.all(16.0), - // child: Column( - // children: [ - // Text( - // "Contributors", - // style: textTheme.headlineMedium?.copyWith( - // color: colorScheme.primary, - // ), - // ), - // // Image.network( - // // "https://avatars.githubusercontent.com/u/41967492?v=4"), - // ], - // )), - // ) ], ), ), @@ -109,7 +121,7 @@ class AboutInfo extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Version", + AppLocalizations.of(context)!.versionLabel, style: textTheme.bodyMedium?.copyWith( color: colorScheme.onSurface, ), @@ -139,7 +151,7 @@ class AboutInfo extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Package name", + AppLocalizations.of(context)!.packageNameLabel, style: textTheme.bodyMedium?.copyWith( color: colorScheme.onSurface, ), @@ -174,7 +186,7 @@ class AboutInfo extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "License", + AppLocalizations.of(context)!.licenseLabel, style: textTheme.bodyMedium?.copyWith( color: colorScheme.onSurface, ), @@ -220,7 +232,7 @@ class AboutInfo extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Email", + AppLocalizations.of(context)!.emailLabel, style: textTheme.bodyMedium?.copyWith( color: colorScheme.onSurface, ), @@ -256,7 +268,7 @@ class AboutInfo extends StatelessWidget { ), const SizedBox(width: 16.0), Text( - "View on Github", + AppLocalizations.of(context)!.viewOnGithubLabel, style: textTheme.bodyMedium?.copyWith( color: colorScheme.onBackground, ), diff --git a/lib/settings/screens/contributors.dart b/lib/settings/screens/contributors.dart new file mode 100644 index 00000000..81e751c1 --- /dev/null +++ b/lib/settings/screens/contributors.dart @@ -0,0 +1,85 @@ +import 'dart:convert'; + +import 'package:clock_app/common/widgets/card_container.dart'; +import 'package:clock_app/navigation/widgets/app_top_bar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +Future readGitContributors() async { + final String response = + await rootBundle.loadString('assets/contributors/git.json'); + return await json.decode(response); +} + +class ContributorsScreen extends StatelessWidget { + ContributorsScreen({super.key}); + final Future gitContributors = readGitContributors(); + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final ColorScheme colorScheme = theme.colorScheme; + final TextTheme textTheme = theme.textTheme; + return Scaffold( + appBar: AppTopBar( + title: Text(AppLocalizations.of(context)!.contributorsSetting, + style: textTheme.titleMedium?.copyWith( + color: colorScheme.onBackground.withOpacity(0.6), + )), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: FutureBuilder( + future: gitContributors, + builder: (context, snapshot) { + if (snapshot.hasData) { + final dynamic contributors = snapshot.data!; + return Column( + children: [ + for (final contributor in contributors) + CardContainer( + onTap: () async { + if (contributor['profile_url'] != null) { + await launchUrl( + Uri.parse(contributor['profile_url'])); + } + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + CardContainer( + child: Image( + width: 48, + image: + AssetImage(contributor['avatar_url']), + ), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + contributor['username'], + style: textTheme.headlineMedium, + maxLines: 1, + overflow: TextOverflow.ellipsis, + softWrap: false, + ), + ), + ], + ), + ), + ), + ], + ); + } else { + return const CircularProgressIndicator(); + } + }, + )), + ), + ); + } +} diff --git a/lib/settings/screens/donors.dart b/lib/settings/screens/donors.dart new file mode 100644 index 00000000..2fccc6b4 --- /dev/null +++ b/lib/settings/screens/donors.dart @@ -0,0 +1,84 @@ +import 'dart:convert'; + +import 'package:clock_app/common/widgets/card_container.dart'; +import 'package:clock_app/navigation/widgets/app_top_bar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +Future readDonors() async { + final String response = + await rootBundle.loadString('assets/patreons/patreons.json'); + return await json.decode(response); +} + +class DonorsScreen extends StatelessWidget { + DonorsScreen({super.key}); + final Future donors = readDonors(); + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final ColorScheme colorScheme = theme.colorScheme; + final TextTheme textTheme = theme.textTheme; + return Scaffold( + appBar: AppTopBar( + title: Text(AppLocalizations.of(context)!.donorsSetting, + style: textTheme.titleMedium?.copyWith( + color: colorScheme.onBackground.withOpacity(0.6), + )), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: FutureBuilder( + future: donors, + builder: (context, snapshot) { + if (snapshot.hasData) { + final dynamic contributors = snapshot.data!; + return Column( + children: [ + for (final contributor in contributors) + CardContainer( + // onTap: () async { + // if (contributor['profile_url'] != null) { + // await launchUrl( + // Uri.parse(contributor['profile_url'])); + // } + // }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + // CardContainer( + // child: Image( + // width: 48, + // image: + // AssetImage(contributor['name']), + // ), + // ), + // const SizedBox(width: 8), + Expanded( + child: Text( + contributor['name'], + style: textTheme.headlineMedium, + maxLines: 1, + overflow: TextOverflow.ellipsis, + softWrap: false, + ), + ), + ], + ), + ), + ), + ], + ); + } else { + return const CircularProgressIndicator(); + } + }, + )), + ), + ); + } +} diff --git a/lib/settings/screens/licenses.dart b/lib/settings/screens/licenses.dart index 97a4e869..e675d1b7 100644 --- a/lib/settings/screens/licenses.dart +++ b/lib/settings/screens/licenses.dart @@ -4,6 +4,7 @@ import 'package:clock_app/settings/types/setting_action.dart'; import 'package:clock_app/settings/widgets/setting_action_card.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class LicensesScreen extends StatelessWidget { const LicensesScreen({super.key}); @@ -15,7 +16,7 @@ class LicensesScreen extends StatelessWidget { final TextTheme textTheme = theme.textTheme; return Scaffold( appBar: AppTopBar( - title: Text("Credits", + title: Text(AppLocalizations.of(context)!.openSourceLicensesSetting, style: textTheme.titleMedium?.copyWith( color: colorScheme.onBackground.withOpacity(0.6), )), diff --git a/lib/theme/widgets/theme_preview_card.dart b/lib/theme/widgets/theme_preview_card.dart index 8ca5f6c0..21ac9dfa 100644 --- a/lib/theme/widgets/theme_preview_card.dart +++ b/lib/theme/widgets/theme_preview_card.dart @@ -1,6 +1,7 @@ import 'package:clock_app/common/logic/card_decoration.dart'; import 'package:clock_app/common/widgets/card_container.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class ThemePreviewCard extends StatelessWidget { const ThemePreviewCard({ @@ -25,7 +26,7 @@ class ThemePreviewCard extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( - "Preview", + AppLocalizations.of(context)!.previewLabel, style: textTheme.headlineMedium?.copyWith( color: colorScheme.onBackground, ), @@ -42,7 +43,7 @@ class ThemePreviewCard extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(16.0), child: Text( - "Card", + AppLocalizations.of(context)!.cardLabel, style: textTheme.headlineSmall?.copyWith( color: colorScheme.onSurface, ), @@ -55,7 +56,7 @@ class ThemePreviewCard extends StatelessWidget { color: colorScheme.primary, child: Padding( padding: const EdgeInsets.all(16.0), - child: Text("Accent", + child: Text(AppLocalizations.of(context)!.accentLabel, style: textTheme.bodyMedium ?.copyWith(color: colorScheme.onPrimary)), ), @@ -65,7 +66,7 @@ class ThemePreviewCard extends StatelessWidget { color: colorScheme.error, child: Padding( padding: const EdgeInsets.all(16.0), - child: Text("Error", + child: Text(AppLocalizations.of(context)!.errorLabel, style: textTheme.bodyMedium ?.copyWith(color: colorScheme.onError)), ), diff --git a/patreons.csv b/patreons.csv new file mode 100644 index 00000000..7bb8b8ee --- /dev/null +++ b/patreons.csv @@ -0,0 +1,4 @@ +Name,Email,Discord,Patron Status,Follows You,Free Member,Free Trial,Lifetime Amount,Pledge Amount,Charge Frequency,Tier,Addressee,Street,City,State,Zip,Country,Phone,Patronage Since Date,Last Charge Date,Last Charge Status,Additional Details,User ID,Last Updated,Currency,Max Posts,Access Expiration,Next Charge Date +Potato,patreon@cinna.boo,,Active patron,No,No,No,3.66,3.66,monthly,,,,,,,,,2024-05-07 11:33:33,2024-05-07 11:33:35,Paid,,128102512,2024-05-07 11:58:39,USD,,,2024-06-07 00:00:00 +Thorsten,patreon.com@th23.net,,Active patron,No,Yes,No,53.76,0.00,monthly,Free,,,,,,,,2024-05-04 06:21:11,2024-05-04 06:21:13,Paid,,127707165,2024-05-04 06:46:20,USD,,2024-06-04 00:00:00,2024-06-04 00:00:00 +Azeem Sarwar,azeemswr.as@gmail.com,,,No,Yes,No,0.00,0.00,,Free,,,,,,,,2024-04-13 13:26:21,,,,124960783,2024-04-13 13:26:21,USD,,, diff --git a/pubspec.yaml b/pubspec.yaml index a6125d7c..b2e6de8e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -87,8 +87,10 @@ flutter: assets: - assets/timezones.db - assets/images/ + - assets/contributors/ + - assets/contributors/avatars/ + - assets/patreons/ - assets/ringtones/ - - assets/contributors.json fonts: - family: Rubik fonts: diff --git a/scripts/contributors.py b/scripts/contributors.py new file mode 100644 index 00000000..489d2d1f --- /dev/null +++ b/scripts/contributors.py @@ -0,0 +1,44 @@ +import requests +import os +import json + +def fetch_contributors(repo_owner, repo_name): + url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/contributors" + response = requests.get(url) + contributors_data = response.json() + return contributors_data + +def download_avatar(contributor, output_dir): + avatar_url = contributor['avatar_url'] + avatar_name = f"{avatar_url.split('/')[-1]}.jpg" + avatar_path = os.path.join(output_dir, avatar_name) + with open(avatar_path, 'wb') as avatar_file: + response = requests.get(avatar_url) + avatar_file.write(response.content) + return avatar_name + +def main(repo_owner, repo_name): + contributors_data = fetch_contributors(repo_owner, repo_name) + output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../assets/contributors/') + avatar_output_dir = os.path.join(output_dir, 'avatars') + json_output_dir = os.path.join(output_dir, 'git.json') + os.makedirs(avatar_output_dir, exist_ok=True) + + contributors = [] + for contributor in contributors_data: + avatar_name = download_avatar(contributor, avatar_output_dir) + contributor_info = { + 'username': contributor['login'], + 'avatar_url': f'assets/contributors/avatars/{avatar_name}', + 'profile_url': contributor['html_url'] + } + contributors.append(contributor_info) + + with open(json_output_dir, 'w') as json_file: + json.dump(contributors, json_file, indent=4) + print("Contributors data saved to git.json") + +if __name__ == "__main__": + repo_owner = "vicolo-dev" + repo_name = "chrono" + main(repo_owner, repo_name) diff --git a/scripts/patreons.py b/scripts/patreons.py new file mode 100644 index 00000000..802fd687 --- /dev/null +++ b/scripts/patreons.py @@ -0,0 +1,26 @@ +import csv +import json +import requests +import os + +def csv_to_json(csv_file, json_file): + members = [] + with open(csv_file, 'r') as file: + csv_reader = csv.DictReader(file) + for row in csv_reader: + if(float(row['Lifetime Amount']) > 0): + member_info = { + 'name': row['Name'], + 'lifetime_amount': row['Lifetime Amount'], + 'email': row['Email'], + } + members.append(member_info) + json_output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../assets/patreons/') + os.makedirs(json_output_dir, exist_ok=True) + json_output_path = os.path.join(json_output_dir, 'patreons.json') + with open(json_output_path, 'w') as json_file: + json.dump(members, json_file, indent=4) + print("CSV converted to JSON") + +if __name__ == "__main__": + csv_to_json('patreons.csv', 'patreons.json') From 4ec2dbae2f768c75879a11e68f6401f7f7832634 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Wed, 8 May 2024 14:03:44 +0500 Subject: [PATCH 086/112] Fix tests for localization --- test/alarm/logic/schedule_description_test.dart | 15 ++++++++++----- test/alarm/widgets/alarm_card_test.dart | 4 ++++ test/clock/widgets/time_display_test.dart | 1 + test/clock/widgets/timezone_card_test.dart | 6 +++++- test/clock/widgets/timezone_search_card_test.dart | 4 ++++ test/common/utils/weekday_utils_test.dart | 8 ++++---- .../widgets/fields/date_picker_field_test.dart | 4 ++++ test/common/widgets/fields/input_field_test.dart | 4 ++++ test/common/widgets/fields/select_field_test.dart | 4 ++++ test/common/widgets/fields/slider_field_test.dart | 4 ++++ test/common/widgets/fields/switch_field_test.dart | 4 ++++ test/common/widgets/fields/toggle_field_test.dart | 4 ++++ test/common/widgets/time_picker_test.dart | 4 ++++ test/theme/widgets/theme_card_test.dart | 7 ++++++- test/theme/widgets/theme_preview_card_test.dart | 4 ++++ test/timer/widgets/timer_card_test.dart | 8 ++++++-- 16 files changed, 72 insertions(+), 13 deletions(-) diff --git a/test/alarm/logic/schedule_description_test.dart b/test/alarm/logic/schedule_description_test.dart index 5b44a6bf..5c717db5 100644 --- a/test/alarm/logic/schedule_description_test.dart +++ b/test/alarm/logic/schedule_description_test.dart @@ -6,15 +6,20 @@ import 'package:clock_app/common/types/time.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:intl/intl.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; void testDescription(String name, Function(BuildContext) callback) { testWidgets(name, (WidgetTester tester) async { await tester.pumpWidget( - Builder( - builder: (BuildContext context) { - callback(context); - return const Placeholder(); - }, + Localizations( + delegates: AppLocalizations.localizationsDelegates, + locale: const Locale('en'), + child: Builder( + builder: (BuildContext context) { + callback(context); + return const Placeholder(); + }, + ), ), ); }); diff --git a/test/alarm/widgets/alarm_card_test.dart b/test/alarm/widgets/alarm_card_test.dart index 669f8b05..f38dacb9 100644 --- a/test/alarm/widgets/alarm_card_test.dart +++ b/test/alarm/widgets/alarm_card_test.dart @@ -4,6 +4,7 @@ import 'package:clock_app/common/types/time.dart'; import 'package:clock_app/theme/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const testKey = Key('key'); var sampleAlarm = Alarm(const Time(hour: 2, minute: 30)); @@ -88,6 +89,9 @@ void main() { Future _renderWidget(WidgetTester tester, [Alarm? alarm]) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, theme: defaultTheme, home: Scaffold( body: AlarmCard( diff --git a/test/clock/widgets/time_display_test.dart b/test/clock/widgets/time_display_test.dart index d7c16c98..76c91c4a 100644 --- a/test/clock/widgets/time_display_test.dart +++ b/test/clock/widgets/time_display_test.dart @@ -3,6 +3,7 @@ import 'package:clock_app/theme/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:intl/intl.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; void main() { testWidgets('TimeDisplay shows time correctly ...', (tester) async { diff --git a/test/clock/widgets/timezone_card_test.dart b/test/clock/widgets/timezone_card_test.dart index 698b31f1..f5937715 100644 --- a/test/clock/widgets/timezone_card_test.dart +++ b/test/clock/widgets/timezone_card_test.dart @@ -4,6 +4,7 @@ import 'package:clock_app/theme/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:timezone/data/latest_all.dart' as timezone_db; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; bool deleted = false; const testKey = Key('key'); @@ -30,11 +31,14 @@ void main() { Future _renderWidget(WidgetTester tester) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, theme: defaultTheme, home: TimeZoneCard( city: sampleCity, key: testKey, - onDelete: (){}, + onDelete: () {}, ), ), ); diff --git a/test/clock/widgets/timezone_search_card_test.dart b/test/clock/widgets/timezone_search_card_test.dart index d5e09910..6cd921e4 100644 --- a/test/clock/widgets/timezone_search_card_test.dart +++ b/test/clock/widgets/timezone_search_card_test.dart @@ -4,6 +4,7 @@ import 'package:clock_app/theme/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:timezone/data/latest_all.dart' as timezone_db; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; var sampleCity = City("Tokyo", "Japan", "Asia/Tokyo"); @@ -35,6 +36,9 @@ void main() { Future _renderWidget(WidgetTester tester) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, theme: defaultTheme, home: TimeZoneSearchCard( city: sampleCity, diff --git a/test/common/utils/weekday_utils_test.dart b/test/common/utils/weekday_utils_test.dart index c96aac55..79a335f9 100644 --- a/test/common/utils/weekday_utils_test.dart +++ b/test/common/utils/weekday_utils_test.dart @@ -6,25 +6,25 @@ void main() { group('weekdaysContains', () { test('returns true when the weekday is contained in the list', () { final testWeekdays = [weekdays[0]]; - expect(weekdaysContains(testWeekdays, 'Mon'), isTrue); + expect(weekdaysContains(testWeekdays, 1), isTrue); }); test('returns false when the weekday is not contained in the list', () { final testWeekdays = [weekdays[0]]; - expect(weekdaysContains(testWeekdays, 'Tue'), isFalse); + expect(weekdaysContains(testWeekdays, 2), isFalse); }); }); group('weekdaysContainsAll', () { test('returns true when all the weekdays are contained in the list', () { final testWeekdays = [weekdays[5], weekdays[6]]; - expect(weekdaysContainsAll(testWeekdays, ['Sat', 'Sun']), isTrue); + expect(weekdaysContainsAll(testWeekdays, [6, 7]), isTrue); }); test('returns false when at least one weekday is not contained in the list', () { final testWeekdays = [weekdays[4], weekdays[6]]; - expect(weekdaysContainsAll(testWeekdays, ['Sat', 'Mon']), isFalse); + expect(weekdaysContainsAll(testWeekdays, [6, 1]), isFalse); }); }); } diff --git a/test/common/widgets/fields/date_picker_field_test.dart b/test/common/widgets/fields/date_picker_field_test.dart index 51406f3b..369a9072 100644 --- a/test/common/widgets/fields/date_picker_field_test.dart +++ b/test/common/widgets/fields/date_picker_field_test.dart @@ -2,6 +2,7 @@ import 'package:clock_app/common/widgets/fields/date_picker_field.dart'; import 'package:clock_app/theme/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const title = 'Test'; const hintText = 'TestHint'; @@ -76,6 +77,9 @@ Future _renderWidget(WidgetTester tester, void Function(List)? onChanged}) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, theme: defaultTheme, home: Scaffold( body: DatePickerField( diff --git a/test/common/widgets/fields/input_field_test.dart b/test/common/widgets/fields/input_field_test.dart index e1652e0a..3506d8ff 100644 --- a/test/common/widgets/fields/input_field_test.dart +++ b/test/common/widgets/fields/input_field_test.dart @@ -1,6 +1,7 @@ import 'package:clock_app/common/widgets/fields/input_field.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const title = 'Test'; const hintText = 'TestHint'; @@ -108,6 +109,9 @@ Future _renderWidget(WidgetTester tester, {String value = "", void Function(String)? onChanged}) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: InputField( value: value, diff --git a/test/common/widgets/fields/select_field_test.dart b/test/common/widgets/fields/select_field_test.dart index 947af00d..274c8cef 100644 --- a/test/common/widgets/fields/select_field_test.dart +++ b/test/common/widgets/fields/select_field_test.dart @@ -3,6 +3,7 @@ import 'package:clock_app/common/widgets/fields/select_field/option_cards/text_o import 'package:clock_app/common/widgets/fields/select_field/select_field.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const title = 'Test'; final choices = [ @@ -140,6 +141,9 @@ Future _renderWidget(WidgetTester tester, {int selectedIndex = 0, void Function(List)? onChanged}) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: SelectField( selectedIndices: [selectedIndex], diff --git a/test/common/widgets/fields/slider_field_test.dart b/test/common/widgets/fields/slider_field_test.dart index 50227e32..04a5ae9e 100644 --- a/test/common/widgets/fields/slider_field_test.dart +++ b/test/common/widgets/fields/slider_field_test.dart @@ -1,6 +1,7 @@ import 'package:clock_app/common/widgets/fields/slider_field.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const name = 'Test Slider'; const unit = 'unit'; @@ -37,6 +38,9 @@ Future _renderWidget(WidgetTester tester, {double value = 0, void Function(double)? onChanged}) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: SliderField( value: value, diff --git a/test/common/widgets/fields/switch_field_test.dart b/test/common/widgets/fields/switch_field_test.dart index 27b66816..7ad75abd 100644 --- a/test/common/widgets/fields/switch_field_test.dart +++ b/test/common/widgets/fields/switch_field_test.dart @@ -1,6 +1,7 @@ import 'package:clock_app/common/widgets/fields/switch_field.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const name = 'Test Switch'; @@ -67,6 +68,9 @@ Future _renderWidget(WidgetTester tester, {value = false, void Function(bool) onChanged = _defaultOnChanged}) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: SwitchField( name: name, diff --git a/test/common/widgets/fields/toggle_field_test.dart b/test/common/widgets/fields/toggle_field_test.dart index 5ae7ec31..4670505b 100644 --- a/test/common/widgets/fields/toggle_field_test.dart +++ b/test/common/widgets/fields/toggle_field_test.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:clock_app/common/widgets/fields/toggle_field.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const List> testOptions = [ ToggleOption('Option 1', 1), @@ -56,6 +57,9 @@ Future _renderWidget(WidgetTester tester, void Function(int)? onChange}) async { await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: ToggleField( name: name ?? 'Test Field', diff --git a/test/common/widgets/time_picker_test.dart b/test/common/widgets/time_picker_test.dart index 4ce8224a..a3d017b2 100644 --- a/test/common/widgets/time_picker_test.dart +++ b/test/common/widgets/time_picker_test.dart @@ -2,6 +2,7 @@ import 'package:clock_app/common/types/picker_result.dart'; import 'package:clock_app/common/widgets/time_picker.dart'; import 'package:flutter/material.dart' hide TimePickerDialog; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; TimeOfDay selectedTime = const TimeOfDay(hour: 12, minute: 30); @@ -126,6 +127,9 @@ void main() { Future _renderWidget(WidgetTester tester) async { return await tester.pumpWidget( MaterialApp( + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: Builder( builder: (BuildContext context) { diff --git a/test/theme/widgets/theme_card_test.dart b/test/theme/widgets/theme_card_test.dart index b2ca262d..3c23b1b4 100644 --- a/test/theme/widgets/theme_card_test.dart +++ b/test/theme/widgets/theme_card_test.dart @@ -6,6 +6,7 @@ import 'package:clock_app/theme/utils/style_theme.dart'; import 'package:clock_app/theme/widgets/theme_card.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const testKey = Key('key'); var sampleStyleTheme = StyleTheme(); @@ -74,6 +75,9 @@ Future _renderStyleThemeCard(WidgetTester tester, await tester.pumpWidget( MaterialApp( theme: defaultTheme, + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: ThemeCard( themeItem: sampleStyleTheme, @@ -81,7 +85,8 @@ Future _renderStyleThemeCard(WidgetTester tester, onPressDelete: () {}, onPressDuplicate: () {}, onPressEdit: () {}, - getThemeFromItem: (theme, item) => getTheme(colorScheme:theme.colorScheme, styleTheme: item), + getThemeFromItem: (theme, item) => + getTheme(colorScheme: theme.colorScheme, styleTheme: item), key: testKey, ), ), diff --git a/test/theme/widgets/theme_preview_card_test.dart b/test/theme/widgets/theme_preview_card_test.dart index 161bb16d..02cab6f5 100644 --- a/test/theme/widgets/theme_preview_card_test.dart +++ b/test/theme/widgets/theme_preview_card_test.dart @@ -3,6 +3,7 @@ import 'package:clock_app/theme/theme.dart'; import 'package:clock_app/theme/widgets/theme_preview_card.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const testKey = Key('key'); var defaultColorScheme = defaultTheme.colorScheme; @@ -70,6 +71,9 @@ Future _renderStyleThemeCard(WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: defaultTheme, + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: const Scaffold( body: ThemePreviewCard( key: testKey, diff --git a/test/timer/widgets/timer_card_test.dart b/test/timer/widgets/timer_card_test.dart index 415eadc9..d7a3da20 100644 --- a/test/timer/widgets/timer_card_test.dart +++ b/test/timer/widgets/timer_card_test.dart @@ -4,6 +4,7 @@ import 'package:clock_app/timer/widgets/timer_card.dart'; import 'package:clock_app/theme/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const testKey = Key('key'); var sampleTimer = @@ -78,14 +79,17 @@ Future _renderWidget(WidgetTester tester, [ClockTimer? timer]) async { await tester.pumpWidget( MaterialApp( theme: defaultTheme, + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: TimerCard( timer: timer ?? sampleTimer, onToggleState: () {}, onPressDelete: () {}, onPressDuplicate: () {}, - onPressReset: (){}, - onPressAddTime: (){}, + onPressReset: () {}, + onPressAddTime: () {}, key: testKey, ), ), From 62bca415121ae8e333cc96e1585c6f48226c39a3 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Wed, 8 May 2024 14:12:03 +0500 Subject: [PATCH 087/112] Fix syntax error in spanish --- lib/l10n/app_es.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 3c7e5d1e..920d32b7 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -543,7 +543,7 @@ "@searchCityPlaceholder": {}, "durationPickerTitle": "Elige la duración", "@durationPickerTitle": {}, - "relativeTime": "{hours}h {relativo, seleccionar, adelante{ahead} detrás{behind} otros{Other}}", + "relativeTime": "{hours}h {relative, select, ahead{adelante} behind{detrás} other{Other}}", "@relativeTime": {}, "thursdayFull": "Jueves", "@thursdayFull": {}, From ce612264c3cfebdeed96115d17bef2b68191d624 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Wed, 8 May 2024 09:26:36 +0000 Subject: [PATCH 088/112] Translated using Weblate (Spanish) Currently translated at 100.0% (300 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/es/ --- lib/l10n/app_es.arb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 920d32b7..e36a5e15 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -584,5 +584,19 @@ "cityAlreadyInFavorites": "Esta ciudad ya está en tus favoritos", "@cityAlreadyInFavorites": {}, "mondayFull": "Lunes", - "@mondayFull": {} + "@mondayFull": {}, + "openSourceLicensesSetting": "Licencias de código abierto", + "@openSourceLicensesSetting": {}, + "contributorsSetting": "Colaboradores", + "@contributorsSetting": {}, + "donorsSetting": "Donantes", + "@donorsSetting": {}, + "donateButton": "Donar", + "@donateButton": {}, + "donateDescription": "Donar para apoyar el desarrollo de la aplicación", + "@donateDescription": {}, + "donorsDescription": "Nuestros generosos mecenas", + "@donorsDescription": {}, + "contributorsDescription": "Personas que hacen posible esta aplicación", + "@contributorsDescription": {} } From 14c73c297ebfe6c58db08e4e7bc60dd442c75b75 Mon Sep 17 00:00:00 2001 From: "Brice dOliveira ([#]b-do)" Date: Wed, 8 May 2024 09:39:36 +0000 Subject: [PATCH 089/112] Translated using Weblate (French) Currently translated at 98.6% (296 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index ae43bfb1..188ec01e 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -103,7 +103,7 @@ "@alarmScheduleSettingGroup": {}, "soundSettingGroup": "Son", "@soundSettingGroup": {}, - "settingGroupMore": "Paramètres supplémentaires", + "settingGroupMore": "Plus", "@settingGroupMore": {}, "melodySetting": "Mélodie", "@melodySetting": {}, @@ -592,5 +592,13 @@ "styleThemeElevationSetting": "Élévation", "@styleThemeElevationSetting": {}, "searchSettingPlaceholder": "Rechercher", - "@searchSettingPlaceholder": {} + "@searchSettingPlaceholder": {}, + "openSourceLicensesSetting": "Licence open source", + "@openSourceLicensesSetting": {}, + "contributorsSetting": "Contributeurs", + "@contributorsSetting": {}, + "donorsSetting": "Donateurs", + "@donorsSetting": {}, + "donateButton": "Donner", + "@donateButton": {} } From 1277349f71144e161fb19ad6aaacbb2af79dd51e Mon Sep 17 00:00:00 2001 From: "Brice dOliveira ([#]b-do)" Date: Wed, 8 May 2024 09:43:31 +0000 Subject: [PATCH 090/112] Translated using Weblate (French) Currently translated at 100.0% (300 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 188ec01e..88365b72 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -543,7 +543,7 @@ "@sameTime": {}, "searchCityPlaceholder": "Rechercher une ville", "@searchCityPlaceholder": {}, - "relativeTime": "{hours}h {relative, select, ahead{ahead} behind{behind} other{Other}}", + "relativeTime": "{hours}h {relative, select, ahead{d’avance} behind{de retard} other{Other}}", "@relativeTime": {}, "cityAlreadyInFavorites": "Cette ville est déjà dans vos favoris", "@cityAlreadyInFavorites": {}, @@ -600,5 +600,11 @@ "donorsSetting": "Donateurs", "@donorsSetting": {}, "donateButton": "Donner", - "@donateButton": {} + "@donateButton": {}, + "donorsDescription": "Nos généreux patreons", + "@donorsDescription": {}, + "contributorsDescription": "Personnes qui ont rendu cette app possible", + "@contributorsDescription": {}, + "donateDescription": "Donner pour supporter le développement de l’application", + "@donateDescription": {} } From f5b323f7c6482d61a81062726d038c2619283ef0 Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Wed, 8 May 2024 23:10:29 +0000 Subject: [PATCH 091/112] Translated using Weblate (Portuguese) Currently translated at 53.0% (159 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 88 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 6 deletions(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index b8246140..1e7c5b8b 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -15,7 +15,7 @@ "@timerTitle": { "description": "Title of the timer screen" }, - "backupSettingGroup": "Backup", + "backupSettingGroup": "Definições", "@backupSettingGroup": {}, "developerOptionsSettingGroup": "Opções de programador", "@developerOptionsSettingGroup": {}, @@ -213,7 +213,7 @@ "@durationPickerSetting": {}, "pickerRings": "Anéis", "@pickerRings": {}, - "swipeActionSetting": "Ação de deslizae", + "swipeActionSetting": "Ação de deslize", "@swipeActionSetting": {}, "system": "Sistema", "@system": {}, @@ -221,7 +221,7 @@ "@languageSetting": {}, "dateFormatSetting": "Formato da data", "@dateFormatSetting": {}, - "timeFormatSetting": "Formato das horas", + "timeFormatSetting": "Formato da hora", "@timeFormatSetting": {}, "timeFormat12": "12 horas", "@timeFormat12": {}, @@ -231,7 +231,7 @@ "@timeFormatDevice": {}, "showSecondsSetting": "Mostrar segundos", "@showSecondsSetting": {}, - "timePickerSetting": "Seletor de horas", + "timePickerSetting": "Seletor de hora", "@timePickerSetting": {}, "pickerDial": "Marcador", "@pickerDial": {}, @@ -249,8 +249,84 @@ "@melodiesSetting": {}, "tagsSetting": "Etiquetas", "@tagsSetting": {}, - "vendorSetting": "Definição d fornecedor", + "vendorSetting": "Definição do fabricante", "@vendorSetting": {}, "batteryOptimizationSetting": "Desativar otimização de bateria", - "@batteryOptimizationSetting": {} + "@batteryOptimizationSetting": {}, + "colorSetting": "Cor", + "@colorSetting": {}, + "textColorSetting": "Texto", + "@textColorSetting": {}, + "styleThemeShapeSettingGroup": "Forma", + "@styleThemeShapeSettingGroup": {}, + "styleThemeElevationSetting": "Elevação", + "@styleThemeElevationSetting": {}, + "styleThemeShadowSettingGroup": "Sombra", + "@styleThemeShadowSettingGroup": {}, + "autoStartSetting": "Arranque automático", + "@autoStartSetting": {}, + "vendorSettingDescription": "Desativar otimizações definidas pelo fabricante", + "@vendorSettingDescription": {}, + "batteryOptimizationSettingDescription": "Desativar otimização de bateria para permitir um correto funcionamento da aplicação", + "@batteryOptimizationSettingDescription": {}, + "allowNotificationSettingDescription": "Permitir notificações no ecrã de bloqueio", + "@allowNotificationSettingDescription": {}, + "autoStartSettingDescription": "Em alguns dispositivos, tem que ativar o arranque automático para ativar os alarmes quando a aplicação está fechada", + "@autoStartSettingDescription": {}, + "allowNotificationSetting": "Permitir notificações", + "@allowNotificationSetting": {}, + "extraAnimationSetting": "Animações adicionais", + "@extraAnimationSetting": {}, + "animationSettingGroup": "Animações", + "@animationSettingGroup": {}, + "animationSpeedSetting": "Velocidade das animações", + "@animationSpeedSetting": {}, + "nameField": "Nome", + "@nameField": {}, + "colorSchemeNamePlaceholder": "Esquema de cores", + "@colorSchemeNamePlaceholder": {}, + "colorSchemeBackgroundSettingGroup": "Fundo", + "@colorSchemeBackgroundSettingGroup": {}, + "colorSchemeAccentSettingGroup": "Destaque", + "@colorSchemeAccentSettingGroup": {}, + "colorSchemeErrorSettingGroup": "Erro", + "@colorSchemeErrorSettingGroup": {}, + "colorSchemeCardSettingGroup": "Cartão", + "@colorSchemeCardSettingGroup": {}, + "colorSchemeOutlineSettingGroup": "Contorno", + "@colorSchemeOutlineSettingGroup": {}, + "colorSchemeShadowSettingGroup": "Sombra", + "@colorSchemeShadowSettingGroup": {}, + "colorSchemeUseAccentAsOutlineSetting": "Mesma cor para destaque e contorno", + "@colorSchemeUseAccentAsOutlineSetting": {}, + "colorSchemeUseAccentAsShadowSetting": "Mesma cor para destaque e sombra", + "@colorSchemeUseAccentAsShadowSetting": {}, + "styleThemeNamePlaceholder": "Estilo do tema", + "@styleThemeNamePlaceholder": {}, + "styleThemeRadiusSetting": "Curva dos cantos", + "@styleThemeRadiusSetting": {}, + "styleThemeOpacitySetting": "Opacidade", + "@styleThemeOpacitySetting": {}, + "styleThemeBlurSetting": "Desfoque", + "@styleThemeBlurSetting": {}, + "styleThemeOutlineSettingGroup": "Contorno", + "@styleThemeOutlineSettingGroup": {}, + "styleThemeOutlineWidthSetting": "Largura", + "@styleThemeOutlineWidthSetting": {}, + "showIstantAlarmButtonSetting": "Mostrar botão de alarme rápido", + "@showIstantAlarmButtonSetting": {}, + "showIstantTimerButtonSetting": "Mostrar botão de cronómetro rápido", + "@showIstantTimerButtonSetting": {}, + "logsSettingGroup": "Registos", + "@logsSettingGroup": {}, + "maxLogsSetting": "Máximo", + "@maxLogsSetting": {}, + "alarmLogSetting": "Registo de alarmes", + "@alarmLogSetting": {}, + "resetButton": "Repor", + "@resetButton": {}, + "previewLabel": "Antevisão", + "@previewLabel": {}, + "cardLabel": "Cartão", + "@cardLabel": {} } From 06fbfff6eb96164bde8d161968260990f4b1ff62 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Thu, 9 May 2024 18:47:56 +0500 Subject: [PATCH 092/112] Make widgets configurable --- android/app/src/main/AndroidManifest.xml | 4 +- .../chrono/AnalogueClockWidgetProvider.kt | 90 +++++++------- .../chrono/DigitalClockWidgetProvider.kt | 110 ++++++++++-------- .../main/res/layout/digital_clock_widget.xml | 2 + .../main/res/xml/analogue_clock_widget.xml | 5 +- .../src/main/res/xml/digital_clock_widget.xml | 7 +- lib/app.dart | 37 +++++- lib/navigation/screens/nav_scaffold.dart | 2 + lib/widgets/logic/update_widgets.dart | 10 ++ pubspec.lock | 7 ++ pubspec.yaml | 4 + 11 files changed, 179 insertions(+), 99 deletions(-) create mode 100644 lib/widgets/logic/update_widgets.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index db796bcf..e34d8a59 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -126,14 +126,14 @@ - + - + diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt index 917a2e42..eba3e283 100644 --- a/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt +++ b/android/app/src/main/kotlin/com/vicolo/chrono/AnalogueClockWidgetProvider.kt @@ -3,59 +3,65 @@ package com.vicolo.chrono import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetProvider -import android.content.ComponentName import android.content.Context import android.content.Intent -import android.os.Bundle import android.widget.RemoteViews -import com.vicolo.chrono.MainActivity // import es.antonborri.home_widget.HomeWidgetBackgroundIntent // import es.antonborri.home_widget.HomeWidgetLaunchIntent // import es.antonborri.home_widget.HomeWidgetProvider class AnalogueClockWidgetProvider : AppWidgetProvider() { - - override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { // Perform this loop procedure for each widget that belongs to this + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray, + ) { // Perform this loop procedure for each widget that belongs to this // provider. appWidgetIds.forEach { appWidgetId -> // Create an Intent to launch ExampleActivity. - // Open App on Widget Click - val views = RemoteViews(context.packageName, R.layout.analogue_clock_widget).apply { - // Open App on Widget Click - val pendingIntent: PendingIntent = PendingIntent.getActivity( - /* context = */ context, - /* requestCode = */ 0, - /* intent = */ Intent(context, MainActivity::class.java), - /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - // Swap Title Text by calling Dart Code in the Background - // setTextViewText(R.id.widget_title, widgetData.getString("title", null) - // ?: "No Title Set") - // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( - // context, - // Uri.parse("homeWidgetExample://titleClicked") - // ) - // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) - // - // val message = widgetData.getString("message", null) - // setTextViewText(R.id.widget_message, message - // ?: "No Message Set") - // // Show Images saved with `renderFlutterWidget` - // val image = widgetData.getString("dashIcon", null) - // if (image != null) { - // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) - // setViewVisibility(R.id.widget_img, View.VISIBLE) - // } else { - // setViewVisibility(R.id.widget_img, View.GONE) - // } - // - // // Detect App opened via Click inside Flutter - // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( - // context, - // MainActivity::class.java, - // Uri.parse("homeWidgetExample://message?message=$message")) - // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) - } + // Open App on Widget Click + val views = + RemoteViews(context.packageName, R.layout.analogue_clock_widget).apply { + // Open App on Widget Click + val pendingIntent: PendingIntent = + PendingIntent.getActivity( + // context = + context, + // requestCode = + 0, + // intent = + Intent(context, MainActivity::class.java), + // flags = + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + // Swap Title Text by calling Dart Code in the Background + // setTextViewText(R.id.widget_title, widgetData.getString("title", null) + // ?: "No Title Set") + // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + // context, + // Uri.parse("homeWidgetExample://titleClicked") + // ) + // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + // + // val message = widgetData.getString("message", null) + // setTextViewText(R.id.widget_message, message + // ?: "No Message Set") + // // Show Images saved with `renderFlutterWidget` + // val image = widgetData.getString("dashIcon", null) + // if (image != null) { + // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) + // setViewVisibility(R.id.widget_img, View.VISIBLE) + // } else { + // setViewVisibility(R.id.widget_img, View.GONE) + // } + // + // // Detect App opened via Click inside Flutter + // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + // context, + // MainActivity::class.java, + // Uri.parse("homeWidgetExample://message?message=$message")) + // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) + } // Get the layout for the widget and attach an onClick listener to // the button. // val views: RemoteViews = RemoteViews( diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt index 112748a3..22e8ee7d 100644 --- a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt +++ b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt @@ -3,59 +3,77 @@ package com.vicolo.chrono import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetProvider -import android.content.ComponentName import android.content.Context import android.content.Intent -import android.os.Bundle import android.widget.RemoteViews -import com.vicolo.chrono.MainActivity -// import es.antonborri.home_widget.HomeWidgetBackgroundIntent -// import es.antonborri.home_widget.HomeWidgetLaunchIntent -// import es.antonborri.home_widget.HomeWidgetProvider +import android.content.SharedPreferences +import es.antonborri.home_widget.HomeWidgetBackgroundIntent +import es.antonborri.home_widget.HomeWidgetLaunchIntent +import es.antonborri.home_widget.HomeWidgetProvider +import es.antonborri.home_widget.HomeWidgetPlugin +import android.util.Log -class DigitalClockWidgetProvider : AppWidgetProvider() { - - override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { // Perform this loop procedure for each widget that belongs to this +class DigitalClockWidgetProvider : HomeWidgetProvider() { + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray, + widgetData: SharedPreferences, + ) { // Perform this loop procedure for each widget that belongs to this // provider. + Log.d("TAG", "======================================YOO") + appWidgetIds.forEach { appWidgetId -> // Create an Intent to launch ExampleActivity. - // Open App on Widget Click - val views = RemoteViews(context.packageName, R.layout.digital_clock_widget).apply { - // Open App on Widget Click - val pendingIntent: PendingIntent = PendingIntent.getActivity( - /* context = */ context, - /* requestCode = */ 0, - /* intent = */ Intent(context, MainActivity::class.java), - /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - // Swap Title Text by calling Dart Code in the Background - // setTextViewText(R.id.widget_title, widgetData.getString("title", null) - // ?: "No Title Set") - // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( - // context, - // Uri.parse("homeWidgetExample://titleClicked") - // ) - // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) - // - // val message = widgetData.getString("message", null) - // setTextViewText(R.id.widget_message, message - // ?: "No Message Set") - // // Show Images saved with `renderFlutterWidget` - // val image = widgetData.getString("dashIcon", null) - // if (image != null) { - // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) - // setViewVisibility(R.id.widget_img, View.VISIBLE) - // } else { - // setViewVisibility(R.id.widget_img, View.GONE) - // } - // - // // Detect App opened via Click inside Flutter - // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( - // context, - // MainActivity::class.java, - // Uri.parse("homeWidgetExample://message?message=$message")) - // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) - } + // Open App on Widget Click + val views = + RemoteViews(context.packageName, R.layout.digital_clock_widget).apply { + // Open App on Widget Click + val pendingIntent: PendingIntent = + PendingIntent.getActivity( + // context = + context, + // requestCode = + 0, + // intent = + Intent(context, MainActivity::class.java), + // flags = + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + val dateFormat = widgetData.getString("dateFormat", "EEE, d MMM") + val timeFormat = widgetData.getString("timeFormat", "HH:mm") + setCharSequence (R.id.widget_text_clock, "setFormat24Hour", timeFormat) + setCharSequence (R.id.widget_text_clock, "setFormat12Hour", timeFormat) + setCharSequence (R.id.widget_date, "setFormat24Hour", dateFormat) + setCharSequence (R.id.widget_date, "setFormat12Hour", dateFormat) + // Swap Title Text by calling Dart Code in the Background + // setTextViewText(R.id.widget_title, widgetData.getString("title", null) + // ?: "No Title Set") + // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + // context, + // Uri.parse("homeWidgetExample://titleClicked") + // ) + // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + // + // val message = widgetData.getString("message", null) + // setTextViewText(R.id.widget_message, message + // ?: "No Message Set") + // // Show Images saved with `renderFlutterWidget` + // val image = widgetData.getString("dashIcon", null) + // if (image != null) { + // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) + // setViewVisibility(R.id.widget_img, View.VISIBLE) + // } else { + // setViewVisibility(R.id.widget_img, View.GONE) + // } + // + // // Detect App opened via Click inside Flutter + // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + // context, + // MainActivity::class.java, + // Uri.parse("homeWidgetExample://message?message=$message")) + // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) + } // Get the layout for the widget and attach an onClick listener to // the button. // val views: RemoteViews = RemoteViews( diff --git a/android/app/src/main/res/layout/digital_clock_widget.xml b/android/app/src/main/res/layout/digital_clock_widget.xml index 7da2af89..38beb6d3 100644 --- a/android/app/src/main/res/layout/digital_clock_widget.xml +++ b/android/app/src/main/res/layout/digital_clock_widget.xml @@ -26,6 +26,7 @@ android:gravity="center" android:includeFontPadding="false" android:maxLines="1" + android:textColor="@android:color/white" android:shadowColor="@android:color/black" android:shadowDy="1" android:shadowRadius="1" @@ -44,6 +45,7 @@ android:gravity="center" android:includeFontPadding="false" android:maxLines="1" + android:textColor="@android:color/white" android:shadowColor="@android:color/black" android:shadowDy="1" android:shadowRadius="1" diff --git a/android/app/src/main/res/xml/analogue_clock_widget.xml b/android/app/src/main/res/xml/analogue_clock_widget.xml index 023ee094..631b3554 100644 --- a/android/app/src/main/res/xml/analogue_clock_widget.xml +++ b/android/app/src/main/res/xml/analogue_clock_widget.xml @@ -2,10 +2,11 @@ diff --git a/android/app/src/main/res/xml/digital_clock_widget.xml b/android/app/src/main/res/xml/digital_clock_widget.xml index 9f49f20a..9392489d 100644 --- a/android/app/src/main/res/xml/digital_clock_widget.xml +++ b/android/app/src/main/res/xml/digital_clock_widget.xml @@ -1,11 +1,12 @@ diff --git a/lib/app.dart b/lib/app.dart index b1caa69f..a789a711 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,6 +1,8 @@ import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:clock_app/alarm/screens/alarm_notification_screen.dart'; +import 'package:clock_app/clock/types/time.dart'; import 'package:clock_app/common/data/app_info.dart'; +import 'package:clock_app/common/utils/time_format.dart'; import 'package:clock_app/l10n/language_local.dart'; import 'package:clock_app/navigation/data/route_observer.dart'; import 'package:clock_app/navigation/screens/nav_scaffold.dart'; @@ -19,11 +21,13 @@ import 'package:clock_app/theme/theme.dart'; import 'package:clock_app/theme/types/style_theme.dart'; import 'package:clock_app/theme/utils/color_scheme.dart'; import 'package:clock_app/timer/screens/timer_notification_screen.dart'; +import 'package:clock_app/widgets/logic/update_widgets.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:home_widget/home_widget.dart'; class App extends StatefulWidget { const App({super.key}); @@ -54,27 +58,52 @@ class _AppState extends State { late SettingGroup _styleSettings; late Setting _animationSpeedSetting; late SettingGroup _generalSettings; + late Setting _timeFormatSetting; + late Setting _dateFormatSetting; + + void updateDateFormat(dynamic value) async { + await HomeWidget.saveWidgetData("dateFormat", value); + updateWidgets(); + } + + void updateTimeFormat(dynamic value) async { + await HomeWidget.saveWidgetData( + "timeFormat", getTimeFormatString(context, value)); + updateWidgets(); + } @override void initState() { super.initState(); + // HomeWidget.updateWidget( + // androidName: 'DigitalClockWidgetProvider', + // ); + NotificationController.setListeners(); _appearanceSettings = appSettings.getGroup("Appearance"); _colorSettings = _appearanceSettings.getGroup("Colors"); _styleSettings = _appearanceSettings.getGroup("Style"); _generalSettings = appSettings.getGroup("General"); - _animationSpeedSetting = _generalSettings - .getGroup("Animations") - .getSetting("Animation Speed"); + _animationSpeedSetting = + _generalSettings.getGroup("Animations").getSetting("Animation Speed"); _animationSpeedSetting.addListener(setAnimationSpeed); + _timeFormatSetting = + _generalSettings.getGroup("Display").getSetting("Time Format"); + _dateFormatSetting = + _generalSettings.getGroup("Display").getSetting("Date Format"); + _timeFormatSetting.addListener(updateTimeFormat); + _dateFormatSetting.addListener(updateDateFormat); + updateDateFormat(_dateFormatSetting.value); + updateTimeFormat(_timeFormatSetting.value); + setAnimationSpeed(_animationSpeedSetting.value); } void setAnimationSpeed(dynamic speed) { // setState(() { - timeDilation = 1 / speed; + timeDilation = 1 / speed; // }); } diff --git a/lib/navigation/screens/nav_scaffold.dart b/lib/navigation/screens/nav_scaffold.dart index 644a532c..59f05442 100644 --- a/lib/navigation/screens/nav_scaffold.dart +++ b/lib/navigation/screens/nav_scaffold.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:clock_app/alarm/logic/new_alarm_snackbar.dart'; import 'package:clock_app/alarm/types/alarm.dart'; +import 'package:clock_app/common/data/app_info.dart'; import 'package:clock_app/common/utils/snackbar.dart'; import 'package:clock_app/icons/flux_icons.dart'; import 'package:clock_app/navigation/data/tabs.dart'; @@ -15,6 +16,7 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/system/logic/handle_intents.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:home_widget/home_widget.dart'; import 'package:receive_intent/receive_intent.dart' as intent_handler; class NavScaffold extends StatefulWidget { diff --git a/lib/widgets/logic/update_widgets.dart b/lib/widgets/logic/update_widgets.dart new file mode 100644 index 00000000..b9d5c89a --- /dev/null +++ b/lib/widgets/logic/update_widgets.dart @@ -0,0 +1,10 @@ +import 'package:home_widget/home_widget.dart'; + +void updateWidgets() { + HomeWidget.updateWidget( + androidName: 'DigitalClockWidgetProvider', + name: 'DigitalClockWidgetProvider', + qualifiedAndroidName: + 'com.vicolo.chrono.DigitalClockWidgetProvider', + ); +} diff --git a/pubspec.lock b/pubspec.lock index 3257899e..47603ad5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -472,6 +472,13 @@ packages: url: "https://github.com/AhsanSarwar45/great_list_view" source: git version: "0.2.3" + home_widget: + dependency: "direct main" + description: + path: "../home_widget" + relative: true + source: path + version: "0.5.0" html: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b2e6de8e..ab82868c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,6 +69,10 @@ dependencies: material_color_utilities: ^0.8.0 flutter_oss_licenses: ^3.0.2 locale_names: ^1.1.1 + # home_widget: ^0.5.0 + home_widget: + path: "../home_widget/" + dev_dependencies: flutter_test: From 60d11f3ee2baa1a66cf76054442241157c437d0b Mon Sep 17 00:00:00 2001 From: hopefutuuuuure886 Date: Thu, 9 May 2024 17:38:16 +0200 Subject: [PATCH 093/112] Added translation using Weblate (Chinese (Simplified)) --- lib/l10n/app_zh_Hans.arb | 1 + 1 file changed, 1 insertion(+) create mode 100644 lib/l10n/app_zh_Hans.arb diff --git a/lib/l10n/app_zh_Hans.arb b/lib/l10n/app_zh_Hans.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_zh_Hans.arb @@ -0,0 +1 @@ +{} From ae1a3ecb27c9dce0485576519d4d2795f2fcae41 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Thu, 9 May 2024 21:28:33 +0500 Subject: [PATCH 094/112] Add actions in select menues --- android/app/src/main/AndroidManifest.xml | 10 +- .../chrono/DigitalClockDateWidgetProvider.kt | 91 ++++++++++++++++++ .../chrono/DigitalClockWidgetProvider.kt | 2 + .../res/layout/digital_clock_date_widget.xml | 68 +++++++++++++ .../main/res/layout/digital_clock_widget.xml | 18 ++-- .../res/xml/digital_clock_date_widget.xml | 12 +++ .../src/main/res/xml/digital_clock_widget.xml | 4 +- lib/alarm/data/alarm_settings_schema.dart | 27 +++++- lib/alarm/widgets/alarm_card.dart | 4 +- lib/common/logic/show_select.dart | 20 ++-- lib/common/types/popup_action.dart | 6 +- lib/common/utils/popup_action.dart | 8 +- lib/common/widgets/card_edit_menu.dart | 8 +- .../select_field/select_bottom_sheet.dart | 95 +++++++++++++------ .../fields/select_field/select_field.dart | 19 ++-- lib/settings/types/setting.dart | 13 +++ .../dynamic_multi_select_setting_card.dart | 1 + .../widgets/dynamic_select_setting_card.dart | 1 + .../widgets/multi_select_setting_card.dart | 4 +- lib/settings/widgets/select_setting_card.dart | 1 + lib/timer/data/timer_settings_schema.dart | 29 ++++++ lib/timer/widgets/timer_card.dart | 11 ++- 22 files changed, 376 insertions(+), 76 deletions(-) create mode 100644 android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockDateWidgetProvider.kt create mode 100644 android/app/src/main/res/layout/digital_clock_date_widget.xml create mode 100644 android/app/src/main/res/xml/digital_clock_date_widget.xml diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e34d8a59..07d76efd 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -139,7 +139,15 @@ - + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockDateWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockDateWidgetProvider.kt new file mode 100644 index 00000000..03b9dd1f --- /dev/null +++ b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockDateWidgetProvider.kt @@ -0,0 +1,91 @@ +package com.vicolo.chrono + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.content.Intent +import android.widget.RemoteViews +import android.content.SharedPreferences +import es.antonborri.home_widget.HomeWidgetBackgroundIntent +import es.antonborri.home_widget.HomeWidgetLaunchIntent +import es.antonborri.home_widget.HomeWidgetProvider +import es.antonborri.home_widget.HomeWidgetPlugin +import android.util.Log + +class DigitalClockDateWidgetProvider : HomeWidgetProvider() { + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray, + widgetData: SharedPreferences, + ) { // Perform this loop procedure for each widget that belongs to this + // provider. + Log.d("TAG", "======================================YOO") + + appWidgetIds.forEach { appWidgetId -> + // Create an Intent to launch ExampleActivity. + // Open App on Widget Click + val views = + RemoteViews(context.packageName, R.layout.digital_clock_date_widget).apply { + // Open App on Widget Click + val pendingIntent: PendingIntent = + PendingIntent.getActivity( + // context = + context, + // requestCode = + 0, + // intent = + Intent(context, MainActivity::class.java), + // flags = + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + val dateFormat = widgetData.getString("dateFormat", "EEE, d MMM") + val timeFormat = widgetData.getString("timeFormat", "HH:mm") + setCharSequence (R.id.widget_text_clock, "setFormat24Hour", timeFormat) + setCharSequence (R.id.widget_text_clock, "setFormat12Hour", timeFormat) + setCharSequence (R.id.widget_date, "setFormat24Hour", dateFormat) + setCharSequence (R.id.widget_date, "setFormat12Hour", dateFormat) + // Swap Title Text by calling Dart Code in the Background + // setTextViewText(R.id.widget_title, widgetData.getString("title", null) + // ?: "No Title Set") + // val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + // context, + // Uri.parse("homeWidgetExample://titleClicked") + // ) + // setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + // + // val message = widgetData.getString("message", null) + // setTextViewText(R.id.widget_message, message + // ?: "No Message Set") + // // Show Images saved with `renderFlutterWidget` + // val image = widgetData.getString("dashIcon", null) + // if (image != null) { + // setImageViewBitmap(R.id.widget_img, BitmapFactory.decodeFile(image)) + // setViewVisibility(R.id.widget_img, View.VISIBLE) + // } else { + // setViewVisibility(R.id.widget_img, View.GONE) + // } + // + // // Detect App opened via Click inside Flutter + // val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + // context, + // MainActivity::class.java, + // Uri.parse("homeWidgetExample://message?message=$message")) + // setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) + } + // Get the layout for the widget and attach an onClick listener to + // the button. + // val views: RemoteViews = RemoteViews( + // context.packageName, + // R.layout.appwidget_provider_layout + // ).apply { + // setOnClickPendingIntent(R.id.button, pendingIntent) + // } + + // Tell the AppWidgetManager to perform an update on the current + // widget. + appWidgetManager.updateAppWidget(appWidgetId, views) + } + } +} diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt index 22e8ee7d..9dc5a4b5 100644 --- a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt +++ b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt @@ -12,6 +12,7 @@ import es.antonborri.home_widget.HomeWidgetLaunchIntent import es.antonborri.home_widget.HomeWidgetProvider import es.antonborri.home_widget.HomeWidgetPlugin import android.util.Log +import android.view.View class DigitalClockWidgetProvider : HomeWidgetProvider() { override fun onUpdate( @@ -46,6 +47,7 @@ class DigitalClockWidgetProvider : HomeWidgetProvider() { setCharSequence (R.id.widget_text_clock, "setFormat12Hour", timeFormat) setCharSequence (R.id.widget_date, "setFormat24Hour", dateFormat) setCharSequence (R.id.widget_date, "setFormat12Hour", dateFormat) + // setViewVisibility(R.id.widget_date, View.GONE) // Swap Title Text by calling Dart Code in the Background // setTextViewText(R.id.widget_title, widgetData.getString("title", null) // ?: "No Title Set") diff --git a/android/app/src/main/res/layout/digital_clock_date_widget.xml b/android/app/src/main/res/layout/digital_clock_date_widget.xml new file mode 100644 index 00000000..e0194f67 --- /dev/null +++ b/android/app/src/main/res/layout/digital_clock_date_widget.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/digital_clock_widget.xml b/android/app/src/main/res/layout/digital_clock_widget.xml index 38beb6d3..e6a75922 100644 --- a/android/app/src/main/res/layout/digital_clock_widget.xml +++ b/android/app/src/main/res/layout/digital_clock_widget.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/widget_holder" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="match_parent"> - - + + + + + + + @@ -81,6 +81,6 @@ - + diff --git a/android/app/src/main/res/xml/digital_clock_date_widget.xml b/android/app/src/main/res/xml/digital_clock_date_widget.xml new file mode 100644 index 00000000..b5f74582 --- /dev/null +++ b/android/app/src/main/res/xml/digital_clock_date_widget.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/app/src/main/res/xml/digital_clock_widget.xml b/android/app/src/main/res/xml/digital_clock_widget.xml index 9392489d..4f340999 100644 --- a/android/app/src/main/res/xml/digital_clock_widget.xml +++ b/android/app/src/main/res/xml/digital_clock_widget.xml @@ -1,9 +1,9 @@ const RingtonesScreen()), + ); + }, + Icons.add, + ), + ], // shouldCloseOnSelect: false, ), SelectSetting( @@ -278,6 +292,17 @@ SettingGroup alarmSettingsSchema = SettingGroup( (context) => AppLocalizations.of(context)!.tagsSetting, getTagOptions, defaultValue: [], + actions: [ + MenuAction( + "Add", + (context) async { + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => const TagsScreen()), + ); + }, + Icons.add, + ), + ], ), // ListSetting() diff --git a/lib/alarm/widgets/alarm_card.dart b/lib/alarm/widgets/alarm_card.dart index 3b71298a..928a6f94 100644 --- a/lib/alarm/widgets/alarm_card.dart +++ b/lib/alarm/widgets/alarm_card.dart @@ -207,11 +207,11 @@ class _AlarmCardState extends State { getDeletePopupAction(context, widget.onPressDelete), getDuplicatePopupAction(context, widget.onPressDuplicate), if (widget.alarm.canBeSkipped) - PopupAction( + MenuAction( widget.alarm.shouldSkipNextAlarm ? AppLocalizations.of(context)!.cancelSkipAlarmButton : AppLocalizations.of(context)!.skipAlarmButton, - () { + (context) { if (widget.alarm.shouldSkipNextAlarm) { widget.onSkipChange(false); } else { diff --git a/lib/common/logic/show_select.dart b/lib/common/logic/show_select.dart index d6d8d159..ce4dd607 100644 --- a/lib/common/logic/show_select.dart +++ b/lib/common/logic/show_select.dart @@ -1,14 +1,18 @@ +import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/types/select_choice.dart'; import 'package:clock_app/common/widgets/fields/select_field/select_bottom_sheet.dart'; import 'package:flutter/material.dart'; Future showSelectBottomSheet( - BuildContext context, void Function(List? indices) onChanged, - {required bool multiSelect, - required String title, - required String? description, - required List choices, - required List initialSelectedIndices}) async { + BuildContext context, + void Function(List? indices) onChanged, { + required bool multiSelect, + required String title, + required String? description, + required List choices, + required List initialSelectedIndices, + List actions = const [], +}) async { List? selectedIndices; await showModalBottomSheet>( @@ -34,8 +38,7 @@ Future showSelectBottomSheet( } else { if (indices.length == 1) { currentSelectedIndices = [indices[0]]; - } - else{ + } else { debugPrint("Too many indices"); } } @@ -53,6 +56,7 @@ Future showSelectBottomSheet( currentSelectedIndices: currentSelectedIndices, onSelect: handleSelect, multiSelect: multiSelect, + actions: actions, ); }, ); diff --git a/lib/common/types/popup_action.dart b/lib/common/types/popup_action.dart index 115b0862..4bb79db8 100644 --- a/lib/common/types/popup_action.dart +++ b/lib/common/types/popup_action.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -class PopupAction { +class MenuAction { IconData icon; String name; - Function action; + void Function(BuildContext context) action; Color? color; - PopupAction(this.name, this.action, this.icon, [this.color]); + MenuAction(this.name, this.action, this.icon, [this.color]); } diff --git a/lib/common/utils/popup_action.dart b/lib/common/utils/popup_action.dart index 7e166c8f..f3776d56 100644 --- a/lib/common/utils/popup_action.dart +++ b/lib/common/utils/popup_action.dart @@ -3,11 +3,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -PopupAction getDeletePopupAction(BuildContext context, Function callback) { - return PopupAction(AppLocalizations.of(context)!.deleteButton, callback, Icons.delete_rounded, +MenuAction getDeletePopupAction(BuildContext context, void Function() callback) { + return MenuAction(AppLocalizations.of(context)!.deleteButton, (context) => callback(), Icons.delete_rounded, Theme.of(context).colorScheme.error); } -PopupAction getDuplicatePopupAction(BuildContext context, Function callback) { - return PopupAction(AppLocalizations.of(context)!.duplicateButton, callback, Icons.copy_rounded); +MenuAction getDuplicatePopupAction(BuildContext context, void Function() callback) { + return MenuAction(AppLocalizations.of(context)!.duplicateButton, (context)=>callback, Icons.copy_rounded); } diff --git a/lib/common/widgets/card_edit_menu.dart b/lib/common/widgets/card_edit_menu.dart index 4ba40006..efa2432d 100644 --- a/lib/common/widgets/card_edit_menu.dart +++ b/lib/common/widgets/card_edit_menu.dart @@ -9,7 +9,7 @@ class CardEditMenu extends StatelessWidget { required this.actions, }); - final List actions; + final List actions; // final GlobalKey _buttonKey = GlobalKey(); List> getItems() { @@ -24,10 +24,10 @@ class CardEditMenu extends StatelessWidget { return items; } - void onSelected(String action) { + void onSelected(BuildContext context, String action) { for (var item in actions) { if (item.name == action) { - item.action(); + item.action(context); } } } @@ -43,7 +43,7 @@ class CardEditMenu extends StatelessWidget { color: colorScheme.onSurface, ), padding: EdgeInsets.zero, - onSelected: onSelected, + onSelected: (action) => onSelected(context, action), itemBuilder: (BuildContext context) => getItems(), ); } diff --git a/lib/common/widgets/fields/select_field/select_bottom_sheet.dart b/lib/common/widgets/fields/select_field/select_bottom_sheet.dart index bffcd657..4fcf8fe7 100644 --- a/lib/common/widgets/fields/select_field/select_bottom_sheet.dart +++ b/lib/common/widgets/fields/select_field/select_bottom_sheet.dart @@ -1,12 +1,13 @@ import 'package:clock_app/common/types/file_item.dart'; +import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/types/select_choice.dart'; import 'package:clock_app/common/widgets/fields/select_field/option_cards/audio_option_card.dart'; import 'package:clock_app/common/widgets/fields/select_field/option_cards/color_option_card.dart'; import 'package:clock_app/common/widgets/fields/select_field/option_cards/text_option_card.dart'; +import 'package:clock_app/icons/flux_icons.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class SelectBottomSheet extends StatelessWidget { const SelectBottomSheet({ super.key, @@ -15,6 +16,7 @@ class SelectBottomSheet extends StatelessWidget { required this.choices, required this.currentSelectedIndices, required this.onSelect, + this.actions = const [], this.multiSelect = false, }); @@ -24,6 +26,7 @@ class SelectBottomSheet extends StatelessWidget { final List currentSelectedIndices; final bool multiSelect; final void Function(List) onSelect; + final List actions; Widget _getOptionCard() { if (choices[0].value is Color) { @@ -103,15 +106,29 @@ class SelectBottomSheet extends StatelessWidget { ), const SizedBox(height: 12.0), Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - title, - style: textTheme.titleMedium?.copyWith( - color: colorScheme.onSurface.withOpacity(0.6)), - textAlign: TextAlign.center, + Row( + children: [ + // Expanded(child: Container()), + if (actions.isNotEmpty) const SizedBox(width: 8), + Expanded( + child: Text( + title, + style: textTheme.titleMedium?.copyWith( + color: colorScheme.onSurface.withOpacity(0.6)), + textAlign: actions.isEmpty ? TextAlign.center : null, + ), + ), + for (var action in actions) + IconButton( + icon: Icon(action.icon, + color: action.color ?? colorScheme.primary), + onPressed: () => action.action(context), + ), + ], ), if (description != null) const SizedBox(height: 8.0), if (description != null) @@ -123,37 +140,55 @@ class SelectBottomSheet extends StatelessWidget { ], ), ), - // const SizedBox(height: 16.0), + // Row( + // children: [ + // Icon(FluxIcons.add), + // Text(AppLocalizations.of(context)!.addButton, + // style: textTheme.labelMedium + // ?.copyWith(color: colorScheme.primary)), + // + // ], + // ), + const SizedBox(height: 12.0), Flexible( child: _getOptionCard(), ), // if (multiSelect) const SizedBox(height: 8.0), if (multiSelect) Padding( - padding: const EdgeInsets.only(left: 16.0, right:16.0, bottom: 4.0), - child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( + padding: + const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 4.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - IconButton( - onPressed: () { - onSelect([]); - }, - icon: Icon(Icons.clear_rounded, color: colorScheme.primary), - ), - IconButton( - onPressed: () { - onSelect([for (var i = 0; i < choices.length; i += 1) i]); - }, - icon: Icon(Icons.select_all_rounded, color: colorScheme.primary), + Row( + children: [ + IconButton( + onPressed: () { + onSelect([]); + }, + icon: Icon(Icons.clear_rounded, + color: colorScheme.primary), + ), + IconButton( + onPressed: () { + onSelect([ + for (var i = 0; i < choices.length; i += 1) i + ]); + }, + icon: Icon(Icons.select_all_rounded, + color: colorScheme.primary), + ), + ], ), - ], - ), - TextButton(onPressed: (){ - Navigator.of(context).pop(); - }, child: Text(AppLocalizations.of(context)!.saveButton, - style: textTheme.labelMedium?.copyWith( - color:colorScheme.primary))), - ]), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text(AppLocalizations.of(context)!.saveButton, + style: textTheme.labelMedium + ?.copyWith(color: colorScheme.primary))), + ]), ) ], ), diff --git a/lib/common/widgets/fields/select_field/select_field.dart b/lib/common/widgets/fields/select_field/select_field.dart index 8c66e97d..6a09d951 100644 --- a/lib/common/widgets/fields/select_field/select_field.dart +++ b/lib/common/widgets/fields/select_field/select_field.dart @@ -1,5 +1,6 @@ import 'package:clock_app/common/logic/show_select.dart'; import 'package:clock_app/common/types/file_item.dart'; +import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/types/select_choice.dart'; import 'package:clock_app/common/types/tag.dart'; import 'package:clock_app/common/widgets/fields/select_field/field_cards/audio_field_card.dart'; @@ -17,6 +18,7 @@ class SelectField extends StatefulWidget { required this.choices, required this.onChanged, this.multiSelect = false, + this.actions = const [], }); final List selectedIndices; @@ -25,6 +27,7 @@ class SelectField extends StatefulWidget { final bool multiSelect; final List choices; final void Function(List indices) onChanged; + final List actions; @override State createState() => _SelectFieldState(); @@ -85,12 +88,16 @@ class _SelectFieldState extends State { return Material( color: Colors.transparent, child: InkWell( - onTap: () => showSelectBottomSheet(context, showSelect, - title: widget.title, - description: widget.description, - choices: widget.choices, - initialSelectedIndices: widget.selectedIndices, - multiSelect: widget.multiSelect), + onTap: () => showSelectBottomSheet( + context, + showSelect, + title: widget.title, + description: widget.description, + choices: widget.choices, + initialSelectedIndices: widget.selectedIndices, + multiSelect: widget.multiSelect, + actions: widget.actions, + ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: _getFieldCard(), diff --git a/lib/settings/types/setting.dart b/lib/settings/types/setting.dart index d840855c..37762295 100644 --- a/lib/settings/types/setting.dart +++ b/lib/settings/types/setting.dart @@ -1,5 +1,6 @@ import 'package:clock_app/common/types/json.dart'; import 'package:clock_app/common/types/list_item.dart'; +import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/utils/json_serialize.dart'; import 'package:clock_app/common/utils/list_item.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; @@ -383,6 +384,7 @@ class SliderSetting extends Setting { class SelectSetting extends Setting { final List> _options; + final List actions; List> get options => _options; int get selectedIndex => _value; @@ -415,6 +417,7 @@ class SelectSetting extends Setting { bool isVisual = true, List enableConditions = const [], List searchTags = const [], + this.actions = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, enableConditions, searchTags, isVisual); @@ -430,6 +433,7 @@ class SelectSetting extends Setting { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + actions: actions, ); } } @@ -438,6 +442,7 @@ class SelectSetting extends Setting { // This is so that if the options changes, the value remains the same; class DynamicSelectSetting extends Setting { List> Function() optionsGetter; + final List actions; List> get options => optionsGetter(); @override dynamic get value => options[selectedIndex].value; @@ -453,6 +458,7 @@ class DynamicSelectSetting extends Setting { bool isVisual = true, List enableConditions = const [], List searchTags = const [], + this.actions = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, enableConditions, searchTags, isVisual) { if (defaultValue != -1) { @@ -472,6 +478,7 @@ class DynamicSelectSetting extends Setting { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + actions: actions, ); } @@ -517,6 +524,7 @@ class DynamicSelectSetting extends Setting { class MultiSelectSetting extends Setting> { final List> _options; + final List actions; List> get options => _options; List get selectedIndices => _value; @@ -552,6 +560,7 @@ class MultiSelectSetting extends Setting> { bool isVisual = true, List enableConditions = const [], List searchTags = const [], + this.actions = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, enableConditions, searchTags, isVisual); @@ -567,6 +576,7 @@ class MultiSelectSetting extends Setting> { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + actions: actions, ); } @@ -586,6 +596,7 @@ class MultiSelectSetting extends Setting> { // This is so that if the options changes, the value remains the same; class DynamicMultiSelectSetting extends Setting> { List> Function() optionsGetter; + final List actions; List> get options => optionsGetter(); @override dynamic get value { @@ -607,6 +618,7 @@ class DynamicMultiSelectSetting extends Setting> { bool isVisual = true, List enableConditions = const [], List searchTags = const [], + this.actions = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, enableConditions, searchTags, isVisual) { if (!defaultValue.contains(-1)) { @@ -626,6 +638,7 @@ class DynamicMultiSelectSetting extends Setting> { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + actions: actions, ); } diff --git a/lib/settings/widgets/dynamic_multi_select_setting_card.dart b/lib/settings/widgets/dynamic_multi_select_setting_card.dart index 34bf71b9..b89c9282 100644 --- a/lib/settings/widgets/dynamic_multi_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_multi_select_setting_card.dart @@ -29,6 +29,7 @@ class _DynamicMultiSelectSettingCardState selectedIndices: widget.setting.selectedIndices, title: widget.setting.name, multiSelect: true, + actions: widget.setting.actions, choices: widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), diff --git a/lib/settings/widgets/dynamic_select_setting_card.dart b/lib/settings/widgets/dynamic_select_setting_card.dart index a0c5313a..aca7ffe8 100644 --- a/lib/settings/widgets/dynamic_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_select_setting_card.dart @@ -28,6 +28,7 @@ class _DynamicSelectSettingCardState SelectField selectWidget = SelectField( selectedIndices: [widget.setting.selectedIndex], title: widget.setting.displayName(context), + actions: widget.setting.actions, choices: widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), diff --git a/lib/settings/widgets/multi_select_setting_card.dart b/lib/settings/widgets/multi_select_setting_card.dart index 1b9ee9f5..118461b8 100644 --- a/lib/settings/widgets/multi_select_setting_card.dart +++ b/lib/settings/widgets/multi_select_setting_card.dart @@ -16,7 +16,8 @@ class MultiSelectSettingCard extends StatefulWidget { final bool showAsCard; @override - State> createState() => _MultiSelectSettingCardState(); + State> createState() => + _MultiSelectSettingCardState(); } class _MultiSelectSettingCardState extends State> { @@ -26,6 +27,7 @@ class _MultiSelectSettingCardState extends State> { selectedIndices: widget.setting.selectedIndices, title: widget.setting.name, multiSelect: true, + actions: widget.setting.actions, choices: widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), diff --git a/lib/settings/widgets/select_setting_card.dart b/lib/settings/widgets/select_setting_card.dart index 9232313b..b7f32299 100644 --- a/lib/settings/widgets/select_setting_card.dart +++ b/lib/settings/widgets/select_setting_card.dart @@ -25,6 +25,7 @@ class _SelectSettingCardState extends State> { SelectField selectWidget = SelectField( selectedIndices: [widget.setting.selectedIndex], title: widget.setting.displayName(context), + actions: widget.setting.actions, choices: widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), diff --git a/lib/timer/data/timer_settings_schema.dart b/lib/timer/data/timer_settings_schema.dart index 3ac43a37..7b37c6c2 100644 --- a/lib/timer/data/timer_settings_schema.dart +++ b/lib/timer/data/timer_settings_schema.dart @@ -3,8 +3,11 @@ import 'package:clock_app/audio/audio_channels.dart'; import 'package:clock_app/audio/types/ringtone_player.dart'; import 'package:clock_app/common/logic/tags.dart'; import 'package:clock_app/common/types/file_item.dart'; +import 'package:clock_app/common/types/popup_action.dart'; import 'package:clock_app/common/types/tag.dart'; import 'package:clock_app/common/utils/ringtones.dart'; +import 'package:clock_app/settings/screens/ringtones_screen.dart'; +import 'package:clock_app/settings/screens/tags_screen.dart'; import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_enable_condition.dart'; import 'package:clock_app/settings/types/setting_group.dart'; @@ -36,6 +39,19 @@ SettingGroup timerSettingsSchema = SettingGroup( onChange: (context, index) { RingtonePlayer.stop(); }, + actions: [ + MenuAction( + "Add", + (context) async { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const RingtonesScreen()), + ); + }, + Icons.add, + ), + ], + // shouldCloseOnSelect: false, ), SelectSetting( @@ -84,6 +100,19 @@ SettingGroup timerSettingsSchema = SettingGroup( (context) => AppLocalizations.of(context)!.tagsSetting, getTagOptions, defaultValue: [], + actions: [ + MenuAction( + "Add", + (context) async { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const TagsScreen()), + ); + }, + Icons.add, + ), + ], + ), ], ); diff --git a/lib/timer/widgets/timer_card.dart b/lib/timer/widgets/timer_card.dart index 82f3e9d5..3008ec00 100644 --- a/lib/timer/widgets/timer_card.dart +++ b/lib/timer/widgets/timer_card.dart @@ -15,7 +15,8 @@ class TimerCard extends StatefulWidget { required this.onToggleState, required this.onPressDelete, required this.onPressDuplicate, - required this.onPressReset, required this.onPressAddTime, + required this.onPressReset, + required this.onPressAddTime, }); final ClockTimer timer; @@ -140,15 +141,15 @@ class _TimerCardState extends State { getDeletePopupAction(context, widget.onPressDelete), getDuplicatePopupAction(context, widget.onPressDuplicate), if (!widget.timer.isStopped) - PopupAction( + MenuAction( "Reset", - widget.onPressReset, + (context) => widget.onPressReset(), Icons.replay_rounded, ), if (!widget.timer.isStopped) - PopupAction( + MenuAction( '+${widget.timer.addLength.floor()}:00', - widget.onPressAddTime, + (context) => widget.onPressAddTime(), Icons.add_rounded, ) ]), From 0293a6d6225bc0c67ad6ea2ee2304e3c60521a5c Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Thu, 9 May 2024 22:17:29 +0500 Subject: [PATCH 095/112] Fix select menu not reloading after update --- lib/alarm/data/alarm_settings_schema.dart | 4 +- lib/common/logic/show_select.dart | 11 ++++-- lib/common/types/popup_action.dart | 2 +- .../select_field/select_bottom_sheet.dart | 8 +++- .../fields/select_field/select_field.dart | 31 ++++++++------- lib/common/widgets/list/list_filter_chip.dart | 39 ++++++++++--------- lib/common/widgets/time_picker.dart | 5 +-- .../dynamic_multi_select_setting_card.dart | 4 +- .../widgets/dynamic_select_setting_card.dart | 4 +- .../widgets/multi_select_setting_card.dart | 4 +- lib/settings/widgets/select_setting_card.dart | 4 +- lib/timer/data/timer_settings_schema.dart | 24 ++++++------ .../logic/edit_duration_picker_mode.dart | 4 +- 13 files changed, 79 insertions(+), 65 deletions(-) diff --git a/lib/alarm/data/alarm_settings_schema.dart b/lib/alarm/data/alarm_settings_schema.dart index 04b8069f..d6a23c40 100644 --- a/lib/alarm/data/alarm_settings_schema.dart +++ b/lib/alarm/data/alarm_settings_schema.dart @@ -160,7 +160,7 @@ SettingGroup alarmSettingsSchema = SettingGroup( MenuAction( "Add", (context) async { - Navigator.of(context).push( + await Navigator.of(context).push( MaterialPageRoute( builder: (context) => const RingtonesScreen()), ); @@ -296,7 +296,7 @@ SettingGroup alarmSettingsSchema = SettingGroup( MenuAction( "Add", (context) async { - Navigator.of(context).push( + await Navigator.of(context).push( MaterialPageRoute(builder: (context) => const TagsScreen()), ); }, diff --git a/lib/common/logic/show_select.dart b/lib/common/logic/show_select.dart index ce4dd607..b060d6c8 100644 --- a/lib/common/logic/show_select.dart +++ b/lib/common/logic/show_select.dart @@ -9,8 +9,8 @@ Future showSelectBottomSheet( required bool multiSelect, required String title, required String? description, - required List choices, - required List initialSelectedIndices, + required List Function() getChoices, + required List Function() getCurrentSelectedIndices, List actions = const [], }) async { List? selectedIndices; @@ -20,7 +20,8 @@ Future showSelectBottomSheet( isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { - List currentSelectedIndices = initialSelectedIndices; + List currentSelectedIndices = getCurrentSelectedIndices(); + List choices = getChoices(); return StatefulBuilder( builder: (BuildContext context, StateSetter setState) { void handleSelect(List indices) { @@ -57,6 +58,10 @@ Future showSelectBottomSheet( onSelect: handleSelect, multiSelect: multiSelect, actions: actions, + reload: () => setState(() { + choices = getChoices(); + currentSelectedIndices = getCurrentSelectedIndices(); + }), ); }, ); diff --git a/lib/common/types/popup_action.dart b/lib/common/types/popup_action.dart index 4bb79db8..9b994122 100644 --- a/lib/common/types/popup_action.dart +++ b/lib/common/types/popup_action.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; class MenuAction { IconData icon; String name; - void Function(BuildContext context) action; + Function(BuildContext context) action; Color? color; MenuAction(this.name, this.action, this.icon, [this.color]); diff --git a/lib/common/widgets/fields/select_field/select_bottom_sheet.dart b/lib/common/widgets/fields/select_field/select_bottom_sheet.dart index 4fcf8fe7..a19cdf19 100644 --- a/lib/common/widgets/fields/select_field/select_bottom_sheet.dart +++ b/lib/common/widgets/fields/select_field/select_bottom_sheet.dart @@ -18,6 +18,7 @@ class SelectBottomSheet extends StatelessWidget { required this.onSelect, this.actions = const [], this.multiSelect = false, + this.reload, }); final String title; @@ -27,6 +28,7 @@ class SelectBottomSheet extends StatelessWidget { final bool multiSelect; final void Function(List) onSelect; final List actions; + final Function? reload; Widget _getOptionCard() { if (choices[0].value is Color) { @@ -126,7 +128,11 @@ class SelectBottomSheet extends StatelessWidget { IconButton( icon: Icon(action.icon, color: action.color ?? colorScheme.primary), - onPressed: () => action.action(context), + onPressed: () async { + // Navigator.pop(context, currentSelectedIndices); + await action.action(context); + reload?.call(); + }, ), ], ), diff --git a/lib/common/widgets/fields/select_field/select_field.dart b/lib/common/widgets/fields/select_field/select_field.dart index 6a09d951..a3cb3ada 100644 --- a/lib/common/widgets/fields/select_field/select_field.dart +++ b/lib/common/widgets/fields/select_field/select_field.dart @@ -12,20 +12,20 @@ import 'package:flutter/material.dart'; class SelectField extends StatefulWidget { const SelectField({ super.key, - required this.selectedIndices, + required this.getSelectedIndices, required this.title, this.description, - required this.choices, + required this.getChoices, required this.onChanged, this.multiSelect = false, this.actions = const [], }); - final List selectedIndices; + final List Function() getSelectedIndices; final String title; final String? description; final bool multiSelect; - final List choices; + final List Function() getChoices; final void Function(List indices) onChanged; final List actions; @@ -34,14 +34,16 @@ class SelectField extends StatefulWidget { } class _SelectFieldState extends State { - Widget _getFieldCard() { + Widget _getFieldCard(List choices, List selectedIndices) { + + if (widget.multiSelect) { - List choices = - widget.selectedIndices.map((index) => widget.choices[index]).toList(); + List selectedChoices = + selectedIndices.map((index) => choices[index]).toList(); if (choices.isNotEmpty && choices[0].value.runtimeType == Tag) { return MultiSelectFieldCard( title: widget.title, - choices: choices + choices: selectedChoices .map((e) => SelectChoice( name: e.name, value: e.value, @@ -51,7 +53,7 @@ class _SelectFieldState extends State { } return MultiSelectFieldCard(title: widget.title, choices: choices); } else { - SelectChoice choice = widget.choices[widget.selectedIndices[0]]; + SelectChoice choice = choices[selectedIndices[0]]; if (choice.value is Color) { return ColorFieldCard( choice: SelectChoice( @@ -79,9 +81,12 @@ class _SelectFieldState extends State { @override Widget build(BuildContext context) { + List choices = widget.getChoices(); + List selectedIndices = widget.getSelectedIndices(); + void showSelect(List? selectedIndices) async { setState(() { - widget.onChanged(selectedIndices ?? widget.selectedIndices); + widget.onChanged(selectedIndices ?? widget.getSelectedIndices()); }); } @@ -93,14 +98,14 @@ class _SelectFieldState extends State { showSelect, title: widget.title, description: widget.description, - choices: widget.choices, - initialSelectedIndices: widget.selectedIndices, + getChoices: widget.getChoices, + getCurrentSelectedIndices: widget.getSelectedIndices, multiSelect: widget.multiSelect, actions: widget.actions, ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - child: _getFieldCard(), + child: _getFieldCard(choices, selectedIndices), ), ), ); diff --git a/lib/common/widgets/list/list_filter_chip.dart b/lib/common/widgets/list/list_filter_chip.dart index d0fb92ec..38bb2890 100644 --- a/lib/common/widgets/list/list_filter_chip.dart +++ b/lib/common/widgets/list/list_filter_chip.dart @@ -7,7 +7,6 @@ import 'package:clock_app/common/widgets/list/action_bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class ListFilterChip extends StatelessWidget { const ListFilterChip({ super.key, @@ -86,7 +85,8 @@ class ListFilterActionChip extends StatelessWidget { child: Row( children: [ Padding( - padding: const EdgeInsets.only(left: 8.0, right: 6.0, top:6.0, bottom: 6.0), + padding: const EdgeInsets.only( + left: 8.0, right: 6.0, top: 6.0, bottom: 6.0), child: Icon( Icons.filter_list_rounded, color: colorScheme.onPrimary, @@ -133,10 +133,11 @@ class ListFilterSelectChip extends StatelessWidget { }, title: listFilter.displayName(context), description: "", - choices: listFilter.filters - .map((e) => SelectChoice(name: e.displayName(context), value: e.id)) + getChoices: () => listFilter.filters + .map((e) => + SelectChoice(name: e.displayName(context), value: e.id)) .toList(), - initialSelectedIndices: [listFilter.selectedIndex], + getCurrentSelectedIndices: () => [listFilter.selectedIndex], multiSelect: false); } @@ -199,10 +200,11 @@ class ListFilterMultiSelectChip extends StatelessWidget { }, title: listFilter.displayName(context), description: "", - choices: listFilter.filters - .map((e) => SelectChoice(name: e.displayName(context), value: e.id)) + getChoices: () => listFilter.filters + .map((e) => + SelectChoice(name: e.displayName(context), value: e.id)) .toList(), - initialSelectedIndices: selectedIndices, + getCurrentSelectedIndices: () => selectedIndices, multiSelect: true); } @@ -249,7 +251,8 @@ class ListSortChip extends StatelessWidget { const ListSortChip({ super.key, required this.sortOptions, - required this.onChange, required this.selectedIndex, + required this.onChange, + required this.selectedIndex, }); @override @@ -265,10 +268,11 @@ class ListSortChip extends StatelessWidget { }, title: AppLocalizations.of(context)!.sortGroup, description: "", - choices: sortOptions - .map((e) => SelectChoice(name: e.displayName(context), value: e.getLocalizedName)) + getChoices: () => sortOptions + .map((e) => SelectChoice( + name: e.displayName(context), value: e.getLocalizedName)) .toList(), - initialSelectedIndices: [selectedIndex], + getCurrentSelectedIndices: () => [selectedIndex], multiSelect: false); } @@ -282,17 +286,14 @@ class ListSortChip extends StatelessWidget { top: 8.0, bottom: 8.0, left: 16.0, right: 2.0), child: Text( "${AppLocalizations.of(context)!.sortGroup}${isFirstSelected ? "" : ": ${sortOptions[selectedIndex].displayName(context)}"}", - style: textTheme.headlineSmall?.copyWith( - color: colorScheme.onSurface - ), + style: textTheme.headlineSmall + ?.copyWith(color: colorScheme.onSurface), ), ), Padding( padding: const EdgeInsets.only(left: 2.0, right: 8.0), - child: Icon( - Icons.keyboard_arrow_down_rounded, - color:colorScheme.onSurface.withOpacity(0.6) - ), + child: Icon(Icons.keyboard_arrow_down_rounded, + color: colorScheme.onSurface.withOpacity(0.6)), ), ], ), diff --git a/lib/common/widgets/time_picker.dart b/lib/common/widgets/time_picker.dart index 2af00c74..a74ba332 100644 --- a/lib/common/widgets/time_picker.dart +++ b/lib/common/widgets/time_picker.dart @@ -20,7 +20,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - // Examples can assume: // late BuildContext context; @@ -307,13 +306,13 @@ class _TitleBar extends StatelessWidget { }, title: setting.name, description: setting.displayDescription(context), - choices: setting.options + getChoices: () => setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, description: option.getDescription(context))) .toList(), - initialSelectedIndices: [setting.selectedIndex], + getCurrentSelectedIndices: () => [setting.selectedIndex], multiSelect: false, ); diff --git a/lib/settings/widgets/dynamic_multi_select_setting_card.dart b/lib/settings/widgets/dynamic_multi_select_setting_card.dart index b89c9282..8eab05fe 100644 --- a/lib/settings/widgets/dynamic_multi_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_multi_select_setting_card.dart @@ -26,11 +26,11 @@ class _DynamicMultiSelectSettingCardState @override Widget build(BuildContext context) { SelectField selectWidget = SelectField( - selectedIndices: widget.setting.selectedIndices, + getSelectedIndices: () => widget.setting.selectedIndices, title: widget.setting.name, multiSelect: true, actions: widget.setting.actions, - choices: widget.setting.options + getChoices: () => widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, diff --git a/lib/settings/widgets/dynamic_select_setting_card.dart b/lib/settings/widgets/dynamic_select_setting_card.dart index aca7ffe8..2510e8cd 100644 --- a/lib/settings/widgets/dynamic_select_setting_card.dart +++ b/lib/settings/widgets/dynamic_select_setting_card.dart @@ -26,10 +26,10 @@ class _DynamicSelectSettingCardState @override Widget build(BuildContext context) { SelectField selectWidget = SelectField( - selectedIndices: [widget.setting.selectedIndex], + getSelectedIndices: () => [widget.setting.selectedIndex], title: widget.setting.displayName(context), actions: widget.setting.actions, - choices: widget.setting.options + getChoices: () => widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, diff --git a/lib/settings/widgets/multi_select_setting_card.dart b/lib/settings/widgets/multi_select_setting_card.dart index 118461b8..534ca77b 100644 --- a/lib/settings/widgets/multi_select_setting_card.dart +++ b/lib/settings/widgets/multi_select_setting_card.dart @@ -24,11 +24,11 @@ class _MultiSelectSettingCardState extends State> { @override Widget build(BuildContext context) { SelectField selectWidget = SelectField( - selectedIndices: widget.setting.selectedIndices, + getSelectedIndices: () => widget.setting.selectedIndices, title: widget.setting.name, multiSelect: true, actions: widget.setting.actions, - choices: widget.setting.options + getChoices: () => widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, diff --git a/lib/settings/widgets/select_setting_card.dart b/lib/settings/widgets/select_setting_card.dart index b7f32299..8c5d2df6 100644 --- a/lib/settings/widgets/select_setting_card.dart +++ b/lib/settings/widgets/select_setting_card.dart @@ -23,10 +23,10 @@ class _SelectSettingCardState extends State> { @override Widget build(BuildContext context) { SelectField selectWidget = SelectField( - selectedIndices: [widget.setting.selectedIndex], + getSelectedIndices: () => [widget.setting.selectedIndex], title: widget.setting.displayName(context), actions: widget.setting.actions, - choices: widget.setting.options + getChoices: () => widget.setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, diff --git a/lib/timer/data/timer_settings_schema.dart b/lib/timer/data/timer_settings_schema.dart index 7b37c6c2..2b189dfd 100644 --- a/lib/timer/data/timer_settings_schema.dart +++ b/lib/timer/data/timer_settings_schema.dart @@ -43,7 +43,7 @@ SettingGroup timerSettingsSchema = SettingGroup( MenuAction( "Add", (context) async { - Navigator.of(context).push( + await Navigator.of(context).push( MaterialPageRoute( builder: (context) => const RingtonesScreen()), ); @@ -101,18 +101,16 @@ SettingGroup timerSettingsSchema = SettingGroup( getTagOptions, defaultValue: [], actions: [ - MenuAction( - "Add", - (context) async { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const TagsScreen()), - ); - }, - Icons.add, - ), - ], - + MenuAction( + "Add", + (context) async { + await Navigator.of(context).push( + MaterialPageRoute(builder: (context) => const TagsScreen()), + ); + }, + Icons.add, + ), + ], ), ], ); diff --git a/lib/timer/logic/edit_duration_picker_mode.dart b/lib/timer/logic/edit_duration_picker_mode.dart index ff3ec827..d078582c 100644 --- a/lib/timer/logic/edit_duration_picker_mode.dart +++ b/lib/timer/logic/edit_duration_picker_mode.dart @@ -21,13 +21,13 @@ Future editDurationPickerMode( }, title: setting.name, description: setting.getDescription(context), - choices: setting.options + getChoices: () => setting.options .map((option) => SelectChoice( name: option.getLocalizedName(context), value: option.value, description: option.getDescription(context))) .toList(), - initialSelectedIndices: [setting.selectedIndex], + getCurrentSelectedIndices: () => [setting.selectedIndex], multiSelect: false, ); From fc9af0c0d571c95ade4b14de3cf98e384436e20c Mon Sep 17 00:00:00 2001 From: Evgeniy Khramov <65224669+thejenja@users.noreply.github.com> Date: Fri, 10 May 2024 03:10:09 +0000 Subject: [PATCH 096/112] Translated using Weblate (Russian) Currently translated at 24.0% (72 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/ru/ --- lib/l10n/app_ru.arb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index bea50b18..80d9128b 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -162,5 +162,7 @@ "colorSchemeNamePlaceholder": "Цветовая схема", "@colorSchemeNamePlaceholder": {}, "vendorSetting": "Настройки производителя", - "@vendorSetting": {} + "@vendorSetting": {}, + "timePickerSetting": "Выбор времени", + "@timePickerSetting": {} } From 6af1c42ebdf358725996f55026fc225e0293f234 Mon Sep 17 00:00:00 2001 From: Lorenzo Spadoni Date: Fri, 10 May 2024 00:03:15 +0000 Subject: [PATCH 097/112] Translated using Weblate (Italian) Currently translated at 9.3% (28 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/it/ --- lib/l10n/app_it.arb | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index d3645022..4bc72fa2 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -34,5 +34,33 @@ "system": "Sistema", "@system": {}, "melodiesSetting": "Melodie", - "@melodiesSetting": {} + "@melodiesSetting": {}, + "appearanceSettingGroup": "Aspetto", + "@appearanceSettingGroup": {}, + "appearanceSettingGroupDescription": "Cambia tema, colori e layout", + "@appearanceSettingGroupDescription": {}, + "timePickerSetting": "Imposta ora", + "@timePickerSetting": {}, + "pickerInput": "Input", + "@pickerInput": {}, + "swipeActionSetting": "Azioni di scorrimento", + "@swipeActionSetting": {}, + "animationSettingGroup": "Animazioni", + "@animationSettingGroup": {}, + "animationSpeedSetting": "Velocità delle animazioni", + "@animationSpeedSetting": {}, + "extraAnimationSetting": "Animazioni aggiuntive", + "@extraAnimationSetting": {}, + "nameField": "Nome", + "@nameField": {}, + "colorSetting": "Colore", + "@colorSetting": {}, + "textColorSetting": "Testo", + "@textColorSetting": {}, + "colorSchemeNamePlaceholder": "Palette dei colori", + "@colorSchemeNamePlaceholder": {}, + "colorSchemeBackgroundSettingGroup": "Sfondo", + "@colorSchemeBackgroundSettingGroup": {}, + "colorSchemeErrorSettingGroup": "Errore", + "@colorSchemeErrorSettingGroup": {} } From 98f81fa153375e078f47e6ed86b406951d3496e2 Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Thu, 9 May 2024 18:41:17 +0000 Subject: [PATCH 098/112] Translated using Weblate (Portuguese) Currently translated at 72.3% (217 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 134 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 123 insertions(+), 11 deletions(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 1e7c5b8b..42240ffe 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -35,7 +35,7 @@ "@materialBrightnessSetting": {}, "overrideAccentSetting": "Substituir cor de destaque", "@overrideAccentSetting": {}, - "useMaterialStyleSetting": "Material Style", + "useMaterialStyleSetting": "Estilo Material You", "@useMaterialStyleSetting": {}, "styleThemeSetting": "Estilo do tema", "@styleThemeSetting": {}, @@ -45,11 +45,11 @@ "@colorSchemeSetting": {}, "customizeButton": "Personalizar", "@customizeButton": {}, - "saveButton": "Botão \"Guardar\"", + "saveButton": "Guardar", "@saveButton": {}, - "labelField": "Texto", + "labelField": "Etiqueta", "@labelField": {}, - "labelFieldPlaceholder": "Adicionar texto", + "labelFieldPlaceholder": "Adicionar etiqueta", "@labelFieldPlaceholder": {}, "alarmScheduleSettingGroup": "Agendar", "@alarmScheduleSettingGroup": {}, @@ -67,11 +67,11 @@ "@generalSettingGroupDescription": {}, "appearanceSettingGroupDescription": "Temas, cores e esquemas", "@appearanceSettingGroupDescription": {}, - "backupSettingGroupDescription": "Exportar ou importar as definições", + "backupSettingGroupDescription": "Exportar ou importar definições", "@backupSettingGroupDescription": {}, "selectTime": "Definir hora", "@selectTime": {}, - "scheduleTypeOnceDescription": "Será ativado na próxima ocorrência de hora", + "scheduleTypeOnceDescription": "Será ativado na próxima ocorrência da hora", "@scheduleTypeOnceDescription": {}, "settingGroupMore": "Mais", "@settingGroupMore": {}, @@ -117,7 +117,7 @@ "@retypeLowercaseSetting": {}, "whileSnoozedSettingGroup": "Em snooze", "@whileSnoozedSettingGroup": {}, - "soundSettingGroup": "Som e vibração", + "soundSettingGroup": "Som", "@soundSettingGroup": {}, "generalSettingGroup": "Geral", "@generalSettingGroup": {}, @@ -125,7 +125,7 @@ "@appearanceSettingGroup": {}, "accessibilitySettingGroup": "Acessibilidade", "@accessibilitySettingGroup": {}, - "darkColorSchemeSetting": "Cor escura", + "darkColorSchemeSetting": "Esquema escuro", "@darkColorSchemeSetting": {}, "clockSettingGroup": "Relógio", "@clockSettingGroup": {}, @@ -161,7 +161,7 @@ "@tomorrowFilter": {}, "snoozedFilter": "Snoozed", "@snoozedFilter": {}, - "disabledFilter": "Desligado", + "disabledFilter": "Desativado", "@disabledFilter": {}, "completedFilter": "Terminado", "@completedFilter": {}, @@ -239,7 +239,7 @@ "@pickerInput": {}, "swipActionCardAction": "Ações em cartões", "@swipActionCardAction": {}, - "swipeActionCardActionDescription": "Deslizar para os lados no cartão para executar ações", + "swipeActionCardActionDescription": "Deslizar à direita/esquerda no cartão para executar ações", "@swipeActionCardActionDescription": {}, "swipActionSwitchTabs": "Troca de separadores", "@swipActionSwitchTabs": {}, @@ -328,5 +328,117 @@ "previewLabel": "Antevisão", "@previewLabel": {}, "cardLabel": "Cartão", - "@cardLabel": {} + "@cardLabel": {}, + "alarmDeleteAfterRingingSetting": "Eliminar após descartar", + "@alarmDeleteAfterRingingSetting": {}, + "alarmDeleteAfterFinishingSetting": "Eliminar após terminar", + "@alarmDeleteAfterFinishingSetting": {}, + "timePickerModeButton": "Modo", + "@timePickerModeButton": {}, + "scheduleTypeDate": "Em datas específicas", + "@scheduleTypeDate": {}, + "soundAndVibrationSettingGroup": "Sim e vibração", + "@soundAndVibrationSettingGroup": {}, + "timeToFullVolumeSetting": "Duração para volume total", + "@timeToFullVolumeSetting": {}, + "maxSnoozesSetting": "N.° máximo", + "@maxSnoozesSetting": {}, + "snoozePreventDeletionSetting": "Impedir eliminação", + "@snoozePreventDeletionSetting": {}, + "mathEasyDifficulty": "Fácil (X + Y)", + "@mathEasyDifficulty": {}, + "mathMediumDifficulty": "Média (X × Y)", + "@mathMediumDifficulty": {}, + "mathHardDifficulty": "Difícil (X × Y + Z)", + "@mathHardDifficulty": {}, + "mathVeryHardDifficulty": "Muito difícil (X × Y × Z)", + "@mathVeryHardDifficulty": {}, + "numberOfProblemsSetting": "Número de problemas", + "@numberOfProblemsSetting": {}, + "noAlarmMessage": "Não existem alarmes", + "@noAlarmMessage": {}, + "noTimerMessage": "Não existem temporizadores", + "@noTimerMessage": {}, + "noStopwatchMessage": "Não existem cronómetros", + "@noStopwatchMessage": {}, + "noTaskMessage": "Não existem tarefas", + "@noTaskMessage": {}, + "noPresetsMessage": "Não existem pré-ajustes", + "@noPresetsMessage": {}, + "noLogsMessage": "Não existem registos de alarmes", + "@noLogsMessage": {}, + "cancelSkipAlarmButton": "Cancelar ignorar", + "@cancelSkipAlarmButton": {}, + "dateFilterGroup": "Data", + "@dateFilterGroup": {}, + "scheduleDateFilterGroup": "Data de agendamento", + "@scheduleDateFilterGroup": {}, + "inactiveFilter": "Inativo", + "@inactiveFilter": {}, + "runningTimerFilter": "Em execução", + "@runningTimerFilter": {}, + "pausedTimerFilter": "Em pausa", + "@pausedTimerFilter": {}, + "stoppedTimerFilter": "Parado", + "@stoppedTimerFilter": {}, + "sortGroup": "Organizar", + "@sortGroup": {}, + "nameAsc": "Nome (A-Z)", + "@nameAsc": {}, + "nameDesc": "Nome (Z-A)", + "@nameDesc": {}, + "materialBrightnessLight": "Claro", + "@materialBrightnessLight": {}, + "accentColorSetting": "Cor de destaque", + "@accentColorSetting": {}, + "audioChannelAlarm": "Alarme", + "@audioChannelAlarm": {}, + "audioChannelNotification": "Notificação", + "@audioChannelNotification": {}, + "audioChannelRingtone": "Toque", + "@audioChannelRingtone": {}, + "audioChannelMedia": "Multimédia", + "@audioChannelMedia": {}, + "dismissAlarmButton": "Descartar", + "@dismissAlarmButton": {}, + "createdDateFilterGroup": "Data de criação", + "@createdDateFilterGroup": {}, + "stateFilterGroup": "Estado", + "@stateFilterGroup": {}, + "activeFilter": "Ativo", + "@activeFilter": {}, + "defaultLabel": "Padrão", + "@defaultLabel": {}, + "durationAsc": "Mais curta", + "@durationAsc": {}, + "durationDesc": "Mais longa", + "@durationDesc": {}, + "logTypeFilterGroup": "Tipo", + "@logTypeFilterGroup": {}, + "accentLabel": "Destaque", + "@accentLabel": {}, + "errorLabel": "Erro", + "@errorLabel": {}, + "materialBrightnessSystem": "Sistema", + "@materialBrightnessSystem": {}, + "materialBrightnessDark": "Escuro", + "@materialBrightnessDark": {}, + "alarmWeekdaysSetting": "Dias da semana", + "@alarmWeekdaysSetting": {}, + "alarmIntervalWeekly": "Semanalmente", + "@alarmIntervalWeekly": {}, + "alarmDatesSetting": "Datas", + "@alarmDatesSetting": {}, + "alarmRangeSetting": "Intervalo de data", + "@alarmRangeSetting": {}, + "alarmIntervalSetting": "Intervalo", + "@alarmIntervalSetting": {}, + "alarmIntervalDaily": "Diariamente", + "@alarmIntervalDaily": {}, + "cannotDisableAlarmWhileSnoozedSnackbar": "Não pode desativar o alarme se estiver em snooze", + "@cannotDisableAlarmWhileSnoozedSnackbar": {}, + "filterActions": "Ações de filtros", + "@filterActions": {}, + "clearFiltersAction": "Limpar todos", + "@clearFiltersAction": {} } From 712345c4427842fcea763fe1592473573f4d6b1e Mon Sep 17 00:00:00 2001 From: hopefutuuuuure886 Date: Thu, 9 May 2024 15:56:25 +0000 Subject: [PATCH 099/112] Translated using Weblate (Chinese (Simplified)) Currently translated at 13.6% (41 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/zh_Hans/ --- lib/l10n/app_zh_Hans.arb | 91 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_zh_Hans.arb b/lib/l10n/app_zh_Hans.arb index 0967ef42..39ec3b36 100644 --- a/lib/l10n/app_zh_Hans.arb +++ b/lib/l10n/app_zh_Hans.arb @@ -1 +1,90 @@ -{} +{ + "timerTitle": "计时器", + "@timerTitle": { + "description": "Title of the timer screen" + }, + "stopwatchTitle": "秒表", + "@stopwatchTitle": { + "description": "Title of the stopwatch screen" + }, + "system": "系统", + "@system": {}, + "generalSettingGroupDescription": "应用的全局设置,如时间格式", + "@generalSettingGroupDescription": {}, + "timeFormatSetting": "时间格式", + "@timeFormatSetting": {}, + "timeFormat12": "12小时制", + "@timeFormat12": {}, + "timeFormat24": "24小时制", + "@timeFormat24": {}, + "timeFormatDevice": "跟随系统设置", + "@timeFormatDevice": {}, + "timePickerSetting": "时间选择器样式", + "@timePickerSetting": {}, + "swipActionCardAction": "操作卡片", + "@swipActionCardAction": {}, + "pickerSpinner": "Spinner", + "@pickerSpinner": {}, + "durationPickerSetting": "计时器时间选择器样式", + "@durationPickerSetting": {}, + "pickerRings": "Rings", + "@pickerRings": {}, + "swipeActionSetting": "滑动时行为", + "@swipeActionSetting": {}, + "melodiesSetting": "铃声", + "@melodiesSetting": {}, + "tagsSetting": "标签", + "@tagsSetting": {}, + "batteryOptimizationSettingDescription": "禁用制造商的电池优化,以防止闹钟延迟响铃", + "@batteryOptimizationSettingDescription": {}, + "allowNotificationSettingDescription": "打开闹钟和计时器的锁屏通知", + "@allowNotificationSettingDescription": {}, + "vendorSetting": "制造商设置", + "@vendorSetting": {}, + "allowNotificationSetting": "打开通知", + "@allowNotificationSetting": {}, + "autoStartSetting": "自启动", + "@autoStartSetting": {}, + "animationSettingGroup": "动画", + "@animationSettingGroup": {}, + "animationSpeedSetting": "动画速度", + "@animationSpeedSetting": {}, + "extraAnimationSetting": "启用更多动画", + "@extraAnimationSetting": {}, + "appearanceSettingGroup": "外观", + "@appearanceSettingGroup": {}, + "clockTitle": "时钟", + "@clockTitle": { + "description": "Title of the clock screen" + }, + "alarmTitle": "闹钟", + "@alarmTitle": { + "description": "Title of the alarm screen" + }, + "generalSettingGroup": "通用设置", + "@generalSettingGroup": {}, + "languageSetting": "语言", + "@languageSetting": {}, + "dateFormatSetting": "日期格式", + "@dateFormatSetting": {}, + "showSecondsSetting": "显示秒数", + "@showSecondsSetting": {}, + "pickerInput": "Input", + "@pickerInput": {}, + "swipeActionCardActionDescription": "在卡片上向左或向右滑动以执行操作", + "@swipeActionCardActionDescription": {}, + "swipActionSwitchTabs": "切换选项卡", + "@swipActionSwitchTabs": {}, + "swipeActionSwitchTabsDescription": "在选项卡间切换", + "@swipeActionSwitchTabsDescription": {}, + "batteryOptimizationSetting": "关闭电池优化", + "@batteryOptimizationSetting": {}, + "vendorSettingDescription": "手动关闭制造商的特殊优化", + "@vendorSettingDescription": {}, + "autoStartSettingDescription": "当应用关闭时,部分设备需打开自启动才可响铃", + "@autoStartSettingDescription": {}, + "pickerDial": "Dial", + "@pickerDial": {}, + "appearanceSettingGroupDescription": "设置主题,颜色和布局", + "@appearanceSettingGroupDescription": {} +} From 33a1b94da2de7433bac0d062cda0fe109ee7a016 Mon Sep 17 00:00:00 2001 From: Terry Date: Fri, 10 May 2024 03:11:50 +0000 Subject: [PATCH 100/112] Translated using Weblate (Chinese (Simplified)) Currently translated at 13.6% (41 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/zh_Hans/ --- lib/l10n/app_zh_Hans.arb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_zh_Hans.arb b/lib/l10n/app_zh_Hans.arb index 39ec3b36..fa860c3f 100644 --- a/lib/l10n/app_zh_Hans.arb +++ b/lib/l10n/app_zh_Hans.arb @@ -86,5 +86,7 @@ "pickerDial": "Dial", "@pickerDial": {}, "appearanceSettingGroupDescription": "设置主题,颜色和布局", - "@appearanceSettingGroupDescription": {} + "@appearanceSettingGroupDescription": {}, + "nameField": "姓名", + "@nameField": {} } From 28897761d43787cd48b71498957daa308207f770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=8D=E4=BA=88?= Date: Fri, 10 May 2024 07:58:03 +0000 Subject: [PATCH 101/112] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (300 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/zh_Hans/ --- lib/l10n/app_zh_Hans.arb | 544 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 531 insertions(+), 13 deletions(-) diff --git a/lib/l10n/app_zh_Hans.arb b/lib/l10n/app_zh_Hans.arb index fa860c3f..d066d428 100644 --- a/lib/l10n/app_zh_Hans.arb +++ b/lib/l10n/app_zh_Hans.arb @@ -23,13 +23,13 @@ "@timePickerSetting": {}, "swipActionCardAction": "操作卡片", "@swipActionCardAction": {}, - "pickerSpinner": "Spinner", + "pickerSpinner": "转盘", "@pickerSpinner": {}, - "durationPickerSetting": "计时器时间选择器样式", + "durationPickerSetting": "计时器时长选择器", "@durationPickerSetting": {}, - "pickerRings": "Rings", + "pickerRings": "环状", "@pickerRings": {}, - "swipeActionSetting": "滑动时行为", + "swipeActionSetting": "滑动操作", "@swipeActionSetting": {}, "melodiesSetting": "铃声", "@melodiesSetting": {}, @@ -69,24 +69,542 @@ "@dateFormatSetting": {}, "showSecondsSetting": "显示秒数", "@showSecondsSetting": {}, - "pickerInput": "Input", + "pickerInput": "输入框", "@pickerInput": {}, - "swipeActionCardActionDescription": "在卡片上向左或向右滑动以执行操作", + "swipeActionCardActionDescription": "向左或向右滑动卡片以执行操作", "@swipeActionCardActionDescription": {}, "swipActionSwitchTabs": "切换选项卡", "@swipActionSwitchTabs": {}, "swipeActionSwitchTabsDescription": "在选项卡间切换", "@swipeActionSwitchTabsDescription": {}, - "batteryOptimizationSetting": "关闭电池优化", + "batteryOptimizationSetting": "禁用电池优化", "@batteryOptimizationSetting": {}, - "vendorSettingDescription": "手动关闭制造商的特殊优化", + "vendorSettingDescription": "手动关闭特定制造商的优化设置", "@vendorSettingDescription": {}, - "autoStartSettingDescription": "当应用关闭时,部分设备需打开自启动才可响铃", + "autoStartSettingDescription": "对于部分设备,应用需要“自启动”权限以在关闭时响铃", "@autoStartSettingDescription": {}, - "pickerDial": "Dial", + "pickerDial": "拨盘", "@pickerDial": {}, - "appearanceSettingGroupDescription": "设置主题,颜色和布局", + "appearanceSettingGroupDescription": "设置主题、颜色和布局", "@appearanceSettingGroupDescription": {}, - "nameField": "姓名", - "@nameField": {} + "nameField": "名称", + "@nameField": {}, + "colorSetting": "颜色", + "@colorSetting": {}, + "textColorSetting": "文本", + "@textColorSetting": {}, + "colorSchemeBackgroundSettingGroup": "背景色", + "@colorSchemeBackgroundSettingGroup": {}, + "colorSchemeAccentSettingGroup": "强调色", + "@colorSchemeAccentSettingGroup": {}, + "colorSchemeCardSettingGroup": "卡片颜色", + "@colorSchemeCardSettingGroup": {}, + "colorSchemeOutlineSettingGroup": "轮廓色", + "@colorSchemeOutlineSettingGroup": {}, + "colorSchemeShadowSettingGroup": "阴影颜色", + "@colorSchemeShadowSettingGroup": {}, + "colorSchemeUseAccentAsOutlineSetting": "将强调色用于轮廓色", + "@colorSchemeUseAccentAsOutlineSetting": {}, + "colorSchemeUseAccentAsShadowSetting": "将强调色用于阴影", + "@colorSchemeUseAccentAsShadowSetting": {}, + "styleThemeNamePlaceholder": "样式主题", + "@styleThemeNamePlaceholder": {}, + "styleThemeShapeSettingGroup": "形状", + "@styleThemeShapeSettingGroup": {}, + "styleThemeRadiusSetting": "圆角半径", + "@styleThemeRadiusSetting": {}, + "styleThemeOutlineWidthSetting": "宽度", + "@styleThemeOutlineWidthSetting": {}, + "backupSettingGroup": "设置", + "@backupSettingGroup": {}, + "developerOptionsSettingGroup": "开发者设置", + "@developerOptionsSettingGroup": {}, + "styleThemeSpreadSetting": "散布", + "@styleThemeSpreadSetting": {}, + "accessibilitySettingGroup": "辅助功能", + "@accessibilitySettingGroup": {}, + "logsSettingGroup": "日志", + "@logsSettingGroup": {}, + "aboutSettingGroup": "关于", + "@aboutSettingGroup": {}, + "restoreSettingGroup": "恢复默认值", + "@restoreSettingGroup": {}, + "resetButton": "重置", + "@resetButton": {}, + "previewLabel": "预览", + "@previewLabel": {}, + "cardLabel": "卡片", + "@cardLabel": {}, + "accentLabel": "强调色", + "@accentLabel": {}, + "errorLabel": "错误", + "@errorLabel": {}, + "displaySettingGroup": "显示", + "@displaySettingGroup": {}, + "showIstantAlarmButtonSetting": "显示即时闹钟按钮", + "@showIstantAlarmButtonSetting": {}, + "showIstantTimerButtonSetting": "显示即时计时器按钮", + "@showIstantTimerButtonSetting": {}, + "useMaterialYouColorSetting": "使用 Material You 样式", + "@useMaterialYouColorSetting": {}, + "materialBrightnessSetting": "亮度", + "@materialBrightnessSetting": {}, + "materialBrightnessLight": "浅色", + "@materialBrightnessLight": {}, + "overrideAccentSetting": "覆盖强调色", + "@overrideAccentSetting": {}, + "accentColorSetting": "强调色", + "@accentColorSetting": {}, + "useMaterialStyleSetting": "使用 Material 风格", + "@useMaterialStyleSetting": {}, + "styleThemeSetting": "样式主题", + "@styleThemeSetting": {}, + "darkColorSchemeSetting": "深色主题", + "@darkColorSchemeSetting": {}, + "clockSettingGroup": "时钟", + "@clockSettingGroup": {}, + "stopwatchSettingGroup": "秒表", + "@stopwatchSettingGroup": {}, + "backupSettingGroupDescription": "在本地导出或导入设置", + "@backupSettingGroupDescription": {}, + "alarmWeekdaysSetting": "星期", + "@alarmWeekdaysSetting": {}, + "alarmDatesSetting": "日期", + "@alarmDatesSetting": {}, + "alarmRangeSetting": "日期范围", + "@alarmRangeSetting": {}, + "alarmIntervalSetting": "间隔", + "@alarmIntervalSetting": {}, + "alarmIntervalDaily": "每天", + "@alarmIntervalDaily": {}, + "alarmIntervalWeekly": "每周", + "@alarmIntervalWeekly": {}, + "alarmDeleteAfterRingingSetting": "关闭后删除", + "@alarmDeleteAfterRingingSetting": {}, + "alarmDeleteAfterFinishingSetting": "结束后删除", + "@alarmDeleteAfterFinishingSetting": {}, + "cannotDisableAlarmWhileSnoozedSnackbar": "无法禁用处于贪睡状态的闹钟", + "@cannotDisableAlarmWhileSnoozedSnackbar": {}, + "timePickerModeButton": "模式", + "@timePickerModeButton": {}, + "labelField": "标签", + "@labelField": {}, + "labelFieldPlaceholder": "添加标签", + "@labelFieldPlaceholder": {}, + "alarmScheduleSettingGroup": "时间计划", + "@alarmScheduleSettingGroup": {}, + "scheduleTypeDaily": "每天", + "@scheduleTypeDaily": {}, + "scheduleTypeOnceDescription": "将在下一次到达此时间时响铃", + "@scheduleTypeOnceDescription": {}, + "scheduleTypeDailyDescription": "将每天响铃", + "@scheduleTypeDailyDescription": {}, + "scheduleTypeWeek": "指定星期", + "@scheduleTypeWeek": {}, + "scheduleTypeWeekDescription": "将在指定星期重复响铃", + "@scheduleTypeWeekDescription": {}, + "scheduleTypeDate": "指定日期", + "@scheduleTypeDate": {}, + "scheduleTypeRange": "日期范围", + "@scheduleTypeRange": {}, + "settingGroupMore": "更多", + "@settingGroupMore": {}, + "scheduleTypeDateDescription": "将在指定日期重复响铃", + "@scheduleTypeDateDescription": {}, + "scheduleTypeRangeDescription": "将在指定日期范围内重复响铃", + "@scheduleTypeRangeDescription": {}, + "audioChannelSetting": "音频通道", + "@audioChannelSetting": {}, + "audioChannelAlarm": "闹钟", + "@audioChannelAlarm": {}, + "audioChannelMedia": "媒体", + "@audioChannelMedia": {}, + "volumeSetting": "音量", + "@volumeSetting": {}, + "snoozeSettingGroup": "贪睡", + "@snoozeSettingGroup": {}, + "snoozeEnableSetting": "启用", + "@snoozeEnableSetting": {}, + "risingVolumeSetting": "铃声渐响", + "@risingVolumeSetting": {}, + "timeToFullVolumeSetting": "至最大音量用时", + "@timeToFullVolumeSetting": {}, + "whileSnoozedSettingGroup": "处于贪睡状态时", + "@whileSnoozedSettingGroup": {}, + "settings": "设置", + "@settings": {}, + "tasksSetting": "任务", + "@tasksSetting": {}, + "noItemMessage": "还没有添加{items}", + "@noItemMessage": {}, + "chooseTaskTitle": "选择待添加任务", + "@chooseTaskTitle": {}, + "mathTask": "数学题", + "@mathTask": {}, + "mathEasyDifficulty": "简单 (X + Y)", + "@mathEasyDifficulty": {}, + "mathMediumDifficulty": "中等 (X × Y)", + "@mathMediumDifficulty": {}, + "retypeTask": "重输文本", + "@retypeTask": {}, + "sequenceTask": "数列", + "@sequenceTask": {}, + "taskTryButton": "试一试", + "@taskTryButton": {}, + "mathTaskDifficultySetting": "难度", + "@mathTaskDifficultySetting": {}, + "retypeLowercaseSetting": "包括小写字母", + "@retypeLowercaseSetting": {}, + "sequenceLengthSetting": "数列长度", + "@sequenceLengthSetting": {}, + "sequenceGridSizeSetting": "网格大小", + "@sequenceGridSizeSetting": {}, + "numberOfProblemsSetting": "问题数", + "@numberOfProblemsSetting": {}, + "saveReminderAlert": "你想要不保存退出吗?", + "@saveReminderAlert": {}, + "yesButton": "是", + "@yesButton": {}, + "noAlarmMessage": "未创建闹钟", + "@noAlarmMessage": {}, + "noTimerMessage": "未创建计时器", + "@noTimerMessage": {}, + "noStopwatchMessage": "未创建秒表", + "@noStopwatchMessage": {}, + "noTaskMessage": "未创建任务", + "@noTaskMessage": {}, + "noPresetsMessage": "未创建预设", + "@noPresetsMessage": {}, + "noLogsMessage": "无闹钟日志", + "@noLogsMessage": {}, + "deleteButton": "删除", + "@deleteButton": {}, + "skipAlarmButton": "跳过下次闹钟", + "@skipAlarmButton": {}, + "cancelSkipAlarmButton": "取消跳过", + "@cancelSkipAlarmButton": {}, + "scheduleDateFilterGroup": "计划日期", + "@scheduleDateFilterGroup": {}, + "todayFilter": "今天", + "@todayFilter": {}, + "completedFilter": "已完成", + "@completedFilter": {}, + "runningTimerFilter": "进行中", + "@runningTimerFilter": {}, + "pausedTimerFilter": "已暂停", + "@pausedTimerFilter": {}, + "stoppedTimerFilter": "已停止", + "@stoppedTimerFilter": {}, + "sortGroup": "排序", + "@sortGroup": {}, + "defaultLabel": "默认", + "@defaultLabel": {}, + "remainingTimeDesc": "按剩余时间降序", + "@remainingTimeDesc": {}, + "remainingTimeAsc": "按剩余时间升序", + "@remainingTimeAsc": {}, + "durationAsc": "时长由短到长", + "@durationAsc": {}, + "durationDesc": "时长由长到短", + "@durationDesc": {}, + "nameAsc": "标签 A-Z", + "@nameAsc": {}, + "nameDesc": "标签 Z-A", + "@nameDesc": {}, + "timeOfDayAsc": "时间由早到晚", + "@timeOfDayAsc": {}, + "clearFiltersAction": "清除所有过滤器", + "@clearFiltersAction": {}, + "enableAllFilteredAlarmsAction": "启用所有已过滤闹钟", + "@enableAllFilteredAlarmsAction": {}, + "cancelSkipAllFilteredAlarmsAction": "取消跳过所有已过滤闹钟", + "@cancelSkipAllFilteredAlarmsAction": {}, + "skippingDescriptionSuffix": "(下一次已跳过)", + "@skippingDescriptionSuffix": {}, + "alarmDescriptionFinished": "无未来响铃", + "@alarmDescriptionFinished": {}, + "stopwatchPrevious": "上一圈", + "@stopwatchPrevious": {}, + "stopwatchFastest": "最快", + "@stopwatchFastest": {}, + "alarmDescriptionDays": "在 {days}", + "@alarmDescriptionDays": {}, + "stopwatchSlowest": "最慢", + "@stopwatchSlowest": {}, + "stopwatchAverage": "平均", + "@stopwatchAverage": {}, + "defaultSettingGroup": "默认设置", + "@defaultSettingGroup": {}, + "alarmsDefaultSettingGroupDescription": "设置新闹钟默认值", + "@alarmsDefaultSettingGroupDescription": {}, + "alarmDescriptionRange": "从 {startDate} 到 {endDate} {interval, select, daily{每天} weekly{每周} other{其他时间}}响铃", + "@alarmDescriptionRange": {}, + "alarmDescriptionDates": "在 {date}{count, plural, =0{} =1{ 及另外一个日期} other{ 及另外 {count} 日期}}响铃", + "@alarmDescriptionDates": {}, + "showFiltersSetting": "显示过滤器", + "@showFiltersSetting": {}, + "showSortSetting": "显示排序", + "@showSortSetting": {}, + "notificationsSettingGroup": "通知", + "@notificationsSettingGroup": {}, + "showUpcomingAlarmNotificationSetting": "显示将响闹钟通知", + "@showUpcomingAlarmNotificationSetting": {}, + "showSnoozeNotificationSetting": "显示贪睡通知", + "@showSnoozeNotificationSetting": {}, + "presetsSetting": "预设", + "@presetsSetting": {}, + "newPresetPlaceholder": "新预设", + "@newPresetPlaceholder": {}, + "dismissActionSetting": "关闭操作类型", + "@dismissActionSetting": {}, + "dismissActionSlide": "滑动", + "@dismissActionSlide": {}, + "dismissActionButtons": "按钮", + "@dismissActionButtons": {}, + "upcomingLeadTimeSetting": "提前通知时间", + "@upcomingLeadTimeSetting": {}, + "comparisonLapBarsSettingGroup": "圈用时比较条", + "@comparisonLapBarsSettingGroup": {}, + "showPreviousLapSetting": "显示上一圈", + "@showPreviousLapSetting": {}, + "showFastestLapSetting": "显示最快一圈", + "@showFastestLapSetting": {}, + "showAverageLapSetting": "显示平均用时", + "@showAverageLapSetting": {}, + "leftHandedSetting": "左手模式", + "@leftHandedSetting": {}, + "exportSettingsSetting": "导出", + "@exportSettingsSetting": {}, + "exportSettingsSettingDescription": "将设置导出到本地文件", + "@exportSettingsSettingDescription": {}, + "importSettingsSettingDescription": "从本地文件导入设置", + "@importSettingsSettingDescription": {}, + "versionLabel": "版本", + "@versionLabel": {}, + "licenseLabel": "许可证", + "@licenseLabel": {}, + "emailLabel": "电子邮箱", + "@emailLabel": {}, + "donorsSetting": "捐赠者", + "@donorsSetting": {}, + "donateButton": "捐赠", + "@donateButton": {}, + "addLengthSetting": "添加时长", + "@addLengthSetting": {}, + "sameTime": "时间相同", + "@sameTime": {}, + "searchSettingPlaceholder": "搜索设置", + "@searchSettingPlaceholder": {}, + "searchCityPlaceholder": "搜索城市", + "@searchCityPlaceholder": {}, + "cityAlreadyInFavorites": "此城市已被收藏", + "@cityAlreadyInFavorites": {}, + "durationPickerTitle": "选择时长", + "@durationPickerTitle": {}, + "relativeTime": "{relative, select, ahead{早} behind{晚} other{其他}} {hours} 小时", + "@relativeTime": {}, + "wednesdayShort": "三", + "@wednesdayShort": {}, + "thursdayShort": "四", + "@thursdayShort": {}, + "fridayShort": "五", + "@fridayShort": {}, + "saturdayShort": "六", + "@saturdayShort": {}, + "sundayShort": "日", + "@sundayShort": {}, + "mondayLetter": "M", + "@mondayLetter": {}, + "tuesdayLetter": "T", + "@tuesdayLetter": {}, + "wednesdayLetter": "W", + "@wednesdayLetter": {}, + "thursdayLetter": "T", + "@thursdayLetter": {}, + "fridayLetter": "F", + "@fridayLetter": {}, + "saturdayLetter": "S", + "@saturdayLetter": {}, + "sundayLetter": "S", + "@sundayLetter": {}, + "donateDescription": "捐赠以支持本应用开发", + "@donateDescription": {}, + "donorsDescription": "慷慨的赞助商", + "@donorsDescription": {}, + "contributorsDescription": "助力本应用实现的人们", + "@contributorsDescription": {}, + "mathHardDifficulty": "困难 (X × Y + Z)", + "@mathHardDifficulty": {}, + "mathVeryHardDifficulty": "非常困难 (X × Y × Z)", + "@mathVeryHardDifficulty": {}, + "retypeNumberChars": "字符数", + "@retypeNumberChars": {}, + "retypeIncludeNumSetting": "包括数字", + "@retypeIncludeNumSetting": {}, + "noButton": "否", + "@noButton": {}, + "duplicateButton": "创建副本", + "@duplicateButton": {}, + "dismissAlarmButton": "关闭", + "@dismissAlarmButton": {}, + "allFilter": "所有", + "@allFilter": {}, + "dateFilterGroup": "日期", + "@dateFilterGroup": {}, + "logTypeFilterGroup": "类型", + "@logTypeFilterGroup": {}, + "stateFilterGroup": "状态", + "@stateFilterGroup": {}, + "colorSchemeNamePlaceholder": "颜色主题", + "@colorSchemeNamePlaceholder": {}, + "colorSchemeErrorSettingGroup": "错误颜色", + "@colorSchemeErrorSettingGroup": {}, + "styleThemeElevationSetting": "高度", + "@styleThemeElevationSetting": {}, + "styleThemeShadowSettingGroup": "阴影颜色", + "@styleThemeShadowSettingGroup": {}, + "styleThemeOpacitySetting": "透明度", + "@styleThemeOpacitySetting": {}, + "styleThemeBlurSetting": "模糊", + "@styleThemeBlurSetting": {}, + "styleThemeOutlineSettingGroup": "轮廓", + "@styleThemeOutlineSettingGroup": {}, + "maxLogsSetting": "日志上限", + "@maxLogsSetting": {}, + "alarmLogSetting": "闹钟日志", + "@alarmLogSetting": {}, + "colorsSettingGroup": "颜色", + "@colorsSettingGroup": {}, + "soundSettingGroup": "声音", + "@soundSettingGroup": {}, + "reliabilitySettingGroup": "可靠性", + "@reliabilitySettingGroup": {}, + "styleSettingGroup": "样式", + "@styleSettingGroup": {}, + "materialBrightnessSystem": "跟随系统", + "@materialBrightnessSystem": {}, + "materialBrightnessDark": "深色", + "@materialBrightnessDark": {}, + "systemDarkModeSetting": "系统深色模式", + "@systemDarkModeSetting": {}, + "melodySetting": "铃声", + "@melodySetting": {}, + "audioChannelNotification": "通知", + "@audioChannelNotification": {}, + "colorSchemeSetting": "颜色主题", + "@colorSchemeSetting": {}, + "vibrationSetting": "振动", + "@vibrationSetting": {}, + "audioChannelRingtone": "铃声", + "@audioChannelRingtone": {}, + "timerSettingGroup": "计时器", + "@timerSettingGroup": {}, + "selectTime": "选择时间", + "@selectTime": {}, + "cancelButton": "取消", + "@cancelButton": {}, + "customizeButton": "自定义", + "@customizeButton": {}, + "saveButton": "保存", + "@saveButton": {}, + "soundAndVibrationSettingGroup": "声音与振动", + "@soundAndVibrationSettingGroup": {}, + "scheduleTypeField": "类型", + "@scheduleTypeField": {}, + "scheduleTypeOnce": "仅一次", + "@scheduleTypeOnce": {}, + "snoozeLengthSetting": "时长", + "@snoozeLengthSetting": {}, + "maxSnoozesSetting": "最大贪睡次数", + "@maxSnoozesSetting": {}, + "snoozePreventDisablingSetting": "防止禁用", + "@snoozePreventDisablingSetting": {}, + "snoozePreventDeletionSetting": "防止删除", + "@snoozePreventDeletionSetting": {}, + "createdDateFilterGroup": "创建日期", + "@createdDateFilterGroup": {}, + "activeFilter": "活跃", + "@activeFilter": {}, + "disabledFilter": "已禁用", + "@disabledFilter": {}, + "tomorrowFilter": "明天", + "@tomorrowFilter": {}, + "inactiveFilter": "不活跃", + "@inactiveFilter": {}, + "snoozedFilter": "贪睡", + "@snoozedFilter": {}, + "timeOfDayDesc": "时间由晚到早", + "@timeOfDayDesc": {}, + "filterActions": "过滤器操作", + "@filterActions": {}, + "disableAllFilteredAlarmsAction": "禁用所有已过滤闹钟", + "@disableAllFilteredAlarmsAction": {}, + "skipAllFilteredAlarmsAction": "跳过所有已过滤闹钟", + "@skipAllFilteredAlarmsAction": {}, + "deleteAllFilteredAction": "删除所有已过滤闹钟", + "@deleteAllFilteredAction": {}, + "alarmDescriptionSnooze": "贪睡至 {date}", + "@alarmDescriptionSnooze": {}, + "alarmDescriptionNotScheduled": "无计划", + "@alarmDescriptionNotScheduled": {}, + "alarmDescriptionToday": "就在今天", + "@alarmDescriptionToday": {}, + "alarmDescriptionTomorrow": "就在明天", + "@alarmDescriptionTomorrow": {}, + "alarmDescriptionEveryDay": "每天", + "@alarmDescriptionEveryDay": {}, + "alarmDescriptionWeekend": "每周末", + "@alarmDescriptionWeekend": {}, + "alarmDescriptionWeekday": "每个工作日", + "@alarmDescriptionWeekday": {}, + "alarmDescriptionWeekly": "每 {days}", + "@alarmDescriptionWeekly": {}, + "timerDefaultSettingGroupDescription": "设置新计时器默认值", + "@timerDefaultSettingGroupDescription": {}, + "filtersSettingGroup": "过滤器", + "@filtersSettingGroup": {}, + "showNotificationSetting": "显示通知", + "@showNotificationSetting": {}, + "dismissActionAreaButtons": "区域按钮", + "@dismissActionAreaButtons": {}, + "stopwatchTimeFormatSettingGroup": "时间格式", + "@stopwatchTimeFormatSettingGroup": {}, + "stopwatchShowMillisecondsSetting": "显示毫秒", + "@stopwatchShowMillisecondsSetting": {}, + "showSlowestLapSetting": "显示最慢一圈", + "@showSlowestLapSetting": {}, + "importSettingsSetting": "导入", + "@importSettingsSetting": {}, + "packageNameLabel": "软件包名称", + "@packageNameLabel": {}, + "viewOnGithubLabel": "在 GitHub 上查看", + "@viewOnGithubLabel": {}, + "openSourceLicensesSetting": "开放源代码许可", + "@openSourceLicensesSetting": {}, + "contributorsSetting": "贡献者", + "@contributorsSetting": {}, + "wednesdayFull": "星期三", + "@wednesdayFull": {}, + "editButton": "编辑", + "@editButton": {}, + "noLapsMessage": "还没有计圈", + "@noLapsMessage": {}, + "elapsedTime": "总用时", + "@elapsedTime": {}, + "tuesdayFull": "星期二", + "@tuesdayFull": {}, + "thursdayFull": "星期四", + "@thursdayFull": {}, + "mondayFull": "星期一", + "@mondayFull": {}, + "fridayFull": "星期五", + "@fridayFull": {}, + "saturdayFull": "星期六", + "@saturdayFull": {}, + "tuesdayShort": "二", + "@tuesdayShort": {}, + "sundayFull": "星期日", + "@sundayFull": {}, + "mondayShort": "一", + "@mondayShort": {} } From 785a1a50ffe920a8fb2496ee347e99ef465a3dbe Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sat, 11 May 2024 13:19:53 +0500 Subject: [PATCH 102/112] Add customization for widgets --- .../chrono/DigitalClockWidgetProvider.kt | 61 +++++++-- .../main/res/layout/digital_clock_widget.xml | 10 +- lib/app.dart | 22 +--- .../widgets/color_picker/picker_selector.dart | 2 +- .../widgets/fields/color_bottom_sheet.dart | 7 +- lib/common/widgets/fields/color_field.dart | 15 ++- lib/l10n/app_en.arb | 19 ++- lib/navigation/screens/nav_scaffold.dart | 16 +-- lib/settings/data/backup_settings_schema.dart | 6 +- .../data/general_settings_schema.dart | 53 ++++---- lib/settings/data/settings_schema.dart | 2 + lib/settings/data/widget_settings_schema.dart | 117 ++++++++++++++++++ lib/settings/logic/initialize_settings.dart | 1 + .../screens/settings_group_screen.dart | 4 +- lib/settings/types/setting.dart | 4 + lib/settings/widgets/color_setting_card.dart | 1 + lib/settings/widgets/setting_group_card.dart | 6 +- lib/settings/widgets/settings_top_bar.dart | 17 ++- lib/widgets/logic/update_widgets.dart | 47 ++++++- pubspec.lock | 8 +- pubspec.yaml | 4 +- 21 files changed, 325 insertions(+), 97 deletions(-) create mode 100644 lib/settings/data/widget_settings_schema.dart diff --git a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt index 9dc5a4b5..0c5f0c7b 100644 --- a/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt +++ b/android/app/src/main/kotlin/com/vicolo/chrono/DigitalClockWidgetProvider.kt @@ -2,17 +2,16 @@ package com.vicolo.chrono import android.app.PendingIntent import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetProvider import android.content.Context import android.content.Intent -import android.widget.RemoteViews import android.content.SharedPreferences -import es.antonborri.home_widget.HomeWidgetBackgroundIntent -import es.antonborri.home_widget.HomeWidgetLaunchIntent -import es.antonborri.home_widget.HomeWidgetProvider -import es.antonborri.home_widget.HomeWidgetPlugin import android.util.Log +import android.widget.RemoteViews +import android.graphics.Color +import es.antonborri.home_widget.HomeWidgetProvider +import android.view.ViewGroup.LayoutParams import android.view.View +import android.util.TypedValue class DigitalClockWidgetProvider : HomeWidgetProvider() { override fun onUpdate( @@ -22,7 +21,7 @@ class DigitalClockWidgetProvider : HomeWidgetProvider() { widgetData: SharedPreferences, ) { // Perform this loop procedure for each widget that belongs to this // provider. - Log.d("TAG", "======================================YOO") + Log.d("TAG", "Updating Digital Clock Widget"); appWidgetIds.forEach { appWidgetId -> // Create an Intent to launch ExampleActivity. @@ -43,11 +42,49 @@ class DigitalClockWidgetProvider : HomeWidgetProvider() { ) val dateFormat = widgetData.getString("dateFormat", "EEE, d MMM") val timeFormat = widgetData.getString("timeFormat", "HH:mm") - setCharSequence (R.id.widget_text_clock, "setFormat24Hour", timeFormat) - setCharSequence (R.id.widget_text_clock, "setFormat12Hour", timeFormat) - setCharSequence (R.id.widget_date, "setFormat24Hour", dateFormat) - setCharSequence (R.id.widget_date, "setFormat12Hour", dateFormat) - // setViewVisibility(R.id.widget_date, View.GONE) + val dateSize = widgetData.getInt("dateSize", 25) + val timeSize = widgetData.getInt("timeSize", 100) + val textColor = widgetData.getString("textColor", "#FFFFFF") + // val shadowColor = widgetData.getString("shadowColor", "#000000") + // val shadowElevation = widgetData.getFloat("shadowElevation", 1.0f) + // val shadowBlur = widgetData.getFloat("shadowBlur", 1.0f) + val showDate = widgetData.getBoolean("showDate", true) + + setCharSequence(R.id.widget_text_clock, "setFormat24Hour", timeFormat) + setCharSequence(R.id.widget_text_clock, "setFormat12Hour", timeFormat) + setCharSequence(R.id.widget_date, "setFormat24Hour", "EEE, d MMM") + setCharSequence(R.id.widget_date, "setFormat12Hour", "EEE, d MMM") + setColorInt(R.id.widget_text_clock, "setTextColor", Color.parseColor(textColor), Color.parseColor(textColor)) + setColorInt(R.id.widget_date, "setTextColor", Color.parseColor(textColor), Color.parseColor(textColor)) + // setFloat(R.id.widget_text_clock, "setTextSize", timeSize.toFloat()) + // setFloat(R.id.widget_date, "setTextSize", dateSize.toFloat()) + setViewLayoutHeight(R.id.widget_text_clock, timeSize.toFloat(), TypedValue.COMPLEX_UNIT_SP) + setViewLayoutHeight(R.id.widget_date, dateSize.toFloat(), TypedValue.COMPLEX_UNIT_SP) + setViewVisibility(R.id.widget_date, if(showDate) View.VISIBLE else View.GONE) + // + // R.layout.digital_clock_widget.findViewById(R.id.widget_text_clock).apply { + // val param = + // LinearLayout.LayoutParams( + // LayoutParams.MATCH_PARENT, + // LayoutParams.MATCH_PARENT, + // timeSize, + // ) + // setLayoutParams(param) + // setShadowLayer(shadowBlur, 0f, shadowElevation, shadowColor) + // } + // + // R.layout.digital_clock_widget.findViewById(R.id.widget_date).apply { + // val param = + // LinearLayout.LayoutParams( + // LayoutParams.MATCH_PARENT, + // LayoutParams.MATCH_PARENT, + // dateSize, + // ) + // setLayoutParams(param) + // setTextColor(textColor) + // setShadowLayer(shadowBlur, 0f, shadowElevation, shadowColor) + // } + // Swap Title Text by calling Dart Code in the Background // setTextViewText(R.id.widget_title, widgetData.getString("title", null) // ?: "No Title Set") diff --git a/android/app/src/main/res/layout/digital_clock_widget.xml b/android/app/src/main/res/layout/digital_clock_widget.xml index e6a75922..e587fbd4 100644 --- a/android/app/src/main/res/layout/digital_clock_widget.xml +++ b/android/app/src/main/res/layout/digital_clock_widget.xml @@ -15,10 +15,9 @@ { late SettingGroup _styleSettings; late Setting _animationSpeedSetting; late SettingGroup _generalSettings; - late Setting _timeFormatSetting; - late Setting _dateFormatSetting; - - void updateDateFormat(dynamic value) async { - await HomeWidget.saveWidgetData("dateFormat", value); - updateWidgets(); - } - - void updateTimeFormat(dynamic value) async { - await HomeWidget.saveWidgetData( - "timeFormat", getTimeFormatString(context, value)); - updateWidgets(); - } @override void initState() { @@ -79,6 +66,7 @@ class _AppState extends State { // HomeWidget.updateWidget( // androidName: 'DigitalClockWidgetProvider', // ); + setDigitalClockWidgetData(context); NotificationController.setListeners(); @@ -89,14 +77,6 @@ class _AppState extends State { _animationSpeedSetting = _generalSettings.getGroup("Animations").getSetting("Animation Speed"); _animationSpeedSetting.addListener(setAnimationSpeed); - _timeFormatSetting = - _generalSettings.getGroup("Display").getSetting("Time Format"); - _dateFormatSetting = - _generalSettings.getGroup("Display").getSetting("Date Format"); - _timeFormatSetting.addListener(updateTimeFormat); - _dateFormatSetting.addListener(updateDateFormat); - updateDateFormat(_dateFormatSetting.value); - updateTimeFormat(_timeFormatSetting.value); setAnimationSpeed(_animationSpeedSetting.value); } diff --git a/lib/common/widgets/color_picker/picker_selector.dart b/lib/common/widgets/color_picker/picker_selector.dart index cdfe5219..eb520e88 100644 --- a/lib/common/widgets/color_picker/picker_selector.dart +++ b/lib/common/widgets/color_picker/picker_selector.dart @@ -51,7 +51,7 @@ class PickerSelector extends StatelessWidget { }, options: options.where((option) => pickers[option.value]!).toList(), square: false, - innerPadding: 16, + innerPadding: 12, ), ), ); diff --git a/lib/common/widgets/fields/color_bottom_sheet.dart b/lib/common/widgets/fields/color_bottom_sheet.dart index 9cc98718..45efe10b 100644 --- a/lib/common/widgets/fields/color_bottom_sheet.dart +++ b/lib/common/widgets/fields/color_bottom_sheet.dart @@ -10,12 +10,14 @@ class ColorBottomSheet extends StatefulWidget { this.description, required this.value, required this.onChange, + this.enableOpacity = false, }); final String title; final String? description; final Color value; final void Function(Color)? onChange; + final bool enableOpacity; @override State createState() => _ColorBottomSheetState(); @@ -79,7 +81,7 @@ class _ColorBottomSheetState extends State { ), // const SizedBox(height: 16.0), ColorPicker( - wheelDiameter: MediaQuery.of(context).size.width - 8, + wheelDiameter: MediaQuery.of(context).size.width - (widget.enableOpacity ? 64 : 32), color: _color, onColorChanged: (Color color) => setState(() { _color = color; @@ -103,6 +105,9 @@ class _ColorBottomSheetState extends State { style: textTheme.titleSmall ?.copyWith(color: colorScheme.onSurface)), showColorCode: true, + enableOpacity: widget.enableOpacity, + opacityTrackHeight: 20, + opacityThumbRadius: 14, copyPasteBehavior: const ColorPickerCopyPasteBehavior( copyFormat: ColorPickerCopyFormat.hexRRGGBB), customPickerSelectBuilder: diff --git a/lib/common/widgets/fields/color_field.dart b/lib/common/widgets/fields/color_field.dart index cb2539f7..1719ff1b 100644 --- a/lib/common/widgets/fields/color_field.dart +++ b/lib/common/widgets/fields/color_field.dart @@ -3,15 +3,18 @@ import 'package:clock_app/common/widgets/fields/color_bottom_sheet.dart'; import 'package:flutter/material.dart'; class ColorField extends StatefulWidget { - const ColorField( - {super.key, - required this.value, - required this.onChange, - required this.name}); + const ColorField({ + super.key, + required this.value, + required this.onChange, + required this.name, + this.enableOpacity = false, + }); final String name; final Color value; final void Function(Color value)? onChange; + final bool enableOpacity; @override State createState() => _ColorFieldState(); @@ -31,6 +34,8 @@ class _ColorFieldState extends State { description: "", value: widget.value, onChange: widget.onChange, + enableOpacity: widget.enableOpacity, + ); }, ); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 562f0bbb..1ec02de0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -606,6 +606,21 @@ "donorsDescription": "Our generous patreons", "@donorsDescription" : {}, "contributorsDescription" : "People who make this app possible", - "@contributorsDescription" : {} - + "@contributorsDescription" : {}, + "widgetsSettingGroup": "Widgets", + "@widgetsSettingGroup": {}, + "digitalClockSettingGroup": "Digital Clock", + "@digitalClockSettingGroup": {}, + "layoutSettingGroup": "Layout", + "@layoutSettingGroup": {}, + "timeSizeSetting": "Time Size", + "@timeSizeSetting": {}, + "dateSizeSetting": "Date Size", + "@dateSizeSetting": {}, + "textSettingGroup": "Text", + "@textSettingGroup": {}, + "showDateSetting": "ShowDate", + "@showDateSetting": {}, + "settingsTitle": "Settings", + "@settingsTitle": {} } diff --git a/lib/navigation/screens/nav_scaffold.dart b/lib/navigation/screens/nav_scaffold.dart index 59f05442..654fde84 100644 --- a/lib/navigation/screens/nav_scaffold.dart +++ b/lib/navigation/screens/nav_scaffold.dart @@ -121,13 +121,15 @@ class _NavScaffoldState extends State { return Scaffold( appBar: orientation == Orientation.portrait ? AppTopBar( - title: Text(tabs[_selectedTabIndex].title, - style: Theme.of(context).textTheme.titleMedium?.copyWith( - color: Theme.of(context) - .colorScheme - .onBackground - .withOpacity(0.6), - )), + title: Text( + tabs[_selectedTabIndex].title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: Theme.of(context) + .colorScheme + .onBackground + .withOpacity(0.6), + ), + ), actions: [ IconButton( onPressed: () { diff --git a/lib/settings/data/backup_settings_schema.dart b/lib/settings/data/backup_settings_schema.dart index 0e8c5a10..f34fcc90 100644 --- a/lib/settings/data/backup_settings_schema.dart +++ b/lib/settings/data/backup_settings_schema.dart @@ -6,6 +6,7 @@ import 'package:clock_app/app.dart'; import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/settings/types/setting_action.dart'; import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:clock_app/widgets/logic/update_widgets.dart'; import 'package:flutter/material.dart'; import 'package:pick_or_save/pick_or_save.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -36,11 +37,12 @@ SettingGroup backupSettingsSchema = SettingGroup( (context) => AppLocalizations.of(context)!.importSettingsSetting, (context) async { loadBackupFile( - (data) { + (data) async { appSettings.loadValueFromJson(json.decode(data)); appSettings.callAllListeners(); App.refreshTheme(context); - appSettings.save(); + await appSettings.save(); + if (context.mounted) setDigitalClockWidgetData(context); }, ); }, diff --git a/lib/settings/data/general_settings_schema.dart b/lib/settings/data/general_settings_schema.dart index 9f46b98c..d15675a2 100644 --- a/lib/settings/data/general_settings_schema.dart +++ b/lib/settings/data/general_settings_schema.dart @@ -15,6 +15,7 @@ import 'package:clock_app/settings/types/setting.dart'; import 'package:clock_app/settings/types/setting_action.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_link.dart'; +import 'package:clock_app/widgets/logic/update_widgets.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -32,6 +33,25 @@ SelectSettingOption _getDateSettingOption(String format) { format); } +final dateFormatOptions = [ + _getDateSettingOption("dd/MM/yyyy"), + _getDateSettingOption("dd-MM-yyyy"), + _getDateSettingOption("d/M/yyyy"), + _getDateSettingOption("d-M-yyyy"), + _getDateSettingOption("MM/dd/yyyy"), + _getDateSettingOption("MM-dd-yyyy"), + _getDateSettingOption("M/d/yy"), + _getDateSettingOption("M-d-yy"), + _getDateSettingOption("M/d/yyyy"), + _getDateSettingOption("M-d-yyyy"), + _getDateSettingOption("yyyy/dd/MM"), + _getDateSettingOption("yyyy-dd-MM"), + _getDateSettingOption("yyyy/MM/dd"), + _getDateSettingOption("yyyy-MM-dd"), + _getDateSettingOption("d MMM yyyy"), + _getDateSettingOption("d MMMM yyyy"), +]; + enum SwipeAction { cardActions, switchTabs, @@ -70,35 +90,24 @@ SettingGroup generalSettingsSchema = SettingGroup( SelectSetting( "Date Format", (context) => AppLocalizations.of(context)!.dateFormatSetting, - [ - _getDateSettingOption("dd/MM/yyyy"), - _getDateSettingOption("dd-MM-yyyy"), - _getDateSettingOption("d/M/yyyy"), - _getDateSettingOption("d-M-yyyy"), - _getDateSettingOption("MM/dd/yyyy"), - _getDateSettingOption("MM-dd-yyyy"), - _getDateSettingOption("M/d/yy"), - _getDateSettingOption("M-d-yy"), - _getDateSettingOption("M/d/yyyy"), - _getDateSettingOption("M-d-yyyy"), - _getDateSettingOption("yyyy/dd/MM"), - _getDateSettingOption("yyyy-dd-MM"), - _getDateSettingOption("yyyy/MM/dd"), - _getDateSettingOption("yyyy-MM-dd"), - // SelectSettingOption(DateTime.now().toIso8601Date(), "YYYY-MM-DD"), - _getDateSettingOption("d MMM yyyy"), - _getDateSettingOption("d MMMM yyyy"), - ], + dateFormatOptions, getDescription: (context) => "How to display the dates", + onChange: (context, index) async { + // await HomeWidget.saveWidgetData( + // "dateFormat", dateFormatOptions[index].value); + // updateDigitalClockWidget(); + }, ), SelectSetting( "Time Format", (context) => AppLocalizations.of(context)!.timeFormatSetting, timeFormatOptions, getDescription: (context) => "12 or 24 hour time", - onChange: (context, index) { - saveTextFile("time_format_string", - getTimeFormatString(context, timeFormatOptions[index].value)); + onChange: (context, index) async { + String timeFormat = + getTimeFormatString(context, timeFormatOptions[index].value); + saveTextFile("time_format_string", timeFormat); + setDigitalClockWidgetData(context); }, ), SwitchSetting( diff --git a/lib/settings/data/settings_schema.dart b/lib/settings/data/settings_schema.dart index fd700233..b26375aa 100644 --- a/lib/settings/data/settings_schema.dart +++ b/lib/settings/data/settings_schema.dart @@ -6,6 +6,7 @@ import 'package:clock_app/settings/data/developer_settings_schema.dart'; import 'package:clock_app/settings/data/general_settings_schema.dart'; import 'package:clock_app/settings/data/stopwatch_settings_schema.dart'; import 'package:clock_app/settings/data/timer_app_settings_schema.dart'; +import 'package:clock_app/settings/data/widget_settings_schema.dart'; import 'package:clock_app/settings/screens/about_screen.dart'; import 'package:clock_app/settings/types/setting_group.dart'; import 'package:clock_app/settings/types/setting_link.dart'; @@ -25,6 +26,7 @@ SettingGroup appSettings = SettingGroup( alarmAppSettingsSchema, timerAppSettingsSchema, stopwatchSettingsSchema, + widgetSettingSchema, accessibilitySettingsSchema, backupSettingsSchema, developerSettingsSchema, diff --git a/lib/settings/data/widget_settings_schema.dart b/lib/settings/data/widget_settings_schema.dart new file mode 100644 index 00000000..0f1456f7 --- /dev/null +++ b/lib/settings/data/widget_settings_schema.dart @@ -0,0 +1,117 @@ +import 'package:clock_app/settings/types/setting.dart'; +import 'package:clock_app/settings/types/setting_enable_condition.dart'; +import 'package:clock_app/settings/types/setting_group.dart'; +import 'package:clock_app/widgets/logic/update_widgets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:home_widget/home_widget.dart'; + +SettingGroup widgetSettingSchema = SettingGroup( + "Widgets", + (context) => AppLocalizations.of(context)!.widgetsSettingGroup, + [ + SettingGroup( + "Digital Clock", + (context) => AppLocalizations.of(context)!.digitalClockSettingGroup, + [ + SettingGroup( + "Layout", + (context) => AppLocalizations.of(context)!.layoutSettingGroup, + [ + SwitchSetting( + "Show Date", + (context) => AppLocalizations.of(context)!.showDateSetting, + true, + onChange: (context, value) async { + setDigitalClockWidgetData(context); + }, + ), + SliderSetting( + "Time Size", + (context) => AppLocalizations.of(context)!.timeSizeSetting, + 10, + 100, + 100, + onChange: (context, value) async { + setDigitalClockWidgetData(context); + }, + // snapLength: 1, + ), + SliderSetting( + "Date Size", + (context) => AppLocalizations.of(context)!.dateSizeSetting, + 10, + 100, + 25, + onChange: (context, value) async { + setDigitalClockWidgetData(context); + }, + enableConditions: [ + ValueCondition(["Show Date"], (value) => value == true) + ], + // snapLength: 1, + ), + ], + ), + SettingGroup( + "Text", + (context) => AppLocalizations.of(context)!.textSettingGroup, + [ + ColorSetting( + "Color", + (context) => AppLocalizations.of(context)!.colorSetting, + Colors.white, + // enableOpacity: true, + onChange: (context, value) async { + setDigitalClockWidgetData(context); + }, + ), + ], + ), + // SettingGroup( + // "Shadow", + // (context) => + // AppLocalizations.of(context)!.styleThemeShadowSettingGroup, + // [ + // SliderSetting( + // "Elevation", + // (context) => + // AppLocalizations.of(context)!.styleThemeElevationSetting, + // 0, + // 5, + // 1, + // onChange: (context, value) async { + // await HomeWidget.saveWidgetData( + // "shadowElevation", value); + // updateDigitalClockWidget(); + // }, + // ), + // SliderSetting( + // "Blur", + // (context) => AppLocalizations.of(context)!.styleThemeBlurSetting, + // 0, + // 5, + // 1, + // onChange: (context, value) async { + // await HomeWidget.saveWidgetData("shadowBlur", value); + // updateDigitalClockWidget(); + // }, + // ), + // ColorSetting( + // "Color", + // (context) => AppLocalizations.of(context)!.colorSetting, + // Colors.black, + // enableOpacity: true, + // onChange: (context, value) async { + // await HomeWidget.saveWidgetData( + // "shadowColor", '#${value.value.toRadixString(16)}'); + // updateDigitalClockWidget(); + // }, + // ), + // ], + // ), + ], + ), + ], + icon: Icons.widgets_outlined, +); diff --git a/lib/settings/logic/initialize_settings.dart b/lib/settings/logic/initialize_settings.dart index 91711a00..30e4036d 100644 --- a/lib/settings/logic/initialize_settings.dart +++ b/lib/settings/logic/initialize_settings.dart @@ -23,6 +23,7 @@ import 'package:clock_app/timer/data/default_timer_presets.dart'; import 'package:clock_app/timer/logic/update_timers.dart'; import 'package:clock_app/timer/types/timer.dart'; import 'package:clock_app/timer/types/timer_preset.dart'; +import 'package:clock_app/widgets/logic/update_widgets.dart'; import 'package:flutter/foundation.dart'; import 'package:get_storage/get_storage.dart'; diff --git a/lib/settings/screens/settings_group_screen.dart b/lib/settings/screens/settings_group_screen.dart index 44e967f2..e647bbcf 100644 --- a/lib/settings/screens/settings_group_screen.dart +++ b/lib/settings/screens/settings_group_screen.dart @@ -39,6 +39,7 @@ class _SettingGroupScreenState extends State { return Scaffold( appBar: SettingsTopBar( + title: widget.settingGroup.displayName(context), onSearch: (settingItems) { setState(() { searchedItems = settingItems; @@ -66,7 +67,8 @@ class _SettingGroupScreenState extends State { SettingPageLinkCard( setting: SettingPageLink( 'Restore default values', - (context) =>AppLocalizations.of(context)!.restoreSettingGroup, + (context) => AppLocalizations.of(context)! + .restoreSettingGroup, RestoreDefaultScreen( settingGroup: widget.settingGroup, onRestore: () async { diff --git a/lib/settings/types/setting.dart b/lib/settings/types/setting.dart index 37762295..a69d2e81 100644 --- a/lib/settings/types/setting.dart +++ b/lib/settings/types/setting.dart @@ -268,6 +268,8 @@ class NumberSetting extends Setting { } class ColorSetting extends Setting { + final bool enableOpacity; + ColorSetting( String name, String Function(BuildContext) getLocalizedName, @@ -275,6 +277,7 @@ class ColorSetting extends Setting { void Function(BuildContext, Color)? onChange, String Function(BuildContext) getDescription = defaultDescription, bool isVisual = true, + this.enableOpacity = false, List enableConditions = const [], List searchTags = const [], }) : super(name, getLocalizedName, getDescription, defaultValue, onChange, @@ -302,6 +305,7 @@ class ColorSetting extends Setting { enableConditions: enableConditions, isVisual: isVisual, searchTags: searchTags, + enableOpacity: enableOpacity, ); } } diff --git a/lib/settings/widgets/color_setting_card.dart b/lib/settings/widgets/color_setting_card.dart index 87492d47..6fa68b51 100644 --- a/lib/settings/widgets/color_setting_card.dart +++ b/lib/settings/widgets/color_setting_card.dart @@ -24,6 +24,7 @@ class _ColorSettingCardState extends State { ColorField toggleCard = ColorField( name: widget.setting.displayName(context), value: widget.setting.value, + enableOpacity: widget.setting.enableOpacity, onChange: (value) { setState(() { widget.setting.setValue(context, value); diff --git a/lib/settings/widgets/setting_group_card.dart b/lib/settings/widgets/setting_group_card.dart index 3ae8873b..6f154e08 100644 --- a/lib/settings/widgets/setting_group_card.dart +++ b/lib/settings/widgets/setting_group_card.dart @@ -6,7 +6,6 @@ import 'package:clock_app/settings/types/setting_item.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class SettingGroupCard extends StatefulWidget { final SettingGroup settingGroup; final VoidCallback? checkDependentEnableConditions; @@ -87,8 +86,9 @@ class _SettingGroupCardState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Icon(widget.settingGroup.icon, color: colorScheme.onBackground), - const SizedBox(width: 16), + if (widget.settingGroup.icon != null) + Icon(widget.settingGroup.icon, color: colorScheme.onBackground), + if (widget.settingGroup.icon != null) const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/settings/widgets/settings_top_bar.dart b/lib/settings/widgets/settings_top_bar.dart index 1c25ac23..63b4beb3 100644 --- a/lib/settings/widgets/settings_top_bar.dart +++ b/lib/settings/widgets/settings_top_bar.dart @@ -5,15 +5,18 @@ import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class SettingsTopBar extends StatefulWidget implements PreferredSizeWidget { @override Size get preferredSize => const Size(0, 56); const SettingsTopBar( - {super.key, required this.onSearch, this.showSearch = false}); + {super.key, + required this.onSearch, + this.showSearch = false, + required this.title}); final void Function(List settings) onSearch; + final String title; final bool showSearch; @override @@ -83,7 +86,13 @@ class _SettingsTopBarState extends State { ); } else { return AppTopBar( - title: Text("Settings", style: Theme.of(context).textTheme.titleMedium), + title: Text( + widget.title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: + Theme.of(context).colorScheme.onBackground.withOpacity(0.6), + ), + ), actions: [ if (widget.showSearch) IconButton( @@ -95,7 +104,7 @@ class _SettingsTopBarState extends State { icon: Icon( Icons.search, color: - Theme.of(context).colorScheme.onBackground.withOpacity(0.6), + Theme.of(context).colorScheme.onBackground, ), ) ], diff --git a/lib/widgets/logic/update_widgets.dart b/lib/widgets/logic/update_widgets.dart index b9d5c89a..d69c14d3 100644 --- a/lib/widgets/logic/update_widgets.dart +++ b/lib/widgets/logic/update_widgets.dart @@ -1,10 +1,45 @@ +import 'package:clock_app/common/utils/time_format.dart'; +import 'package:clock_app/settings/data/general_settings_schema.dart'; +import 'package:clock_app/settings/data/settings_schema.dart'; +import 'package:flutter/material.dart'; import 'package:home_widget/home_widget.dart'; -void updateWidgets() { +void setDigitalClockWidgetData(BuildContext context) async { + final digitalClockSettingGroup = + appSettings.getGroup('Widgets').getGroup('Digital Clock'); + final bool showDate = + digitalClockSettingGroup.getGroup('Layout').getSetting('Show Date').value; + final int timeSize = digitalClockSettingGroup + .getGroup('Layout') + .getSetting('Time Size') + .value + .round(); + final int dateSize = digitalClockSettingGroup + .getGroup('Layout') + .getSetting('Date Size') + .value + .round(); + final String textColor = + '#${digitalClockSettingGroup.getGroup('Text').getSetting('Color').value.value.toRadixString(16)}'; + final String timeFormat = getTimeFormatString(context, appSettings + .getGroup('General') + .getGroup('Display') + .getSetting('Time Format') + .value); + + await HomeWidget.saveWidgetData("timeFormat", timeFormat); + await HomeWidget.saveWidgetData('showDate', showDate); + await HomeWidget.saveWidgetData('timeSize', timeSize); + await HomeWidget.saveWidgetData('dateSize', dateSize); + await HomeWidget.saveWidgetData('textColor', textColor); + + updateDigitalClockWidget(); +} + +void updateDigitalClockWidget() { HomeWidget.updateWidget( - androidName: 'DigitalClockWidgetProvider', - name: 'DigitalClockWidgetProvider', - qualifiedAndroidName: - 'com.vicolo.chrono.DigitalClockWidgetProvider', - ); + androidName: 'DigitalClockWidgetProvider', + name: 'DigitalClockWidgetProvider', + qualifiedAndroidName: 'com.vicolo.chrono.DigitalClockWidgetProvider', + ); } diff --git a/pubspec.lock b/pubspec.lock index 47603ad5..457ce5dd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -475,9 +475,11 @@ packages: home_widget: dependency: "direct main" description: - path: "../home_widget" - relative: true - source: path + path: "." + ref: main + resolved-ref: "5788ac45f62bef72ff44c52cbd77dc1f9258f633" + url: "https://github.com/AhsanSarwar45/home_widget" + source: git version: "0.5.0" html: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index ab82868c..af25ae43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -71,7 +71,9 @@ dependencies: locale_names: ^1.1.1 # home_widget: ^0.5.0 home_widget: - path: "../home_widget/" + git: + url: https://github.com/AhsanSarwar45/home_widget + ref: main dev_dependencies: From 1647baa0032dd55fc4bc7fc1dcc2e46b2a2c20bc Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sat, 11 May 2024 22:08:13 +0500 Subject: [PATCH 103/112] Change app move to background behaviour --- lib/alarm/logic/alarm_isolate.dart | 18 ++++++--- lib/navigation/data/fullscreen_intent.dart | 1 + lib/navigation/types/app_visibility.dart | 12 +++--- .../logic/notification_callbacks.dart | 6 --- .../fullscreen_notification_manager.dart | 40 ++++++++++++------- lib/settings/logic/initialize_settings.dart | 19 ++------- lib/system/logic/handle_intents.dart | 6 +++ 7 files changed, 55 insertions(+), 47 deletions(-) create mode 100644 lib/navigation/data/fullscreen_intent.dart diff --git a/lib/alarm/logic/alarm_isolate.dart b/lib/alarm/logic/alarm_isolate.dart index 272a0b71..332cd03c 100644 --- a/lib/alarm/logic/alarm_isolate.dart +++ b/lib/alarm/logic/alarm_isolate.dart @@ -8,7 +8,6 @@ import 'package:clock_app/system/logic/initialize_isolate.dart'; import 'package:clock_app/timer/types/time_duration.dart'; import 'package:clock_app/timer/types/timer.dart'; import 'package:flutter/foundation.dart'; -import 'package:get_storage/get_storage.dart'; import 'package:clock_app/alarm/logic/schedule_alarm.dart'; import 'package:clock_app/alarm/logic/update_alarms.dart'; import 'package:clock_app/alarm/types/alarm.dart'; @@ -19,6 +18,8 @@ import 'package:clock_app/alarm/utils/alarm_id.dart'; import 'package:clock_app/common/utils/time_of_day.dart'; import 'package:clock_app/timer/logic/update_timers.dart'; import 'package:clock_app/timer/utils/timer_id.dart'; +import 'package:flutter/services.dart'; +import 'package:receive_intent/receive_intent.dart'; const String stopAlarmPortName = "stopAlarmPort"; const String updatePortName = "updatePort"; @@ -51,6 +52,16 @@ void triggerScheduledNotification(int scheduleId, Json params) async { stopScheduledNotification(message); }); + try { + final receivedIntent = await ReceiveIntent.getInitialIntent(); + print("reeeeeeeeeeeeeeeeeeeeeeeeeee ${receivedIntent}"); + // Validate receivedIntent and warn the user, if it is not correct, + // but keep in mind it could be `null` or "empty"(`receivedIntent.isNull`). + } on PlatformException { + // Handle exception + } + + if (notificationType == ScheduledNotificationType.alarm) { triggerAlarm(scheduleId, params); } else if (notificationType == ScheduledNotificationType.timer) { @@ -104,8 +115,6 @@ void triggerAlarm(int scheduleId, Json params) async { return; } - GetStorage().write("fullScreenNotificationRecentlyShown", true); - // Pause any currently ringing timers. We will continue them after the alarm // is dismissed if (RingingManager.isTimerRinging) { @@ -168,9 +177,6 @@ void triggerTimer(int scheduleId, Json params) async { await updateTimers("triggerTimer(): Updating all timers on trigger"); - // Notify the front-end to update the timers - GetStorage().write("fullScreenNotificationRecentlyShown", true); - // Pause any currently ringing alarms. We will continue them after the timer // is dismissed if (RingingManager.isAlarmRinging) { diff --git a/lib/navigation/data/fullscreen_intent.dart b/lib/navigation/data/fullscreen_intent.dart new file mode 100644 index 00000000..faa0c3f9 --- /dev/null +++ b/lib/navigation/data/fullscreen_intent.dart @@ -0,0 +1 @@ +const fullscreenIntentKey = "fullscreen_intent"; diff --git a/lib/navigation/types/app_visibility.dart b/lib/navigation/types/app_visibility.dart index d68ec1a7..069a7774 100644 --- a/lib/navigation/types/app_visibility.dart +++ b/lib/navigation/types/app_visibility.dart @@ -1,7 +1,8 @@ import 'dart:async'; +import 'package:clock_app/common/utils/list_storage.dart'; +import 'package:clock_app/navigation/data/fullscreen_intent.dart'; import 'package:flutter_fgbg/flutter_fgbg.dart'; -import 'package:get_storage/get_storage.dart'; class AppVisibility { static StreamSubscription? subscription; @@ -15,12 +16,11 @@ class AppVisibility { } static void initialize() { - if (GetStorage().read("fullScreenNotificationRecentlyShown") == - true) { - GetStorage().write("fullScreenNotificationRecentlyShown", false); - } else { + // if (loadTextFileSync(fullscreenIntentKey) == "true") { + // saveTextFile(fullscreenIntentKey, "false"); + // } else { setState(FGBGType.foreground); - } + // } subscription = FGBGEvents.stream.listen((event) { setState(event); diff --git a/lib/notifications/logic/notification_callbacks.dart b/lib/notifications/logic/notification_callbacks.dart index b56137a9..faacc9a3 100644 --- a/lib/notifications/logic/notification_callbacks.dart +++ b/lib/notifications/logic/notification_callbacks.dart @@ -1,13 +1,7 @@ import 'package:awesome_notifications/awesome_notifications.dart'; -import 'package:clock_app/alarm/logic/alarm_reminder_notifications.dart'; -import 'package:clock_app/alarm/logic/update_alarms.dart'; -import 'package:clock_app/alarm/types/alarm.dart'; -import 'package:clock_app/alarm/utils/alarm_id.dart'; -import 'package:clock_app/common/types/notification_type.dart'; import 'package:clock_app/notifications/data/notification_channel.dart'; import 'package:clock_app/notifications/types/fullscreen_notification_data.dart'; import 'package:clock_app/notifications/types/fullscreen_notification_manager.dart'; -import 'package:clock_app/settings/data/settings_schema.dart'; import 'package:clock_app/stopwatch/logic/update_stopwatch.dart'; import 'package:clock_app/system/logic/initialize_isolate.dart'; import 'package:clock_app/timer/logic/update_timers.dart'; diff --git a/lib/notifications/types/fullscreen_notification_manager.dart b/lib/notifications/types/fullscreen_notification_manager.dart index 7bce2bb1..86d12ee1 100644 --- a/lib/notifications/types/fullscreen_notification_manager.dart +++ b/lib/notifications/types/fullscreen_notification_manager.dart @@ -8,21 +8,25 @@ import 'package:clock_app/alarm/logic/alarm_isolate.dart'; import 'package:clock_app/alarm/logic/update_alarms.dart'; import 'package:clock_app/app.dart'; import 'package:clock_app/common/types/notification_type.dart'; +import 'package:clock_app/common/utils/list_storage.dart'; +import 'package:clock_app/navigation/data/fullscreen_intent.dart'; import 'package:clock_app/notifications/data/notification_channel.dart'; import 'package:clock_app/alarm/logic/schedule_alarm.dart'; import 'package:clock_app/navigation/types/app_visibility.dart'; import 'package:clock_app/navigation/types/routes.dart'; import 'package:clock_app/notifications/types/fullscreen_notification_data.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_fgbg/flutter_fgbg.dart'; import 'package:flutter_show_when_locked/flutter_show_when_locked.dart'; import 'package:get_storage/get_storage.dart'; import 'package:move_to_background/move_to_background.dart'; +import 'package:receive_intent/receive_intent.dart'; class AlarmNotificationManager { static const String _snoozeActionKey = "snooze"; static const String _dismissActionKey = "dismiss"; - static FGBGType _appVisibilityWhenCreated = FGBGType.foreground; + static FGBGType appVisibilityWhenCreated = FGBGType.foreground; static void showFullScreenNotification({ required ScheduledNotificationType type, @@ -98,22 +102,29 @@ class AlarmNotificationManager { static Future closeNotification(ScheduledNotificationType type) async { await removeNotification(type); - await GetStorage.init(); - // await LockScreenFlagManager.clearLockScreenFlags(); await FlutterShowWhenLocked().hide(); - // If we were on the alarm screen, pop it off the stack. Sometimes the system - // decides to show a heads up notification instead of a full screen one, so - // we can't always pop the top screen. - Routes.popIf(alarmNotificationData[type]?.route); - // If notification was created while app was in background, move app back // to background when we close the notification - if (_appVisibilityWhenCreated == FGBGType.background && + + if (appVisibilityWhenCreated == FGBGType.background && AppVisibility.state == FGBGType.foreground) { MoveToBackground.moveTaskToBack(); } - GetStorage().write("fullScreenNotificationRecentlyShown", false); + + // try { + // final receivedIntent = await ReceiveIntent.getInitialIntent(); + // print("reeeeeeeeeeeeeeeeeeeeeeeeeee ${receivedIntent}"); + // // Validate receivedIntent and warn the user, if it is not correct, + // // but keep in mind it could be `null` or "empty"(`receivedIntent.isNull`). + // } on PlatformException { + // // Handle exception + // } + + // If we were on the alarm screen, pop it off the stack. Sometimes the system + // decides to show a heads up notification instead of a full screen one, so + // we can't always pop the top screen. + Routes.popIf(alarmNotificationData[type]?.route); } static Future snoozeAlarm( @@ -149,7 +160,6 @@ class AlarmNotificationManager { break; } await closeNotification(type); - } static Future stopAlarm(int scheduleId, ScheduledNotificationType type, @@ -162,8 +172,7 @@ class AlarmNotificationManager { } static void handleNotificationCreated(ReceivedNotification notification) { - _appVisibilityWhenCreated = AppVisibility.state; - GetStorage().write("fullScreenNotificationRecentlyShown", false); + // _appVisibilityWhenCreated = AppVisibility.state; } static Future openNotificationScreen( @@ -197,7 +206,7 @@ class AlarmNotificationManager { (json.decode((payload['scheduleIds'])!) as List).cast(); if (scheduleIds.isEmpty) return; - if (tasksRequired && dismissType != AlarmDismissType.snooze){ + if (tasksRequired && dismissType != AlarmDismissType.snooze) { await openNotificationScreen(data, scheduleIds, tasksOnly: true, dismissType: dismissType); } else { @@ -223,7 +232,10 @@ class AlarmNotificationManager { break; default: + /* print("ahsan is the besttttttttttttttttttttt ${AppVisibility.state}"); */ + await openNotificationScreen(data, scheduleIds); + break; } } diff --git a/lib/settings/logic/initialize_settings.dart b/lib/settings/logic/initialize_settings.dart index 30e4036d..6f1ecdb2 100644 --- a/lib/settings/logic/initialize_settings.dart +++ b/lib/settings/logic/initialize_settings.dart @@ -23,20 +23,12 @@ import 'package:clock_app/timer/data/default_timer_presets.dart'; import 'package:clock_app/timer/logic/update_timers.dart'; import 'package:clock_app/timer/types/timer.dart'; import 'package:clock_app/timer/types/timer_preset.dart'; -import 'package:clock_app/widgets/logic/update_widgets.dart'; import 'package:flutter/foundation.dart'; import 'package:get_storage/get_storage.dart'; - Future _clearSettings() async { - // List timers = await loadList('timers'); - // List alarms = await loadList('alarms'); // We need to remove all scheduled alarms and timers before clearing the data // Otherwise, there would be no way to remove them in the future - - // for (var timer in timers) { - // timer.reset(); - // } await cancelAllAlarms(); await cancelAllTimers(); await GetStorage().erase(); @@ -60,13 +52,10 @@ Future initializeStorage([bool clearSettingsOnDebug = true]) async { // Comment this out after the preferences are cleared if (kDebugMode && clearSettingsOnDebug) await _clearSettings(); - bool? firstLaunch = GetStorage().read('first_launch'); - if (firstLaunch == null) { - // This is used to show alarm and timer edit animations - GetStorage().write('first_alarm_created', false); - GetStorage().write('first_timer_created', false); - } - + // bool? firstLaunch = GetStorage().read('first_launch'); + // if (firstLaunch == null) { + // } + // await initList("alarms", []); await initList("tags", defaultTags); await initList("alarm_events", []); diff --git a/lib/system/logic/handle_intents.dart b/lib/system/logic/handle_intents.dart index d6b9219b..421115e3 100644 --- a/lib/system/logic/handle_intents.dart +++ b/lib/system/logic/handle_intents.dart @@ -4,6 +4,8 @@ import 'package:clock_app/alarm/types/alarm.dart'; import 'package:clock_app/alarm/types/schedules/weekly_alarm_schedule.dart'; import 'package:clock_app/common/types/notification_type.dart'; import 'package:clock_app/common/utils/list_storage.dart'; +import 'package:clock_app/navigation/types/app_visibility.dart'; +import 'package:clock_app/notifications/types/fullscreen_notification_manager.dart'; import 'package:clock_app/settings/types/listener_manager.dart'; import 'package:flutter/material.dart' hide Intent; import 'package:receive_intent/receive_intent.dart'; @@ -92,6 +94,10 @@ void handleIntent(Intent? receivedIntent, BuildContext context, Function(Alarm) break; case "android.intent.action.VIEW_TIMERS": break; + case "SELECT_NOTIFICATION": + AlarmNotificationManager.appVisibilityWhenCreated = AppVisibility.state; + // print("************************************** ${AppVisibility.state}"); + break; default: break; } From db53400887078b7fef4e76d14e44699be6271624 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sat, 11 May 2024 23:04:19 +0500 Subject: [PATCH 104/112] Fix select test --- test/common/widgets/fields/select_field_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/common/widgets/fields/select_field_test.dart b/test/common/widgets/fields/select_field_test.dart index 274c8cef..ca305c56 100644 --- a/test/common/widgets/fields/select_field_test.dart +++ b/test/common/widgets/fields/select_field_test.dart @@ -146,9 +146,9 @@ Future _renderWidget(WidgetTester tester, supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: SelectField( - selectedIndices: [selectedIndex], + getSelectedIndices: () => [selectedIndex], title: title, - choices: choices, + getChoices: () => choices, onChanged: onChanged ?? (_) {}, ), ), From 5193561046d8bf841b76307322daa7a4aaed211a Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sat, 11 May 2024 23:06:05 +0500 Subject: [PATCH 105/112] Remove extra csv file --- patreons.csv | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 patreons.csv diff --git a/patreons.csv b/patreons.csv deleted file mode 100644 index 7bb8b8ee..00000000 --- a/patreons.csv +++ /dev/null @@ -1,4 +0,0 @@ -Name,Email,Discord,Patron Status,Follows You,Free Member,Free Trial,Lifetime Amount,Pledge Amount,Charge Frequency,Tier,Addressee,Street,City,State,Zip,Country,Phone,Patronage Since Date,Last Charge Date,Last Charge Status,Additional Details,User ID,Last Updated,Currency,Max Posts,Access Expiration,Next Charge Date -Potato,patreon@cinna.boo,,Active patron,No,No,No,3.66,3.66,monthly,,,,,,,,,2024-05-07 11:33:33,2024-05-07 11:33:35,Paid,,128102512,2024-05-07 11:58:39,USD,,,2024-06-07 00:00:00 -Thorsten,patreon.com@th23.net,,Active patron,No,Yes,No,53.76,0.00,monthly,Free,,,,,,,,2024-05-04 06:21:11,2024-05-04 06:21:13,Paid,,127707165,2024-05-04 06:46:20,USD,,2024-06-04 00:00:00,2024-06-04 00:00:00 -Azeem Sarwar,azeemswr.as@gmail.com,,,No,Yes,No,0.00,0.00,,Free,,,,,,,,2024-04-13 13:26:21,,,,124960783,2024-04-13 13:26:21,USD,,, From 9248e31b249c95844b97a215e3ac34c3cea59d73 Mon Sep 17 00:00:00 2001 From: Sergio Marques Date: Sat, 11 May 2024 10:47:15 +0000 Subject: [PATCH 106/112] Translated using Weblate (Portuguese) Currently translated at 76.6% (230 of 300 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/pt/ --- lib/l10n/app_pt.arb | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 42240ffe..a5798f63 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -440,5 +440,31 @@ "filterActions": "Ações de filtros", "@filterActions": {}, "clearFiltersAction": "Limpar todos", - "@clearFiltersAction": {} + "@clearFiltersAction": {}, + "deleteAllFilteredAction": "Eliminar alarmes filtrados", + "@deleteAllFilteredAction": {}, + "alarmDescriptionWeekly": "A cada {days}", + "@alarmDescriptionWeekly": {}, + "defaultSettingGroup": "Definições padrão", + "@defaultSettingGroup": {}, + "alarmsDefaultSettingGroupDescription": "Definir valores padrão para novos alarmes", + "@alarmsDefaultSettingGroupDescription": {}, + "timerDefaultSettingGroupDescription": "Definir valores padrão para novos temporizadores", + "@timerDefaultSettingGroupDescription": {}, + "filtersSettingGroup": "Filtros", + "@filtersSettingGroup": {}, + "showFiltersSetting": "Mostrar filtros", + "@showFiltersSetting": {}, + "showSortSetting": "Mostrar ordenados", + "@showSortSetting": {}, + "notificationsSettingGroup": "Notificações", + "@notificationsSettingGroup": {}, + "cancelSkipAllFilteredAlarmsAction": "Cancelar Ignorar alarmes filtrados", + "@cancelSkipAllFilteredAlarmsAction": {}, + "enableAllFilteredAlarmsAction": "Ativar alarmes filtrados", + "@enableAllFilteredAlarmsAction": {}, + "disableAllFilteredAlarmsAction": "Desativar alarmes filtrados", + "@disableAllFilteredAlarmsAction": {}, + "skipAllFilteredAlarmsAction": "Ignorar alarmes filtrados", + "@skipAllFilteredAlarmsAction": {} } From bfc74da64d44b49dadb39fd95d7c0f783ea60ada Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sat, 11 May 2024 23:40:48 +0500 Subject: [PATCH 107/112] Change chinese code --- lib/l10n/{app_zh_Hans.arb => app_zh.arb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/l10n/{app_zh_Hans.arb => app_zh.arb} (100%) diff --git a/lib/l10n/app_zh_Hans.arb b/lib/l10n/app_zh.arb similarity index 100% rename from lib/l10n/app_zh_Hans.arb rename to lib/l10n/app_zh.arb From 979e3fcbe75b763f2a52e3e14aa206d375b0ada2 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sun, 12 May 2024 00:05:43 +0500 Subject: [PATCH 108/112] Add wrapping to theme preview card --- lib/theme/widgets/theme_preview_card.dart | 78 +++++++++++------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/theme/widgets/theme_preview_card.dart b/lib/theme/widgets/theme_preview_card.dart index 21ac9dfa..72cae966 100644 --- a/lib/theme/widgets/theme_preview_card.dart +++ b/lib/theme/widgets/theme_preview_card.dart @@ -20,24 +20,24 @@ class ThemePreviewCard extends StatelessWidget { color: colorScheme.background, child: Padding( padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Text( - AppLocalizations.of(context)!.previewLabel, - style: textTheme.headlineMedium?.copyWith( - color: colorScheme.onBackground, + child: SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text( + AppLocalizations.of(context)!.previewLabel, + style: textTheme.headlineMedium?.copyWith( + color: colorScheme.onBackground, + ), ), ), - ), - const SizedBox(height: 8.0), - Row( - children: [ - Expanded( - flex: 1, - child: CardContainer( + const SizedBox(height: 8.0), + Wrap( + children: [ + CardContainer( color: getCardColor(context), key: const Key("Preview Card - Card"), child: Padding( @@ -50,30 +50,30 @@ class ThemePreviewCard extends StatelessWidget { ), ), ), - ), - CardContainer( - key: const Key("Preview Card - Accent"), - color: colorScheme.primary, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Text(AppLocalizations.of(context)!.accentLabel, - style: textTheme.bodyMedium - ?.copyWith(color: colorScheme.onPrimary)), - ), - ), - CardContainer( - key: const Key("Preview Card - Error"), - color: colorScheme.error, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Text(AppLocalizations.of(context)!.errorLabel, - style: textTheme.bodyMedium - ?.copyWith(color: colorScheme.onError)), + CardContainer( + key: const Key("Preview Card - Accent"), + color: colorScheme.primary, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Text(AppLocalizations.of(context)!.accentLabel, + style: textTheme.bodyMedium + ?.copyWith(color: colorScheme.onPrimary)), + ), ), - ) - ], - ), - ], + CardContainer( + key: const Key("Preview Card - Error"), + color: colorScheme.error, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Text(AppLocalizations.of(context)!.errorLabel, + style: textTheme.bodyMedium + ?.copyWith(color: colorScheme.onError)), + ), + ) + ], + ), + ], + ), ), ), ); From fba960fa1469ac5c298ab5037a684e534caa505e Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Sat, 11 May 2024 18:42:57 +0000 Subject: [PATCH 109/112] Translated using Weblate (English) Currently translated at 100.0% (308 of 308 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/en/ --- lib/l10n/app_en.arb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1ec02de0..8cb0ceef 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -604,9 +604,9 @@ "donateDescription": "Donate to support the development of the app", "@donateDescription": {}, "donorsDescription": "Our generous patreons", - "@donorsDescription" : {}, - "contributorsDescription" : "People who make this app possible", - "@contributorsDescription" : {}, + "@donorsDescription": {}, + "contributorsDescription": "People who make this app possible", + "@contributorsDescription": {}, "widgetsSettingGroup": "Widgets", "@widgetsSettingGroup": {}, "digitalClockSettingGroup": "Digital Clock", @@ -619,7 +619,7 @@ "@dateSizeSetting": {}, "textSettingGroup": "Text", "@textSettingGroup": {}, - "showDateSetting": "ShowDate", + "showDateSetting": "Show Date", "@showDateSetting": {}, "settingsTitle": "Settings", "@settingsTitle": {} From 58492db99c41b4e42e8410a69c7396356fc93ba1 Mon Sep 17 00:00:00 2001 From: Ahsan Sarwar Date: Sat, 11 May 2024 19:06:15 +0000 Subject: [PATCH 110/112] Translated using Weblate (French) Currently translated at 97.4% (300 of 308 strings) Translation: Chrono/App Translate-URL: https://hosted.weblate.org/projects/chrono/app/fr/ --- lib/l10n/app_fr.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 88365b72..7854792d 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -341,7 +341,7 @@ "@resetButton": {}, "cardLabel": "Carte", "@cardLabel": {}, - "accentLabel": "Couleur primaire & d’accent", + "accentLabel": "Accent", "@accentLabel": {}, "errorLabel": "Erreur", "@errorLabel": {}, From c03e501f9d6e528756b3b11e82da689769d32c8b Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sun, 12 May 2024 00:57:49 +0500 Subject: [PATCH 111/112] Fix time picker mode --- lib/common/widgets/clock/time_display.dart | 4 +- lib/common/widgets/time_picker.dart | 130 +++------------------ 2 files changed, 19 insertions(+), 115 deletions(-) diff --git a/lib/common/widgets/clock/time_display.dart b/lib/common/widgets/clock/time_display.dart index d2c9021e..829ef769 100644 --- a/lib/common/widgets/clock/time_display.dart +++ b/lib/common/widgets/clock/time_display.dart @@ -4,6 +4,7 @@ import 'package:intl/intl.dart'; class TimeDisplay extends StatelessWidget { const TimeDisplay({ + super.key, required this.format, required this.fontSize, @@ -20,7 +21,8 @@ class TimeDisplay extends StatelessWidget { @override Widget build(BuildContext context) { - String formattedTime = DateFormat(format).format(dateTime); + Locale locale = Localizations.localeOf(context); + String formattedTime = DateFormat(format, locale.languageCode).format(dateTime); return Text( formattedTime, style: Theme.of(context).textTheme.displaySmall?.copyWith( diff --git a/lib/common/widgets/time_picker.dart b/lib/common/widgets/time_picker.dart index a74ba332..ddab85ec 100644 --- a/lib/common/widgets/time_picker.dart +++ b/lib/common/widgets/time_picker.dart @@ -1450,6 +1450,7 @@ class _TimePickerInput extends StatefulWidget { required this.autofocusHour, required this.autofocusMinute, required this.onChanged, + required this.use24hFormat, this.restorationId, // required this.entryMode, // required this.handleEntryModeToggle, @@ -1481,6 +1482,8 @@ class _TimePickerInput extends StatefulWidget { final ValueChanged onChanged; + final bool use24hFormat; + /// Restoration ID to save and restore the state of the time picker input /// widget. /// @@ -1613,7 +1616,7 @@ class _TimePickerInputState extends State<_TimePickerInput> final MediaQueryData media = MediaQuery.of(context); final TimeOfDayFormat timeOfDayFormat = MaterialLocalizations.of(context) .timeOfDayFormat(alwaysUse24HourFormat: media.alwaysUse24HourFormat); - final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; + // final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; final ThemeData theme = Theme.of(context); final TextStyle hourMinuteStyle = TimePickerTheme.of(context).hourMinuteTextStyle ?? @@ -1635,7 +1638,7 @@ class _TimePickerInputState extends State<_TimePickerInput> child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (!use24HourDials && + if (!widget.use24hFormat && timeOfDayFormat == TimeOfDayFormat.a_space_h_colon_mm) ...[ _DayPeriodControl( @@ -1719,7 +1722,7 @@ class _TimePickerInputState extends State<_TimePickerInput> ], ), ), - if (!use24HourDials && + if (!widget.use24hFormat && timeOfDayFormat != TimeOfDayFormat.a_space_h_colon_mm) ...[ const SizedBox(width: 12.0), @@ -2382,7 +2385,7 @@ class _TimePickerDialogState extends State final MediaQueryData media = MediaQuery.of(context); final TimeOfDayFormat timeOfDayFormat = localizations.timeOfDayFormat( alwaysUse24HourFormat: media.alwaysUse24HourFormat); - final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; + // final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; final ThemeData theme = Theme.of(context); final ShapeBorder shape = TimePickerTheme.of(context).shape ?? _kDefaultShape; @@ -2445,113 +2448,13 @@ class _TimePickerDialogState extends State final Size dialogSize = _dialogSize(context, type); final Widget picker; - // switch (_entryMode.value) { - // case TimePickerEntryMode.dial: - // case TimePickerEntryMode.dialOnly: - // final Widget dial = Padding( - // padding: orientation == Orientation.portrait - // ? const EdgeInsets.symmetric(horizontal: 24, vertical: 16) - // : const EdgeInsets.only(right: 12, left: 12, top: 24, bottom: 12), - // child: ExcludeSemantics( - // child: AspectRatio( - // aspectRatio: 1.0, - // child: _Dial( - // mode: _mode.value, - // use24HourDials: use24HourDials, - // selectedTime: _selectedTime.value, - // onChanged: _handleTimeChanged, - // onHourSelected: _handleHourSelected, - // ), - // ), - // ), - // ); - // - // final Widget header = _TimePickerHeader( - // selectedTime: _selectedTime.value, - // mode: _mode.value, - // orientation: orientation, - // onModeChanged: _handleModeChanged, - // onChanged: _handleTimeChanged, - // onHourDoubleTapped: _handleHourDoubleTapped, - // onMinuteDoubleTapped: _handleMinuteDoubleTapped, - // use24HourDials: use24HourDials, - // helpText: widget.title, - // entryMode: _entryMode, - // handleEntryModeToggle: _handleEntryModeToggle, - // ); - // - // switch (orientation) { - // case Orientation.portrait: - // picker = Column( - // mainAxisSize: MainAxisSize.min, - // crossAxisAlignment: CrossAxisAlignment.stretch, - // children: [ - // // header, - // Expanded( - // child: Column( - // mainAxisSize: MainAxisSize.min, - // children: [ - // // Dial grows and shrinks with the available space. - // Expanded(child: dial), - // actions, - // ], - // ), - // ), - // ], - // ); - // break; - // case Orientation.landscape: - // picker = Column( - // children: [ - // Expanded( - // child: Row( - // children: [ - // // header, - // Expanded(child: dial), - // ], - // ), - // ), - // actions, - // ], - // ); - // break; - // } - // break; - // case TimePickerEntryMode.input: - // case TimePickerEntryMode.inputOnly: - // picker = Form( - // key: _formKey, - // autovalidateMode: _autovalidateMode.value, - // child: SingleChildScrollView( - // restorationId: 'time_picker_scroll_view', - // child: Column( - // mainAxisSize: MainAxisSize.min, - // children: [ - // - // _TimePickerInput( - // initialSelectedTime: _selectedTime.value, - // helpText: widget.title, - // errorInvalidText: widget.errorInvalidText, - // hourLabelText: widget.hourLabelText, - // minuteLabelText: widget.minuteLabelText, - // autofocusHour: _autofocusHour.value, - // autofocusMinute: _autofocusMinute.value, - // onChanged: _handleTimeChanged, - // restorationId: 'time_picker_input', - // entryMode: _entryMode, - // handleEntryModeToggle: _handleEntryModeToggle, - // ), - // actions, - // ], - // ), - // ), - // ); - // break; - // } -// ThemeData theme = Theme.of(context); - TextTheme textTheme = theme.textTheme; + TextTheme textTheme = theme.textTheme; ColorScheme colorScheme = theme.colorScheme; + bool use24hMode = MediaQuery.of(context).alwaysUse24HourFormat || + appSettings.getSetting("Time Format").value == + TimeFormat.h24; + switch (type) { case TimePickerType.spinner: picker = SizedBox( @@ -2567,9 +2470,7 @@ class _TimePickerDialogState extends State padding: const EdgeInsets.symmetric(horizontal: 24.0), child: TimePickerSpinner( time: _selectedTime.value.toDateTime(), - is24HourMode: MediaQuery.of(context).alwaysUse24HourFormat || - appSettings.getSetting("Time Format").value == - TimeFormat.h24, + is24HourMode: use24hMode, normalTextStyle: orientation == Orientation.portrait ? textTheme.displayMedium?.copyWith( color: colorScheme.onSurface.withOpacity(0.5)) @@ -2605,7 +2506,7 @@ class _TimePickerDialogState extends State onChanged: _handleTimeChanged, onHourDoubleTapped: () => _handleHourDoubleTapped(type), onMinuteDoubleTapped: () => _handleMinuteDoubleTapped(type), - use24HourDials: use24HourDials, + use24HourDials: use24hMode, helpText: widget.title, // entryMode: _entryMode, handlePickerModeChange: _handlePickerTypeChange, @@ -2631,7 +2532,7 @@ class _TimePickerDialogState extends State aspectRatio: 1.0, child: _Dial( mode: _mode.value, - use24HourDials: use24HourDials, + use24HourDials: use24hMode, selectedTime: _selectedTime.value, onChanged: _handleTimeChanged, onHourSelected: _handleHourSelected, @@ -2658,6 +2559,7 @@ class _TimePickerDialogState extends State autofocusMinute: _autofocusMinute.value, onChanged: _handleTimeChanged, restorationId: 'time_picker_input', + use24hFormat: use24hMode, // entryMode: _entryMode, // handleEntryModeToggle: _handleEntryModeToggle, onModeChanged: _handlePickerTypeChange, From 8b5f620591c1f2e9eaf4d1fb6cffd1915a94f670 Mon Sep 17 00:00:00 2001 From: AhsanSarwar45 Date: Sun, 12 May 2024 01:03:02 +0500 Subject: [PATCH 112/112] Fix time display test --- test/clock/widgets/time_display_test.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/clock/widgets/time_display_test.dart b/test/clock/widgets/time_display_test.dart index 76c91c4a..f246f745 100644 --- a/test/clock/widgets/time_display_test.dart +++ b/test/clock/widgets/time_display_test.dart @@ -11,6 +11,9 @@ void main() { String format = "hh:mm"; await tester.pumpWidget(MaterialApp( theme: defaultTheme, + locale: const Locale('en'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: TimeDisplay(format: format, fontSize: 32, dateTime: dateTime), ));