From d5bd9fa54d31e85f8508be27981d15289cfad7a9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 13 Mar 2020 10:56:03 +0400 Subject: [PATCH] View filter box, removing chats and chat types. --- .../Resources/icons/filters_type_archived.png | Bin 0 -> 528 bytes .../icons/filters_type_archived@2x.png | Bin 0 -> 1052 bytes .../icons/filters_type_archived@3x.png | Bin 0 -> 1576 bytes .../Resources/icons/filters_type_bots.png | Bin 0 -> 503 bytes .../Resources/icons/filters_type_bots@2x.png | Bin 0 -> 1077 bytes .../Resources/icons/filters_type_bots@3x.png | Bin 0 -> 1712 bytes .../Resources/icons/filters_type_channels.png | Bin 0 -> 454 bytes .../icons/filters_type_channels@2x.png | Bin 0 -> 913 bytes .../icons/filters_type_channels@3x.png | Bin 0 -> 1402 bytes .../Resources/icons/filters_type_contacts.png | Bin 0 -> 372 bytes .../icons/filters_type_contacts@2x.png | Bin 0 -> 699 bytes .../icons/filters_type_contacts@3x.png | Bin 0 -> 1223 bytes .../Resources/icons/filters_type_groups.png | Bin 0 -> 508 bytes .../icons/filters_type_groups@2x.png | Bin 0 -> 984 bytes .../icons/filters_type_groups@3x.png | Bin 0 -> 1712 bytes .../Resources/icons/filters_type_muted.png | Bin 0 -> 576 bytes .../Resources/icons/filters_type_muted@2x.png | Bin 0 -> 1318 bytes .../Resources/icons/filters_type_muted@3x.png | Bin 0 -> 2101 bytes .../icons/filters_type_noncontacts.png | Bin 0 -> 573 bytes .../icons/filters_type_noncontacts@2x.png | Bin 0 -> 1252 bytes .../icons/filters_type_noncontacts@3x.png | Bin 0 -> 1951 bytes .../Resources/icons/filters_type_read.png | Bin 0 -> 672 bytes .../Resources/icons/filters_type_read@2x.png | Bin 0 -> 1420 bytes .../Resources/icons/filters_type_read@3x.png | Bin 0 -> 2180 bytes Telegram/Resources/langs/lang.strings | 20 +- .../SourceFiles/boxes/manage_filters_box.cpp | 510 ++++++++++++++++-- .../SourceFiles/boxes/manage_filters_box.h | 7 +- .../SourceFiles/data/data_chat_filters.cpp | 16 +- Telegram/SourceFiles/data/data_chat_filters.h | 15 +- Telegram/SourceFiles/storage/localstorage.cpp | 8 - Telegram/SourceFiles/window/window.style | 17 + .../SourceFiles/window/window_controller.cpp | 5 + .../SourceFiles/window/window_controller.h | 1 + .../window/window_filters_menu.cpp | 6 +- 34 files changed, 540 insertions(+), 65 deletions(-) create mode 100644 Telegram/Resources/icons/filters_type_archived.png create mode 100644 Telegram/Resources/icons/filters_type_archived@2x.png create mode 100644 Telegram/Resources/icons/filters_type_archived@3x.png create mode 100644 Telegram/Resources/icons/filters_type_bots.png create mode 100644 Telegram/Resources/icons/filters_type_bots@2x.png create mode 100644 Telegram/Resources/icons/filters_type_bots@3x.png create mode 100644 Telegram/Resources/icons/filters_type_channels.png create mode 100644 Telegram/Resources/icons/filters_type_channels@2x.png create mode 100644 Telegram/Resources/icons/filters_type_channels@3x.png create mode 100644 Telegram/Resources/icons/filters_type_contacts.png create mode 100644 Telegram/Resources/icons/filters_type_contacts@2x.png create mode 100644 Telegram/Resources/icons/filters_type_contacts@3x.png create mode 100644 Telegram/Resources/icons/filters_type_groups.png create mode 100644 Telegram/Resources/icons/filters_type_groups@2x.png create mode 100644 Telegram/Resources/icons/filters_type_groups@3x.png create mode 100644 Telegram/Resources/icons/filters_type_muted.png create mode 100644 Telegram/Resources/icons/filters_type_muted@2x.png create mode 100644 Telegram/Resources/icons/filters_type_muted@3x.png create mode 100644 Telegram/Resources/icons/filters_type_noncontacts.png create mode 100644 Telegram/Resources/icons/filters_type_noncontacts@2x.png create mode 100644 Telegram/Resources/icons/filters_type_noncontacts@3x.png create mode 100644 Telegram/Resources/icons/filters_type_read.png create mode 100644 Telegram/Resources/icons/filters_type_read@2x.png create mode 100644 Telegram/Resources/icons/filters_type_read@3x.png diff --git a/Telegram/Resources/icons/filters_type_archived.png b/Telegram/Resources/icons/filters_type_archived.png new file mode 100644 index 0000000000000000000000000000000000000000..790d50335ecfb394b84a8e2c2aa962bbd4c80447 GIT binary patch literal 528 zcmV+r0`L8aP)4`0aERVsgS9Vssbvz zIYYiyC?1caQmJ4x8euw}Vm6y$KA&T;SYWwaVzpXfyGV(!1OjL@8b~A($Ye4Y3Sd_keZp=|sNInr*oSu&ZtwqP*m%q86(Z#J8b zKPfsnZa!)la&*i2d}ifxS(>C!D6qrf;GQD&eE{kmh%#L+7shYxyF~eXp7DE1fT7NV z#Imv1fb5LbYSjsx&1Ttdx3f*c_hUemwN|S!g5mF%0O9WV4m2K*-SIu?G}m{aQmNz# z!tGov7X1gJ6;fa?l_Fn{FiiU`<3Jygw{L2{DGiXSqNYNoLaGX=?B)!qD)bNWOsL-n SFtK3(0000!lvNA9*U-ooy z45?szJJZ_3*iqoPx?|v?4CM}vE*F6{thra*e1vt5TngK`Y1@XYZX3kbjbuuIc}3^Nqfg$x&7Co0Mni;7*jK^+%-jv+BckkYzn>QtEYHJ-e!_AKtz_yScckN-9LXh48mz;Z~|MKO_Oyh0;Up{!iFzMuy;vK1z z(uExhN=jHJPoC_zJ*7H3+xt?><>?wK0#anL)#%F~{oj87+ea)IR47&VW zm!CdOeV7{f@6{`=Gi7dpGjHB%*t*s9#fujjTKu1!O0wcID?k4H*|~V};?mnva&q79 zMjI`7wJq>cdrtdQhCs`;?|^}pU6zoM!67dv_s8eTopR18hw7x*J8X?W zUmxDR+ghwATG6QCgyJpUIrHbQ=UBOYyLf(HUd;Wq=O!|_$X&kQ+1lD_soy~ zti)&O2}Y&k_4W0Im6bP(*X`ady?*`r+?gU*yHymfJOAo;i`O=GEa_fl=glm1KX8ep z@!7J&9%)8g&$drqk@<0}#NU$~+N`O!tH1Romp;$b{P5>b%-6+%`OKRyj)zT zp(^|6&6_o!AFaKfdHdU!N$RtgJ{H(DjopQLF{8QCq!Vrp1sqid4J+cge(v3Co1U2{ z&AaVu#!jbN_Ae2Y7d8HgDnAPJdKAA=9~p>^o$H6B08WVY&8{u!C@%-_9S<5AXZ_^7-w3pZ9?SjSN>rDuO^D`1x~0$Ngme zCk4p9r}?_Q*$+8C0+j#))uchcGr%Aa_``W3!8uZ9g==wc%|@li@AOw2IVC7vj-UdC z(ovm!lHfuGk?;j%H^k?6^QT;i*!nMl7!0xAK?Q?hS=$VepipR+N1G(C>GsQOW_eW8 zyxF;4l)EX-;M?xz&bLsOFHAxA*%n*ZRwt1|d$L&wLXnmoyny${OgT>P9LyWwDCrnv z<5J-Iq`Ntn2aHWq5HieAiysK+`?}{Au5U=C$pr=4N(yqUJC2Ty%2N?OK6WW-Y1?XW zirMO$7sbW4hv4vDE?2Xqtqo%$+}?h|nSd@ao!uvZ>k&y~U z-q_o*vAva**zu8(S=7vdz5KKGdl?zZHBC)uVP9W3GA=Go@afYFhrbg(e0?%gS=YKF zl{S@DR;mI3aDY}aaT13+Qn9zQGwS*j^Hl5f!otGp+M08=jl8^kZF4h%I`;ZChjzrd ze{k?=fFqf7G$K;hd3szb5d3ziUo6hY7#glp?m>ve{<5-T`KF}^P0bX4zxr3n>*h(S zYHAmno5|UYjixM}&VLpMoOwJRsSg?mSvi4ZzB5Z@h{a+{#PIO2FZ1-3!t`|A(RG&> zb>-!KPFfT9WLGRIcs$wy2g9B*Ha0$d@xk}8_4NiCAvX4v`=v{7M`P&mzV6}S4Z(XP zGC4dvu7Xn{KAxX0<$2n<+z<+d)+rL!QOb({Afu|PO3%tlbTLDFePd(8U<7C<|D^{M zX*}o6reEOffIC8%D)ml!-2=OcIV^;U`uP9q4>>qFImyY*MGiL!haeMnU@uJ$w`omGJ z1Swr467lDodg|(M>i~mXJuuP%440NE@rtnx zp@X<9^cwboB_#o`rL{Gqq@;ug^bQVY_w@AC*a=D>CCswQvh~~>q0`pUksT;-dCRV?t)2b+Irz5Q$BI+&x%KVl zJHsbo2s|Dy?CvIs9QFq_H!wicwCZ>3k_q(4?!qr#r zEQU{YFHDRJKtik;rMH5D%6*O+Z!*2T0fAyrIreTt#qrMec_hSt)SodvH5IIg#$u_w zsw$5#z_wgYH*e9t=*&ctj7Lu7*!XyW!Y`*zx$r70FIIO(XUc(4i?!qOu>hzp_d7Z! zCMKLcBCsy&?)13DXWHjghi|dgzL~*f2LdCWIoF{92QT6Nu_V|*m4kd`Z@Rl>h<3FA z+t+9`x+M4Eadma|vo5K3&yi7lGK(_LI+YlW3yW|r^_B!4KdIqp1W4PKo zkyKeK-W(o?LrEVaPQu!!nc7=u23wJDco?-y*YGE_cMc&{FOy=}u8`BXX};lFTcv%j{pDw literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_bots.png b/Telegram/Resources/icons/filters_type_bots.png new file mode 100644 index 0000000000000000000000000000000000000000..34d2ed00a682157eb7fc616c1e2b70883a965067 GIT binary patch literal 503 zcmV^w{p^|&DW!S4uuX$9gzHCh6d}< zWHM3f^;%sn7j?Z}^}-p?;QNo^ufuyqQAEq-lA5NWE`tvkVEe>=VEx5_fJDZss-mJO zC`l4Z)0F1(IUSEjWV6|LV_#zV z3*w>GNv6}O7PQ@N35iX>_Wf)&(^znf-)9%UL!3lm!A7Hz-cP5K-d&f&;h^1ygBUE{ zMX^3-1-eYWFxnhxJRUnaz~*^w@og^7!g2#l)OOI_Zbw;`bq0oSzuz0`Q!#=ViXH&o z-Wx~N4*sT~Mejkv(>51pmx(jvA`jvFIzc~Dm33X)S9QPNRUG%L0UTI6j+C==IGOn5 zJD<;XP<;>Jyv7mkpOd=4i^alMhsA;8iuuOpF9>8LK-IU~%_e<4zz579#K=E;7V%N* tH=!Sp76eI64jl>|k~$#y!wg9s`UL`=rZ?kkAaMWy002ovPDHLkV1jDd=7RtL literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_bots@2x.png b/Telegram/Resources/icons/filters_type_bots@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1f37ff794076b3dba76f95df6c7732d0fae022cc GIT binary patch literal 1077 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!Ea{HEjtmSN`?>!lvNA9*zwvZ& z45?szJ7d3>iJ`!OVtM&RN@7Y?U9IIZ9Q#^0#Ig$icJe1Ark2|^t^LlRRFR|_aU<#n z$E}FY`hc7xP9man^*8T0t(Km*Y4+^D4r&{6CY}6qQh)Q!H`AsBEzsBGW2%?=d+D#Q z1B2j7g$5P@#|8m!Hco{m2E}PSLJlm9PCAk*4IE4@5k?*if-D>xQzkGdaR?-xRA6)w zP&hKlk*Pz$p+mKq!=awja&|>gQP9=brCayxS)((I9oCp@0K|M)TR?%lg9PoMTK zt*Kel*VnhmEZU$Y@lR&_jnK7WiS_mJ`}XZSu>C>A700_u$$!6v%FIdI%=!NP`+YH1 z$M){s%XmveLdbr>zkhWZ+i%MXpS#_-?LwO4f**`KAK2L19{l#r>_sidvSrH_tY6RH z*4DNlZ1urcue4-jWDXoZe!O4i;N${rvq8KYX|_S1C*U z%Z`t!0(q;x&HMc44-Yptw~BBPQ9>m=g#rO-VXDywrGyg?!6!O zvZ%0dVjkO7e}8}8zgzUfZQ7iUxe3%>_mcKrBhAdr+$L`;=n%VS!@6X%b$Oo-9(252 zv*>l#@on=L=CVz5G~_zfXL4=(@9N69gOj(##?(Fjx99rr@M*n@B1zNugCw2i)Tc3Jv@lqV*RbS*DXo*xbA$&dxVChE5w%*>}2|KG_F5-8y$e7JP;U8a@LSc%~ zEf i5;6^HZc}3T%iMED_v6Q2fl6RGz~JfX=d#Wzp$PzSH2Ew5 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_bots@3x.png b/Telegram/Resources/icons/filters_type_bots@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..afc773a3c86e54081e136405509a34b1adcc8371 GIT binary patch literal 1712 zcmd5-`!^E`93LxOk9p*k8%Yd#E=-KFv90A1x-+>m+f=w0CDtgJF?m~MYD$DWPF_C6<3} zd+wAt+Wu!-#qJFcQQ568ui8gFmM+gVx+RXjdX`vh%hfsm0nta7<$OF<8Ub>2BxfrE zBZ+-`Ou;wNhQR%c07$z>uc0ACIcG?yJ}=fB)16p2-5K^$zL@kO20^@ zsSp^TRt<(ry$A)yL;YvOc6?z2c)YRh&D!gHN33mr6S$@C%Fd zmb?Cf`E!a~E_W9U221c4!vJp?EzJmDi4Hj8cij}$k8*_g`ugI7s8lL%ak2K<9ut$W z*49@2$sWJvrlzrSH>iut$<@_W{Z7P}4YB9W+{p>)fv z`6wX)kogqUk-tz^XBiY8Zp=>b_V(`J_wg8?i&Q{FCnu+{i7VOJz)Zc}E;cqcZ^a*= zA?BbS8xXPMQs&IeOcy!i!iAQ$_VyqIFiyn_>CDjdo1@^2c9x8cjA&QVyNU`6V<_n; z^RZrKC5Jtb+uPf7 zlVWJ}q);{@>86>P9!KBs=YFbi zZpP0#JFS?X3JTO~pv7h5H`gxHbTlid_Z5wHjV!+#%@)aEi{1xub*2?V%STUZO$z0^ z5@wbW4|t`&YwC8NT;7zKA9i)cSq_%GzZc=|DGS|e>lnUvr-}m6)6=srF8j9Q2?2|( zDdvw?si_{rnV+4nAU&#N_{!t%{RZxcl%wkDU&CqjbV^c^H1E6DsNU#_H_wMUey-;l zr_Ms%C?CmppK~}9IL~H@C5>u zvpgR7%i3BbCLv~Qr=-#%0Q9cAn>{*uyt%E-s-vUBCn)F|x9!lK{M~Bprc2}F*I(0c z&p39|-xp~_`Dv}tWh!Vf@>7vL1~az#zA8VrlPR3?;W&X+X6r4D;YsX^0ZOO>(|bIAQ)kqU z^bZicswdQn)7<#mVVY7xm99~1S$TPwP$*2`_o^R)!8iifdD5|_8IY6}J?^b4yG=*# zS0%2jtbp;}g*{c;{npy$=qnTCn3$OQz@$QM)WqkBeNqnS%7VnPBm?or#L&4+PDd8dPmJ~VBcrP|-l8rT zNtLq68URrG4Uw4T3WhWZwcMMvBBAHQu3Q6LEBnd&X7up$=|Z| z**L4SG76xdV)(+5nocjhlx23EUfE5w&-fqr3!1p#UpXFN1X%up02pL|&qD+;<8Ox3 BE5#|) zQU2e0NY`}|1Od6-Zp3w6k&aoOJ+7NAP1C?}94N~YhPdDFYwB+&h8--5qCv-OUvX%h zAj2>qj$^2*3fi`PT3MEH7rL&S2^s!uF6ekX4z*wIjPzAt1t~p{ZttUM8ltM|TacnC zOwl5S}HibFAVjy z!Z73$`*1icVx~1Gzt;<5j?g!Xi(2_CV1%s~#7<+|HWWnxm&;}L$tEYokUwG2gOL(_ wCD7OYD{3f-6eMz5IwTzuIUvf*9uhh900^lm16mxMzyJUM07*qoM6N<$f!lvNA9*dw9Ay zhEy=Vo$2q*5LZT723LnY`>#DCD-+|c9Xl3$|6b1AcJ-vxytcPx0R|FF{FWyl zJ$&W=dxoo7rot_$vg;T{dfiqAt-NsgvT*P5Eo|oSqw!&>c{hJ7c5?^yxjD!MV$T@_d?I*a?4)@|MdFxU7) z4R0Sy3jAo3xUh`zYn5$*clpUvvR^)Yc%a9m5dE~F>!{L>rN2|2p8o8#a6`)4?xhzq zQl5mYzg~FY4oBntj?j{IHHRXbjvqf>QeN)eRQDISm(|-;!Anp|dUG@|!3f-Y+RR_3z%l57wJL`)%Hd z@9x*HU*EEQd%AUq&xT*mly=TlzPt6+o$RjowGZyAi1M|+{P%C( zlcoKhN-OaELUe-fC- O7(8A5T-G@yGywowJ_oK2){Ri^!mhJcx$a6_nl8iOHvR@_ePwa@Fth3 z%hP7gP5V8cTjmbkN1+mMcxN@_x^dxQSKs|h4qKr8i%|stvebGDjbZk`(zfeicu96n zPGU+*8JEkQ|NNQVFO@cQc8)({x z>%{=mmQ0}_L?V%=XD3e3^pO|u-o{1dWMpKh42FsKmIER~e}8dn4gbhxgRA7t;vy*7Ixs$3i^VCJ@&&W{iPsOR|yh2TiP=-!)q^neZi^Lt9LXVU;o9Jj!FiA{Y;@7R>8fjo}Fdq zLW1~wK37?Az&_--L9ahqQ&Uqv1fWd@~Vf_3!zjZayyPZA4l}hF4@GwrN({a-_ zKWa=Y5S)*h>#Y0pbjLQ!#4|6_tavgI=4$#8n=)-r@+dLm1U}2agS=_oe4T_jmq_H=x>cN9s z_Xro<+}+bEhBz9n_C|Jg_Ky!A7OJlU6P6h(DwUI#iOAY9^{lTiP=9Q=eJi^Jz%1L@ z*@Y)1!G%KMohrHwys5dle?X;K??kwe%33av$>ijNte>kBXf$?R$a3ChRC>L>gCSun z&P7LaDn#b$d4vIv-)&+7z5Oj>;G47M;0U6`0tSPr78gAyYM~!w_Mc|FJwN4f{AxcDrd#!<=seCvSj=aAVyHm0@qr3(%>B`5 z-I?yh*r`3`RbltR?#Stbfb!xU%KcXcI&LYhhnyprIT`oBzkZv?Qq<+h$nx8W055{Q zR4V0)>>aIgO(K8sfW!MnM=LtTV$=NPmY~$Z!9kqA&}dK8kbs`!;5zN(a=buZ3oE3q lQmhIAS@O02OeQjuRS0GKEI89`wR=;hppZZ!z8M!+^bfpAdQ$)Z literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_contacts.png b/Telegram/Resources/icons/filters_type_contacts.png new file mode 100644 index 0000000000000000000000000000000000000000..1cfb2a57518a49122229b5b16b35ddef4f0299e6 GIT binary patch literal 372 zcmV-)0gL{LP)R66F*`$EPQENB0aaD$cN_N|raVKQArk{8yYHc&W9S17nuYLC SAj7x-0000!lvNA9*6?wWi zhEy=VooU#2$Uwk#?$t03K1bJsiVh|wGMrrJ9R2y#8`@^IF|joDF*j(OtP=1P6sc=6 zl3Vh3+9Hf_6juFqW=myW&qH?Q#RgFElP+n8nU-D21#A~&JF^Lia;*9FgUwgit)2t4^v5YPA`Ltk_*m;4+Gu|XAs)dE}Ffplcaxna2 ztuojdwtDINs88$4cHeC}S|@&jC1CZ{qPc#@OLxa!&)Xim`KHf96?5$gea9Ey&N0i| z7_sAN(aUYObCuX_mq*X)UsWXQ8VL03-eUq zoJcU}DBm5M$l)q|YKBpnko(6q%pUt5o=gcU*(bk!vc##pON=H`y>|0TZuT917;xFs zs^L$*UF!3nh1H!)zjmzLoAu-7uWG*VKgr94dODR3tYXX98r68=>d9FfugGnDwJhIy t(yZp3<)N`9OiVhQ#Kk4H=x4Yf-`cuzN4&z$IACgI@O1TaS?83{1ONkrB3%Fg literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_contacts@3x.png b/Telegram/Resources/icons/filters_type_contacts@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f3ac2f12a2609356cf61050b4109bbc14bf19008 GIT binary patch literal 1223 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz1|<8_!p{OJmUKs7M+SzC{oH>NS%KU-PZ!6K z3dXmy?e$FpMUI`{=kaH4hK35)!o>@O*19?F-}{5XuJePahlrEvM2{7kFFH5^F9awm z{<~9tF719w^VZ@sbMJnB^ZQOp(%E^{?~3Q&m#cn$PNT!agU?KW{a?e2C1*A&$3Z{OywxN72-yp{h|&FNi+iK?Q)X6EME zg}*-S`*v~PfeRlRwr<_p+T7f%Z*Xbejr;fcXEBRN$!)lL_3Dj%QD+?NU`S{$voAuAR=o+Td!gTHS z?Px{YbEj>JjsD>xNCgZ*6V8&ClK?TW^W#-~B6})NP#3Ba+MWuEfQ}SZ&7qqC$N^9;x!z2OBcK zeyo#F*z*5lpYfGVb}QH9&(7mIfByXGJ9p;v^!A=SaKJ(H-Lq$Ietv!_)z#74wrx`g zZ<()tN92H=|Eihw?YCZLqzPm`cT32eTO{P3;ODSpsv`#b`YV^?>r=jb`EugJhYdWu zyi@!B{i}QV?wy$Jdf)jQ>uYMJJTc7Oxo3}#?DOZ(mww(ab-__xBVqC4#YV=)%9AHg zHZn9+R904=^rmb^j*ncW_TR%tE?%4{BPVz2-Me*j=FOW`WMXA;Yi)mu(#2w5U*FcJ zPoEYP76!ikc<9V?)9rl=lb;&4pRjy9droLVdU|?9LQ~FEJy`*|mNVz6uIEpXm6c7bt+n0tF;aMy+SO+qF^?O!ZrReZ zckkXc_nuvg-@4LG{el#KPG+X2`Q~KRuwIt1xKOpzuOjw6o91p>#qjJ=-HqF~XRFi~ z3EBVI_WgT#W^V4E)YaSxo{>LPLl>T@nizM{^p^KKRkzKX>^fr@s%vZ4p3gDvdE~m7 zJ0Uwe`_rdSlMbG%*}cl_>WhUtfAD=yVCiBL7i~+L#y*$jS!0tUbED*$PXb;EavBmQ j0y7Tk@Gl(1!hcxRGC3OOX+?blmP`zuu6{1-oD!M9>B&%@B$W=f{kae^cJ2%ixdG{L2Pmb zMG!2kgaidebbj9AhL{h|u3E@v2iBRLdColFE{QoJ;&^?H{d^6RI}t}nIuWOkQ%F)k zs=GV%{}syT^E4a|X}jI3g&4U{8s25bYcLpa){wL5Az;nPpwViz%JNY;J)~SNv+w&H zhN1G<>zbjrBZNU&LrxEyOePQI@pzonG)C}tgr?K!!$541(?ha^(_}S9@OFf1wHohs zyMz>CEr1SxHd<0000KTy literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_groups@2x.png b/Telegram/Resources/icons/filters_type_groups@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..114156e547ff75bb975e716bbc744f601c7ba27b GIT binary patch literal 984 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!Ea{HEjtmSN`?>!lvNA9*_j|fH zhEy=Vow?ha*-_w_dQ#@X-Xuk#jRGzcM4~dKg1vW%Y}@uv`+pE#J*)9R!$G}g`Ake4 zQ<@lr92yuVENx;DP+&+|sldp>!4RqC!NADmFpZ0_RGsjG7(Msr&!2z!@#DsxA2W0J z@BO&Hc21nLvvXE{zW+?A>^G0AGGz{{`0vDWS@&&xO8dKuRnis z8VzhW@c;hjKC<;HU3b4mAg z7wiz-vUziI%VW+r$$}mF(?9nnEeyC&+<&d9MqErRp+H1_hRTtH?moXG-yW~+wzapf zZcW;=x&LkD_NSY0OxHRY_$1&lqqeg1Yi_Hoy72e@{-aG|cUQlSf8Siyn)vDe%DE+vs-1qR>2@4Q zm~e4hZc0jv(M+DRXU|^z^2MZZe)Qst3$nI)JuRB)=jS)8_IC2|v(I@h967?0x;Zi` zHg@ULr>RmhJo2v|KW;vE?%azPFFN@6`90;mYO}r7CYzX4w{T@RL?<~LNp?l-L>ni!R7Z>{FpSgH3aH;*IV^gkQzn+zxeE8e?$z=>@ z&zxzQx2tzG6Vv=BmfP7g3kwBZG)jw$7k?>_(>~Vy_H!Qlg^wQ%=Tz+Ho3p#NaQX7( z2BP&o;bCDlg>NmZDz-6u?4S5x$?wt!ciwW}x^t&z%BxqePKjTir~GR3*7??L?d@M@ zDQ~lE&08K7DeWe-yJ>kPk7|h8lDsPB z5z*L{qGU|9JjO_6g%mco>;4h<{_y#J&iQ;l=X}rkobNdwn)eYm2uK42001B!?wF&S z9QQ92w`|Vbh=74jl8Z!pp#gx#TqP+%9st-9>48D}rphdYc3g zbN~+{`nz8DU@QnsEL_tQ`;x@O>iHB_Qe}YpS^FG(p!x2F1 zke#q#+dB89schxT+(C(e{OTYyOZn(Yfr-zaA!r$PnJpVv63&v<EUP2Q5p$F zhGFWVWrR%~6zEzU3D=A$l`R?)ssFbYezv;*v17ViF1M$<`%>!p^PsqI>N)6%U$xyA z!!%k&Gc$eF)rRWTXmHOB+ifI##0@`RU%lL%9K^X5)^4JXLXg(Z#g|AEOG`hoSp2tz z^H1Q6qjRK5B@Ov?wt{n#p)dyxt^MqrX;;gwuz5Heu~54@uLhZVH)5}TWAd@k^0uw)*9fi zWj2)6wq9wONDJ#B&4@&ISyWp_`c&^BQ&X?_goMwI@6gw0uOHp+}rc2R)7!*`0l}hO#s8DCW)?QK4wCXNCpC2P_wA@b@ zi{tZ4;2#=vw3o0^Lly>MPZ}F{oQCbE7Zs@bFWu4S5@Gi&Cjc*zEm@P+9Gvdn44?@w2<7&DXtC zQku0iGzwx;TIzV_+hnbH>A{CTK5dptFH}d|iB(UPfW}YXDk;gcv$Nx(y0Wf`>e1c{ zY&P37*{VGomYeCV6l41rtJ46;{K!Mu+ZS;-oF#t!aUGi@0vqwL2D5CuKR{1f#Lq%8-kCZR;T|qV8)My}d4MGu{bTfz)N!&~^n~2EhU6SuoW| z&^s^p=A$k8CW`RetGniQ7)R;Z>c0*T*Y z1^(R=s%J&VL_9&n!OM#D+~eT1m#Hpe<|tE-yfJfV>0)*RAvL&Q&;NR0T}^gKM6hSI RJ=?4xfQQQwOr29$#y`BtDVqQQ literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_muted.png b/Telegram/Resources/icons/filters_type_muted.png new file mode 100644 index 0000000000000000000000000000000000000000..92e3b1adc70b7559fb98d11171307b0e7050f54e GIT binary patch literal 576 zcmV-G0>Axh-#+PcV--3^ptli*z^~ zXti2VBoetwTq>1lx7!iS>2zNC1Yz*ZV?c<{=kv7R?-?oopAq1DQj)>J9{`bUMu?LJ7Z{ECm&@^l zU6Q$6E`|yO0yLY=*yZ#2M3j0S2$1L-IWe+djy*v7{XW@jHvNDA1&GOH!hK`6+eMPA z#r%yzaw)A=E4kfnwM0VqOy`YGm-n#G|4;pD9Sw!F6gCtx6w*>a%YOu?(!>=}(J%!7 O0000qTaRTu8>oldW4vyphjY)S;;uF z+>o@$R18zJrR&P&k4t1YoQG&?8EURZnjj{Y&HmpX`{TWL@9zEi?o+~uiSmH^!9gI9 zM>H*xxt6rgg1N4Ff<+Ux77z~kTQUgLT;}$H<+4`Cqa(@jIbciWv*10kUY$#mrO>T` zQ?g?+;F?nT@WFIJ3BQynqcc~X=K>!tLzPoKDuR@T+YuBEYmWk!-Z)aKbjv9Nx@P_U zl--*}!~0iS>=PQ}T%%@K=LcoGmzQnl!rr%Uy4E!Z0nksp0ra|JG^zMDG@1kfQ??(V zIeiI3CjCv`fFz5Nbc9R{b1FJ2ltLnr==cXv*H$eA-|iZ5NV39G1r5{U$^kjv}x8vNFamvadsbE!(${zP-RLJL29@eUAQB@y;vWl6pT-c0imY-$PM@`My zM2@HLVnosb*i|YGfk4P>L?V$?Dy_z|>iqrvJx*jw-oE8_C6=C@UGhP|Jc5FQB`YhU z^@FRcL;#C@?OnLKT96|WnP(cRHoL(v-abBE` zh>=Vd3o|w`!56TVbUIyPFvN1l8m(q92AH0Jak<>^l|_!%wxLsx{G{{#RF~o!onGIv zu)wb+@%zf>Eosl{--U>gV*Zh?Lv;Gc;$mA>j_;{uwr?|!RFc?u|9-`}^XEGRUjzoG z%#x3yP^jyCo~FJYhYASzCqQGqhSA{<6$l$uDtZ?GL;6ebWoVn-Z)9YImz%qMau9mA zi71(en#8+@HXFS0(`XXPC8P*&Wkg0obUIzCWxoEhR45dN(+mc~z4rD#3ukRm z2)Ifc5@|G8H?ApnEZ^1DHT>)GY=^@UPSet9CX?w!E!!)D%bl627v|kWxjo(36A=+1 z$0#&LrKB&J~LreZyE)UyneA9fA-i{}^Cue5IVNo!s%aF2z}+5_UhK1VP?)Sp0W7m~6RD=0DEt?gRbE^G literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_muted@3x.png b/Telegram/Resources/icons/filters_type_muted@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..0f0f81dbb4e36ed1580fcb9f10f1134d49996e96 GIT binary patch literal 2101 zcmchZ>08p<7RP^J&Kj9GAGIu;$q^gXNafVM(#blQsUd`t1KNNXnkZRe&d2mPrJ}dg z98t;%O-NI+D9r&&%Q-a3)Es)8>i*7ua9`aQd#@LJth)x zJ$2IcENChJ90fV>P9vXx1DYL|(O5J9)TJqJ5oG~D{_81M^q+Lde7-OV{s&wbGBk+d z7@1<=YW{B$A$I1*aJTnvXs>7V#Yyz8&WG~bGOn&_$L<+n;GOwrY?4eRfFz$9#ou__ zV?ZvgjB2?NRkpd>78k&))DcK z;P{^`q>p4U%*jEvO3#Y05pdfnW-A8~DCurvY(6G-uu!`jeHz2UfBoDRN&19In#c-| z2awL4QwB>=IS5Nd=Y*kC^vR^$n^(sLkl=yG9z}0qy7u?*&!YYw`Ew(Bez^YDa1xM7 z^4nsfRTQ?qeQJ4H)GQwlGc4^&(K}kOxRrk_(w4FQ9nqLjwM>(WBOBEA7WuYJDyl$L zwXK<>ZHxy9iln=aBz$}-!?;=h)e-j58#SwL#!rxtwOr9Xk`iN~MrVLLaTXreC}6*w`5y}#l1 z2!bKnMYM&{f9Ors|*D#fzA)NK8!Rx{o{!%HYwYo}Pt;TJ9HPS7tp1 zo2fHZ-2LoFLMvWIy1tcHEfXvcnL(tleZ4S;eCJOpJ6$k4`s}8d7o*hF8a|$+t+Rh- zG)KCeVZF11E-KGnFYi#CeOqueCeH@HPXLWpOEq*3gTKp6&`ATs^or|4hEiAf*mL#4 z%R9UP0^5mE;n^!v#`9yaIV91F^-NRfNJIEkSBmI0L!S!KOlov>jI3N;V|&*Jm#lnG z?0d3a^RJBy*-@YQG26UKOGTYJz*Bwi>ixDO;j@4BNy#;H;A>pO>KyL8&JUFa!JcTa zmj<5Smj4@H9C59;=Lm`{(x!cWrEy+oMnx>x(~9@>IO2a?RnI}xiFTHr?LFYv_SJkU zpBPP-?$odx8}dP;v?e+OreCIG9;m6&er`qfXf}j>3a;`wsUJOBd6htsi!|3MT3nv# zd1S&$X_v;b!$Gw|Lj3qKB?gXB+S1{#siw|{1;=HcJCKB_D5W%95NDN}ZRK~CgMXGx z+ZRXTA}$C3)pNd6!nA|5tUOc*#^jH}7Xe*&Z17`kj1(FPii{K-pWOVhU?0@C|KXy- z@KWAIbT16*O@f*ZrTRmuMc7g@bwq70WV$MrvYPL?{vu8-3 z?iIPg+=Z9DWR)v{ksNaiin=DP4l_}Qx-rraD)u2_{698b>*C#IvQBD!Jmzo;M!{tt zxaf;MCEVj9q zEIIR{mu*NMsrchfFwYK-V&3>0-Mn|KsMWdj)B&zT!mY!XJlf}6m=W!2NP%idNd`Ui zMBseOR z4c+Bu%wnv5f_sR#%0}!)-dvmCzNg=X>XwnaRY&-O+Q+VprU`xvEG;OQBzj*}$XqZa zTh*>Cn5;u2@1IaU*tP?|Dc-7?}eb%;{1*!gPFG{z9#8HEFS16SGUa-A*xy$l&v+_m9CJ+x1w(RJ}A5 ntv#DEcmJQZ;6ID><1fIBvb#Pr!N?u_2LPwsPP^8eAjJI_rTg-Y literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_noncontacts.png b/Telegram/Resources/icons/filters_type_noncontacts.png new file mode 100644 index 0000000000000000000000000000000000000000..213633ac0ba338618801089897a2c0a455aa2701 GIT binary patch literal 573 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 BtKI+r literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/filters_type_read.png b/Telegram/Resources/icons/filters_type_read.png new file mode 100644 index 0000000000000000000000000000000000000000..689da4ca766231dd4f6c30bf3caef608c9abf0cc GIT binary patch literal 672 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 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index f3f815b62..7984173cc 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2240,14 +2240,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_filters_recommended" = "Recommended"; "lng_filters_recommended_add" = "Add"; "lng_filters_restore" = "Undo"; -"lng_filters_new" = "New folder"; +"lng_filters_new" = "New Folder"; +"lng_filters_edit" = "Edit Folder"; "lng_filters_new_name" = "Folder name"; "lng_filters_add_chats" = "Add chats"; -"lng_filters_include" = "Include"; +"lng_filters_include" = "Included Chats"; "lng_filters_include_about" = "Choose chats and types of chats that will appear in this folder."; -"lng_filters_exclude" = "Exclude"; +"lng_filters_exclude" = "Excluded Chats"; "lng_filters_exclude_about" = "Choose chats and types of chats that will never appear in this folder."; +"lng_filters_create_button" = "Create"; "lng_filters_add_title" = "Add Chats"; +"lng_filters_include_title" = "Include Chats"; +"lng_filters_exclude_title" = "Exclude Chats"; "lng_filters_edit_types" = "Chat types"; "lng_filters_edit_chats" = "Chats"; "lng_filters_include_contacts" = "Contacts"; @@ -2260,6 +2264,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_filters_exclude_archived" = "Archived"; "lng_filters_add" = "Done"; "lng_filters_limit" = "Sorry, you have reached folders limit."; +"lng_filters_empty" = "Please choose at least one chat for this folder."; +"lng_filters_default" = "Please change at least one rule for this folder."; +"lng_filters_type_contacts" = "Contacts"; +"lng_filters_type_non_contacts" = "Non-Contacts"; +"lng_filters_type_groups" = "Groups"; +"lng_filters_type_channels" = "Channels"; +"lng_filters_type_bots" = "Bots"; +"lng_filters_type_no_archived" = "No Archived"; +"lng_filters_type_no_muted" = "No Muted"; +"lng_filters_type_no_read" = "No Read"; // Wnd specific diff --git a/Telegram/SourceFiles/boxes/manage_filters_box.cpp b/Telegram/SourceFiles/boxes/manage_filters_box.cpp index b0726e85e..3f194157d 100644 --- a/Telegram/SourceFiles/boxes/manage_filters_box.cpp +++ b/Telegram/SourceFiles/boxes/manage_filters_box.cpp @@ -10,14 +10,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_chat_filters.h" #include "data/data_folder.h" +#include "data/data_peer.h" +#include "history/history.h" #include "main/main_session.h" #include "window/window_session_controller.h" #include "window/window_controller.h" #include "ui/layers/generic_box.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/input_fields.h" #include "ui/text/text_utilities.h" #include "ui/wrap/slide_wrap.h" +#include "ui/painter.h" #include "settings/settings_common.h" #include "lang/lang_keys.h" #include "apiwrap.h" @@ -25,11 +29,72 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_layers.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" +#include "styles/style_window.h" namespace { constexpr auto kRefreshSuggestedTimeout = 7200 * crl::time(1000); constexpr auto kFiltersLimit = 10; +constexpr auto kMaxFilterTitleLength = 20; + +using namespace Settings; + +using Flag = Data::ChatFilter::Flag; +using Flags = Data::ChatFilter::Flags; +using ExceptionPeersRef = const base::flat_set> &; +using ExceptionPeersGetter = ExceptionPeersRef(Data::ChatFilter::*)() const; + +constexpr auto kAllTypes = { + Flag::Contacts, + Flag::NonContacts, + Flag::Groups, + Flag::Channels, + Flag::Bots, + Flag::NoMuted, + Flag::NoArchived, + Flag::NoRead +}; + +class FilterChatsPreview final : public Ui::RpWidget { +public: + FilterChatsPreview( + not_null parent, + Flags flags, + const base::flat_set> &peers); + + [[nodiscard]] rpl::producer flagRemoved() const; + [[nodiscard]] rpl::producer> peerRemoved() const; + + int resizeGetHeight(int newWidth) override; + +private: + using Button = base::unique_qptr; + struct FlagButton { + Flag flag = Flag(); + Button button; + }; + struct PeerButton { + not_null history; + Button button; + }; + + void paintEvent(QPaintEvent *e) override; + + void setup( + Flags flags, + const base::flat_set> &peers); + void refresh(); + void removeFlag(Flag flag); + void removePeer(not_null history); + void paintFlagIcon(QPainter &p, int left, int top, Flag flag) const; + + std::vector _removeFlag; + std::vector _removePeer; + + rpl::event_stream _flagRemoved; + rpl::event_stream> _peerRemoved; + +}; class FilterRowButton final : public Ui::RippleButton { public: @@ -43,6 +108,7 @@ public: const QString &description); void setRemoved(bool removed); + void updateData(const Data::ChatFilter &filter); [[nodiscard]] rpl::producer<> removeRequests() const; [[nodiscard]] rpl::producer<> restoreRequests() const; @@ -57,6 +123,7 @@ private: FilterRowButton( not_null parent, + Main::Session *session, const Data::ChatFilter &filter, const QString &description, State state); @@ -67,6 +134,8 @@ private: void setState(State state, bool force = false); void updateButtonsVisibility(); + Main::Session *_session = nullptr; + Ui::IconButton _remove; Ui::RoundButton _restore; Ui::RoundButton _add; @@ -101,10 +170,16 @@ private: [[nodiscard]] int ComputeCount( not_null session, - const Data::ChatFilter &filter) { + const Data::ChatFilter &filter, + bool check = false) { const auto &list = session->data().chatsFilters().list(); const auto id = filter.id(); - if (ranges::contains(list, id, &Data::ChatFilter::id)) { + const auto i = ranges::find(list, id, &Data::ChatFilter::id); + if (i != end(list) + && (!check + || (i->flags() == filter.flags() + && i->always() == filter.always() + && i->never() == filter.never()))) { const auto chats = session->data().chatsFilters().chatsList(id); return chats->indexed()->size(); } @@ -113,19 +188,188 @@ private: [[nodiscard]] QString ComputeCountString( not_null session, - const Data::ChatFilter &filter) { - const auto count = ComputeCount(session, filter); + const Data::ChatFilter &filter, + bool check = false) { + const auto count = ComputeCount(session, filter, check); return count ? tr::lng_filters_chats_count(tr::now, lt_count_short, count) : tr::lng_filters_no_chats(tr::now); } +FilterChatsPreview::FilterChatsPreview( + not_null parent, + Flags flags, + const base::flat_set> &peers) +: RpWidget(parent) { + setup(flags, peers); +} + +void FilterChatsPreview::setup( + Flags flags, + const base::flat_set> &peers) { + const auto makeButton = [&](Fn handler) { + auto result = base::make_unique_q( + this, + st::windowFilterSmallRemove); + result->setClickedCallback(std::move(handler)); + return result; + }; + for (const auto flag : kAllTypes) { + if (flags & flag) { + _removeFlag.push_back({ + flag, + makeButton([=] { removeFlag(flag); }) }); + } + } + for (const auto history : peers) { + _removePeer.push_back({ + history, + makeButton([=] { removePeer(history); }) }); + } + refresh(); +} + +void FilterChatsPreview::refresh() { + resizeToWidth(width()); +} + +int FilterChatsPreview::resizeGetHeight(int newWidth) { + const auto right = st::windowFilterSmallRemoveRight; + const auto add = (st::windowFilterSmallItem.height + - st::windowFilterSmallRemove.height) / 2; + auto top = 0; + const auto moveNextButton = [&](not_null button) { + button->moveToRight(right, top + add, newWidth); + top += st::windowFilterSmallItem.height; + }; + for (const auto &[flag, button] : _removeFlag) { + moveNextButton(button.get()); + } + for (const auto &[history, button] : _removePeer) { + moveNextButton(button.get()); + } + return top; +} + +[[nodiscard]] QString TypeName(Flag flag) { + switch (flag) { + case Flag::Contacts: return tr::lng_filters_type_contacts(tr::now); + case Flag::NonContacts: + return tr::lng_filters_type_non_contacts(tr::now); + case Flag::Groups: return tr::lng_filters_type_groups(tr::now); + case Flag::Channels: return tr::lng_filters_type_channels(tr::now); + case Flag::Bots: return tr::lng_filters_type_bots(tr::now); + case Flag::NoMuted: return tr::lng_filters_type_no_muted(tr::now); + case Flag::NoArchived: return tr::lng_filters_type_no_archived(tr::now); + case Flag::NoRead: return tr::lng_filters_type_no_read(tr::now); + } + Unexpected("Flag in TypeName."); +} + +void FilterChatsPreview::paintEvent(QPaintEvent *e) { + auto p = Painter(this); + auto top = 0; + const auto &st = st::windowFilterSmallItem; + const auto iconLeft = st.photoPosition.x(); + const auto iconTop = st.photoPosition.y(); + const auto nameLeft = st.namePosition.x(); + p.setFont(st::windowFilterSmallItem.nameStyle.font); + const auto nameTop = st.namePosition.y(); + for (const auto &[flag, button] : _removeFlag) { + paintFlagIcon(p, iconLeft, top + iconTop, flag); + + p.setPen(st::contactsNameFg); + p.drawTextLeft(nameLeft, top + nameTop, width(), TypeName(flag)); + top += st.height; + } + for (const auto &[history, button] : _removePeer) { + history->peer->paintUserpicLeft( + p, + iconLeft, + top + iconTop, + width(), + st.photoSize); + history->peer->nameText().drawLeftElided( + p, + nameLeft, + top + nameTop, + button->x() - nameLeft, + width()); + top += st.height; + } +} + +void FilterChatsPreview::paintFlagIcon( + QPainter &p, + int left, + int top, + Flag flag) const { + const auto &color = [&]() -> const style::color& { + switch (flag) { + case Flag::Contacts: return st::historyPeer4UserpicBg; + case Flag::NonContacts: return st::historyPeer7UserpicBg; + case Flag::Groups: return st::historyPeer2UserpicBg; + case Flag::Channels: return st::historyPeer1UserpicBg; + case Flag::Bots: return st::historyPeer6UserpicBg; + case Flag::NoMuted: return st::historyPeer6UserpicBg; + case Flag::NoArchived: return st::historyPeer4UserpicBg; + case Flag::NoRead: return st::historyPeer7UserpicBg; + } + Unexpected("Flag in color paintFlagIcon."); + }(); + const auto &icon = [&]() -> const style::icon& { + switch (flag) { + case Flag::Contacts: return st::windowFilterTypeContacts; + case Flag::NonContacts: return st::windowFilterTypeNonContacts; + case Flag::Groups: return st::windowFilterTypeGroups; + case Flag::Channels: return st::windowFilterTypeChannels; + case Flag::Bots: return st::windowFilterTypeBots; + case Flag::NoMuted: return st::windowFilterTypeNoMuted; + case Flag::NoArchived: return st::windowFilterTypeNoArchived; + case Flag::NoRead: return st::windowFilterTypeNoRead; + } + Unexpected("Flag in icon paintFlagIcon."); + }(); + const auto size = st::windowFilterSmallItem.photoSize; + const auto rect = QRect(left, top, size, size); + auto hq = PainterHighQualityEnabler(p); + p.setBrush(color->b); + p.setPen(Qt::NoPen); + p.drawEllipse(rect); + icon.paintInCenter(p, rect); +} + +void FilterChatsPreview::removeFlag(Flag flag) { + const auto i = ranges::find(_removeFlag, flag, &FlagButton::flag); + Assert(i != end(_removeFlag)); + _removeFlag.erase(i); + refresh(); + _flagRemoved.fire_copy(flag); +} + +void FilterChatsPreview::removePeer(not_null history) { + const auto i = ranges::find(_removePeer, history, &PeerButton::history); + Assert(i != end(_removePeer)); + _removePeer.erase(i); + refresh(); + _peerRemoved.fire_copy(history); +} + +rpl::producer FilterChatsPreview::flagRemoved() const { + return _flagRemoved.events(); +} + +rpl::producer> FilterChatsPreview::peerRemoved() const { + return _peerRemoved.events(); +} + FilterRowButton::FilterRowButton( not_null parent, not_null session, const Data::ChatFilter &filter) : FilterRowButton( parent, + session, filter, ComputeCountString(session, filter), State::Normal) { @@ -135,15 +379,17 @@ FilterRowButton::FilterRowButton( not_null parent, const Data::ChatFilter &filter, const QString &description) -: FilterRowButton(parent, filter, description, State::Suggested) { +: FilterRowButton(parent, nullptr, filter, description, State::Suggested) { } FilterRowButton::FilterRowButton( not_null parent, + Main::Session *session, const Data::ChatFilter &filter, const QString &status, State state) : RippleButton(parent, st::defaultRippleAnimation) +, _session(session) , _remove(this, st::filtersRemove) , _restore(this, tr::lng_filters_restore(), st::stickersUndoRemove) , _add(this, tr::lng_filters_recommended_add(), st::stickersTrendingAdd) @@ -155,6 +401,14 @@ void FilterRowButton::setRemoved(bool removed) { setState(removed ? State::Removed : State::Normal); } +void FilterRowButton::updateData(const Data::ChatFilter &filter) { + Expects(_session != nullptr); + + _title.setText(st::contactsNameStyle, filter.title()); + _status = ComputeCountString(_session, filter, true); + update(); +} + void FilterRowButton::setState(State state, bool force) { if (!force && _state == state) { return; @@ -292,13 +546,15 @@ void ManageFiltersPrepare::showBox() { } void ManageFiltersPrepare::showBoxWithSuggested() { - _window->window().show(Box(CreateBox, _window, _suggested)); + _window->window().show(Box(SetupBox, _window, _suggested)); } -void ManageFiltersPrepare::CreateBox( +void ManageFiltersPrepare::SetupBox( not_null box, not_null window, const std::vector &suggestions) { + box->setTitle(tr::lng_filters_title()); + struct FilterRow { not_null button; Data::ChatFilter filter; @@ -306,11 +562,9 @@ void ManageFiltersPrepare::CreateBox( bool added = false; }; - box->setTitle(tr::lng_filters_title()); - const auto session = &window->session(); const auto content = box->verticalLayout(); - Settings::AddSubsectionTitle(content, tr::lng_filters_subtitle()); + AddSubsectionTitle(content, tr::lng_filters_subtitle()); const auto rows = box->lifetime().make_state>(); const auto find = [=](not_null button) { @@ -319,8 +573,14 @@ void ManageFiltersPrepare::CreateBox( return &*i; }; const auto countNonRemoved = [=] { + }; + const auto showLimitReached = [=] { const auto removed = ranges::count_if(*rows, &FilterRow::removed); - return rows->size() - removed; + if (rows->size() < kFiltersLimit + removed) { + return false; + } + window->window().showToast(tr::lng_filters_limit(tr::now)); + return true; }; const auto wrap = content->add(object_ptr(content)); const auto addFilter = [=](const Data::ChatFilter &filter) { @@ -333,11 +593,27 @@ void ManageFiltersPrepare::CreateBox( }, button->lifetime()); button->restoreRequests( ) | rpl::start_with_next([=] { - if (countNonRemoved() < kFiltersLimit) { - button->setRemoved(false); - find(button)->removed = false; + if (showLimitReached()) { + return; } + button->setRemoved(false); + find(button)->removed = false; }, button->lifetime()); + button->setClickedCallback([=] { + const auto found = find(button); + if (found->removed) { + return; + } + const auto doneCallback = [=](const Data::ChatFilter &result) { + find(button)->filter = result; + button->updateData(result); + }; + window->window().show(Box( + EditBox, + window, + found->filter, + crl::guard(button, doneCallback))); + }); rows->push_back({ button, filter }); }; const auto &list = session->data().chatsFilters().list(); @@ -345,11 +621,24 @@ void ManageFiltersPrepare::CreateBox( addFilter(filter); } - Settings::AddButton( + AddButton( content, tr::lng_filters_create() | Ui::Text::ToUpper(), - st::settingsUpdate); - Settings::AddSkip(content); + st::settingsUpdate + )->setClickedCallback([=] { + if (showLimitReached()) { + return; + } + const auto doneCallback = [=](const Data::ChatFilter &result) { + addFilter(result); + }; + window->window().show(Box( + EditBox, + window, + Data::ChatFilter(), + crl::guard(box, doneCallback))); + }); + AddSkip(content); const auto emptyAbout = content->add( object_ptr>( content, @@ -365,24 +654,15 @@ void ManageFiltersPrepare::CreateBox( object_ptr(content)) )->setDuration(0); const auto aboutRows = nonEmptyAbout->entity(); - Settings::AddDividerText(aboutRows, tr::lng_filters_about()); - Settings::AddSkip(aboutRows); - Settings::AddSubsectionTitle(aboutRows, tr::lng_filters_recommended()); + AddDividerText(aboutRows, tr::lng_filters_about()); + AddSkip(aboutRows); + AddSubsectionTitle(aboutRows, tr::lng_filters_recommended()); + const auto changed = box->lifetime().make_state(); const auto suggested = box->lifetime().make_state>(); for (const auto &suggestion : suggestions) { - const auto filter = suggestion.filter; - const auto already = [&] { - for (const auto &entry : list) { - if (entry.flags() == filter.flags() - && entry.always() == filter.always() - && entry.never() == filter.never()) { - return true; - } - } - return false; - }(); - if (already) { + const auto &filter = suggestion.filter; + if (ranges::contains(list, filter)) { continue; } *suggested = suggested->current() + 1; @@ -392,6 +672,9 @@ void ManageFiltersPrepare::CreateBox( suggestion.description)); button->addRequests( ) | rpl::start_with_next([=] { + if (showLimitReached()) { + return; + } addFilter(filter); *suggested = suggested->current() - 1; delete button; @@ -427,15 +710,19 @@ void ManageFiltersPrepare::CreateBox( const auto save = [=] { auto ids = prepareGoodIdsForNewFilters(); - auto requests = std::deque(); + using Requests = std::vector; + auto addRequests = Requests(), removeRequests = Requests(); auto &realFilters = session->data().chatsFilters(); const auto &list = realFilters.list(); auto order = QVector(); for (const auto &row : *rows) { const auto id = row.filter.id(); const auto removed = row.removed; - if (removed - && !ranges::contains(list, id, &Data::ChatFilter::id)) { + const auto i = ranges::find(list, id, &Data::ChatFilter::id); + if (removed && i == end(list)) { + continue; + } else if (!removed && i != end(list) && *i == row.filter) { + order.push_back(MTP_int(id)); continue; } const auto newId = ids.take(id).value_or(id); @@ -447,9 +734,9 @@ void ManageFiltersPrepare::CreateBox( MTP_int(newId), tl); if (removed) { - requests.push_front(request); + removeRequests.push_back(request); } else { - requests.push_back(request); + addRequests.push_back(request); order.push_back(MTP_int(newId)); } realFilters.apply(MTP_updateDialogFilter( @@ -460,12 +747,13 @@ void ManageFiltersPrepare::CreateBox( tl)); } auto previousId = mtpRequestId(0); + auto &&requests = ranges::view::concat(removeRequests, addRequests); for (auto &request : requests) { previousId = session->api().request( std::move(request) ).afterRequest(previousId).send(); } - if (!order.isEmpty()) { + if (!order.isEmpty() && !addRequests.empty()) { realFilters.apply( MTP_updateDialogFilterOrder(MTP_vector(order))); session->api().request(MTPmessages_UpdateDialogFiltersOrder( @@ -474,6 +762,148 @@ void ManageFiltersPrepare::CreateBox( } box->closeBox(); }; - box->addButton(tr::lng_settings_save(), save); - box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); + box->boxClosing() | rpl::start_with_next(save, box->lifetime()); + box->addButton(tr::lng_about_done(), [=] { box->closeBox(); }); } + +void SetupChatsPreview( + not_null content, + not_null data, + Flags flags, + ExceptionPeersGetter peers) { + const auto preview = content->add(object_ptr( + content, + data->flags() & flags, + (data->*peers)())); + + preview->flagRemoved( + ) | rpl::start_with_next([=](Flag flag) { + *data = Data::ChatFilter( + data->id(), + data->title(), + (data->flags() & ~flag), + data->always(), + data->never()); + }, preview->lifetime()); + + preview->peerRemoved( + ) | rpl::start_with_next([=](not_null history) { + auto always = data->always(); + auto never = data->never(); + always.remove(history); + never.remove(history); + *data = Data::ChatFilter( + data->id(), + data->title(), + data->flags(), + std::move(always), + std::move(never)); + }, preview->lifetime()); +} + +void ManageFiltersPrepare::EditBox( + not_null box, + not_null window, + const Data::ChatFilter &filter, + Fn doneCallback) { + const auto creating = filter.title().isEmpty(); + box->setTitle(creating ? tr::lng_filters_new() : tr::lng_filters_edit()); + + const auto content = box->verticalLayout(); + const auto name = content->add( + object_ptr( + box, + st::defaultInputField, + tr::lng_filters_new_name(), + filter.title()), + st::markdownLinkFieldPadding); + name->setMaxLength(kMaxFilterTitleLength); + + const auto data = box->lifetime().make_state(filter); + + constexpr auto kTypes = Flag::Contacts + | Flag::NonContacts + | Flag::Groups + | Flag::Channels + | Flag::Bots; + constexpr auto kExcludeTypes = Flag::NoMuted + | Flag::NoArchived + | Flag::NoRead; + + box->setFocusCallback([=] { + name->setFocusFast(); + }); + + AddSkip(content); + AddDivider(content); + AddSkip(content); + AddSubsectionTitle(content, tr::lng_filters_include()); + + SetupChatsPreview( + content, + data, + kTypes, + &Data::ChatFilter::always); + + AddButton( + content, + tr::lng_filters_add_chats() | Ui::Text::ToUpper(), + st::settingsUpdate + )->setClickedCallback([=] { + }); + + AddSkip(content); + AddDividerText(content, tr::lng_filters_include_about()); + AddSkip(content); + + AddSubsectionTitle(content, tr::lng_filters_exclude()); + + SetupChatsPreview( + content, + data, + kExcludeTypes, + &Data::ChatFilter::never); + + AddButton( + content, + tr::lng_filters_add_chats() | Ui::Text::ToUpper(), + st::settingsUpdate + )->setClickedCallback([=] { + }); + AddSkip(content); + content->add( + object_ptr( + content, + tr::lng_filters_exclude_about(), + st::boxDividerLabel), + st::settingsDividerLabelPadding); + + const auto save = [=] { + const auto title = name->getLastText().trimmed(); + if (title.isEmpty()) { + name->showError(); + return; + } else if (!(data->flags() & kTypes) && data->always().empty()) { + window->window().showToast(tr::lng_filters_empty(tr::now)); + return; + } else if ((data->flags() == (kTypes | Flag::NoArchived)) + && data->always().empty() + && data->never().empty()) { + window->window().showToast(tr::lng_filters_default(tr::now)); + return; + } + const auto result = Data::ChatFilter( + data->id(), + title, + data->flags(), + data->always(), + data->never()); + box->closeBox(); + + doneCallback(result); + }; + box->addButton( + creating ? tr::lng_filters_create_button() : tr::lng_settings_save(), + save); + box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); +} \ No newline at end of file diff --git a/Telegram/SourceFiles/boxes/manage_filters_box.h b/Telegram/SourceFiles/boxes/manage_filters_box.h index 1b4bd94e5..9900927e5 100644 --- a/Telegram/SourceFiles/boxes/manage_filters_box.h +++ b/Telegram/SourceFiles/boxes/manage_filters_box.h @@ -34,10 +34,15 @@ private: }; void showBoxWithSuggested(); - static void CreateBox( + static void SetupBox( not_null box, not_null window, const std::vector &suggested); + static void EditBox( + not_null box, + not_null window, + const Data::ChatFilter &filter, + Fn doneCallback); const not_null _window; const not_null _api; diff --git a/Telegram/SourceFiles/data/data_chat_filters.cpp b/Telegram/SourceFiles/data/data_chat_filters.cpp index 7dfe88416..c015de468 100644 --- a/Telegram/SourceFiles/data/data_chat_filters.cpp +++ b/Telegram/SourceFiles/data/data_chat_filters.cpp @@ -40,11 +40,11 @@ ChatFilter ChatFilter::FromTL( const auto flags = (data.is_contacts() ? Flag::Contacts : Flag(0)) | (data.is_non_contacts() ? Flag::NonContacts : Flag(0)) | (data.is_groups() ? Flag::Groups : Flag(0)) - | (data.is_broadcasts() ? Flag::Broadcasts : Flag(0)) + | (data.is_broadcasts() ? Flag::Channels : Flag(0)) | (data.is_bots() ? Flag::Bots : Flag(0)) | (data.is_exclude_muted() ? Flag::NoMuted : Flag(0)) | (data.is_exclude_read() ? Flag::NoRead : Flag(0)) - | (data.is_exclude_archived() ? Flag::NoArchive : Flag(0)); + | (data.is_exclude_archived() ? Flag::NoArchived : Flag(0)); auto &&to_histories = ranges::view::transform([&]( const MTPInputPeer &data) { const auto peer = data.match([&](const MTPDinputPeerUser &data) { @@ -87,11 +87,11 @@ MTPDialogFilter ChatFilter::tl() const { | ((_flags & Flag::Contacts) ? TLFlag::f_contacts : TLFlag(0)) | ((_flags & Flag::NonContacts) ? TLFlag::f_non_contacts : TLFlag(0)) | ((_flags & Flag::Groups) ? TLFlag::f_groups : TLFlag(0)) - | ((_flags & Flag::Broadcasts) ? TLFlag::f_broadcasts : TLFlag(0)) + | ((_flags & Flag::Channels) ? TLFlag::f_broadcasts : TLFlag(0)) | ((_flags & Flag::Bots) ? TLFlag::f_bots : TLFlag(0)) | ((_flags & Flag::NoMuted) ? TLFlag::f_exclude_muted : TLFlag(0)) | ((_flags & Flag::NoRead) ? TLFlag::f_exclude_read : TLFlag(0)) - | ((_flags & Flag::NoArchive) + | ((_flags & Flag::NoArchived) ? TLFlag::f_exclude_archived : TLFlag(0)); auto always = QVector(); @@ -147,7 +147,7 @@ bool ChatFilter::contains(not_null history) const { return Flag::Groups; } else if (const auto channel = peer->asChannel()) { if (channel->isBroadcast()) { - return Flag::Broadcasts; + return Flag::Channels; } else { return Flag::Groups; } @@ -162,7 +162,7 @@ bool ChatFilter::contains(not_null history) const { || ((_flags & flag) && (!(_flags & Flag::NoMuted) || !history->mute()) && (!(_flags & Flag::NoRead) || history->unreadCountForBadge()) - && (!(_flags & Flag::NoArchive) + && (!(_flags & Flag::NoArchived) || (history->folderKnown() && !history->folder()))) || _always.contains(history); } @@ -172,9 +172,9 @@ ChatFilters::ChatFilters(not_null owner) : _owner(owner) { //const auto all = Flag::Contacts // | Flag::NonContacts // | Flag::Groups - // | Flag::Broadcasts + // | Flag::Channels // | Flag::Bots - // | Flag::NoArchive; + // | Flag::NoArchived; //_list.push_back( // ChatFilter(1, "Unmuted", all | Flag::NoMuted, {}, {})); //_list.push_back( diff --git a/Telegram/SourceFiles/data/data_chat_filters.h b/Telegram/SourceFiles/data/data_chat_filters.h index ca9735200..7e6b2775d 100644 --- a/Telegram/SourceFiles/data/data_chat_filters.h +++ b/Telegram/SourceFiles/data/data_chat_filters.h @@ -25,11 +25,11 @@ public: Contacts = 0x01, NonContacts = 0x02, Groups = 0x04, - Broadcasts = 0x08, + Channels = 0x08, Bots = 0x10, NoMuted = 0x20, NoRead = 0x40, - NoArchive = 0x80, + NoArchived = 0x80, }; friend constexpr inline bool is_flag_type(Flag) { return true; }; using Flags = base::flags; @@ -64,6 +64,17 @@ private: }; +inline bool operator==(const ChatFilter &a, const ChatFilter &b) { + return (a.title() == b.title()) + && (a.flags() == b.flags()) + && (a.always() == b.always()) + && (a.never() == b.never()); +} + +inline bool operator!=(const ChatFilter &a, const ChatFilter &b) { + return !(a == b); +} + class ChatFilters final { public: explicit ChatFilters(not_null owner); diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 26ef1bf9f..7fb7c92e1 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -1173,14 +1173,6 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting if (!_checkStreamStatus(stream)) return false; Global::SetDialogsFiltersEnabled(enabled == 1); - auto mode = FilterId(0); - if (enabled) { - mode = FilterId(modeInt); - if (mode == 1) { // #TODO filters - - } - } - Global::SetDialogsFilterId(mode); } break; case dbiModerateMode: { diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index bbbd6c1fd..aaabe5800 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -299,6 +299,23 @@ windowFiltersCustom: SideBarButton(windowFiltersButton) { windowFiltersSetup: SideBarButton(windowFiltersButton) { icon: icon {{ "filters_setup", sideBarIconFg }}; } +windowFilterSmallItem: PeerListItem(defaultPeerListItem) { + height: 44px; + photoPosition: point(15px, 5px); + namePosition: point(62px, 14px); + photoSize: 34px; +} +windowFilterSmallRemove: IconButton(notifyClose) { +} +windowFilterSmallRemoveRight: 10px; +windowFilterTypeContacts: icon {{ "filters_type_contacts", historyPeerUserpicFg }}; +windowFilterTypeNonContacts: icon {{ "filters_type_noncontacts", historyPeerUserpicFg }}; +windowFilterTypeGroups: icon {{ "filters_type_groups", historyPeerUserpicFg }}; +windowFilterTypeChannels: icon {{ "filters_type_channels", historyPeerUserpicFg }}; +windowFilterTypeBots: icon {{ "filters_type_bots", historyPeerUserpicFg }}; +windowFilterTypeNoMuted: icon {{ "filters_type_muted", historyPeerUserpicFg }}; +windowFilterTypeNoArchived: icon {{ "filters_type_archived", historyPeerUserpicFg }}; +windowFilterTypeNoRead: icon {{ "filters_type_read", historyPeerUserpicFg }}; // Mac specific diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 766d25a2f..b754c9a2f 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_account.h" #include "ui/layers/box_content.h" #include "ui/layers/layer_widget.h" +#include "ui/toast/toast.h" #include "window/window_session_controller.h" #include "window/themes/window_theme.h" #include "window/themes/window_theme_editor.h" @@ -80,6 +81,10 @@ void Controller::showSettings() { _widget.showSettings(); } +void Controller::showToast(const QString &text) { + Ui::Toast::Show(_widget.bodyWidget(), text); +} + void Controller::showBox( object_ptr content, Ui::LayerOptions options, diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h index 289d6d390..75953a07c 100644 --- a/Telegram/SourceFiles/window/window_controller.h +++ b/Telegram/SourceFiles/window/window_controller.h @@ -52,6 +52,7 @@ public: showBox(std::move(content), options, animated); return result; } + void showToast(const QString &text); void showRightColumn(object_ptr widget); void sideBarChanged(); diff --git a/Telegram/SourceFiles/window/window_filters_menu.cpp b/Telegram/SourceFiles/window/window_filters_menu.cpp index 844bb2604..7e9bd6141 100644 --- a/Telegram/SourceFiles/window/window_filters_menu.cpp +++ b/Telegram/SourceFiles/window/window_filters_menu.cpp @@ -37,11 +37,11 @@ enum class Type { const auto all = Flag::Contacts | Flag::NonContacts | Flag::Groups - | Flag::Broadcasts + | Flag::Channels | Flag::Bots; const auto removed = Flag::NoRead | Flag::NoMuted; const auto people = Flag::Contacts | Flag::NonContacts; - const auto allNoArchive = all | Flag::NoArchive; + const auto allNoArchive = all | Flag::NoArchived; if (!filter.always().empty() || !filter.never().empty() || !(filter.flags() & all)) { @@ -52,7 +52,7 @@ enum class Type { return Type::People; } else if ((filter.flags() & all) == Flag::Groups) { return Type::Groups; - } else if ((filter.flags() & all) == Flag::Broadcasts) { + } else if ((filter.flags() & all) == Flag::Channels) { return Type::Channels; } else if ((filter.flags() & all) == Flag::Bots) { return Type::Bots;