From 50cc84461e8e46d228a9c6906d0dc75b0eb97867 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 6 Apr 2025 15:39:00 +0330 Subject: [PATCH] feat : button , outlined button fab button , fab outlined button , input , pagination widget's --- assets/icons/add.svg | 8 + assets/icons/arrow_left.svg | 7 + assets/icons/arrow_right.svg | 7 + assets/icons/download.svg | 10 + assets/icons/edit.svg | 9 + assets/icons/filter.svg | 8 + assets/icons/scan.svg | 14 + assets/icons/trash.svg | 11 + assets/vec/add.svg.vec | Bin 0 -> 367 bytes assets/vec/arrow_left.svg.vec | Bin 0 -> 84 bytes assets/vec/arrow_right.svg.vec | Bin 0 -> 84 bytes assets/vec/download.svg.vec | Bin 0 -> 1181 bytes assets/vec/edit.svg.vec | Bin 0 -> 1054 bytes assets/vec/filter.svg.vec | Bin 0 -> 1063 bytes assets/vec/scan.svg.vec | Bin 0 -> 2129 bytes assets/vec/trash.svg.vec | Bin 0 -> 1324 bytes fonts/iranyekanregularfanum.ttf | Bin 0 -> 60268 bytes lib/main.dart | 267 +++++- lib/presentation/common/app_fonts.dart | 155 ++++ lib/presentation/common/assets.dart | 24 + lib/presentation/utils/color_utils.dart | 24 + lib/presentation/widget/buttons/elevated.dart | 58 ++ lib/presentation/widget/buttons/fab.dart | 232 ++++++ .../widget/buttons/fab_outlined.dart | 605 ++++++++++++++ .../widget/buttons/outline_elevated.dart | 101 +++ .../widget/buttons/text_button.dart | 77 ++ lib/presentation/widget/inputs/r_input.dart | 216 +++++ .../pagination/pagination_from_until.dart | 255 ++++++ .../widget/pagination/show_more.dart | 78 ++ lib/presentation/widget/tabs/new_tab.dart | 784 ++++++++++++++++++ lib/presentation/widget/tabs/tab.dart | 115 +++ lib/presentation/widget/vec_widget.dart | 47 ++ pubspec.yaml | 32 +- vecGeneratoe.sh | 33 + 34 files changed, 3150 insertions(+), 27 deletions(-) create mode 100644 assets/icons/add.svg create mode 100644 assets/icons/arrow_left.svg create mode 100644 assets/icons/arrow_right.svg create mode 100644 assets/icons/download.svg create mode 100644 assets/icons/edit.svg create mode 100644 assets/icons/filter.svg create mode 100644 assets/icons/scan.svg create mode 100644 assets/icons/trash.svg create mode 100644 assets/vec/add.svg.vec create mode 100644 assets/vec/arrow_left.svg.vec create mode 100644 assets/vec/arrow_right.svg.vec create mode 100644 assets/vec/download.svg.vec create mode 100644 assets/vec/edit.svg.vec create mode 100644 assets/vec/filter.svg.vec create mode 100644 assets/vec/scan.svg.vec create mode 100644 assets/vec/trash.svg.vec create mode 100644 fonts/iranyekanregularfanum.ttf create mode 100644 lib/presentation/common/app_fonts.dart create mode 100644 lib/presentation/common/assets.dart create mode 100644 lib/presentation/utils/color_utils.dart create mode 100644 lib/presentation/widget/buttons/elevated.dart create mode 100644 lib/presentation/widget/buttons/fab.dart create mode 100644 lib/presentation/widget/buttons/fab_outlined.dart create mode 100644 lib/presentation/widget/buttons/outline_elevated.dart create mode 100644 lib/presentation/widget/buttons/text_button.dart create mode 100644 lib/presentation/widget/inputs/r_input.dart create mode 100644 lib/presentation/widget/pagination/pagination_from_until.dart create mode 100644 lib/presentation/widget/pagination/show_more.dart create mode 100644 lib/presentation/widget/tabs/new_tab.dart create mode 100644 lib/presentation/widget/tabs/tab.dart create mode 100644 lib/presentation/widget/vec_widget.dart create mode 100644 vecGeneratoe.sh diff --git a/assets/icons/add.svg b/assets/icons/add.svg new file mode 100644 index 0000000..2d74577 --- /dev/null +++ b/assets/icons/add.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/icons/arrow_left.svg b/assets/icons/arrow_left.svg new file mode 100644 index 0000000..2db56f6 --- /dev/null +++ b/assets/icons/arrow_left.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/arrow_right.svg b/assets/icons/arrow_right.svg new file mode 100644 index 0000000..dfc8100 --- /dev/null +++ b/assets/icons/arrow_right.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/download.svg b/assets/icons/download.svg new file mode 100644 index 0000000..0e8dd4d --- /dev/null +++ b/assets/icons/download.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/edit.svg b/assets/icons/edit.svg new file mode 100644 index 0000000..632a118 --- /dev/null +++ b/assets/icons/edit.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/icons/filter.svg b/assets/icons/filter.svg new file mode 100644 index 0000000..52500e7 --- /dev/null +++ b/assets/icons/filter.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/icons/scan.svg b/assets/icons/scan.svg new file mode 100644 index 0000000..071b59b --- /dev/null +++ b/assets/icons/scan.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/icons/trash.svg b/assets/icons/trash.svg new file mode 100644 index 0000000..6c9b5a1 --- /dev/null +++ b/assets/icons/trash.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/vec/add.svg.vec b/assets/vec/add.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..0e0727a28446e5c03034c4f15b492d77f466d17e GIT binary patch literal 367 zcmZutIS#@w5S+CeiU^4!RZx@?3M9T@om!$O=B@er~bnSr6ffq{Vmi2whW1~PyG3=E8nY#<5*IDo1bI503& T0BHvx2JvS&8pwg<{{II60;3RD literal 0 HcmV?d00001 diff --git a/assets/vec/download.svg.vec b/assets/vec/download.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..cf531fa94ea4db87634334b26797fbef959d3616 GIT binary patch literal 1181 zcma)6T}YE*6n?)g(v5yZMTeWyK*)i@NC~ONx937IytPB35N?U1Z7z(qS!iECk|xpL zot4xbWOLEpLBjqHcql$Ew3Va}$T)>JDzv{0@Sg4LJbgpcmm>ZbYH%rtl84`D8W=Z?M&MRM8@^am`Cq8<) z?h{pSCC*r0Ntx6++hoDbuZ$AO0j!`OH?2Lp}>N+xr0pe%w5^;>8zVMIp?;P0NIxwz2W z{D@+UNFF3{d=2vR$7!bhQh0CV!tw-HLpX&I26#i!eYV>#u?!~6m#Nj4vijJu- zo;T2Q1}XkX68X$QH6CoF^O;|}H*7|JgDUsb@Z&zSEdskRi!?!tN5WsefQn)+W$t&6 zddRm3lfGjTId|VQ-<299^e0}%ztv=o)}yzoSDjyJ#3A1h<=Tqj!pCa6X9}62YWmw0R`g55KO&15m;giQ7* zQhp24{(0K_2gT0AW}f7!=@Cfja;~^S2(R6#+;Km^a&~*AHCTrVZ#7T3qvTTom)yfG zN)`ORHnJNK+im4u?=1veZXTCH*bUTiYcN81o6q=$p!3++^-#WN+?;Bmm?rL#AHn4; z=hxHS8hX6}4TG65Z1Ed>#~sBt^(o&>PC#&VIL09RzEgdJ#L)z=uNS2QIr!BU#?_xW z@U-{gq&*j%9sMwSa#8Sp0BJQBebzyEGx?a@j1uPpl(j_Rk&AG5BLaux0{Qi6_}RXX zTlLSOw4cYVHk#<`sj&dm{FdFMe${i;yqjXM- zq(>Cf(kz{a42x%yxDFr~ixGziX+6xHX5l|Ve!WQBX1LHs_RSLKCd88qgbk1!D>PpZ zUws+=UirdHloE7SZ}8I}9f(Z5<81H}?oo_$>>?IvFDa)KYql5MKU;z7Oqi!GSK*Ty z;*B*m2<%3=xwRG*mI;1psTRwxr}&@4b+}nF%dg$9gKKq8t3jMkp25J5(*0xNZc;PZ zgu$4ukFJ-lpRT8_udcVQzkVLd)uUD^M=cDt}`C2N=k#rw| zxwRP`&LZe_slF=lIF`J{8xJsRKfpVfyL&mb`9<9)P7THT0HpUkY*5?oW r1&a82D6TgeGN#a*TA;B)UBoH0wsNp8^6cj;){?8LWS|lVj2ip{NTPFo literal 0 HcmV?d00001 diff --git a/assets/vec/filter.svg.vec b/assets/vec/filter.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..6c190a39e80c61de99b27f3d6782a329436382ed GIT binary patch literal 1063 zcmbW%OH30%7zgkvB&O7Z25Nj@T1jeg!6%E)*zEidw)KP{CZ-f425OAaz{Lj`F92QgL8uL|rX>`IgdIg6&y(o(IQosFBykV5bD-pG{Nf`@B zRrR1W;wnSB`3UYLiYY!p`2|Qbb)e3ij*{3#jCUFli1)&+PI6&?a75}>Yo+6s<-9S` zj;zOhS|Hve?PqJH_Pgs)phmR4r&N?b9?%-B>+$vNP0e;=3*M)VYJ)Xf5lk3)Q*smZ z5-Z=iXFbmPHt>wGCTX58G#j^~#o?j$RvJgG^p0ypI#+qaD}pUJYfe%ez*IHEHrFAV zuY)Y3`ncdp?56s7q+;G87IhH1$3i$(T}*jxXx0nh^|vECwi)I~7}sgsp|@Me~|KX==vpI6t%;7qKhl46}9!3xj(oV z@2aA_TbqZ5#t<(u>HJ(pBQG8M%x4~*;?~jE(gp0Pw8mF2U8Z;`?>ravo_W+Kov$pG z_3r7i!5Mt1v1@jGD88*Z7v>kePsoX$NRKTb!+f_sP&)k>%Z1Nj#tXy_b6(q$#iGoqN9bd(QculhT(@PON%t_Pychto+k9TdnHK z?5_Ez)vEl5U+t&(HtU&fIeOMRI=kOIeE-w^j{DZfzS(~etXa2D94kEbmp|S9*^dw5 zQA}qElkb#V;wG2kxdw60di!@?IXCCC-e@$6?{EuSSJi*|nR|`&GjHHNy#DO(^z$Xy ztAlURUxc{X!hP^q_!kZNu6I7UPp;Ew$H88XUq^o!wHmrlKf|Dv;$8Q_W4VuZ7txM-!|&=*yHql9Cg5-H^h}6 zJo({9uZ!@MXW}gHlw9H_mpG|KHPlr*^^+DZ_9Kmx=9)kEIaD9ayJ!AkKK!&TzEtgJoZIid*`DLK{Mqxm z9|imGyJ89Z{Lfe43vlOtmlzhF^FA^8<-1}D%U$8foANIs$I^HBCOl^OOm~<4%kj3~ z;k@HJbrY;O(4Sg5KGW^+==-CygvobGE-=bfSL?UvHFhj@p9Fh#@G<(+sNK|k_^|Xg z4ZRA7PTa%7bMF1Ti2fjIGKlxE@C*X4aO6$-*#-EAL5HKWk^A&O97~>M|L~gK!k8?@Q;?@iK9TBhFURk*By zYA!V@wWHRoExg*VJcCjjdeRL%yZ^ROTIgQyppfWd+p1dMR`EMcTE=Ovf8g_#Ck;mA|wAIABkNBPcu&cF`+Z}e%z w(Kj(Hu}O%@FW(hQSmvSq%bbc0o9>SJXSLd?WLh%*zX6A9GV3xMGMmBt1y-uh8~^|S literal 0 HcmV?d00001 diff --git a/assets/vec/trash.svg.vec b/assets/vec/trash.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..7d8c954215a2274c2b22cffe6564c2359ec3c392 GIT binary patch literal 1324 zcmZWpT})eL82(Nfj4~D+#ULv(NydUM>J($p6@A`Br5AGpx~}y{C2sUTDC>;_w~1l zY6tM}(GxVhKMvo{AYERV!h|b8^{Ht*-`PfA-Av(^=MM9<=dro&5LH#hu%WG$e*LQ- zi*N0wt%*JqMINE`+xk$wSVYZhXHc@_BJb)j_FgUII+KXbZls#L85Ef7HC8uR*ff)) z?cQ{@?$?lOVwL9(7v6$WaX9zfMpe}S_P=u*T}A}xT)~my0hIP$MEf6S5&bNR@XaAy z{rO4Aey>OGgY4^R-H7?hDfItS0O8}t2ZeCuU4gUu0rvldJtfa_{4!qpA;$UN;+6gi zS~4#Iytl{q4Q!s>hM_hI@s<*-h{(cvJR^rn*>l@_*n8P~+I!nP*t|T{Sxk*RN6?!t zp-A`%9QSOd<=751J-S`vwR>OGIN|bX40Zcx%ey=A@7zJ=zwM3=wl20#wr;sKL0Xuf z!qLD9TC0nrlyw#!KdcNg9>9h4n|xl0(=7qkb?E6oZ@i%KkaN4n=xnye;~od4$|_L1 z&qQNS^Bp~GeQdpK9^8gQ-6h26Z?DCb(Df7_`A74)<}}T}+@`TLa$4io&-<8*F=~yR zp<_i6`eb2{ym>Av*l?C^)#cNLV-adh$Q>6aj@e}ej7U4opa%YTH#%?*AB$uqB9gw*k@d;zKJ96t}~ z)AD!>(l=S$2bsgO(uK7^KF6Pg%sDssDP-<+`6zQV#`Xl)pU(7~CbyBLa(RFGUGqDu zj32-5*~hbmsMuSfaV%A)(cvxO9o{2Br8+g%r-EepJ2LSdWaW2I`IaV*6WhnXpP)v` z6I<$7{!k`9L~gb2f3qlckZXwk_h=kp4lFyLb=l3&qMKLah@Y5S@q74|ctOecaO`Ut myPac*pWFGCymnp3@=G79-wq*y|M$ua3mg{kf1w<%)9@eD7Q{sW literal 0 HcmV?d00001 diff --git a/fonts/iranyekanregularfanum.ttf b/fonts/iranyekanregularfanum.ttf new file mode 100644 index 0000000000000000000000000000000000000000..72d58080514c4f4e2faf5e9ac2b163ad6f7bcd7c GIT binary patch literal 60268 zcmeFa2Y6FQ)-XJCnwj|58tZqrRTxCg?tK56Halshl0;U-Zgcd^YgkD1eVF@X3 z0;EEKB{+d>vgw^PlHK%d3Y*9@Z&c^{xy2<5x`X7tRuJ84@pLZY7#;xZ@q+%OBtkq)8f zN8o@glB_UjutW$#UP{w8u>pV`7E!mFGmFkdAx#GM-~%G=q~_VNbXT*1f+}>G0aP- zpNDh+^b|DnA{tNCqGzco=vnqY)XmQKUSuzMFLGwo&19lFIt$AD2BDyb&|>a8fWr|y z6|D;T5^W&g1vc;3LEobd><_4o-2~4*3T3j5T2#Yq^nS^_<^4)1 zLN^IJ(M_xqHBkB9i_{9Ze-mn8E6_q_vG>o+4!HgR9cLoYAp4H@B6AUrKcOmU?jj}( zt>M<8W!yJtJR6C&vbks*zSVnC=tOP8qi7Wq;{A%rgX?;+IZyWFh zTH!mG9CSA|3oT)mpgHU@RLHiXa<&_FGP8j0R@4IDTj;ldrYqpoliqKcL*8$>8_)!D zuzEB>@Ddsju0sQY^JqS^AKLdm)V&@Ja0O@*cQcyA>_JUXS3gyP2B>sYOWp7Ngu+PA z^rI%A3C2d?@VpPSjqzQ3o`y5Xq6fy4=O_3c0|$Y@;W^5@kILZu5_OyRB5i?VDzrJ; z`z1@EX9VP?m2m->+TJx3x$`b)j%LXG1?X(W{|PO=`AOn@%|IVEQv7Ulht$SpVMlO2H194+gUX9V)B z4ahZ|$u)vAW^=tBehiQ?0sYL^9fA7b`!eoT7`K6Oa*bSr3@;4GGcU^^+aMbtcL7=B zzk}@YXTRKeVK(FMSHO8X9LM1x_niK-Uv5bmUT%qu^03kV^3NI9O~e(ChLF__!`D62U`t1e*?|us$qU;Lj!mj z8l;|v`Ri%4kUoag%m-);eh6u(2`HW_M*HZENcykNF_awUu-8x$(}il8lju&EleRGu z)F?QKmazMfn(aU**u5~e??fk|gyag@dO0sJ63Ay|P<5IFlK zTE-6W=XpT;aW)#YvO45occMM)LZlWPL`CpS9-Dx|SR?AB%F*rgT9gRqAbKwO*U=tkIqGBHMg7bcG?5xX1pu4OoI!i2NOTJo>OIYjgL5RhSFj%K272~@ ztoHKHeGGHo7jQij&aa>#W(e(IEXcskLn%xVv^g9_!Fd9dDW#&&892+>chF||zMDCQ zW-}ht3+H+#@a%WL5{Wdzl2+_ODlW0BRJ9iH5{S~dCGtegH7Bq!6 zqjETksYlRi=8x!Z#)c{=7dk-c&=P>J0^PWZ5#V6x({bDp)XF`G763h!JkJT=uQ`N5 z@3*8M_&y;0;6JEV?;oKbhT!}sINktRiy!R+(hpZ0%x=)HM+ZrN zfcz7yf*i46jldschb!_e7OV$ye>wc)$Q`5ti()A{h`d}VC+C!$hRfz!xpCZ7ZZ>x# zx0GAUt><=dyScsGUEE>rLGDrRH1|07JMQ<~i`>iH8{C`R-?*Q(5^aLE+xX&e2qZFL=Q}8-a@K^48tw2kZSOTluU0_^<+EHn!oU|n76xKw;8k5F~#{Ldf3XY8fmpTE5Xn*7r0OY%!w5c>I^ zOM^fE=I0#%nQo#e4Hu8?pGv9|N-&^9}h%yXkD&N^PUIQd_9a z)Fx^pbu+aAYNUL~2SgkFJ`0G4IwW3XJ;pj**qv>n}!1n3SFjP6Du=sqMy z526Tk3`L@oC*!nb7xW!!L?5DRRD){4M{uKITn_(=a4{~yrML|3 zMtjj7bPIYKJ&S&ioyh~2jLJLip5yMb73X$VJUFpP2k0H;Kpa@6W}Kc z<7Ew6kJh4fz?<8EJKMkm*a|$_g?6Bwz^Q}i0QwE^D+md}pST0vg$|)Rfp@cjd-nkU zLV<&afrsJXlZ62%A3+bHhk>7RBtIrllJqo;yMhY0iC(&ti3jG%NtU^i{w~wL6 z(HS%Z9DfQuiGBxse-S;0o(JyhkQ!;A4~)ow;-DuIkQv28f4qubLN7zFB%?%>1bveV zy<>&`c@MpV-Ua#i8Z`2s&==@Sl#Xm*MKZiRxcxHuOMwApd_CYVU^K4AHMkbn;d!MEVO_*Q%y-iP<&+wlSX8+;Jofe+z3@m=_Cd=LIFd@qce z7x7E@75o~07yl7|ioe8P;IHsS{5AeF{tNyV{}q3S|Av3S-{T+g-|^3Q7+=C8*n`~^ zMPZ62T*RmFVSEHX2;UyZf5Ip5!|?44SQiMtj6a0W-x8kT`|;3a-r+~^lK}e$ri5qk zefW6b4nBr|2j6M@EPet1Api}WG0dP8Kl|XL0odg;ejdM$pTlq9SMi(pE&MhBmPEGAXzWD5Ed7e;CCQ6ENKj5bBjjNTOe`{*xX)GLh zHpLu@c}OW!9#9@tUW|>3wa3nheJJ+v*cVkuRiv7$I-vT!>aXf3^-T3*_08(N>Ic-P z)o-akR)3?uq~SC&jb4+Y$<~x)JnRztaAwqjX|jjLxJ>*SU06 zx>jAUZl-RLZmn*I?tt#F?u711-OIWQy3cjr=`QIhy;vWkH|f*$E`620Ro|Nu-rYWYmrsbwhroE=SOb?mPn4UGAH+^Wj zX!^;_n8VDm=6JK+d>}qPeo_3z_@5G(gs_Czg!lw|LP0`}CCp;6*exzglcnD>$FkIN zv*k9+Vao~2la>pX&l81-mc-?WUnQj^xspDIf8QrZBwLb;M*p=Z&q+R-d@-dYWlzdI zDIce*Q;SkNQfHKUVXLyOv~%`2 zdxw3C{gnN6`xg$aBhyjh=yfc0Y;io~_~}78?sDGi zJmGxS`M&cj=TDjT%-+l$nP)S<&x*`y$eNS2CF@kyTUj4xM`YWxCuZ-+KAU|ZN0yVB z)0#6a=jNQlIWOjXoEwrGlUtHIEq8tHncVO4GV;3f=H^{+Ay=nsm+N!akNHggl>GVm z`}5D_e_9Yz5MNML&|9#uU{}FC1+Nyy6}A@cDEy*GTU1gsrD#{ttHt8tn&P>|j~9Pf zLX}ubCYCHL*;H~*$?K(DX>RG#(z9j4vhK3eW$%}p%A3lUmOoVfeTA&TRk5hz@k*+) zrt;n@rmDN@Of{;`tzKAtx<*{1ugR!ss99R`R4r4RTRXS*kvde@P`9-1Y~APeA@!N{ z^Xm`RzuW*GAT)`xUQc;BR9~>k&v3eETY98Ij0Gv!pobGDmnqZ$b5Tx3ANNIiO}Ip&Qxw*< zCTGvh3X%rpk2fV(TScrOB+XT3h-+ydqZcHdEH!jGadNVvGtZo#q)>{JDw9Hk4cT$w z;c}=(Ckcy+4LJv703FXFjMspDP9tPAgxm0%p&`tI(dN5{sKszkf{-qSb%fi(Wok-6 zEuOkzLY6jYC^&UO7gpM8Coiv~pB!sn}^uq0M?RB``Sw^3J)^aATZaaM_W-sab8ZIAxLAGy1G(1#D;5? zi?AgrzI1ze@$~FH<}!zl=G6IFX*eE>qUZH#Mde{0r|qkepXxhgB}>Ka!O z9+5gZG1Qq(>cj#yorC2Dy~%7ci|Jn@z{#~&23s@If?j{Ua+xh#UHj0`Gku;v;pkry z6JQG=CO6TTAZLdXE!I*~WtQO|kOlJ4?G|yl^dKs~iZ19i_TTA7x_Vqld`fzx+g&xc zHCy7j^pCsrNYB%EFBoNHfc9BnnyB^03`6*kv7|SzC%)t#bnRYqsY81;qxV1)P@VT% z`dcOvY&*n)@TFp>LX8!XwsaV4*qPz5o6Oj$W_h4o#tArq7*iVCl)iDs=B{Q#f0orM zDzau*2Qf0OXV1aVSW|jMcR_S~kcg7ze`2VUh@_gx)Vot<(JYGvBAq-aBs?#TGE9*r zX4MXC>ozr8OeQ8ZVY7|}HxkB&`%UU?>Mk;-!X0E>^TSF^8E&3@OJC|x^{zi`cfUDg z?LRPsn&sZM^`rf;aNvKAJ_gT4!&o%v%`!2Sh%Y~{rgAWSEU~+>ZqIvLZuX%{b!7!7 znl`X?0zSxl1>DxAL&5kK;ZOdc^JV<X(f3eBt@>>wP12849VWs_1ZLp^#Q4 z*zcY8^$pt_RYS(S+JxwWO!FCPe1EvpW)uX8LqnM3RB%|hSd`bdB-^P?R0d~`@m%s; zTD!PqO5@m=9hlqLJol{$T6Ny~g2u6F?Kjm>XMfjygG&~XSdoE~JPwxWS)8B7&Er#XR)#Z!?`JYE2sr9alX0hyF}!kzGq^p%`@u6tKHmRJ{;KQ=jiWpU`keVlO8sk*v?`XtFv*Te{i zHSWy#$*SxWH8n)_PRw&U!%|ZR91e<}B;-1VqEd?!vDI_Fryb)EQ+W>meQboK*oree z&v%aDO>vA?yWa_30(3U{=;X;XnSIp$`?BQk0-pZhl)hWiqtaKF^zPzMSISd_&?iq+ z%ys2ya&&&C=?pbta(%W_VM*gZ{;426@#Lr=C3&77*UF0&`PMQ7I(>utLeMmN9LfdH z7~v}i2=oR~Yoo&h`auCxii-tZMv)<5AcIRDrX$0LpJ_m&GXm<>{ce6_R2ChX6-Jk) zABJ(UwNZ5@MIE9Ln_9+Cp1Y#5a`RwG<=m}h?%$<##=Fn6Dv{b4FRh#2lQMQpLrs~^ zePP{_mMIPGG21bHbK@6JXw-XWG>)~lFR7s(^E{H_l1Sra`D>TX9%IdzeRTfdt=$%x z)aCw``h*gQL+wkJZMKw8m_FNqC|(a8r8~g;%|ys>c}BTjTgcE67)f8*P0$ufAiKY8 zOp^FaDo`F`Zt0plcO_6hv$%5Zwleoq70az5!S>w~nH#MQS(=#>%2wSt(>fHJXphEC zo)eisqght4X4$M}t7Gu!g2CImEs61>U|Tvhq|9h=EZ^9%=`bIpro3Onm?-CI%>8v5 zIe`t#3toW&k)$KAk4#2_<=3ZEsd#yK_b8dG73Dfp!psS&?JW(}CX{teo9*BO0~EU1eIZ!L%S_e3Co_RI5TO|*KOiv?LSAC1l3$e= zrQ+4$oj!pvcTfLs3QN&c%aC7K*lGQvl0xiT&=>4dum__dMuKb(8!#Cr9b&Tb0?!y6 zMA9!4&dJ+8j82O=lQ@3zY**!$!4iE=eMe7`pr!-Bz1cGz8D8GvsfNC8_y z46`46=O=R=OnGp{*mTT&p45eZIx*PYk+r_UoE9T08r<3F>>byZ(q*WsDAStj^30r6 zuPS_Yfk{nL{F?inq7AQayYYNYTA|q7TvHs?v~9o@o0JiAr!3hR zrOK#DlfYKeFd+Cs=t|C9GY5O#n+?-`NBu|c0#5!uzGMe)eqJw#z z$jc`46WtEBCRoqBtHUw8!pBy~0Cg~Usf)2xb?#`2W0E%lW}Dv30R#zWMg zw79NLmDrsxmI{O+A(9wYD4?lekhL1OfbF5TqGE_h`+6K`9PRW}Od90Ez7`SNnfGI$ zReaOMw6EWxi5i&9u4*C29Pp$iPM$evADq?E>DpPBKDIQ0iY6_LU(kXpn^$QS5_{UR za-&@@rSW{vdYQd)VoAf^`ISi(6DCfy;8)!#lGN-XgSL8wMZt&?Vmv2RW@xj(Ef7Y= z>q_3(4tO7)KY7la8RN^P zZ{i(CJ%`le2A3?o(UxS=DcQL6i0C{Ac%x7^tWGdrait_q0QNcfVWcMVKj0+tE)2vE zOoSd0a61PxUrEMpoYS2`F;wiN(wuE|o(tHNJ*hEE92%QHcCk4{Wu*7ijl6_6=XLkZ zYn15o$2wUd>uguWL=S~)l9Wola#G8Z2b={7oAAB&dp5Y=ZCX%g0(vNP6X@d2>@J9r zcLI547Y(rspa%?7Jt4wj2hV|)6N?l)1PrkY!W{vJ;ihl!@%M=*K^O_Tf*7zw=xGDJ zH?nwQsgdC{dYvd%C5pBshX#L;<)}!E;KX8`E-1zk9i>-iQq^!S8<%CytK+aJv5mR=hp+2D|7?sJSdVC8c&l-VGl2{{}P6Ib~W# zJp7%ZJUebE(>0&SC~9!O%{&IY(8C2-U_Lp>xSk6c9>!ATYu_tTrZd=DdpOm>Q8Jxn zLvzKP?TzZw?(^=q=S@r8)F%mRyLhm%`=L5zOxjFGL3!HP#kK7Hmzv#w15L!oPVlQB zgK~t-K1cqt6eVJr{u&|B4_&VdeR!zdye=hpe%T8KS=cBO!@_(_3>&%*3wR#9!)^s! z5NG&jJn+YQh-+|NW|ZHstx0_vE7J2+!!;G`aLf6CT$xvmk~FPB5$J(CEa%6tl~g0QH4T1J_+I?%1CF zyXuPE{p~%Qy0bJvLE2oKK3}f4q$pTna__j{v}~767dz%wGLLxw?0uE~J6#O6B+v;y z1>>iJC`LM9Pm=l0@A7igIYG2arI0XUWlB+MQl2F?Dk{w0UQ?XZyS+PAmr-0=ps;py zO?EY{xZwtqHBN2LXkM_H6001|xxr~UF1t>XQQ0y+B_>5DrA|~Yy$i^kkgX1q88h@f zLzx|O7tQSeQV4Aqy{|I&0BvTHPpAWlCJ~Y=Nb%Xb{BXU7a%NSbfnlm@PJ?=qiE;okg|g;Gth>385DqcMq_CgFa6NO?@T3(8b|b zO8~LcIRVVRFw=ml;Dz4b`|Rs2E9}bLT&FD1-B(J(_^mzZ7$@iEh3Q6KZkb)8qJk3> zwJhn26mwxla(bFRK_T#W`N+hpL}Kw>?co}+v&0xWgzXlqQg~S!q8s)A{g9hVA7Nau zf(w3y&#(l`0wPO{B2q=P3s^+FIpGUG*;6PgwBwdRm!qjS*|o_&IBk5HT#EB^Gk5oz zYI05H{6>qdIY(VSSXQVl(za_SGO)E$)Oq46r zOD*X=U7*f^xnW{rTYaG{smT%@6YjEQPbe|QnM5LC7^hMVF@pSCdTLg5IrLf8jm>eB z@6Hd86hj+!UdD+qLft$5fPCEy3BEfhN0ptgHbm%=bq&Hfu$SES!Re~mp@+J*q<#2 zc>}MU8HPNq1b)1bUi4X1SLm(`B7R`LKwuaehrvMc1$&_PAsh-8An8?;nHi2g_?H6h z*i7x1)YQJziZ-#pR=44j^i))wm=2AQ$sz=@y3Ps4X!n}Fy?t^p`%^TL_Lv}fl60w@ z;ph!FB^5@8hDFAhmb92n1qT{8RSlRY?sJ7?R*q>XQ&f+$N~kHShMr8LSthq+g@*ESV@K$+Of#}4!w#VkF*FfX{0`LicD0zrvdgC@id|_2qMQAu->4plc2IiE%)e0YOmnSLh0t z+vJApk@n(sN!zo>Ph8%=MBLEOuMh_Uj?psrJ6ssuPkNsZZNnI*iRlW)Y=$jeAux$) zzPnjoT|%IpO#WnOM-Z8SDU>Ku8-4f0o!u$jo#xh-Mtu_9wCAb0im0x>)RIjrX4Zy> zFnC!*gKPcUxBj7K%hGA_scH2!$#sdV@i~J|N;{=nDW%Um`{V=nXG?M)%e!oxJ@Yu8 zNxS94-w>U)4Ps3#fQN>x9)#gR)@K^~-5%cHgRlY)0TlFR+qjLEDKEMoq3SBeB!-@e zG$h7rg??-g583TghE$0TNWUC@+Gsb(f_(7|68psWL#9wLu|QN<1{}=8b{jqv9PAkr z6f`6}5)^a*QY#{4!$ky0Nlj*p3USDWgXXgDTKyVkec@dl@Y#-=-^d8pM%N!KyJ?w^2rI+K@IaD~1V< zj0j6B?GNU%5b$wU5Gqa|B?p!ZA+WzT| z1q)`h=49th-}+-%T0xUtotvgsCcE?@iM0h*sw1~=MQP9eTy7{WDr$(!yM03C%3flC zLY}+VEw}*d=Mq!_-Rfsc4o;!z>xdU{m2v7pJNxE+Vw(c(Vu~B1FSKbRY#kMQS&6yk z{SnJ`J?8V(GwQ6W5K3E@P`!I$wX=79lrdKGe)izVEC9+`oSI?8teH|rW^ z58rvc=1@;e@o~H<&=)l|d|zz7P8WE7{FNqAIM5we_7TZ#pwKM$TkPwg+j5C*1WR+E z8Aj(^5(fz^nfk0BN1$8$!tPVYQ0{7VOvg;D-Lhn|DI-cMtSa#@m_nGp! z|CNUNOo8h)6#5f;+nBlNLH1>m|3W(zg8L3XaFo>_ec&kcwdXg?65Pq2^XK!JoeCC? zGY9q`a(@IL%#wqL4jq64@X)@pus?<5{(wG_3d~Na|A~!THf?(>@Dx|LapP9^{g)pl z&yIYLJH6$j&%$%$c?pJ)-nLC!UOTk^zz1-Qe7|+$MjUtO5IlV7Ajsm~Xox;Qp8#LQ z4CCvH34mxL+COjjeLMfn8aK z%2V4*#T%8db%2B83*!=8c<_J?x{Un#znVAq8A?4Tyg=M{i z*6vN?lI`(>uMFK&7L%rUwCyKIvYr0h>{U3Ybz*B)kg>8r*Hl*wCJLdY5MkB{ZGz>- zQCgrvF<60qqEz6{5GT$_{6C7Mk2rmf9f1Ia{_r*p4gr=%MyQGg8Z>3)C8|h!W|mT= zjwntH5;13RkW_DvI~EiX9v&2Iup3lyLZLZF&*0$GA)2((bZxwxhCpQ~M9J6(nc}`V z=@o0IxI%T=$%b@&BqtClCZ0KROTnZ`)xZ10H{X0VDO;bLUt&q_s)>|hCT-@paB1W0 zh()KD7RIFM!=+NWc}#771hfxUBbdK|jKeGp-ZVdFkwAa|_?(e~iD~OIV~9uR_g}AA z%Hab@&|>2BKvoEIXYPrCtob(#rU!wIdj{iBb*wmEc_K0{I@Dy#H%cRmrmZcpjcsa3 z=+YDxxRkoGtT>CoI3-gqGmK4)i%p>{)Y~Bnks?mnfA+z;y275G2_FvQuq}=I8ndhR z_t=V)RUxLH+?I6^hc~B3-6@4IZ&XU5C963mR!L)_kQ1Ju$Uf9g*eUiC`x(T>$CI9e zEHhsq8S*7~-<-F47*N*+?DN6Jkg5XRNBr{3=|4_2MO<}0Cy26e#gmt>UecQrWlD|I z7Urae?(7Il%qp|=?YBn8gwiQh6MDzTS!@(l=8DT}>g-9;G_^Jt#WO;2P;{{^F)>&k zL1C6YjX4GjXpzv|Ds!-(G0v{#`yM&>;*`Qkway5oCX8th*G7l6H5x1P(}KHB9@)Qk zz-Y7#Z?!Kd-MD_$qQNv>*W7j6Z>E_6Me;=;PQnVzkh=p?8&FHU^G-tUV4V7ulV5ysK4xO-MMXUemo0T1ZFqdFS`${# z*`m*qhl>iVrslEZQWFd{Wx3L59fQMTMXCg4xGX5R^6t)N`cG9s4a<(a@TZ$kE@5y_Kn+Ns24E6eA)G&wz zCSL3bQy~2iDg?{V2C_llVQL-Um%e@Q<>oN8I7AcP`10URA1QW|>^yv$%qtXX@V-PZW*-MX80ZOPnX$XCPgxyu7RXUSZa$SPVzP_e(L2^-HP(*Z? zm%=hlyjdUIF|jDGA9)xi4X_nPg+{w^^&|jU&5Yy zzbY+Grpu~KnEq64LqxjM8Oh326eEd=XXkSE+VKn>v+gm?k0%)-)%!bFzz`Oqf`PD9``g*Ahhi+53`!p=-Fj>#IksQ%Qc#7bMN&QRBJ z>+*?}NrKPuetGVebvNj9D@4VcHcTxT3NINu)#)6x?#4Nj*6q8ekpxmGG{Jk8{Q=_8 z;r#j{$*K95;?O>e1;SKB!;Nb5(P%UuwgiSzpH;V;Gjk&oiqm4`sa4qa>!Ik>RgLLR z{i><@%GpVYMao}9r1Pd~#i9AV^Oogdfo|Ry2&O|cIxjA&wz?^m~N`dj-y2Ry{q=MwF-a5i^W`|B`#PTmetmkGIn*RBlr`%`l#n{ zY-PvP?39U9r#nQ_pz^*#V+5r4U^L(z7VhWrQQkjl11M@dnq>eHCb$-}jNbj=_358| zWIA5Rcy^3QrnYGDl8jTerB?s=fgUB=Zsc%yYNfg=$o+;!|liU1X;p_Xvaq3EgNWVIRL&z5d9Ieb-|f-2Uf$8A_*HO0jl)5&cU-sr3E;(VyDZ5z=opLnCF z7J3Zu7ZKj#r?+`D+vzdGPeEJso(-_mF%|L+k;3og!y*(U9?8R4Gen}fx3o@6lrl9> z$9CAP*mEq~qi3TmPHkLPg1pGp9p?G=zoss_os|NvCTamA<75z@M@npTvb2phDp;u? z7{C2j&qftqW_T$EFOKmXeD9Hi4^VI8YQ?#BJjb)8{hZG8L^q!7A<{&M!vb%~4L$E0?peSctKKJE$jK4_V2> z3SRla1D^Mzs>d{IBQ;^kX(Aybl4KOb2{o~WasezvYPE`z+WMk2A&v=A#VQ0CW1&(d zG3q76^Hg(V1(CW$Rj^nXnWa`JID<@M*U(~Zg;EtN4!74q#zdl45lZ3jgc5nEh^B?n zdWkSROa%b|jZ&&4yz`9VGSNrEY0wJa8Z&7Gq16nH$jHGwwF2LM4XiB^7P|b6SVzQx^u>`NP`|RR zcU)4sKp7+JOtJ}LVj=`VBDw{KgaoOrdFsxz=pt@kck8riX-TZqsDX2`Kx$M=ES5Nt ziZ$9Yqf$$gBOOYxI6!_i+&c7$&;hnsETJF}X!m8dnbXNiFz>ffwx%47HoM8zUyz?) z&~Gg$u-aVQI<>PQ-BzEe%E_59F*|2+c1A`{PR1-~mx_HH-@*M2_PZm@XMURbMG+mo z!=uV?%`u7(q}*s*T#Y~BYJ$|6DXDkl#(>k0JwLJUqn`v9K~Ev@;`#71NREpLjvxhs z86ZmhVlT|C`B>rkNwhdaCK8zQP09>giYz+ZWYPzRt01wG;dGg1v!g}NzQ4?vn5R^R zI7)57AUYDkBu2=>eYrB6<3d7Zx(IRf095CVaj(TO-aVvl`k&YR`9H7Pz4l+L8tQ(U zTY|ELLHyic3peDe#gOXZ?pZ6~pxs9N4f zgQy$7`|C<)jN-2EbkQll=2?;c1Dv$Wx4+G|c6rrSCkO-6t~!2^_w3m#mUxFo*LGn~ z$)i`U?ZVn4_0?5023C%V!${qEnMO}9K5*GJ{B;oQEaWFa1HgFu^e-36N zvsI-v4e@nTqr$aXopj+;lZuK=l*gVBgb1V4g9V|9jgQL8%N*2Tq&Y55Dy{46ip%CA z)KS(Q6N(luTVEHgEVh=0hGuO#P}*seCr7mmb!FJi%c?h7*f2>@MfV-sZ?38un?|-a zgKgaHj%LR)R?39)(BB|pR6yT_TXKhTUxs_7BY))V^p9|lBoL8%Vd$+KWsVv8wasHi z4|+H9`OMvnY z9@CAC&ifScaom3*V-((z4`!$F-YWruEW)&y!+x+cy6Q)dLQ$_uflU9^)P`4_KgD`5FZ{-9vTp}o$gx*XaT)?pe z51GgTPA}r|@cVapILvrFo>zD{zu%R;5y}%M82BlCmCO%(zZ_*(0vuL;37i#sj|2Q` zxF~1W0bJ&XYrMY&I(NYy$Os-T=jW3=;kP`z4Rqd8_863p^p$7C-p_paVPD?^00%FZ z;HP(aKlH<&V;=-~lplVd_aneRo8Jfb5WtCz4&@oW_hW$bd(^m(0UqNo@4~=0-###Q zKfs9(2IZ-KGJlhH!5Si&m%z5?;hVf~0Umzu6MF{WpecCx8{TiAJehxBFA&9%m=avW zJVo~Bz%|%g@Eo7J!%c(dK&zAIxI(nwSB`#~TMTfBYxDRT&;$PZ8`(zy4r@d_+~)n% zhez1Y{s!Q%vd80@>V0h#|Hvr*e0Zl{QUJd|GKxQ+szCVwhsl8%$0ZT`d_Uwz>9_J=} z;NxTTK7e=l;T`Um0M5^skW0>y`7&_LeGTQ{8r}|-kAH_m0I!1f3=5P12d|RAscMu3 za6YG&A4d>*1HMnkPk3Sh&gZmp9F$M>!yos=_~_>KEJxZCXb0#yjI!|h z2;bwq1>j%0&tIhv7lHoS3H2-+Nhi6fP){0P&my|U{Vl+|M#2P;?+I|LAKu}9g_QT@ zvO;}Op0Do%>hD+8x6gZkukT$_AIvj8{ksUC^+GH(kVgv7175i1W9@VklxqyMf4JWV zXRS1uPn-PkbHh~tpGoRx*-?6@F?=yqZ{9(eeZMqW6z}{Eu-@kn;7UJh9SVByfVC`~7Hn0w?m0ft~@u z(oy`gvE6$f+U4Qt*)&>yHn#Hf5ie)VOyDob89eXP=Lex2kw+q5=R7cv`g{TIW`NK4 z!w-0%-vaUs&qH~*?j!a9`_}05F8mad1AH0OAIZ_9&%5x4s0d=OU^jE0G2`Jq$uRR? zy@3HzL*+U?LyhE1keBiJlRtj3Ttr{J{zPBAYPl#l94p-0INkW(32~`6AGo{11lv4{ zQlhWfx^Q`+Xx>$ePt5phR*6j7AsiytNF}N$$xvKO{e=FsYxXQ$u|DJ;yk^k}`r;z2 zoxvUs;8`N!8Q3!Xeg?Qs;(6%Ln}TbIBLeUIIZbd~#9#Y!li<3TzxL+`!F36Ly%5&* z?_wW^>#BJ2yg#P_t}FQa{#*mNu7tk)e>MN+|EF9I=udy_8Ti{v_#KF+!gW8n4#b<` z8b(W?yr3PfC-UX}ab&ojSJ;L>5{=Prn2-j2i`~LVJTu+7mq`VY!7`-j9fu#br z1g#HjdXTaOasr>D06de? zY{B4YdD&?B8Bjim@RL1Bs*b~?!d=ucnXS{^KQ!bFUk$5H0 zX-3d0e1gDv`rqf_GJpdm_?b~SAKw(6066d)uL!`sVZ+ap*dxH9Up=1ye1Pwtu#v-l zIP{k?zgRR8rARVf$>Ug`eQttx2-S3htH9BGhHr^r~OE5Su}i(yn6}Y z{_=h}*m}Z#4q_sH8;#gdfS>nWpB6*|+-K|MQ#q&-;JgjRRRi2->*Z5P-kShFZ$t5L zpAD7IGzQ?@W^N3W_t{YSOow+h%qLy&dk0(CRCojI<=t{**ELxRhgTdxD2aif5lOMn zfUIi>0mEK3lK&+qD+^S*O-ojv1^8^?(n&5^R3v?jlS#!18BPf&;mmbQI`8v7zNRBH zA|g}-uSS?vu&^te>d5ZEj<&&^tw*Hc^;Iczw%k7z*DP1Yim9%oaT~j>^QYB{vSd|l z?Ye@BI8o`0nt05GM(U##Rz;*K_^op~dz>6AkHz8$y;W1avxs7YXquuvPV1l0pzQLs zN%R@4%7f&L?f@KZ6UjY<5G@494Ei{Tkog+N=eCj7=^=6(XdYx^LXrr}@1!Qn(`56Y z0Y6c=bmHZv#zRxt3voIchla??ItN|%c@b%`G(1E|tKL3cuwZ-^xqkRo`? z2;Z}pTmKKbmi_t?!|vm|@?Kxd{>8o=`ZqfcX#6uwJdZ-ZHC*v-g#Ug=N!i8!Yuz&R zztIU~ej)qY**SvyU>xdUZl-Y>Q;&%cQR{w(-6Z$}z>N^n69Bvs=lRAtwM_6izzt+B z$7%2u-!eaZH(x%^51&TL`}Rx;jzal#e(s-6ed0X}@NK+Jc>>^m8yDcu`^vMag8KvI zpl>BPQ0>MjQfo^~}8Nzy4LvxO?8E*eMa0vtI`12yc-QMkR&9R^vp~vP3&cm7L><{Qm*ud_fK#D-OeaFMTW0G+Q z`!v9a&t`^#*z*A^#0Ksl=swsj2j+(oW5Y+wK0UZ%4R_Ep1@HCzL|)sDJ>Rh$4&e^) z<)k*LAs9d(wSKa3#TvM=7fK4@XIMa%d~pooH~Zok`P^g#_K43vX3qhf_m4q$%Dg&& z^Zqdp=l$aV-20VBO#Owu9m*3w(2N%0o!*!DF)`cYhB5J_ClcbhKfrzB50d-ed*3AY zsg<4(OKh)7Vg+jSv@~`T=&&C{qD7Qr!IQ&vETOh zJ>bb8IJ(^?Sa)%eUf|!Q%I{1iX^=Mmdv?gaRqB^-QXNZG?ECw}gSYkBgM_p|QnT>T zB>bZ%XzM5UOp%M?H+^^ue!1uR?@{gay+^gOyfR*E2+Gcycjv_9p`tAx94L3y9Nsr0 z?Yb{f<=g9D2O?e%@icv}Gl2yxlY{J*CzHrOC!D-@lG%=ff-SCiw>$r)UbSZNf2SD& zs-hNOXmVr~DTgdQ^>uTTiW2^#&qMYrc9GB_bMs+RjW zbcQHan=J}q84)Wtid1@YM9b_DS#&5X2@)iQgk;Vz%R%X2_#Kz0U_EImky9yT5cW}j zw~U-;ow&Tia}a*|3-zN8W*n>~3LyTgfLNp%;#5x9!Br0X)Y?!tcn`DSR{)j+Dw#p= zu-nqj{`+{q(1MtB4+WUcPd7yytnhF9H(&y9c_OxB(FIo7{4BZW=_H?k!fM+^zR`Q&BMq)RZ`*9v58wjd z0$*AQvYX%o52dF%+!gR`cUqdA(!#w@Qqt2?JP!Ew1$pjWdzw83z5tWpw{lLRIBpfs zZ+MADTm`r4lAV2#$T|Fm&Pnth+=B?b(-02pmXNXrYnuvzIj&-@^~e$H;lt!}?Mdd2 z_163DCExG8&$^y}7VzQ+;MpKR1W)P!w+^;>J@Bq|gXhO`+_=HY9(~KYayW&JUTKB- zx)JI!_{u|FI;aC`(izGxcIeR$eqJCFugx-CK+<1><(rERm07J-*ON^S=u1AvE&0=bPM1Y0QBUO{m`?F zlI|cM@CZD!9Bh(QE*3mr4LqZR^6<7~{;<(Hsf~tR{cr#ru5@&U=hN0(TRmQ^s`7k= zZSA+VX$BHiI)3o@b5C!( zY5BUXxZ-5ng{OY=>?hCMzHQSXyt8kev+TqBANp8+@y}77_is72X8w$o)0Z8dbK(!O zmtKna>CN4TNT0E2HvHn)Ma~A^pAvFAoFvjMwL=mhWHQP)1Ni?6zCPGH&J%%+%3ZaT4RLVZow`1*!UYSQt|n;t#Bans4&T@AIJi1ds|=sFSLdNYY#yRgP7Y zUe#8Uj+aroj1ogaVN^~|RAGXlBtu7WsZv=*e?j)H2cDX?{)ab?+*pj~Q;Bth<<0lD zzH|Qkg|_>e%V#wtQl#F6Q13iny;3L1wczJ@;$DIVGrL$`gM(eXaQQFmS%%YV+N#nu z)*O|_l_ud*p_YbO<<0lCT{wUKoz{Ds%LnTcsrk70#v^b1uzuQ85A4b==&vB_W*Did zE%YuJS1_ksotA0Fy`D2xTpDzDFwVDnPM%-$?76j!w&&17JlnHj{++#^KTLu*^S<6g z`X1~bbUU+}4I}ms1`B~qFAiO}jd~Ry_tZS=slmserOVHFBJek7@N-aJ<9QZW!!MkG zaVUlKGZ28@*5{XG>zmEQ@MuMsoh#!Ov*~Vi|8t7C*V;Su;GgwE4(`h^wD}o1o{Z#E>~(KpVj8mPTTTadHMP9 zfdgLxYKrc#m6qDli;9R&N&@{j7jOwle#@waq_0qOw-aqSeO3U=sM=)KjiLd)SBqYw z&oKK)+(iWM-gCeaOC229P7hMYJ%4=z@7<60ybkrwEb`TU41;O5;292?cy+pBhW7OD! z#tueBqehJ}#vY@_*pjGlm;XJpdttF9-}n9h^ZfAa*_pYsXU@!=Idf*t+1WmuY;!jN z-wffbTv7f)!$;TxrS`T^X-;lmaStnXQtk7F8lMe(t@55qyPyk};a@kY2mc4VySf*D z1KG7?38uIj>%%^g0^3aOGxn^ucw5R7r!yn&jB_6N@d94%6}&4s1q7F6f`>cK|8pv7qJ0DW`T=u+dM%niDt71K zvD%??S}tf_Pj(!4azKYk?L)-L!{;iZx?NpxQT^&*5pg=Jd#%Tzu*%_=2dGcgQ9as; z#U9|BX85E58{MsS&K9|8xB5f8S*4p`D#}1aKGBz^dlUeE?&($rg z?Tj_*Np&p?p16G80`-*QcIH&Sbu}s+opk1rc-eMx&Zq3%Ri6zUOZ#o`LB?7k0Q}*G zh=L}^E?9tb1%E$iXE-;(Q*=V#P}i6O%Bd&v1ofV}bulZK@q+ohbL!pg%Z^<8;oFV7 z%Cm>h)F=2{OS8F`*hgE{-~Re$t$JB~JTFf@yZ8Xg5vfil57em$o!ZK4l&a4RY=DIqy z(>#t7E$l?vF2CfewoZ~u?t9Yt+-Kry@vQCqI>l|hihe+S=^5%5TJdu2n4XeL+LE%R zESrK)Pj0g{LvGt|$onbUCIoGRKB$P-G(9Vb-o&zga%nHo!&8)89eLBx2sMSYP;c!0 zR=uzswj5UVPgcz%J5)V(`aFAda^U9L>Rd7SWOC9r_R*z@;HdFAw^^|IvwDAw`dmF0 zP?vRItJ7uzE07)yA7`Qt4dvu-iaVWqKRa70c^Y-8uDIEHi0Qm8NAS=rp8xTeIAG_UGh2c+P~jqF%t4 zq{LgfO;4>u+v|9h?-0cL#wt?PTws>NQI}3^Kg+`ls710}Y!Yn|UuoswL$<*#!-!ov;aZ@_P#pzq?*ciMXpU^K1! zIB(0&uHKF~Z$|GyXBSiaBK79pUF!8E;uoy^ZtMXs%Kqipp=;8Oqgg*m;^o`wy6s=H zmRFLlvrfBqsB3OX_}*U?^@93$viev(ftonldAux0bs!%}qR+!!z=*YvRBsQKnk|Mw z2zjYDvEMs`C9mGHWuZDwjIk|N+|(BrZ~nDz@vJFp=nTa{c*`di^t-|;fIU0WjQ82F zs3I18Lmhg|7{^LaQFkIHtJd*Jh`> z?iNmxz~^arZJwydwc1d9wqwjz;C+U9R2wbsTo7U3g=x~q+e3V!&O9wD_&BKBk|`|l zXB#He1v@saP!Eg4Y@aD^k8aKSG0+xQO!8PdVdg>xL_&M;=TX!RmJ3z^Tc!{mK4;`}QiKxBUGSziJZKgQbTUayy>~wtvhb92;+suh?g7vJct!oyNo1~% z<*GS9ug~~qy<7q1(HzhPc=()8FLnBh->`45+cI|A_FiMoCWq%Y@hc;*Bl7^gywbs# zC`t!o7tV`$oB1>5@;)qZGpkX}0?HACI^P8oG;hB_ge{hqx?4$s-U_l#WQ`AvD? zkRdr!fQHwhF3PTg2xN(sk6;X91jOxZ$YZSjU;L?#QAa&xIjYlR>4?}N_gU_JG1|67 zDk)(n05pN2O|EzzF+4`hjEB?Mg1fd`r);$r|!i}3HJvkIH+H-bPb0Ko)3h-jRTvj_BnM*$^HB56=oTE z8cHRk=6GJSiSY^eyA!)v{fR7Wr^(g!LMoQ~gmB4u-K5JX66KgcwsbkSvUCwvAo{JY zDS+9OB>IgygV{Ey_Z}jx4vkUpae$nTey$9Ogzq!aUSL24I${-?ih|8au40vTDp}f< z4vh@-!g=+jq!_0nllO1D%u2pEIBHnm=~*MreRAxEsj}^Mw>6a(tFuOWcAS22&W>Z9 z<3=Vl?XbN2u`RaW(z`p&i)!}A`L2CvT!KI4{@6P!K|ao~EJ4RI(_8`V%Gt@A$~HR@ zugd-Z%)UI-VQ1#hbLSo%{bJUU_MHz-Un+(`_Uv6WK}ojFpR4Xye^ZYCyhF9_{F&Fc zCvXR&PVjmrlKtsiF0K;*Ip#gm2^4I5mJ;LpEVX7RpPU{1K)o~a?$Sd{vSwHpCe2^H zYUAKH1Jrt{&z2ff%I~oV#cCz!tGM?05BI>hF_p9x@h!+MX|J#+bx>=U-EWivB6cHTLY z+QyO9pEouq?Yf$q&~@mN6|-YLXN{QY@U;!1%j#>OdoIRk6|_BUnk>lQon~L&pM0KY zT~p7oBsr4}7!s9MB{Ne}m#aPSz7-oiw0GOw!+4C-O#}E-$ZmyatQr+M`xuDR{0Z`SCL+M-NZ$K&ob-Qy~N~>gfg{Ucup!u605} z>(&ho4V5Roc&L8mveeq>V-r?6H6t{P)DNIV{uqQ6MMTq8AUq-G*iWM}GyAeWkJLKs z`EO#`aZs?6bIXolqt$n9ov9uSU&0m`jUkL{t~-Hp#2CJvEhtYk{>K~R=vEA2-co!> zQz-#7ydVx+DPw+o(lK<;Cv3DiGkHQ{TG7mBhZ|+elg7^brfqMvZ|7~2m+~Ykm-hkiQy&0-;Z9(!&Eqc^IzgV4w$|7QgaW)14L(l=juPa5=n_DyDgk=B z2!;`~F{H2Yq9;6D@PJhu_xOwZ>Q7nQ=FZ>x^}Jcz#g-eG(`f^cKkrECE z?*4xM+XwfkZ6IIN`f>utpD$lfVSj3l!ty2I$*Hr$Gj}))yZHUn%r$9WclvnO^tF&L zf2$c2Y^RmRW9O-d)nDbqH`8rDEWOTg_X6%vJMMhG_i`d;FEsvh&Sej^Ky+oDeUZ6# z`qr-9H&0&=9(QIROdj-nr&x6iK6zfknsws~vG&4SL^p3+F$=iirN=NBIZN<96tk)a z9*WF7C`E4zEiYZPtjR?;O;}t4&yYM4@eJ7+0xDJDwk5KYykuB{PaVukT#88V4^z*4 z)$UQo(Z8}L^+^~$fK}c7@$<|n7lvh;=8PCHkp;B+IIQ!?_S27^SlVhx_oj^+hj$s* zZBa(_*4{CLzu+@x=EVj&b*=+Iq1q|Inc+x<7MeqdX>WcI*DJhO5E+9~)n1R=JA7YsoZZti* zH)Z05bK+B*llpAE)GTK(J?n+B!|<#@Hz~#3kE`A1shy6)(_m!IVEoF+%R^~^5REaK zglTyByD)!w(bY_K(=zq8`ulSA%cHkg@pR@a4b2%W4al7?Ps&{=_2M+bZZ13H`Iq$& zHzwXuQ`yAZSe`%ml}%JrZ;RL2TH8U}cD7AzCN>r8@#o8^)ug}hJfscjA);4J7Fe1# z1E7w$u;M?c)%)GA)Fdc&Km{K)`bQW%d%rlOUXh9~lUwy0ERW(ix?^g84jhGblUCx| z++N~X+eB%=^5tn#+m%zOT^g!G#M8=lE~RR)y37%;hdTwr)>K--5HrK%=UiG`v+ux- z8&bypD%ZAcldh;kg8n*oo|zUi`IjS)gGV+}zyI-R_o%;qRxf_Y%g<1+Fwz6L4uM5W zm-KY?idm~)NtBnamFE)Vf+I@co8`!lV{~=&clAV>co+DR<>0| z15Q%s_FJPuF(_fFB}4gPVdnk|Kkmz1maSx177m!VdiB(C-9NkN_9CYut98H94d(Cl z;a^uZ$>9D?_^>10qC452gO+{|SguKu!N#^gCk!4Lx-OkIdtmew3+kQ{P^>h^gu1~%BY3hyCPj8GHdlP+(x|$U5R4Hv-K;@=?h-oOW^pD{&n|*dq{eZPld$KRo zo~P74q#v`E>Ic6|jl^@gIiGzsUR}*PjsNO139EM0Z3+0a7w1!~kX)Sn-(isYOR}=E zFrZrJZk8SKK0W1&vfY=n(cS^{J_IWXcNp52g8Zoz7_2Rl$V!jT5OA|IR(Eo~I4#fQ z@?u5$-~xFR%9vfDE6dqgO`5BB{v3MoqdA!e*UZ|w;OgP*n8P17WAFX(oRvQM^_&Hp z>da(;Uk|Tm+a1-aeaq14tX9poo#wDp$2$k6_5J#MoqEGAi<6g+>fK{NgMcAxhGca^ z^0o_4E>BoJBL1WH4cj-5o3yiRxsv^weANEKj?S+Ansgha^=E%mbIBXFeZE(0+#jyU zIb7Q-?w`N?dD719rUSI+3EifqUB{6yFaM^rN4pSjyswWv3}+3IHldK}Oj=JxzT;WJ zIWR!1;DtRaS>mKt-qD}rkKItC}v1VYzQT)njlU=^b+VyN%L z`NfphlRlZUZTG-)Z+Bv*5A@bYta zYt+7ne?X76josX9Ik`Hvk=v#n9nyT-(3r@|;+}GDJ;yg|K0Yc~Y$G=uyu5plWkVZE z7+(|FEZHP=ru{680t_hGlx6!!8pUR@cQ@hpH`~KyAqsrZ4((Y2JBNXIXM=P!8U@a@ z;fZ|>G5Dq4r{y)i3rO<|HbqOjdQ}SWu2hpgpoY;=jYYlO&m+JI8#b{jYuBn5I47`c z^H}9oUw{57b6(^qIgQx2wpsVKedkCeUh3@g#0)!F@a|nKh?oJ}kF%v2Q$9;=7__>6 z*UHY`na;gUpNk)cw!k}2!dTNdX^cK^p#`KdHYVno#^L1?QJ8`+*=|4`Ul}(ha5vYL zvDBTCo}9R3N#cNI%sI40i_khPTbjxytz9!9dD*hkP3wNpvR!Cs3*d@_{0=j<0xrz* zMz00#X|S7prViUir*v#%ALo7|jg{ssSHs!f%QlH82eKOdn*`QxRd2-7&j%-_v|CIvfeGQ_ ze(|{C&2>T=tXg&K=(eL^!NS^Rn3Z}@Q;dJg^D&B>R(DxT;&!^2J^=i73q#nj^ ztDq~_hTg*Wp=dVYnjI~by}>XnfhCSSAD*?{8nbgr2Pm|*j$f`>A$86fJaT4p)uJ@! zb!i0MhxWT2u+DM9`XCVVp@);WqtoB&4Oaed=7CS5JKnyhzRhDhyZ<~)avXzJcT`753NzO!;s+5=2vXh#)am#-5SPwhLrmvZdgi) zU(M!uLcK|&iN8J-Z%IADU*vP8Q}SAG zEAyw{ty=Tlu~n;2d>PmI<6d!{I`kIh9qZ4W-r92g_uqeI?mK)$zczh`501lGZbcw> z!t&*g{^4?*n5?-H**$wqaQoq&o!)S)rPYw-5R&;5#ZmWeIqw_KQD)F zZKQ@nm-Xnrd~id#jY!|AYBs(n-@B9PYn!GV2a?bpdVMg;kWhvvG#Q}QOTnOf-4J4%P)4Hd1Kv?`OKm)bwQ9O<`?RU6Q#xZj zeL^MKQhBk@e;vqb_HPopxka4s}i`znY@~*3;(EI%XMFlpG^aCXWGoE|Uuj$U|E7THVkNOyzLDgS3 zG{J+7)o5uCbYIPOT3jljPu~8;q0vF-BU`Fb9TtZ&pSUAM#gT&&CS;0_kDR%^anOhP zrc?3KfX_cU)u-~Hk;9`mUA}l=cgFCxi&;BTA8L}qENM1F^ImQ<#F#Qz4PCJ4dew3` z7<-X_7|n+)2K$n4#RC!ZDxO{sA#;p)#B|6XJDzVjJ!H|yw_?JA?S(DJz}FGQ8n0ZI zzKU6g8WFOQMRx8iMjrPC^<2;Kg7=JgX>p+~SGd-J7uq0yU!|ChP3`Fu7FV;pPrdQu zVk*{&3-YW{*I1x9X5b9h@Zu4HmXx`!AGkEGMZ5>jH;p!r;pLVht~Zu!Q1^_g->YS- z8}hZm?EH|yhRYtktQqE)ZSiTS1M~IVrjEAd zm!C*qNvf@^t2o>?wY2!>ize)@2OFV|SKL;p%5vKgHd}%d1bl#1FWqL0HPBnF#;owP z@OC4zda&5ajSDR8x;5}6axd=6!;+Cwp*Ir~EWy~j$27`QNuEe;p&D1Dj-md@y z%qM^kyGR_Ly)7v76R@8un@}6}P;XD<_hr z##En=1=t9%Plnw#81!{t1Xz-=mFhyy2vEq+Z{A$sk#MG|`u#=tB(N8^AK^uh<156? z1+EF=aoZJEi4}?At_ikWjh9SuIET+lD|L^2Yqj)R0Y?^o&4&HUYvfviU7L-4MXHfJ z<+g6~x7^l^eLYx<`6}a0mSP$aZ?|}>C&|k7uk7B^4q}G?oCa{pKhUt3nCM^8AU`HP zv(s>Zw*&h5pV}dRM82Jn?kktm2p#sXNRhJhCptSl8#z6+(*1{ic>`~})i=Q#{8B%z zMtPqPFb`I$(>vIsM!kPUsC-6ar2sP~$a*C)LCQKGjpOuI<7@MOp!iJ^=vHOkeoEo=a(Ft-KxxF-T-iFy?&W(7nTmP-_ACX$rv2BYQm+wTfML0cSnfTW%fVeg`oF(1+SW;3G~+i76<<%lIk>#t!#^!2SjKK)}}Xue~5>68c9^2v(Kmp||=& z$X{sl&wot^dhMU-C`1~@EIR&ud)UXvKNF*_(p1K`(j$LuA2{|t z>dI*f`%h?kt+Miu1d4&F(bdE3lTyXHG%3}6E3u~CuhDB{owxis-2uXXLb=hWz$gd) zk@jT}3*>h2KFb#iZ>PNK%i;m^sKx{5{tLSG_X+v%HLe8zk#4p$e`WXuR(_2e1qMaF zo$#(NFBK)BZQecQZ#f+@B#?gx#GSitW21wc0xUBFv9CqrJ>TTdG_UX~ zR1&!V5o96xA3^JXy9W|^gum4bsVFVB-sXygPqEOt^*=3_rm44iKe^Go^|o@w6cTm$ zwiexVILbsV|4$Rz7QC7i}18TATZG8mf?o=i8}xlg9d1qSPv{DhqEV z@bJq*LCiadNqU@;h*pDbHGfUrKQpr=b+bHaovxoP14Bm{^Knm540HPy%WzQVNcz#rhZd5>MpBBSoinECs-VOJ)9IWAz{ zz2@0dkJM!><9PE#$!ku}#hbTHny|_=7(UaDW7ew=7fyOKW66stBhJiQ+GlEXz=qH{ zlM`}x*J;rFxL6#7*a=<`lon}5~I>b29_%f44qbNkY&-h}+6)vFF!?C8r= z7ukW~p9MKUI~RC&;B6jSqz1j-ON(tK#(0abmgvb@2EF;8l!wv(hVqv2_4b>6!=!F} z*yoo={-^H>75<@q_EG=(LdEeqqrR=4q4~o-zwEBOZ2x~K`?dZ22154I#!EaF(%4Y$ z$rsW!>%N63sou-o4q2r2gFmNDfAjv$zIks_QC?5qJFgDKw@@d3nLkGLMGKeLO@-a^ zNK;As_$TYCas2168erUzN9LTCeQharv!DGgjz7X$(d*oP;o-SQ_zP~~;WQUS=Oy92 zb7%Wppz%D`&1Ss8MUIJlIqg!Cub>ru0UZ<=o%(pe;Mf-9`=1&AXi;L<7UTO~J{r%G z8Z@8%wK%)0n)d#ObGK1FOU$jl^ygLT+I8w5vnr-vN@vYa4-tR!x_9u<47y;; zdxft2iLsE&-Uqsp{}N79)BM38>GkyoUN_p;d(12Fh*eud2K+7y62?izslv zJTBv48G6|>k1vH^tRU<%1@UKc}&7^;i{fTF{GP?(X5l6Zh>c(j~=#S9nw+{I|vKe zMLk?ZC@YoK!$pM(IPYGgrT*nK&;jJ-Ha0kEj#O&&h z6YG3&VsmYTqLITL_Fej~f%AwGh5pDHkEfy#s)788LO=dwGlWubc4sV)H^h^aCk}c0 z;i`hX?l_q@0sroXGE;ag7Ei_^bueHIa<<03H_i@A0ET3oJk=UcHpf}vu{dLt%I$zq zv=E6{|{{@fQxvw>9pm9943-MZE z?z6WPad}}rulZ8#Qy|~?U+z^ph0jMZliSU8Jd4Ot`{>>IJhc+KV` z)|544%~=c9lC@&3SsT`twPWpB2iB2&%sR2oIN!1>>&Cic+dT@exAue|LM-dWdb2p} zxc6aw;i}Y+^=FAJi49=MEQJkZgV{FJ?#@YjRj*l~7(on+bU6g$nnXJ^=1c8>kP&g1Rxi|j{siT%Vbv!B@& z_6xhpuCeRv2D`~_vD@rdc8C4O?y`IAKKq?LV1KZO>=Ap+p0KCvPxcr4n>}OC*$bA# za+!^(^d79pL{XGPSv27@T4vEAT15x32u|85CKeYoI@=q$R3B}G@Ulvr9UBfcY+ z72g%z#BySJ@jcNUu5O;9msmlpDB=s}Vr8+4SXHbh`iRxV8e&b+SF9!aiT*grCr}K6 zM`eguTMQN77wd?1MSST&3=`{%4a9IULTo5T;>4duVq@sFCU_#5vD$9Yd@Q`MLZ}E&I&aJvRj{*E4brnZ zq52S7#!!P*ppStJzlv<~*3>fz+NFi7$Sn0q2{c6}tyv1`@JLvKIrmTDsqmMuT-YQW6EcO(kUu?f z-a?FU9OFMr_)a(_oDfb5*}`v-lxKz0!uP_LkP;7tnZkMDobUsr-#y`X;d6X#HXbs& zA0$D4AsrHJ03;C2KZ78P215$n#ff~wAw@^v1p1NqO4Kr(;y+p#Ba9X93lD@na`Sdg zo0FSU`I~fc{v30ee7z0Xrgw?0QuLj8#RXpk)v-WY?<-ANYb! zLBx>VSk-_KotO|K4!!;XS}h%U*W<9nAU_~YNlYk|U?|#Gt94LA4QEh8j#H0B8t4g% z(mG6cmnkNfqJ_J>g^h+w`-u@u7P?x1?ue- zY|pQ^Z!Mk8{j{2xhD4<#MCo1M(9o1%DynwL=mOU19+fbV=XfQtpn=c>1q~FU_fbd? zPqgzC=aPJ$(qd5wvAs0>;QM0vu>xFv`VjXs4skzwWsD=!Pw#IW{aNsMur3UPjr95H zgVHa=P;o>Gs)L9Dhd$ndjpGfGg7J?CJ*)MopUxhB^$j@?F<>_`j$Z?<7yKF+vo|ni zZ(t-wXW(F?>_nshJ0bE=Q zgGfPke_su|zpo)NMDL6cW0U*qed%xP%i4Nh);9KKZT<1ug&xkt#Kfk3OWZ7%BG77z5W44 z(T7L@B1EWGmcg-cT;6K|=ngzU`FMcxXoUs%845$hP?+8WNHkw$5FUGg@o&s4%cYZdZ2+($RSd|i-;7kN2ETzMC!OA_30>5 zpN=B!)3-jYN9toHGN8tw4tMB4AC4i;9VfqNJ2TeFqViq94W$>fb-AJJ({0aP=y%mTyo%xFH;22sbc< z8ydoq1z~OejSLU+*VCY`1=ydXu>Cm-+smP_9S6dJe)_Y4NVk`duzhZ?t@l=KV{g^g z=epV&pJ**t-#BOxDd;6c3VNx&-s<&@@~FN(Uf^y=%&Q|b4ln#tfTMw4egk9qh!hlw z2xT|$=gT}EY~=9(bW@(7*kY2LR6e7Ieu7Ff;PGXb-gOEL9vv6_;qlNsN|^V z_?}KZenkFcBr1B<*%>nLE-w~4cB!L&II8`enzCAmf`wLhQtD?;2YtP1pbSw zF(f`Fme5B=_;d9P_sF7gQ5bBb8DX&IM|dStqLPP2Sz_X&dMEbR>fsj{9xiw4(559} z@$=P`L)^L2hdalLdt~u}aq<1T$3?{_w@HfX8CzsXVscFPK8f-DW0Q*~0CrD_O^U^! zNKAG~LPPXUj!KFvNOMR@>@_fMSW;YUe{4Eouh)W=eKDL%kcT^^&>unAmieEE)xLoJ zOokmyf9z2OU~NtBU6VaK3I7ahTe3wb3%3xyjn%IxJYZ&lVF#;}AYrEp--5<&RCR1{ zU>^!8zU*71>}UHCJ|H3|{sojCN!Y0CKok5RBkQ+z7u?#lj-VZ9`Yr|brL~>3H-x3W zvB~{~lKrBR`wC_I_3hV}-t)jSG9c~1Q7L?v4Z9jev3KEy{RtoZO66BZ8tz3FV!s3T z;&-&W;|V-rg;Qf&q!vXk5v%rRfUx+X1q5FA;@GJxC6wT`D~I2T;aB*7p`}8w+YyRg z4S(!fbiz&twHNIbr(kDeFm?bUvHCxZy^UjNyP3it*m>B@+iM4Q>OzD}?8w!}UIXmN zQii~!gZwT?S%!Ev!sl>Z!gUpSZsUF*_s6(D!==I=j{3{!TN(W*!=qGo!-bZS(W-I{ zTmiU3afRWEgpHypuGR>5#MMnWCEb?pOOK^zk}AuxgX}1mlHK^_DOZ+j;1r}#IZTd} zo64=_j&e6ShF^W;BzdqrQXVHyl&8tF<%M#(yjtEUZB9^f~+p2{zz$0oe%ZYnB2H94Egn97?fn5yF2!BtH`raGnurbedbrnaU|@(WWB z+0E3;lweB6H56Z&O*Kt2%`nY1EtWT$7Mqrv)|xh(w&U7k+HX3F-|0GGI%B$Mx?;L% zx@&r9`pcAS`b!ZNOa4_{c2nr0w313$#a*d{asm_|#Sd4AsfSWeiBOs-E%D}e7bRMW zQ~E0dmEp=5Wr8wANy9Z?S)!~|)+<|-9ZH6BP{~rVm2=7^<*IU9xvxA{o++wXHanOd z&85t4W>0fva}9HVIn*3xjx;wlw?@1p;@uFBLA(#*Nr(?de584td7^omdA50>Io-V4 zywSYXyvw`~*J1N_N)z*G^Lg`S+0A?%*B!(k$N}c3xL(Ks7WBA9u@tp9Tgq6 zm&IC~E_*v$OPaS@%Ua#7m8?EiKWm7!o@ul-!rH`I*1VPa+1e8E_PDxOqb*lVMXhnx z{?>uk;b!oab&Pd_bqelj*7?>Y)|J-v)-9&y)*bQ#oLF_xnq|$lp0i%EUd46Wdf&9) zDk}A?k8wS-s@7)?vV((zBfm;HxH)*@sw}^7sNoRc5NZ+}!cf+Ihe*qQho*Enw07v| z(9I#np^rn7!(i)hhmlG>NDV;=BbW!dlJ}QVhNsYJLxM6A(7|+u!ls7=^S1ExID#r< zVcvClHBX_Z1}HO-@|ipl;ZFGa9~^Cz34jhf{jjMe!UBbX^D>1AbKZTz40szUMR>X+ zFU2vBW0rC$ryK%#tV(xags|lGK-fp|A(%H1unE!6X7KO~DxICMMFT#CJOSkSuW}44 zb2lSJl@9|Rq;%0&N=3Mg4YY}4q~QpA+B)L3u^G}v$f#1bP{33wSDH`xl@Zc>gge`O zd7g6!cj0-uP+8KBJV+*~3(+hs&uf4@E2RAhceX_Urc&)BcfupNQ&_yo!{>OoqiHBg ze@dl`z9iw;UBV`Il(!(fFn0!^tQ1E|2LJUbZ;cFF0@~*`;bCFC9egN^)ACTFxRz=y zJj^|ha0ESt)>8o8h*~j&FfcjyDd1ChUf^4V{Mig1?wE&X#Yz0Bjy%Pex9w9Z5g4e% z6V!T=JC((b^YD8V7Pd?71bOY;dF#2WXcMs`@c?>+Fn1(urpp?nobncqU*^yUmMD}W zQfsWWSpYMr9mEX60}BPd%7=2Dd3Yp2`W0;p%xI;R$T^1S5ohyus7bvh&f;|X@Ya*5 zMAnwqw<8bFknba92Ir8GdYCYOX(V ziie9*I@*x(oKOh!LTX9mLArR_l!cUJp6){s=~IyMl%xbWhn`Y--Bn&w3vr0(n;VDp z6FeN6i<~GOC9)a3tyXHB%)?J@Xc;y`OW}BC@cx>?x%w)HCpdhnoIuW}$}Yf_<_y3S z=9^R&ua_t1&oQQSq|-k2<0FTV_b^~B%=V)kC+*$rmgu{-cOh@-b0Z7 zgnq^NMSf)$)mQ4p^Gu`mR5tUJjYJi`e?)K^L9rvzFGf%vlwO8X2!gwS&2*VsPge3O zAZ3?c7d&OUO!*;0h;yEDdhSpPi{mhiY9!9)qkb0WmR%+Rzg{(?UhJtkfx-&#Lxxbw zW}asx=ZBTNg|A9oi2j`0`1LrAP$@BIAHpXn%odWQV%@0q*hpz3;0*rk*CdyuT3TP2 zwo^JEHDbe;f&70`UBr+1ug?gBn4yh3O(tlxad|HD z@MhkRt{ih5agOjX2Q;uUIgx0khtzuF7|wxrI83#T0VQ3iuceJdt-M7W(VX&B9$rad zNV&^^e-jkH<@m!asYvNY&@`0y$WuNB&vOp+QH$c&89cm_(nV*E)196bJ8+5Akz|Fg zdDjy%{z3DW_!>pfRv~=N;Xv9mYl(8&^E-tL;$0Aq#udje#%M`25P65=K1NTUfcq3& zls8Sk&)4tTbN1))<}98?Z{QNxdR$wuj`74ABS;8?{jx1=lX1}gN5URCLs%%Rgne;8 zRz;;?!}nxZTfo*|0XBPIgnVcP!0I6s3d?*XYl@mbfL}mS)(D}Su+rnOY5a;`V3qHP zP+M5zdoY~a1uJ|UEbaplN`j?*BpZj&XxP;!u^9*rghf4#%|~c9TPS3(bc80c#lluL zSCC;NilG>rz~0$oN>%FwTQ6M3FEf(9+df#*z@ z(~$1O!$VCm&`oaeryRAX3iJ`Vf;L7eo%wLi3Zt-ehjW|{A1iz|mbXz(c?eIRWeGt3 zZzwF!=IPq}Gmxh*=6U!CmM2nJw2)ksw-FD@F8tST_*g$h+JU@X!Q757?;N*u=!LUc+S zIp#1*K^{O$5{(S=T9TTkDKt-->JVmjRhtJWPmu{Uw-@oD8d>gA*fN~PuF{+&u2P25 zHGK#3c1M(36kN$*kG=$svS2-nks!ptuFb%ueFYiT>wZX2#J`oVa~-hGEh!Y?>)g`+ z)idyc1m9~{x_)1c`$k+_aqYsj57%K_-{Crq>pZT@xUS=(ym$0FFB$c zv~uu&-YCx1oj6x>-p-pwye)Xs+=5kjEOwjVJe559!nB1 zXY-r`98h}RD9c9t+R0%kpp$hA<#fnG`ZNp2z|(0Hhf3ikI$-`0ym@+2>~=6nBFK2` zZ1jZB0z4DQljxPWf;Pm?0Kc$1fVL5^he4MjR00M+>}u4*{sl@Qt;9awX`~DKC?<^< zU)s*#a4kWanFYrjYDq^5n^o+$2=M1vj{mE|RWVD<;^F0zg8v99Ld=rJ;U6)%c)`E0 z+@4R%{R#vw>@=h+rIb>IaoTehe!c*+T%67imD7nDsay{V4YHg!=e~lG1wa-Se&Pn;Lw>v7Y<8tSenCk zIV{idKx+gxFAgj5bZ-u;a#)Q+KmKbQ4%>0qp2HCwj^c1Eho5pdorV(7f{$R++=99QyI}Kwj?4TtXbvn)8R9ODN?Ro^p-DTLi%+l>XAw z>N)kC(3(U2X&(NC!)qMgBFI8`n4Vq?t1#yk;c*U6a(IfviyZ#U zVHx<0t;fG7^#Q!b2>Nl@hNrjVusw&unD2aCn!)`vmpA zcjMs-99H76GKW_Q z^C=SPR_$i0~fA-$DoVNe24{!5l?{avb!~eZkD-j+@O@dW9H1;#Y zyiXpbGyN`{UQIAiIfY!i_Y3zDyiRh;2CFl z`?{eg!az$5Y*iD{jwgh_m<6>~grYc45odQYI<2Iyp5nk$TmcjGl%hPv3DBOW7*BCA zq*!^1vmvE8PbmeMAega!E(JO~p^erM0(hy>j7sVWy&YeDV1zN25td$zp6ty^0QN&o zWUN)FWU}=+gTu-T6*#@oj3|m>L`5v>Nl#MFcwAI7szFca#lXd}5WYBEIC~#?1Yo39 z5xz`})+`QPI2v>s%0M3wp4)(>L&tH}=B2>#X0kU9ZMVRSmdzxy5jMtenga94-tb}j5>)WPbhHFh&P zVw4O8?PEZ5DmY{kb~R=T^ZDv)CDvbSF(x-+JZ{D5YJ2!9>;%?e)!{e&gYc8^3%(kA z3!c-1g(rBIp)B5D@W7i3@8bOgS|^2}rOe#poX(0Y1^#vi<(0tW^iEA6e8tHJybb)n zKZZB;D0okgg`5}<&+DnMq|Ol*z}tJ7uu511$*=)Z;Y(o~zNY<+Z~&g%r{J}H2Hx72 zuo}FI_23`y{eBD?@DARiaAy_xTN1%&iT2<+3%uQ3AfZS;dBKyt8rG1>@L2y7vZXzw z$|AJaWJsknNTel@L|Y(zc0uwS{#RYtvDu9Lk+_WBgmgKANj zcB1;a@F<^FJEc~Pm6G6dH|%&-Kq)@L1=yKGU{l@?S(*)5`5ENrbjZ$mkeMrluOKCN d!$1BI*2dY8j8`BPTi{(1e0vBm=>G+!{|6jp>}mi2 literal 0 HcmV?d00001 diff --git a/lib/main.dart b/lib/main.dart index 616f2cc..787cc7e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,20 @@ import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; +import 'package:rasadyar_app/presentation/utils/color_utils.dart'; +import 'package:rasadyar_app/presentation/widget/buttons/elevated.dart'; +import 'package:rasadyar_app/presentation/widget/buttons/fab_outlined.dart'; +import 'package:rasadyar_app/presentation/widget/buttons/outline_elevated.dart'; +import 'package:rasadyar_app/presentation/widget/buttons/text_button.dart'; +import 'package:rasadyar_app/presentation/widget/inputs/r_input.dart'; +import 'package:rasadyar_app/presentation/widget/pagination/pagination_from_until.dart'; +import 'package:rasadyar_app/presentation/widget/pagination/show_more.dart'; +import 'package:rasadyar_app/presentation/widget/tabs/tab.dart'; + +import 'presentation/widget/buttons/fab.dart'; void main() { - runApp(const MyApp()); + runApp(MyApp()); } class MyApp extends StatelessWidget { @@ -14,7 +27,259 @@ class MyApp extends StatelessWidget { theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), ), + home: Home(), ); } } +class Home extends StatefulWidget { + const Home({super.key}); + + @override + State createState() => _HomeState(); +} + +class _HomeState extends State { + List _isOpen = [false, false, false, false, false, false]; + + void _handleAdd() { + print("Add FAB pressed"); + } + + void _handleEdit() { + print("Edit FAB pressed"); + } + + void _handleDelete() { + print("Delete FAB pressed"); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text("System design"), centerTitle: true), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ExpansionPanelList( + expansionCallback: (panelIndex, isExpanded) { + setState(() { + _isOpen[panelIndex] = isExpanded; + }); + }, + children: [ + buttonWidget(), + fabWidget(), + outlinedFabWidget(), + paginationWidget(), + tabWidget(), + inputsWidget(), + ], + ), + ), + ), + ); + } + + ExpansionPanel inputsWidget() { + return ExpansionPanel( + isExpanded: _isOpen[5], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "inputs", + style: AppFonts.yekan20Regular.copyWith(color: Colors.red), + ), + ); + }, + body: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + spacing: 14, + children: [ + RTextField( + hintText: 'حجم کشتار را در روز به قطعه وارد کنید', + hintStyle: AppFonts.yekan13Regular, + ), + RTextField( + label: 'تلفن مرغداری', + labelStyle: AppFonts.yekan10Regular, + ), + ], + ), + ), + ); + } + + ExpansionPanel tabWidget() { + return ExpansionPanel( + isExpanded: _isOpen[4], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "tab", + style: AppFonts.yekan20Regular.copyWith(color: Colors.red), + ), + ); + }, + body: Column( + spacing: 14, + children: [ + CupertinoSegmentedControlDemo(), + CupertinoSegmentedControlDemo2(), + ], + ), + ); + } + + ExpansionPanel paginationWidget() { + return ExpansionPanel( + isExpanded: _isOpen[3], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "پیجینیشن", + style: AppFonts.yekan20Regular.copyWith(color: Colors.red), + ), + ); + }, + body: Column(spacing: 14, children: [RShowMore(), PaginationFromUntil()]), + ); + } + + ExpansionPanel outlinedFabWidget() { + return ExpansionPanel( + isExpanded: _isOpen[2], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "Outlined Fab ", + style: AppFonts.yekan20Regular.copyWith(color: Colors.green), + ), + ); + }, + body: Column( + spacing: 14, + children: [ + Row(), + + RFabOutlined.smallAdd(onPressed: () {}), + RFabOutlined.smallAdd(onPressed: null), + + RFabOutlined.smallAddNoBorder(onPressed: () {}), + RFabOutlined.smallAddNoBorder(onPressed: null), + + RFabOutlined.add(onPressed: () {}), + RFabOutlined.add(onPressed: null), + + RFabOutlined.addNoBorder(onPressed: () {}), + RFabOutlined.addNoBorder(onPressed: null), + ], + ), + ); + } + + ExpansionPanel fabWidget() { + return ExpansionPanel( + isExpanded: _isOpen[1], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "Fab", + style: AppFonts.yekan20Regular.copyWith(color: Colors.green), + ), + ); + }, + body: Column( + spacing: 14, + children: [ + Row(), + + RFab.smallAdd(onPressed: () {}), + RFab.smallAdd(onPressed: null), + + RFab.add(onPressed: () {}), + RFab.add(onPressed: null), + + RFab.smallEdit(onPressed: null), + RFab.smallEdit(onPressed: () {}), + + RFab.edit(onPressed: () {}), + RFab.edit(onPressed: null), + + RFab.smallDelete(onPressed: () {}), + RFab.smallDelete(onPressed: null), + + RFab.delete(onPressed: () {}), + RFab.delete(onPressed: null), + + RFab.smallAction(onPressed: () {}), + RFab.smallAction(onPressed: null), + + RFab.action(onPressed: () {}), + RFab.action(onPressed: null), + + RFab.smallFilter(onPressed: () {}), + RFab.smallFilter(onPressed: null), + + RFab.filter(onPressed: () {}), + RFab.filter(onPressed: null), + + RFab.smallDownload(onPressed: () {}), + RFab.smallDownload(onPressed: null), + + RFab.download(onPressed: () {}), + RFab.download(onPressed: null), + + RFab.smallExcel(onPressed: () {}), + RFab.smallExcel(onPressed: null), + + RFab.excel(onPressed: () {}), + RFab.excel(onPressed: null), + + RFab.smallBack(onPressed: () {}), + RFab.smallBack(onPressed: null), + + RFab.back(onPressed: () {}), + RFab.back(onPressed: null), + ], + ), + ); + } + + ExpansionPanel buttonWidget() { + return ExpansionPanel( + isExpanded: _isOpen[0], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "دکمه ها", + style: AppFonts.yekan20Regular.copyWith(color: Colors.green), + ), + ); + }, + body: Column( + spacing: 14, + children: [ + Row(), + + RElevated(text: 'ثبت', onPressed: () {}), + + RElevated(text: 'ثبت', onPressed: null), + + ROutlinedElevated(text: 'ثبت', onPressed: () {}), + ROutlinedElevated( + text: 'ثبتwwww', + onPressed: () {}, + backgroundColor: AppColor.blueNormal.disabledColor, + pressedBackgroundColor: AppColor.blueNormal, + ), + ROutlinedElevated(text: 'ثبت', onPressed: null), + + RTextButton(text: 'ثبت', onPressed: () {}), + RTextButton(text: 'ثبت', onPressed: null), + ], + ), + ); + } +} diff --git a/lib/presentation/common/app_fonts.dart b/lib/presentation/common/app_fonts.dart new file mode 100644 index 0000000..70b06fe --- /dev/null +++ b/lib/presentation/common/app_fonts.dart @@ -0,0 +1,155 @@ +import 'package:flutter/material.dart'; + +class AppFonts { + AppFonts._(); // Private constructor to prevent instantiation + + // --- Font Families --- + static const String yekan = 'yekan'; + + // --- Font Weights --- + static const FontWeight regular = FontWeight.w400; + static const FontWeight bold = FontWeight.w600; + static const double _height = 1.20; + + static const TextStyle yekan61Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 61, + height: _height, + ); + + static const TextStyle yekan49Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 48, + height: _height, + ); + + static const TextStyle yekan39Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 39, + height: _height, + ); + + static const TextStyle yekan31Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 31, + height: _height, + ); + + static const TextStyle yekan25Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 25, + height: _height, + ); + + static const TextStyle yekan24Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 24, + height: _height, + ); + + static const TextStyle yekan20Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 20, + height: _height, + ); + + static const TextStyle yekan16Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 16, + height: _height, + ); + + static const TextStyle yekan13Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 13, + height: _height, + ); + + static const TextStyle yekan10Regular = TextStyle( + // Rounded from 10.24 + fontFamily: yekan, + fontWeight: regular, + fontSize: 10, + height: _height, + ); + + static const TextStyle yekan61Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 61, + height: _height, + ); + + static const TextStyle yekan49Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 48, + height: _height, + ); + + static const TextStyle yekan39Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 39, + height: _height, + ); + + static const TextStyle yekan31Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 31, + height: _height, + ); + + static const TextStyle yekan25Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 25, + height: _height, + ); + + static const TextStyle yekan24Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 24, + height: _height, + ); + + static const TextStyle yekan20Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 20, + height: _height, + ); + + static const TextStyle yekan16Bold = TextStyle( + // Base size bold + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 16, + height: _height, + ); + + static const TextStyle yekan13Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 13, + height: _height, + ); + + static const TextStyle yekan10Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 10, + height: _height, + ); +} diff --git a/lib/presentation/common/assets.dart b/lib/presentation/common/assets.dart new file mode 100644 index 0000000..185d647 --- /dev/null +++ b/lib/presentation/common/assets.dart @@ -0,0 +1,24 @@ +///This file is automatically generated. DO NOT EDIT, all your changes would be lost. +class Assets { + Assets._(); + + static const String iconsAdd = 'assets/icons/add.svg'; + static const String iconsArrowLeft = 'assets/icons/arrow_left.svg'; + static const String iconsArrowRight = 'assets/icons/arrow_right.svg'; + static const String iconsDownload = 'assets/icons/download.svg'; + static const String iconsEdit = 'assets/icons/edit.svg'; + static const String iconsFilter = 'assets/icons/filter.svg'; + static const String iconsScan = 'assets/icons/scan.svg'; + static const String iconsTrash = 'assets/icons/trash.svg'; + static const String imagesInnerSplash = 'assets/images/inner_splash.webp'; + static const String imagesOutterSplash = 'assets/images/outter_splash.webp'; + static const String vecAddSvg = 'assets/vec/add.svg.vec'; + static const String vecArrowLeftSvg = 'assets/vec/arrow_left.svg.vec'; + static const String vecArrowRightSvg = 'assets/vec/arrow_right.svg.vec'; + static const String vecDownloadSvg = 'assets/vec/download.svg.vec'; + static const String vecEditSvg = 'assets/vec/edit.svg.vec'; + static const String vecFilterSvg = 'assets/vec/filter.svg.vec'; + static const String vecScanSvg = 'assets/vec/scan.svg.vec'; + static const String vecTrashSvg = 'assets/vec/trash.svg.vec'; + +} diff --git a/lib/presentation/utils/color_utils.dart b/lib/presentation/utils/color_utils.dart new file mode 100644 index 0000000..46f9bb8 --- /dev/null +++ b/lib/presentation/utils/color_utils.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +extension ColorUtils on Color { + Color _darken([double amount = 0.1]) { + assert(amount >= 0 && amount <= 1, 'مقدار تیرگی باید بین 0 و 1 باشد'); + final hslColor = HSLColor.fromColor(this); + final newLightness = (hslColor.lightness - amount).clamp(0.0, 1.0); + final hslDarkerColor = hslColor.withLightness(newLightness); + return hslDarkerColor.toColor(); + } + + get disabledColor{ + return withAlpha(38); + } + + get hoverColor{ + return _darken(0.5); + } + + get pressedColor{ + return _darken(0.10); + } + +} diff --git a/lib/presentation/widget/buttons/elevated.dart b/lib/presentation/widget/buttons/elevated.dart new file mode 100644 index 0000000..c03bc2e --- /dev/null +++ b/lib/presentation/widget/buttons/elevated.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +class RElevated extends StatefulWidget { + RElevated({ + super.key, + required this.text, + required this.onPressed, + foregroundColor, + backgroundColor, + disabledBackgroundColor, + disabledForegroundColor, + radius, + textStyle, + this.width = 150.0, + this.height = 56.0, + }); + + final String text; + final VoidCallback? onPressed; + final double width; + final double height; + Color? foregroundColor; + Color? backgroundColor; + Color? disabledForegroundColor; + Color? disabledBackgroundColor; + double? radius; + TextStyle? textStyle; + + @override + State createState() => _RElevatedState(); +} + +class _RElevatedState extends State { + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: () { + setState(() {}); + }, + style: ElevatedButton.styleFrom( + backgroundColor: widget.backgroundColor ?? AppColor.blueNormal, + foregroundColor: widget.foregroundColor ?? Colors.white, + disabledBackgroundColor: + widget.disabledBackgroundColor ?? AppColor.blueNormal.withAlpha(38), + disabledForegroundColor: widget.disabledForegroundColor ?? Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(widget.radius ?? 8), + ), + fixedSize: Size(widget.width, widget.height), + padding: EdgeInsets.zero, + textStyle: widget.textStyle ?? AppFonts.yekan24Regular, + ), + child: Text(widget.text), + ); + } +} diff --git a/lib/presentation/widget/buttons/fab.dart b/lib/presentation/widget/buttons/fab.dart new file mode 100644 index 0000000..84a4e8b --- /dev/null +++ b/lib/presentation/widget/buttons/fab.dart @@ -0,0 +1,232 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/assets.dart'; +import 'package:rasadyar_app/presentation/utils/color_utils.dart'; +import 'package:rasadyar_app/presentation/widget/vec_widget.dart'; + +class RFab extends StatefulWidget { + + + final VoidCallback? onPressed; + Color? foregroundColor; + Color? backgroundColor; + Color? disabledForegroundColor; + Color? disabledBackgroundColor; + double? radius; + ShapeBorder? shapeBorder; + Widget? icon; + + @override + State createState() => _RFabState(); + + //region Add + RFab.smallAdd({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecAddSvg), + backgroundColor: AppColor.greenNormal, + key: key, + ); + + RFab.add({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecAddSvg), + backgroundColor: AppColor.greenNormal, + key: key, + ); + + //endregion + + //region Edit + RFab.smallEdit({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecEditSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.edit({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecEditSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region delete + RFab.smallDelete({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecTrashSvg), + backgroundColor: AppColor.redNormal, + key: key, + ); + + RFab.delete({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecTrashSvg), + backgroundColor: AppColor.redNormal, + key: key, + ); + + //endregion + + //region action + RFab.smallAction({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecScanSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.action({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecScanSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region filter + RFab.smallFilter({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecFilterSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.filter({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecFilterSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region download + RFab.smallDownload({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecDownloadSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.download({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecDownloadSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region Excel + RFab.smallExcel({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecDownloadSvg), + backgroundColor: AppColor.greenDark, + key: key, + ); + + RFab.excel({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecDownloadSvg), + backgroundColor: AppColor.greenDark, + key: key, + ); + + //endregion + + //region Back + RFab.smallBack({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecArrowLeftSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.back({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecArrowLeftSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region General + RFab.small({ + required this.onPressed, + required this.icon, + required this.backgroundColor, + super.key, + }) : radius = 40.0, + foregroundColor = Colors.white; + + RFab({ + required this.onPressed, + required this.icon, + required this.backgroundColor, + super.key, + }) : radius = 56.0, + foregroundColor = Colors.white; + + //endregion +} + +class _RFabState extends State { + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: widget.onPressed, + style: ButtonStyle( + side: WidgetStateProperty.all(BorderSide.none), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return widget.backgroundColor?.pressedColor ?? + AppColor.blueNormalActive; + } else if (states.contains(WidgetState.hovered)) { + return widget.backgroundColor?.hoverColor ?? + AppColor.blueNormalHover; + } else if (states.contains(WidgetState.disabled)) { + return widget.backgroundColor?.disabledColor ?? + AppColor.blueNormal.disabledColor; + } + return widget.backgroundColor ?? AppColor.blueNormal; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.disabled)) { + return widget.foregroundColor?.disabledColor; + } + return widget.foregroundColor; + }), + + shape: WidgetStatePropertyAll( + CircleBorder(side: BorderSide(width: 1, color: Colors.transparent)), + ), + fixedSize: WidgetStatePropertyAll( + Size(widget.radius ?? 56, widget.radius ?? 56), + ), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + ), + child: widget.icon, + ); + } +} diff --git a/lib/presentation/widget/buttons/fab_outlined.dart b/lib/presentation/widget/buttons/fab_outlined.dart new file mode 100644 index 0000000..ecd9ea1 --- /dev/null +++ b/lib/presentation/widget/buttons/fab_outlined.dart @@ -0,0 +1,605 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/assets.dart'; +import 'package:rasadyar_app/presentation/utils/color_utils.dart'; +import 'package:rasadyar_app/presentation/widget/vec_widget.dart'; + +class RFabOutlined extends StatefulWidget { + final Widget icon; + VoidCallback? onPressed; + final Color backgroundColor; + final Color? borderColor; + final double? radius; + OutlinedBorder? shapeBorder; + + @override + State createState() => _RFabOutlinedState(); + + //region General + RFabOutlined({ + required this.icon, + required this.onPressed, + required this.backgroundColor, + required this.borderColor, + this.radius = 56.0, + super.key, + }) : shapeBorder = CircleBorder( + side: BorderSide(color: borderColor ?? Colors.transparent), + ); + + RFabOutlined.noBorder({ + required this.icon, + required this.onPressed, + required this.backgroundColor, + super.key, + }) : borderColor = Colors.transparent, + radius = 56.0, + shapeBorder = CircleBorder( + side: BorderSide(color: Colors.transparent, width: 1), + ); + + RFabOutlined.small({ + required this.icon, + required this.onPressed, + required this.backgroundColor, + required this.borderColor, + super.key, + }) : radius = 40.0, + shapeBorder = CircleBorder( + side: BorderSide(color: borderColor ?? Colors.transparent, width: 1), + ); + + RFabOutlined.smallNoBorder({ + required this.icon, + required this.onPressed, + required this.backgroundColor, + super.key, + }) : borderColor = Colors.transparent, + radius = 40.0, + shapeBorder = CircleBorder( + side: BorderSide(color: Colors.transparent, width: 1), + ); + + //endregion + + //region Add + RFabOutlined.smallAdd({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenNormal, + borderColor: AppColor.greenNormal, + icon: vecWidget2( + Assets.vecAddSvg, + + color: AppColor.greenNormal, + ), + ); + + RFabOutlined.smallAddNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenNormal, + icon: vecWidget( + Assets.vecAddSvg, + color: + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + ), + ); + + RFabOutlined.add({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenNormal, + borderColor: AppColor.greenNormal, + icon: vecWidget( + Assets.vecAddSvg, + color: + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + ), + ); + + RFabOutlined.addNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenNormal, + icon: vecWidget( + Assets.vecAddSvg, + color: + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + ), + ); + + //endregion + + //region Edit + RFabOutlined.smallEdit({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecEditSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.smallEditNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecEditSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.edit({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecEditSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.editNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecEditSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + //endregion + + //region Delete + RFabOutlined.smallDelete({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.redNormal, + borderColor: AppColor.redNormal, + icon: vecWidget( + Assets.vecTrashSvg, + color: + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + ), + ); + + RFabOutlined.smallDeleteNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.redNormal, + icon: vecWidget( + Assets.vecTrashSvg, + color: + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + ), + ); + + RFabOutlined.delete({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.redNormal, + borderColor: AppColor.redNormal, + icon: vecWidget( + Assets.vecTrashSvg, + color: + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + ), + ); + + RFabOutlined.deleteNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.redNormal, + icon: vecWidget( + Assets.vecTrashSvg, + color: + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + ), + ); + + //endregion + + //region Action + RFabOutlined.smallAction({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecScanSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.smallActionNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecScanSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.action({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecScanSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.actionNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecScanSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + //endregion + + //region Filter + RFabOutlined.smallFilter({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecFilterSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.smallFilterNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecFilterSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.filter({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecFilterSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.filterNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecFilterSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + //endregion + + //region Download + RFabOutlined.smallDownload({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.smallDownloadNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.download({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.downloadNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + //endregion + + //region Excel + RFabOutlined.smallExcel({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenDark, + borderColor: AppColor.greenDark, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.smallExcelNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenDark, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.excel({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenDark, + borderColor: AppColor.greenDark, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.excelNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenDark, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + //endregion + + //region Back + RFabOutlined.smallBack({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecArrowLeftSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.smallBackNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecArrowLeftSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.back({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecArrowLeftSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.backNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecArrowLeftSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + //endregion +} + +class _RFabOutlinedState extends State { + bool isOnPressed =false; + @override + Widget build(BuildContext context) { + return OutlinedButton( + onPressed:widget.onPressed , + style: ButtonStyle( + side: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.disabled)) { + return BorderSide( + color: + widget.borderColor?.disabledColor ?? + AppColor.blueNormal.disabledColor, + width: 2, + ); + } + return BorderSide( + color: widget.borderColor ?? AppColor.blueNormal, + width: 2, + ); + }), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return widget.backgroundColor; + } else if (states.contains(WidgetState.hovered)) { + return widget.backgroundColor.hoverColor ?? + AppColor.blueNormal.hoverColor; + } else if (states.contains(WidgetState.disabled)) { + return widget.backgroundColor.disabledColor ?? + AppColor.blueNormal.disabledColor; + } + return Colors.transparent; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return Colors.white; + } else if (states.contains(WidgetState.disabled)) { + return widget.backgroundColor.disabledColor ?? + AppColor.blueNormal.disabledColor; + } + return widget.backgroundColor; + }), + + shape: WidgetStatePropertyAll(widget.shapeBorder), + fixedSize: WidgetStatePropertyAll( + Size(widget.radius ?? 56, widget.radius ?? 56), + ), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + ), + child: widget.icon + ); + } +} + diff --git a/lib/presentation/widget/buttons/outline_elevated.dart b/lib/presentation/widget/buttons/outline_elevated.dart new file mode 100644 index 0000000..23272bf --- /dev/null +++ b/lib/presentation/widget/buttons/outline_elevated.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; +import 'package:rasadyar_app/presentation/utils/color_utils.dart'; + +class ROutlinedElevated extends StatefulWidget { + ROutlinedElevated({ + super.key, + required this.text, + required this.onPressed, + this.foregroundColor, + this.backgroundColor, + this.borderColor, + this.disabledBackgroundColor, + this.pressedBackgroundColor, + this.radius, + this.textStyle, + this.width = 150.0, + this.height = 56.0, + }); + + final String text; + final VoidCallback? onPressed; + final double width; + final double height; + Color? foregroundColor; + Color? backgroundColor; + + Color? borderColor; + + Color? disabledBackgroundColor; + Color? pressedBackgroundColor; + double? radius; + TextStyle? textStyle; + + @override + State createState() => _ROutlinedElevatedState(); +} + +class _ROutlinedElevatedState extends State { + @override + Widget build(BuildContext context) { + return OutlinedButton( + onPressed: widget.onPressed, + style: ButtonStyle( + side: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return BorderSide( + color: widget.borderColor ?? AppColor.blueNormal, + width: 2, + ); + } else if (states.contains(WidgetState.disabled)) { + return BorderSide( + color: widget.borderColor ?? AppColor.blueNormal.withAlpha(38), + width: 2, + ); + } + return BorderSide( + color: widget.borderColor ?? AppColor.blueNormal, + width: 2, + ); + }), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + if (widget.pressedBackgroundColor != null) { + return widget.pressedBackgroundColor; + } + return widget.backgroundColor?.pressedColor ?? AppColor.blueNormal; + } else if (states.contains(WidgetState.hovered)) { + return widget.backgroundColor?.hoverColor ?? + AppColor.blueNormal.hoverColor; + } else if (states.contains(WidgetState.disabled)) { + return widget.backgroundColor?.disabledColor ?? Colors.transparent; + } + return widget.backgroundColor; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return Colors.white; + } else if (states.contains(WidgetState.disabled)) { + return AppColor.blueNormal.withAlpha(38); + } + return AppColor.blueNormal; + }), + + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(widget.radius ?? 8), + ), + ), + fixedSize: WidgetStatePropertyAll(Size(widget.width, widget.height)), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + textStyle: WidgetStatePropertyAll( + widget.textStyle ?? + AppFonts.yekan24Regular.copyWith(color: AppColor.blueNormal), + ), + ), + child: Text(widget.text), + ); + } +} diff --git a/lib/presentation/widget/buttons/text_button.dart b/lib/presentation/widget/buttons/text_button.dart new file mode 100644 index 0000000..40fb3a4 --- /dev/null +++ b/lib/presentation/widget/buttons/text_button.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +class RTextButton extends StatefulWidget { + RTextButton({ + super.key, + required this.text, + required this.onPressed, + foregroundColor, + backgroundColor, + borderColor, + disabledBackgroundColor, + radius, + textStyle, + this.width = 150.0, + this.height = 56.0, + }); + + final String text; + final VoidCallback? onPressed; + final double width; + final double height; + Color? foregroundColor; + Color? backgroundColor; + Color? borderColor; + + Color? disabledBackgroundColor; + double? radius; + TextStyle? textStyle; + + @override + State createState() => _RTextButtonState(); +} + +class _RTextButtonState extends State { + @override + Widget build(BuildContext context) { + return TextButton( + style: ButtonStyle( + side: WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return widget.backgroundColor ?? AppColor.blueNormal; + } else if (states.contains(WidgetState.hovered)) { + return widget.backgroundColor?.withAlpha(38) ?? AppColor.blueNormal.withAlpha(38); + } else if (states.contains(WidgetState.disabled)) { + return widget.disabledBackgroundColor ?? Colors.transparent; + } + return Colors.transparent; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return Colors.white; + } else if (states.contains(WidgetState.disabled)) { + return AppColor.blueNormal.withAlpha(38); + } + return AppColor.blueNormal; + }), + + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(widget.radius ?? 8), + ), + ), + fixedSize: WidgetStatePropertyAll(Size(widget.width, widget.height)), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + textStyle: WidgetStatePropertyAll( + widget.textStyle ?? + AppFonts.yekan24Regular.copyWith(color: AppColor.blueNormal), + ), + ), + onPressed:widget.onPressed, + child: Text(widget.text), + ); + } +} diff --git a/lib/presentation/widget/inputs/r_input.dart b/lib/presentation/widget/inputs/r_input.dart new file mode 100644 index 0000000..07edc2b --- /dev/null +++ b/lib/presentation/widget/inputs/r_input.dart @@ -0,0 +1,216 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +@immutable +class RTextField extends StatefulWidget { + RTextField( + {super.key, + this.maxLines, + this.maxLength, + this.hintText, + this.padding, + this.onChanged, + this.onSubmitted, + this.keyboardType, + this.showCounter = false, + this.isDense, + this.initText, + this.isForNumber = false, + this.style, + this.hintStyle, + this.suffixIcon, + this.prefixIcon, + this.validator, + this.readonly = false, + this.boxConstraints, + this.minLines, + this.radius, + this.filled, + this.enabled, + this.errorStyle, + this.labelStyle, + this.label}) { + filled = filled ?? false; + obscure = false; + _inputBorder = OutlineInputBorder( + borderSide: BorderSide(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(radius ?? 16)); + } + + RTextField.noBorder( + {super.key, + this.maxLines, + this.maxLength, + this.hintText, + this.padding, + this.onChanged, + this.onSubmitted, + this.keyboardType, + this.showCounter = false, + this.isDense, + this.initText, + this.style, + this.hintStyle, + this.suffixIcon, + this.radius, + this.validator, + this.boxConstraints, + this.minLines, + this.isForNumber = false, + this.readonly = false, + this.label, + this.filled, + this.errorStyle, + this.labelStyle, + this.enabled}) { + _inputBorder = OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(radius ?? 16)); + obscure = false; + filled = filled ?? true; + } + + RTextField.password( + {super.key, + this.maxLines = 1, + this.maxLength, + this.hintText, + this.padding, + this.onChanged, + this.onSubmitted, + this.keyboardType, + this.showCounter = false, + this.isDense, + this.initText, + this.style, + this.hintStyle, + this.suffixIcon, + this.prefixIcon, + this.radius, + this.validator, + this.boxConstraints, + this.minLines, + this.isForNumber = false, + this.readonly = false, + this.label, + this.filled, + this.errorStyle, + this.labelStyle, + this.enabled}) { + _inputBorder = OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(radius ?? 16)); + filled = filled ?? true; + obscure = true; + _isPassword = true; + prefixIcon = prefixIcon ?? const Icon(CupertinoIcons.person); + } + + final int? maxLines; + final int? minLines; + final int? maxLength; + final String? hintText; + final String? label; + final EdgeInsets? padding; + final TextStyle? style; + final TextStyle? errorStyle; + final TextStyle? hintStyle; + final TextStyle? labelStyle; + final bool showCounter; + final bool? isDense; + final bool? isForNumber; + final bool readonly; + bool? obscure; + final bool? enabled; + final double? radius; + final TextInputType? keyboardType; + final Function(String)? onChanged; + final Function(String)? onSubmitted; + final FormFieldValidator? validator; + final String? initText; + Widget? suffixIcon; + Widget? prefixIcon; + bool? filled; + bool _isPassword = false; + + final BoxConstraints? boxConstraints; + late final InputBorder? _inputBorder; + + @override + State createState() => _RTextFieldState(); +} + +class _RTextFieldState extends State { + final TextEditingController _controller = TextEditingController(); + bool? obscure; + + @override + void initState() { + super.initState(); + if (widget.initText != null) { + _controller.text = widget.initText!; + } + obscure = widget.obscure; + } + + @override + void didUpdateWidget(covariant RTextField oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.initText != oldWidget.initText) { + _controller.text = widget.initText ?? ''; + } + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: widget.padding ?? const EdgeInsets.symmetric(vertical: 6.0), + child: TextFormField( + controller: _controller, + readOnly: widget.readonly, + minLines: widget.minLines, + maxLines: widget.maxLines, + onChanged: widget.onChanged, + validator: widget.validator, + enabled: widget.enabled, + obscureText: obscure ?? false, + onTapOutside: (event) { + FocusScope.of(context).unfocus(); + }, + onFieldSubmitted: widget.onSubmitted, + maxLength: widget.maxLength, + textDirection: TextDirection.rtl, + style: widget.style , + keyboardType: widget.keyboardType, + decoration: InputDecoration( + errorStyle: widget.errorStyle, + errorMaxLines: 1, + isDense: widget.isDense, + suffixIcon: widget.suffixIcon ?? + (widget._isPassword + ? IconButton( + onPressed: () { + setState(() { + obscure = !obscure!; + }); + }, + icon: Icon(!obscure! + ? CupertinoIcons.eye_slash + : CupertinoIcons.eye)) + : null), + suffixIconConstraints: widget.boxConstraints, + prefixIcon: widget.prefixIcon, + prefixIconConstraints: widget.boxConstraints, + hintText: widget.hintText, + labelText: widget.label, + labelStyle: widget.labelStyle, + filled: widget.filled, + counter: widget.showCounter ? null : const SizedBox(), + hintStyle: widget.hintStyle, + enabledBorder: widget._inputBorder, + focusedBorder: widget._inputBorder, + border: widget._inputBorder), + )); + } +} \ No newline at end of file diff --git a/lib/presentation/widget/pagination/pagination_from_until.dart b/lib/presentation/widget/pagination/pagination_from_until.dart new file mode 100644 index 0000000..53f1203 --- /dev/null +++ b/lib/presentation/widget/pagination/pagination_from_until.dart @@ -0,0 +1,255 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +class PaginationFromUntil extends StatefulWidget { + const PaginationFromUntil({super.key}); + + @override + State createState() => _PaginationFromUntilState(); +} + +class _PaginationFromUntilState extends State { + int current = 1; + int total = 10; + + @override + Widget build(BuildContext context) { + return Container( + width: 164, + height: 47, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: const Color(0xFFEAEFFF), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)), + ), + child: Row( + children: [ + FloatingActionButton.small( + onPressed: () { + if(current>1){ + setState(() { + current--; + }); + } + + }, + shape: CircleBorder(), + elevation: 0, + backgroundColor: Colors.white, + child: Icon(CupertinoIcons.arrow_left, color: AppColor.blueNormal), + ), + Expanded( + child: Text( + '$current از $total', + textAlign: TextAlign.center, + textDirection: TextDirection.rtl, + style: AppFonts.yekan16Regular.copyWith( + color: AppColor.blueNormal, + ), + ), + ), + FloatingActionButton.small( + + onPressed:() { + if (current < total) { + setState(() { + current++; + }); + } + }, + shape: CircleBorder(), + elevation: 0, + backgroundColor: AppColor.blueNormal, + child: Icon(CupertinoIcons.arrow_right, color: Colors.white), + ), + ], + ), + ); + } + + Stack buildStack() { + return Stack( + children: [ + Positioned( + left: 4, + top: 4, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 40, + top: 40, + child: Container( + transform: + Matrix4.identity() + ..translate(0.0, 0.0) + ..rotateZ(-3.14), + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: + Colors.white /* Secondary */, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1, + color: + Colors + .white /* Secondary */, + ), + borderRadius: + BorderRadius.circular(50), + ), + ), + child: Stack(), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + Positioned( + left: 8, + top: 8, + child: Container(width: 24, height: 24, child: Stack()), + ), + ], + ), + ), + ), + Positioned( + left: 120, + top: 3, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 40, + top: 40, + child: Container( + transform: + Matrix4.identity() + ..translate(0.0, 0.0) + ..rotateZ(-3.14), + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: const Color( + 0xFF2D5FFF, + ) /* Primary */, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1, + color: const Color( + 0xFF2D5FFF, + ) /* Primary */, + ), + borderRadius: + BorderRadius.circular(50), + ), + ), + child: Stack(), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + Positioned( + left: 8, + top: 8, + child: Container(width: 24, height: 24, child: Stack()), + ), + ], + ), + ), + ), + Positioned( + left: 63, + top: 9, + child: Text( + '1 از 17', + style: TextStyle( + color: const Color(0xFF2D5FFF) /* Primary */, + fontSize: 16, + fontFamily: 'IRANYekanFN', + fontWeight: FontWeight.w400, + height: 1.75, + ), + ), + ), + ], + ); + } +} diff --git a/lib/presentation/widget/pagination/show_more.dart b/lib/presentation/widget/pagination/show_more.dart new file mode 100644 index 0000000..36fb207 --- /dev/null +++ b/lib/presentation/widget/pagination/show_more.dart @@ -0,0 +1,78 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +class RShowMore extends StatefulWidget { + const RShowMore({super.key}); + + @override + State createState() => _RShowMoreState(); +} + +class _RShowMoreState extends State + with SingleTickerProviderStateMixin { + bool _toggled = false; + late final AnimationController _controller; + late final Animation _iconRotation; + + @override + void initState() { + super.initState(); + + _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 500), + ); + _iconRotation = Tween( + begin: 0, + end: 0.50, + ) // 90 degrees (quarter turn) + .animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut)); + } + + void _toggle() { + setState(() => _toggled = !_toggled); + _toggled ? _controller.forward() : _controller.reverse(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: _toggle, + behavior: HitTestBehavior.opaque, + child: Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + RotationTransition( + turns: _iconRotation, + child: const Icon(CupertinoIcons.chevron_down, size: 12,color:AppColor.blueNormal ,), + ), + + AnimatedSwitcher( + duration: const Duration(milliseconds: 500), + transitionBuilder: + (child, animation) => + FadeTransition(opacity: animation, child: child), + child: Text( + _toggled ? 'کمتر' : 'مشاهده بیشتر', + key: ValueKey(_toggled), + style: AppFonts.yekan10Regular.copyWith(color: AppColor.blueNormal), + ), + ), + SizedBox(height: 50,) + ], + + + + ), + ); + } +} diff --git a/lib/presentation/widget/tabs/new_tab.dart b/lib/presentation/widget/tabs/new_tab.dart new file mode 100644 index 0000000..c6e73c4 --- /dev/null +++ b/lib/presentation/widget/tabs/new_tab.dart @@ -0,0 +1,784 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// @docImport 'switch.dart'; +library; + +import 'dart:collection'; +import 'dart:math' as math; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; + +// Minimum padding from edges of the segmented control to edges of +// encompassing widget. +const EdgeInsetsGeometry _kHorizontalItemPadding = EdgeInsets.symmetric( + horizontal: 16.0, +); + +// Minimum height of the segmented control. +const double _kMinSegmentedControlHeight = 28.0; + +// The default color used for the text of the disabled segment. +const Color _kDisableTextColor = Color.fromARGB(115, 122, 122, 122); + +// The duration of the fade animation used to transition when a new widget +// is selected. +const Duration _kFadeDuration = Duration(milliseconds: 165); + +class NewCupertinoSegmentedControl extends StatefulWidget { + /// Creates an iOS-style segmented control bar. + /// + /// The [children] argument must be an ordered [Map] such as a + /// [LinkedHashMap]. Further, the length of the [children] list must be + /// greater than one. + /// + /// Each widget value in the map of [children] must have an associated key + /// that uniquely identifies this widget. This key is what will be returned + /// in the [onValueChanged] callback when a new value from the [children] map + /// is selected. + /// + /// The [groupValue] is the currently selected value for the segmented control. + /// If no [groupValue] is provided, or the [groupValue] is null, no widget will + /// appear as selected. The [groupValue] must be either null or one of the keys + /// in the [children] map. + NewCupertinoSegmentedControl({ + super.key, + required this.children, + required this.onValueChanged, + this.groupValue, + this.unselectedColor, + this.selectedColor, + this.borderColor, + this.pressedColor, + this.disabledColor, + this.disabledTextColor, + this.padding, + this.disabledChildren = const {}, + }) : assert(children.length >= 2), + assert( + groupValue == null || + children.keys.any((T child) => child == groupValue), + 'The groupValue must be either null or one of the keys in the children map.', + ); + + /// The identifying keys and corresponding widget values in the + /// segmented control. + /// + /// The map must have more than one entry. + /// This attribute must be an ordered [Map] such as a [LinkedHashMap]. + final Map children; + + /// The identifier of the widget that is currently selected. + /// + /// This must be one of the keys in the [Map] of [children]. + /// If this attribute is null, no widget will be initially selected. + final T? groupValue; + + /// The callback that is called when a new option is tapped. + /// + /// The segmented control passes the newly selected widget's associated key + /// to the callback but does not actually change state until the parent + /// widget rebuilds the segmented control with the new [groupValue]. + final ValueChanged onValueChanged; + + /// The color used to fill the backgrounds of unselected widgets and as the + /// text color of the selected widget. + /// + /// Defaults to [CupertinoTheme]'s `primaryContrastingColor` if null. + final Color? unselectedColor; + + /// The color used to fill the background of the selected widget and as the text + /// color of unselected widgets. + /// + /// Defaults to [CupertinoTheme]'s `primaryColor` if null. + final Color? selectedColor; + + /// The color used as the border around each widget. + /// + /// Defaults to [CupertinoTheme]'s `primaryColor` if null. + final Color? borderColor; + + /// The color used to fill the background of the widget the user is + /// temporarily interacting with through a long press or drag. + /// + /// Defaults to the selectedColor at 20% opacity if null. + final Color? pressedColor; + + /// The color used to fill the background of the segment when it is disabled. + /// + /// If null, this color will be 50% opacity of the [selectedColor] when + /// the segment is selected. If the segment is unselected, this color will be + /// set to [unselectedColor]. + final Color? disabledColor; + + /// The color used for the text of the segment when it is disabled. + final Color? disabledTextColor; + + /// The CupertinoSegmentedControl will be placed inside this padding. + /// + /// Defaults to EdgeInsets.symmetric(horizontal: 16.0) + final EdgeInsetsGeometry? padding; + + /// The set of identifying keys that correspond to the segments that should be disabled. + /// + /// All segments are enabled by default. + final Set disabledChildren; + + @override + State> createState() => + _SegmentedControlState(); +} + +class _SegmentedControlState + extends State> + with TickerProviderStateMixin> { + T? _pressedKey; + + final List _selectionControllers = + []; + final List _childTweens = []; + + late ColorTween _forwardBackgroundColorTween; + late ColorTween _reverseBackgroundColorTween; + late ColorTween _textColorTween; + + Color? _selectedColor; + Color? _unselectedColor; + Color? _borderColor; + Color? _pressedColor; + Color? _selectedDisabledColor; + Color? _unselectedDisabledColor; + Color? _disabledTextColor; + + AnimationController createAnimationController() { + return AnimationController(duration: _kFadeDuration, vsync: this) + ..addListener(() { + setState(() { + // State of background/text colors has changed + }); + }); + } + + bool _updateColors() { + assert(mounted, 'This should only be called after didUpdateDependencies'); + bool changed = false; + final Color disabledTextColor = + widget.disabledTextColor ?? _kDisableTextColor; + if (_disabledTextColor != disabledTextColor) { + changed = true; + _disabledTextColor = disabledTextColor; + } + final Color selectedColor = + widget.selectedColor ?? CupertinoTheme.of(context).primaryColor; + if (_selectedColor != selectedColor) { + changed = true; + _selectedColor = selectedColor; + } + final Color unselectedColor = + widget.unselectedColor ?? + CupertinoTheme.of(context).primaryContrastingColor; + if (_unselectedColor != unselectedColor) { + changed = true; + _unselectedColor = unselectedColor; + } + final Color selectedDisabledColor = + widget.disabledColor ?? selectedColor.withOpacity(0.5); + final Color unselectedDisabledColor = + widget.disabledColor ?? unselectedColor; + if (_selectedDisabledColor != selectedDisabledColor || + _unselectedDisabledColor != unselectedDisabledColor) { + changed = true; + _selectedDisabledColor = selectedDisabledColor; + _unselectedDisabledColor = unselectedDisabledColor; + } + final Color borderColor = + widget.borderColor ?? CupertinoTheme.of(context).primaryColor; + if (_borderColor != borderColor) { + changed = true; + _borderColor = borderColor; + } + final Color pressedColor = + widget.pressedColor ?? + CupertinoTheme.of(context).primaryColor.withOpacity(0.2); + if (_pressedColor != pressedColor) { + changed = true; + _pressedColor = pressedColor; + } + + _forwardBackgroundColorTween = ColorTween( + begin: _pressedColor, + end: _selectedColor, + ); + _reverseBackgroundColorTween = ColorTween( + begin: _unselectedColor, + end: _selectedColor, + ); + _textColorTween = ColorTween(begin: _selectedColor, end: _unselectedColor); + return changed; + } + + void _updateAnimationControllers() { + assert(mounted, 'This should only be called after didUpdateDependencies'); + for (final AnimationController controller in _selectionControllers) { + controller.dispose(); + } + _selectionControllers.clear(); + _childTweens.clear(); + + for (final T key in widget.children.keys) { + final AnimationController animationController = + createAnimationController(); + if (widget.groupValue == key) { + _childTweens.add(_reverseBackgroundColorTween); + animationController.value = 1.0; + } else { + _childTweens.add(_forwardBackgroundColorTween); + } + _selectionControllers.add(animationController); + } + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + if (_updateColors()) { + _updateAnimationControllers(); + } + } + + @override + void didUpdateWidget(NewCupertinoSegmentedControl oldWidget) { + super.didUpdateWidget(oldWidget); + + if (_updateColors() || + oldWidget.children.length != widget.children.length) { + _updateAnimationControllers(); + } + + if (oldWidget.groupValue != widget.groupValue) { + int index = 0; + for (final T key in widget.children.keys) { + if (widget.groupValue == key) { + _childTweens[index] = _forwardBackgroundColorTween; + _selectionControllers[index].forward(); + } else { + _childTweens[index] = _reverseBackgroundColorTween; + _selectionControllers[index].reverse(); + } + index += 1; + } + } + } + + @override + void dispose() { + for (final AnimationController animationController + in _selectionControllers) { + animationController.dispose(); + } + super.dispose(); + } + + void _onTapDown(T currentKey) { + if (_pressedKey == null && currentKey != widget.groupValue) { + setState(() { + _pressedKey = currentKey; + }); + } + } + + void _onTapCancel() { + setState(() { + _pressedKey = null; + }); + } + + void _onTap(T currentKey) { + if (currentKey != _pressedKey) { + return; + } + if (!widget.disabledChildren.contains(currentKey)) { + if (currentKey != widget.groupValue) { + widget.onValueChanged(currentKey); + } + } + _pressedKey = null; + } + + Color? getTextColor(int index, T currentKey) { + if (widget.disabledChildren.contains(currentKey)) { + return _disabledTextColor; + } + if (_selectionControllers[index].isAnimating) { + return _textColorTween.evaluate(_selectionControllers[index]); + } + if (widget.groupValue == currentKey) { + return _unselectedColor; + } + return _selectedColor; + } + + Color? getBackgroundColor(int index, T currentKey) { + if (widget.disabledChildren.contains(currentKey)) { + return widget.groupValue == currentKey + ? _selectedDisabledColor + : _unselectedDisabledColor; + } + if (_selectionControllers[index].isAnimating) { + return _childTweens[index].evaluate(_selectionControllers[index]); + } + if (widget.groupValue == currentKey) { + return _selectedColor; + } + if (_pressedKey == currentKey) { + return _pressedColor; + } + return _unselectedColor; + } + + @override + Widget build(BuildContext context) { + final List gestureChildren = []; + final List backgroundColors = []; + int index = 0; + int? selectedIndex; + int? pressedIndex; + for (final T currentKey in widget.children.keys) { + selectedIndex = (widget.groupValue == currentKey) ? index : selectedIndex; + pressedIndex = (_pressedKey == currentKey) ? index : pressedIndex; + + final TextStyle textStyle = DefaultTextStyle.of( + context, + ).style.copyWith(color: getTextColor(index, currentKey)); + final IconThemeData iconTheme = IconThemeData( + color: getTextColor(index, currentKey), + ); + + Widget child = Center(child: widget.children[currentKey]); + + child = MouseRegion( + cursor: kIsWeb ? SystemMouseCursors.click : MouseCursor.defer, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: + widget.disabledChildren.contains(currentKey) + ? null + : (TapDownDetails event) { + _onTapDown(currentKey); + }, + onTapCancel: + widget.disabledChildren.contains(currentKey) + ? null + : _onTapCancel, + onTap: () { + _onTap(currentKey); + }, + child: IconTheme( + data: iconTheme, + child: DefaultTextStyle( + style: textStyle, + child: Semantics( + button: true, + inMutuallyExclusiveGroup: true, + selected: widget.groupValue == currentKey, + child: child, + ), + ), + ), + ), + ); + + backgroundColors.add(getBackgroundColor(index, currentKey)!); + gestureChildren.add(child); + index += 1; + } + + final Widget box = _SegmentedControlRenderWidget( + selectedIndex: selectedIndex, + pressedIndex: pressedIndex, + backgroundColors: backgroundColors, + borderColor: _borderColor!, + children: gestureChildren, + ); + + return Padding( + padding: widget.padding ?? _kHorizontalItemPadding, + child: UnconstrainedBox(constrainedAxis: Axis.horizontal, child: box), + ); + } +} + +class _SegmentedControlRenderWidget extends MultiChildRenderObjectWidget { + const _SegmentedControlRenderWidget({ + super.key, + super.children, + required this.selectedIndex, + required this.pressedIndex, + required this.backgroundColors, + required this.borderColor, + }); + + final int? selectedIndex; + final int? pressedIndex; + final List backgroundColors; + final Color borderColor; + + @override + RenderObject createRenderObject(BuildContext context) { + return _RenderSegmentedControl( + textDirection: Directionality.of(context), + selectedIndex: selectedIndex, + pressedIndex: pressedIndex, + backgroundColors: backgroundColors, + borderColor: borderColor, + ); + } + + @override + void updateRenderObject( + BuildContext context, + _RenderSegmentedControl renderObject, + ) { + renderObject + ..textDirection = Directionality.of(context) + ..selectedIndex = selectedIndex + ..pressedIndex = pressedIndex + ..backgroundColors = backgroundColors + ..borderColor = borderColor; + } +} + +class _SegmentedControlContainerBoxParentData + extends ContainerBoxParentData { + RRect? surroundingRect; +} + +typedef _NextChild = RenderBox? Function(RenderBox child); + +class _RenderSegmentedControl extends RenderBox + with + ContainerRenderObjectMixin< + RenderBox, + ContainerBoxParentData + >, + RenderBoxContainerDefaultsMixin< + RenderBox, + ContainerBoxParentData + > { + _RenderSegmentedControl({ + required int? selectedIndex, + required int? pressedIndex, + required TextDirection textDirection, + required List backgroundColors, + required Color borderColor, + }) : _textDirection = textDirection, + _selectedIndex = selectedIndex, + _pressedIndex = pressedIndex, + _backgroundColors = backgroundColors, + _borderColor = borderColor; + + int? get selectedIndex => _selectedIndex; + int? _selectedIndex; + + set selectedIndex(int? value) { + if (_selectedIndex == value) { + return; + } + _selectedIndex = value; + markNeedsPaint(); + } + + int? get pressedIndex => _pressedIndex; + int? _pressedIndex; + + set pressedIndex(int? value) { + if (_pressedIndex == value) { + return; + } + _pressedIndex = value; + markNeedsPaint(); + } + + TextDirection get textDirection => _textDirection; + TextDirection _textDirection; + + set textDirection(TextDirection value) { + if (_textDirection == value) { + return; + } + _textDirection = value; + markNeedsLayout(); + } + + List get backgroundColors => _backgroundColors; + List _backgroundColors; + + set backgroundColors(List value) { + if (_backgroundColors == value) { + return; + } + _backgroundColors = value; + markNeedsPaint(); + } + + Color get borderColor => _borderColor; + Color _borderColor; + + set borderColor(Color value) { + if (_borderColor == value) { + return; + } + _borderColor = value; + markNeedsPaint(); + } + + @override + double computeMinIntrinsicWidth(double height) { + RenderBox? child = firstChild; + double minWidth = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final double childWidth = child.getMinIntrinsicWidth(height); + minWidth = math.max(minWidth, childWidth); + child = childParentData.nextSibling; + } + return minWidth * childCount; + } + + @override + double computeMaxIntrinsicWidth(double height) { + RenderBox? child = firstChild; + double maxWidth = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final double childWidth = child.getMaxIntrinsicWidth(height); + maxWidth = math.max(maxWidth, childWidth); + child = childParentData.nextSibling; + } + return maxWidth * childCount; + } + + @override + double computeMinIntrinsicHeight(double width) { + RenderBox? child = firstChild; + double minHeight = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final double childHeight = child.getMinIntrinsicHeight(width); + minHeight = math.max(minHeight, childHeight); + child = childParentData.nextSibling; + } + return minHeight; + } + + @override + double computeMaxIntrinsicHeight(double width) { + RenderBox? child = firstChild; + double maxHeight = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final double childHeight = child.getMaxIntrinsicHeight(width); + maxHeight = math.max(maxHeight, childHeight); + child = childParentData.nextSibling; + } + return maxHeight; + } + + @override + double? computeDistanceToActualBaseline(TextBaseline baseline) { + return defaultComputeDistanceToHighestActualBaseline(baseline); + } + + @override + void setupParentData(RenderBox child) { + if (child.parentData is! _SegmentedControlContainerBoxParentData) { + child.parentData = _SegmentedControlContainerBoxParentData(); + } + } + + void _layoutRects( + _NextChild nextChild, + RenderBox? leftChild, + RenderBox? rightChild, + ) { + RenderBox? child = leftChild; + double start = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final Offset childOffset = Offset(start, 0.0); + childParentData.offset = childOffset; + final Rect childRect = Rect.fromLTWH( + start, + 0.0, + child.size.width, + child.size.height, + ); + final RRect rChildRect; + if (child == leftChild) { + rChildRect = RRect.fromRectAndCorners( + childRect, + topLeft: const Radius.circular(10.0), + bottomLeft: const Radius.circular(10.0), + ); + } else if (child == rightChild) { + rChildRect = RRect.fromRectAndCorners( + childRect, + topRight: const Radius.circular(10.0), + bottomRight: const Radius.circular(10.0), + ); + } else { + rChildRect = RRect.fromRectAndCorners(childRect); + } + childParentData.surroundingRect = rChildRect; + start += child.size.width; + child = nextChild(child); + } + } + + Size _calculateChildSize(BoxConstraints constraints) { + double maxHeight = _kMinSegmentedControlHeight; + double childWidth = constraints.minWidth / childCount; + RenderBox? child = firstChild; + while (child != null) { + childWidth = math.max( + childWidth, + child.getMaxIntrinsicWidth(double.infinity), + ); + child = childAfter(child); + } + childWidth = math.min(childWidth, constraints.maxWidth / childCount); + child = firstChild; + while (child != null) { + final double boxHeight = child.getMaxIntrinsicHeight(childWidth); + maxHeight = math.max(maxHeight, boxHeight); + child = childAfter(child); + } + return Size(childWidth, maxHeight); + } + + Size _computeOverallSizeFromChildSize(Size childSize) { + return constraints.constrain( + Size(childSize.width * childCount, childSize.height), + ); + } + + @override + double? computeDryBaseline( + covariant BoxConstraints constraints, + TextBaseline baseline, + ) { + final Size childSize = _calculateChildSize(constraints); + final BoxConstraints childConstraints = BoxConstraints.tight(childSize); + + BaselineOffset baselineOffset = BaselineOffset.noBaseline; + for ( + RenderBox? child = firstChild; + child != null; + child = childAfter(child) + ) { + baselineOffset = baselineOffset.minOf( + BaselineOffset(child.getDryBaseline(childConstraints, baseline)), + ); + } + return baselineOffset.offset; + } + + @override + Size computeDryLayout(BoxConstraints constraints) { + final Size childSize = _calculateChildSize(constraints); + return _computeOverallSizeFromChildSize(childSize); + } + + @override + void performLayout() { + final BoxConstraints constraints = this.constraints; + final Size childSize = _calculateChildSize(constraints); + + final BoxConstraints childConstraints = BoxConstraints.tightFor( + width: childSize.width, + height: childSize.height, + ); + + RenderBox? child = firstChild; + while (child != null) { + child.layout(childConstraints, parentUsesSize: true); + child = childAfter(child); + } + + switch (textDirection) { + case TextDirection.rtl: + _layoutRects(childBefore, lastChild, firstChild); + case TextDirection.ltr: + _layoutRects(childAfter, firstChild, lastChild); + } + + size = _computeOverallSizeFromChildSize(childSize); + } + + @override + void paint(PaintingContext context, Offset offset) { + RenderBox? child = firstChild; + int index = 0; + while (child != null) { + _paintChild(context, offset, child, index); + child = childAfter(child); + index += 1; + } + } + + void _paintChild( + PaintingContext context, + Offset offset, + RenderBox child, + int childIndex, + ) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + + context.canvas.drawRRect( + childParentData.surroundingRect!.shift(offset), + Paint() + ..color = backgroundColors[childIndex] + ..style = PaintingStyle.fill, + ); + context.canvas.drawRRect( + childParentData.surroundingRect!.shift(offset), + Paint() + ..color = borderColor + ..strokeWidth = 1.0 + ..style = PaintingStyle.stroke, + ); + + context.paintChild(child, childParentData.offset + offset); + } + + @override + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { + RenderBox? child = lastChild; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + if (childParentData.surroundingRect!.contains(position)) { + return result.addWithPaintOffset( + offset: childParentData.offset, + position: position, + hitTest: (BoxHitTestResult result, Offset localOffset) { + assert(localOffset == position - childParentData.offset); + return child!.hitTest(result, position: localOffset); + }, + ); + } + child = childParentData.previousSibling; + } + return false; + } +} diff --git a/lib/presentation/widget/tabs/tab.dart b/lib/presentation/widget/tabs/tab.dart new file mode 100644 index 0000000..ac2f735 --- /dev/null +++ b/lib/presentation/widget/tabs/tab.dart @@ -0,0 +1,115 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +import 'new_tab.dart'; + +class CupertinoSegmentedControlDemo extends StatefulWidget { + const CupertinoSegmentedControlDemo({super.key}); + + @override + State createState() => + _CupertinoSegmentedControlDemoState(); +} + +class _CupertinoSegmentedControlDemoState + extends State { + int _selectedSegment = 0; + + // The data for the segments + final Map _segments = const { + 0: Text('Segment 1'), + 1: Text('Segment 2'), + 2: Text('Segment 3'), + }; + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CupertinoSlidingSegmentedControl( + children: _segments, + groupValue: _selectedSegment, + + onValueChanged: (int? value) { + setState(() { + _selectedSegment = value!; + }); + }, + ), + const SizedBox(height: 20), + Text( + 'Selected Segment: ${_selectedSegment + 1}', + style: const TextStyle(fontSize: 24), + ), + ], + ), + ); + } +} + +class CupertinoSegmentedControlDemo2 extends StatefulWidget { + const CupertinoSegmentedControlDemo2({super.key}); + + @override + State createState() => + _CupertinoSegmentedControlDemoState2(); +} + +class _CupertinoSegmentedControlDemoState2 + extends State { + int _selectedSegment = 0; + + // The data for the segments + final Map _segments = { + 0:Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50) + ), + child: Text('لاشه', style: AppFonts.yekan13Regular), + ), + 1: Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50) + ), + child: Text('زنده', style: AppFonts.yekan13Regular), + ), + }; + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + NewCupertinoSegmentedControl( + padding: EdgeInsetsDirectional.symmetric( + horizontal: 20, + vertical: 10, + ), + children: _segments, + groupValue: _selectedSegment, + selectedColor: AppColor.blueNormal, + unselectedColor: Colors.white, + borderColor: Colors.grey.shade300, + onValueChanged: (int value) { + setState(() { + _selectedSegment = value; + }); + }, + ), + const SizedBox(height: 20), + Text( + 'Selected Segment: ${_selectedSegment + 1}', + style: const TextStyle(fontSize: 24), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/widget/vec_widget.dart b/lib/presentation/widget/vec_widget.dart new file mode 100644 index 0000000..8f76b40 --- /dev/null +++ b/lib/presentation/widget/vec_widget.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:vector_graphics/vector_graphics.dart'; + +SvgPicture vecWidget( + String assets, { + double? width, + double? height, + BoxFit? fit, + Color? color, +}) { + return SvgPicture( + AssetBytesLoader(assets), + width: width, + height: height, + fit: fit ?? BoxFit.contain, + colorFilter: + color != null ? ColorFilter.mode(color, BlendMode.srcIn) : null, + ); +} +Widget vecWidget2( + String assets, { + double? width, + double? height, + BoxFit? fit, + Color? color, + }) { + final resolvedColor = WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return Colors.white; + } + return color; + }).resolve({}); // You can pass actual states if needed + + return IconTheme( + data: IconThemeData(color: resolvedColor), + child: SvgPicture( + AssetBytesLoader(assets), + width: width, + height: height, + fit: fit ?? BoxFit.contain, + colorFilter: resolvedColor != null + ? ColorFilter.mode(resolvedColor, BlendMode.srcIn) + : null, + ), + ); +} diff --git a/pubspec.yaml b/pubspec.yaml index bb74dfd..52bb4ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,34 +58,14 @@ dev_dependencies: flutter: uses-material-design: true - # To add assets to your application, add an assets section, like this: + assets: - assets/icons/ - assets/images/ - assets/logos/ + - assets/vec/ - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package + fonts: + - family: yekan + fonts: + - asset: fonts/iranyekanregularfanum.ttf diff --git a/vecGeneratoe.sh b/vecGeneratoe.sh new file mode 100644 index 0000000..4f92558 --- /dev/null +++ b/vecGeneratoe.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Directory to read files from +sourcePath="assets/icons" +targetPath="assets/vec" + + +if [ ! -e "$targetPath" ]; then + echo "📁 Directory does not exist. Creating: $targetPath" + mkdir -p "$targetPath" +fi + + +# Loop and delete old vec file +for file in "$targetPath"/* +do + if [ -f "$file" ]; then + + echo "Delete old ===> $file" + rm "$file" + fi +done +# Loop through all files in the directory +for file in "$sourcePath"/* +do + if [ -f "$file" ]; then + echo "Generate Vec file ===> $file" + fileName=$(basename -- "$file") + echo "Generate Vec file ===> $fileName" + dart run vector_graphics_compiler -i "$file" -o "$targetPath/$fileName.vec" + git add . + fi +done \ No newline at end of file