From 4692fdeb5f2d3bfd09ffc4bf1d9fad45263ce131 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 8 Dec 2016 17:08:54 +0300 Subject: [PATCH] Closed beta 10019013: Groups in common now are opened in a section. --- Telegram/Resources/basic.style | 6 - .../Resources/icons/history_empty_dog.png | Bin 2579 -> 0 bytes .../Resources/icons/history_empty_dog@2x.png | Bin 5051 -> 0 bytes Telegram/Resources/winrc/Telegram.rc | 8 +- Telegram/Resources/winrc/Updater.rc | 8 +- Telegram/SourceFiles/app.cpp | 44 +- Telegram/SourceFiles/config.h | 31 +- Telegram/SourceFiles/core/version.h | 2 +- Telegram/SourceFiles/history/history.style | 3 - .../history/history_service_layout.cpp | 8 - Telegram/SourceFiles/historywidget.cpp | 18 +- Telegram/SourceFiles/historywidget.h | 2 +- Telegram/SourceFiles/mainwidget.cpp | 22 +- .../media/player/media_player.style | 9 - Telegram/SourceFiles/mtproto/connection.cpp | 2 +- Telegram/SourceFiles/overview/overview.style | 39 +- .../SourceFiles/overview/overview_layout.cpp | 45 +- .../SourceFiles/overview/overview_layout.h | 4 +- Telegram/SourceFiles/overviewwidget.cpp | 21 +- Telegram/SourceFiles/profile/profile.style | 11 + .../profile/profile_back_button.cpp | 72 +++ .../SourceFiles/profile/profile_back_button.h | 45 ++ .../profile/profile_block_common_groups.cpp | 175 ------- .../profile/profile_block_common_groups.h | 75 --- .../profile/profile_block_info.cpp | 56 +-- .../SourceFiles/profile/profile_block_info.h | 11 - .../profile/profile_common_groups_section.cpp | 446 ++++++++++++++++++ .../profile/profile_common_groups_section.h | 216 +++++++++ .../SourceFiles/profile/profile_fixed_bar.cpp | 53 +-- .../profile/profile_inner_widget.cpp | 12 +- .../profile/profile_inner_widget.h | 7 - .../profile/profile_section_memento.h | 7 - .../SourceFiles/profile/profile_widget.cpp | 5 + Telegram/SourceFiles/profile/profile_widget.h | 6 +- .../ui/effects/send_action_animations.cpp | 4 +- Telegram/SourceFiles/ui/widgets/widgets.style | 10 +- Telegram/build/version | 2 +- Telegram/gyp/Telegram.gyp | 6 +- 38 files changed, 954 insertions(+), 537 deletions(-) delete mode 100644 Telegram/Resources/icons/history_empty_dog.png delete mode 100644 Telegram/Resources/icons/history_empty_dog@2x.png create mode 100644 Telegram/SourceFiles/profile/profile_back_button.cpp create mode 100644 Telegram/SourceFiles/profile/profile_back_button.h delete mode 100644 Telegram/SourceFiles/profile/profile_block_common_groups.cpp delete mode 100644 Telegram/SourceFiles/profile/profile_block_common_groups.h create mode 100644 Telegram/SourceFiles/profile/profile_common_groups_section.cpp create mode 100644 Telegram/SourceFiles/profile/profile_common_groups_section.h diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index 1be52bfde..f10548b37 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -309,12 +309,6 @@ simpleCloseIcon: icon {{ "simple_close", #c7c7c7 }}; simpleCloseIconOver: icon {{ "simple_close", #a3a3a3 }}; dialogsForwardCancelIcon: icon {{ "simple_close", dialogsForwardFg }}; -profileMaxWidth: 410px; -profilePadding: margins(28px, 30px, 28px, 0px); - -profileOnlineFg: statusFgActive; -profileOfflineFg: statusFg; - membersPadding: margins(0px, 10px, 0px, 10px); forwardMargins: margins(30px, 10px, 30px, 10px); diff --git a/Telegram/Resources/icons/history_empty_dog.png b/Telegram/Resources/icons/history_empty_dog.png deleted file mode 100644 index 3e6fef342192e3cfa22ac745907241bab7c30511..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2579 zcmV+u3hecXP))f8NeZKF%esF_(?yu|mJ@?0TU)TLe z006=tj6<0gAk+9uK&A!AH2xBhX#p~gzXW7jfJ`Gh(*h(4nM?+?wY4CXN};5r1S%^l zfzRi|!omW~&(Fi#w{PL`(`j|31DalX|-C=Xf#k#QUcl8*$@l{VP<9qJRT3c zdi4rEefpG4y+|PviQvM83s7HQ4|2I2L?RJwolqzQ_wV0_d-v`^C=`myN2(+ii_vDY zAst*U7xwn{qDrMg4u?b8Cfih1RfQcL9cZ;$Y2~28>({T5&*vX(pS26;RlD`f=&0ajI2VN+8R_V@Rr+wD$B>4O*<8HwnRatieH^uVoKw`hkL z6@LEw33j_3004gd`UNvHGvPcQj|XLCW#QiviGj<7S@w=8?39V10Ii;+E3xx z36u#OKYknlCb93PFcmRNc0FTE5@87>qn^5V*!-o&Ue^VZZpFDYza$(Yq#l=N18jTUp zNbPc=P>8``Fw=%xQlZsqnIDD#00#yJGA(n`@ZiCNSUOS@AeBlpEq54+j7E#aLUv52 zKcbpUrX;Gt9yXf|6$%9c0IJn$)`v8^-Hrl*fJ{Gn0;E!D#?}Ix%@*avxPALJMx!wy0%EM#;nd&XPg_423}RkhUUCRftJSm}>U6q@Is`$W*=&wW`Jtg9 zN_q5pJ#8Civzdu*%m^qiFQ@HrZ=u?s6bc1v<%7W>mY0`P%2QTWM%zwvb93?tAP9nX z^{uO`i&@v@a}2NUDS5F*0d+#F?@Q>RYFd_F%v&$Jr=0C@iVIU{+f zj_h{3J$&Gy0;|xN)9Iwlm&@gBnj?kF~r@8!#vjM`vD0Nv?OqtO7D%Z+-z z=YC2yjvP5cnz!HWO$Am2Oixc!=I7_&52g=703fcAc{(sPHN{$& zxb6s<&E|Njr5sP6K8>p$Yt~dMRiUb=%t7VwUs!{p>~n0N~Qn5^2YyqoWZH3%XF%!FT~30RTXGQ#iwo7T9UmWOWvz{lj>c@~V4Pnp7UR2j?KL9DN@kC=;8 zH%d$uBdp1TNhlQJ?Cfk*J-6G9m6es@IWHEAacF3W(Y=NJrZQs!+S}V15wNwj zg`J(9C=!XnLz5r~?CRInZ=EbjWHKfm&+AlN#^J07sWK?d|RC z3213)VbnO{?lz-VtFfS+7(+y$w4%JMjDWZvX%|bm$OdXJ-SS&xg~e zPeW~OEu24p9x5s-AU{7pRbrBVIvWTC5^ntP;lps|%o!*yE(Wbu3u|j@;Pd(5$B!Sd zva$kSzI*|{-w(ODxgZn@K`a(Sad9ySg+j>5$w|0>CLkq%>h=X&aJgLIa=CEy=uwbJ zBuQ&G8Tcc<9;doVLP|hZR#r-c$pqpeAYF4X9f*s7e-rZZ@<{Xk2m+{XsgV+}|10nR zcUY}f(mcw~=bcU`l$MsJLZ-A~Wn~2l3kyl}DW|}V8#iEKVIk>4r3))7E7027N?C@{ z{}9pXbRd_@fglJtckUcyXJ29T#kaj`3;Y*2>D=jWaNeL=lOXq?#3P_89q@+p-NJ)nX0@6r# z$M50&58gRvX3jk`=gt%NeqthZwbe)n83`c>BGFJ+(Fb=lII{`xz_mTW>Joyef;3bV zk)9cwnE_gfoh+U5 zut`ZVmYFw#xzY)mp|7s|d5^5ILT+gmP$CcrRt^rF6aiB_@5VdyVRL_)D=R6qGo^5w zFOQfm&eqFSn&LB*5|O+#J$-%u-M@doYhjnwY{Ol8vidode#w}`62WC)nqxOgID7i5 z2S!R#w6DqjwSF@MT7DyFq)>-tW_j1M#kmd#LXX)Ocnc7D zfb5Hli!EU!OsL)Yj@&aTw>9c-`~A{`Gc)}T0ha%9!{OP(!}_Ds)0i>e$A*R+pMS>; zkBr1C+Uo^3`4A>IIpqx%nMGETn;fra48)SQN+=6&ZQ!wEK=GSj?rRC5=7XmJYB& znc6FL7e?ZNs(BRs?`8Q!nI6Zo$diH>be}vSF)5`TwZAWOzVR7+5YEYone>?Z9-7xw zn4gcf()&RaiiQDLr{PhLZ)%kYw+%{=Aj`M62NoHoI%lf#0iv+W<)1)X54-a~N z-ZD+ZHdehRzw`HJTQ&g!lC9Zhd7E_97>kUj@MvyIE33G8>Ni~7B4kUIV@n+pF&Ei3 zhi-3g*DFQ;?a%Irrt9Sn$e?6lA?r;QVmVAlVYPR5KH_^5bFjFw5_cwO1XWg6juLWk z$nqJM!9wS+3!hX#>>M0LwCbuRqKqW;m>+Z7LAb*DvWSJmq@<*|fuMn9tAF3#cEP#0 zNCRm3(b67Ux&kpV2P!Hm#2|+1rXJP^BZf!D#_nGjS3qWhbYtJU)OFOwae+A^;&2`d{}t+oQ3S@{%r>? zDt}QivDmX%PV|QlT)d(2@$W&c#offq%QpWPKkJOeoC(%Ji4iF&v@TMadH!vbP;b@X z@UT*WE@F7MjZ8k~l;o@J%IZ*_3P_OB)FgKTTA=enkO-BqbGnj+(_8h-pZgu-`1m-U zRAy|x8G`b!iv%ktXU7X2LA@1!FE2?AcZNtFLBZvXAKa8J9YD$-is0Y&c6dw-@yrW{BI4am5Rl28pu>u8wZ?O(p@wq*tFRyA)xaM-I6iKBci#cl zTwEyjc+#>m#QW-*`f~>d<+pF&=EX*;=EYmB)lY4zK7amPVg>Uasx}c=+uWpSteR6d zHfGQ-Li)!&u(Ecwq_o01pa(+ zE0O1#E5~uRNp>-SG{+T-lR`mN6)(A`l0UlY^XJPmUEbu6pFYJzu`m~xlvFBB4msoU zzy@-Kpx{=8f|tg|#)^KAkx1QL&XAcI^NsZ~r5sj5B5BIP5sd}kAvy&uEn?TDwY4?R zQvhoT;nsY2@3KkBRSV)ICnvYBXeKqxTwk3FRbplXt~2Y(qoN2c1AKQ+eRq~ppHlv= z`0a@7c{$&H%aSRVpk@7#Qir42|59q(?|5?xUoI=Ii{&W*0Bsrhz4?x4WDjL6HpH5x zEb(etYv$bD!y}GiTadQ-Vvnd2;CdXOQz}{R#9B&oTY~@6jI~5QHsT&$Xu>2yey^7%Tp&*Cy3AolofVE?25Y)S7+-& z>;b-Dfd0y*nte46zp`_30;2?mU#RpdKQku=qCwguEvBYX&y;ComN$hK+R{e#VPS`8UQE+bVN0rKm%-Exa zvX9vHE_2wG7yx>00M)U#KEM8_ud&P{Xj}yYbW)iapJNg_I5zg*rK=$lYp|XSf^Oh4 zA%U`aDoK-b<4;3kR2E8@7^lRroU1Cwpk%IL<$YTZ-*~U!+H|Y(U1{lb&AJtGfY^Cw za|~gMfF_WBu)L4)JDOt2@V4!o| z$B;+Y)RZYjC$6(ia!tY!SK-yc1Btm^&mS?@D~V!GlOdal-~a0T!-b%aU`OV2$b@=& zd-Xscl`rTbks;sAg=&QY`1~aUYxk{DtF&#cl^TC`q2ID2~)J zG^7J8^Z;?|za(0;gC{M<%PldmxR|%whEP(f^8!$?C*oBQR< z7c`A=qj$~h1wJYBn`QObM=s&%8eHg}9!+zayL^26=~?as4Uw?kDof1yf>y39o{hEj z>E*O#WebK$y#3{R>hWv<%lm*UFBCnV&Cj%Z8T0e=tRf;*#l^*N0W!K-|MOD#z!gW1 z$nQR~{gnayMss-^_TXRZp&V+lEv7FTIaAgxK+*Uf{kC;E-g?qJm8s1wk*Qr_#4qf& zhV(pLO0@vIA^c)SW~g_Wtn7XofJrtnvGHxOVf14NJ3S^CpKQ;07+~X5Cd&{lzqHX& zhei3G^|A|djpOtwGM z0!eR6!A%%g!W`1P{Qdn~eBnxTPap!e{4x8>$$RO2@XlzevH(iw$6mh-UbGX{cy}0!Q!_;O9fo&a0d2@bC4%F}( zHw!da{d`2ll%UPI?iF6z zi<>(!Q|pvIdwiv*r?=C?R}SmDUQE=XJf-7DM??^`Y7-I>U0%(Mj;h?BdFbH4ci)uk z(W6H=;6OS_F_ZQ?&yp~S?J#QUFfwUWKp(W;vQKn7lsDpmZ2onAd)?eYo34tCSrX(P z+cTj6Zi0&YZlK~`EKnbS#8XpAx=o?7RNg?a&ojRJ51Xd|Q~X`*P7HE7Q?~Oo&hb4Q zGaPlyl<}hUzt~l4o&w|XDsN|GVtPRBMy#-y-oiFHH6{7NJw@ulp%qAdDR)o zTJ`$h@Gcv=wpOg)fR&3Ytfv(d5kdYK3MXUX;?3%_QPwONE_VvEfL)(cu=_B;Pwt=> zwT%i#6wS@w&pHXF64g3Qg*o{|EcK>RO%bU0_(;3Y1O{Rm)j8i@nWx=uJicRFsKaV$ zX<5+=W7WNv|FCA-dF2A1Cs}h8tg+SX(o2id~d*qh|lcStq$HvKh|>lGXL~wpw}He&&;tg}BOn{NVKh17V=%s47B5())yc zjvV=?bYym622E^mCoFRBia*BLZ@9g@yxQgJ!}8_E|X*Hhbous zArvYh))UPE^6rXi`g(d4gE~O#SCUP#8#TP-G>{C!^&}i$pd*WBFPTzCXcPftf!&}%;hdyt%(N_8&jdm{W!%!zTR`ze?Q zs<|~KwV-CTU~2PD7Pdl!&%sWY72<8gW&O1CM!ZsQiU8HdfMq4@_S}P48Cbs(Y22`Y zP{}mO3I9vwCL%AN)dMB8g_G_38&gwI1RiZpaZjiL&K`skKyA0XG2CjMP_SUAb)MF& z`AZ;6Pd2dP=kDz-RpS=4zrQ~OV6^ijP0Ec|Q&Urk#qWS3Wg3)U_O&k{AHOhUb|G;w zcJ>hSd7FLB9^u#GG5ev)XPqBUWnZt7Pk!?fDgOAe<(3RRw|2%~SrIO7Zv6Ge2BWmTr?Sxsj6zUiK~vEleB%G%a8Z*TAA;>(7QNgeBlxquInQc`|=B_?ju^-Ax?FFU0h z#YKrSauyA$lQK)N*59Xp3&3OuV9-z?4nC}g6xh1Q1_rtJ9maQ@*TNID3#pczv!Y8) z>nv|GwSEr1K3!qSF^=%MJp5%bR{Xf))r$7X!H5oS+?A8PJtI|FiUqy8mKF?sEwr$_ ze;O8^Qdd)Bp)=M$Fc9A8bF9h8_M}U5os2{M9&wxc2m1g}8dhTImtonr+%z9PB>7D# z>1$r}3O@HX|Gm^ES^2MMUS3|ipRt_UCZz^d4zhGW{wHfga|hUXY$2dCf`8hG{M)f> zy$k#~;LOl3X9R2^ynK8GROmh%A~!$D8-dQr$;rdPp`7F?4eYzq?<&rXSgbOrLa9Au zUiFQTR3@q1#ZKGYHU@)nIXif6XJ?20@k13@pKnfglQo6uiBZDzDBwLSEISAz;^OG? zCfINuK>WSKg5h@g1qF&GCX9}M>M0;d@M#mVSUO3DHur>M?Y(m$qY4NZ8WOx4D4EWyxajEM`uciZx?ri}t?9O&@WUO?r5+l7Tf}@IlPUcJNU1CjF??fU zKlvJAuWoF#zvSY$Q}<%_M^88>^mV#lviTvG=)uvEEczT!_$ z8N~MnuYE29IY+D$pRkl$w*#&(#c!gnXvHu(=Q<`nmZMw%>3S}gXKwt3h}R7C^iZ;9 zXfoYbT$FJNk4YG@EKm*Z=D85X9xrOHb*#j&a=!;V4Kn-k`j)g%JYH{~}Bs z0@Yz+Vxq3qrQ0&+f?DAurF1)3)zha!guM3fc(#&^D~u%(a3$kzKHrf?Lx@{%COFfI zvF=(0h71_a3X{^oi3x(fzCM+>K%@cLz|Wr{pFZ)cYioxA%T1+Lp5oPVqs0pfaQic* z@dGY)@r_Ci)}Gx{F_xP_38S?OgY)y@pxi>ht)HgD`i{%O50aa#qoXj8)n)6CWUhns zQxyudJT)P1KKON@U5JyZjUO2qx${$GAf_ZRRrF>o(R4ye0N$%>YrlgJ=j7!nCnRo? zb;HOBFse8@vWL__XtgcG$&+emXpqy;-~zY51B(7xxGo8efPg?t760qkuNBnP@c-1i z;+UA4wt~eVo2HDeAct6DR5?D5*@GWEHv&bsWGs8gE-Y0GB%(N+d4@uv>WMBcPWNww z&5f(C;3v9)ysXajP8E9|8peuv;0?cS#~wEgZ$B(&B4?p`gn1wCD(-MiU2I Z;U}=~(_eMg1OPh;Y5b?HQl^9o`X7_dhlBtC diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 7f8a306fb..c1ad6d24d 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,10,19,12 - PRODUCTVERSION 0,10,19,12 + FILEVERSION 0,10,19,13 + PRODUCTVERSION 0,10,19,13 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.10.19.12" + VALUE "FileVersion", "0.10.19.13" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.10.19.12" + VALUE "ProductVersion", "0.10.19.13" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index de7a9f48a..1caac85bc 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,10,19,12 - PRODUCTVERSION 0,10,19,12 + FILEVERSION 0,10,19,13 + PRODUCTVERSION 0,10,19,13 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,10 +43,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Updater" - VALUE "FileVersion", "0.10.19.12" + VALUE "FileVersion", "0.10.19.13" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.10.19.12" + VALUE "ProductVersion", "0.10.19.13" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 8937b9e54..4bf3b5ab4 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2511,26 +2511,26 @@ namespace { if (!fmt.isEmpty()) *format = fmt; } buffer.seek(0); - QString fmt = QString::fromUtf8(*format).toLower(); + auto fmt = QString::fromUtf8(*format).toLower(); if (fmt == "jpg" || fmt == "jpeg") { #ifdef OS_MAC_OLD - ExifData *exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size()); - if (exifData) { - ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); - ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION); - if (exifEntry) { - QTransform orientationFix; - int orientation = exif_get_short(exifEntry->data, byteOrder); - switch (orientation) { - case 2: orientationFix = QTransform(-1, 0, 0, 1, 0, 0); break; - case 3: orientationFix = QTransform(-1, 0, 0, -1, 0, 0); break; - case 4: orientationFix = QTransform(1, 0, 0, -1, 0, 0); break; - case 5: orientationFix = QTransform(0, -1, -1, 0, 0, 0); break; - case 6: orientationFix = QTransform(0, 1, -1, 0, 0, 0); break; - case 7: orientationFix = QTransform(0, 1, 1, 0, 0, 0); break; - case 8: orientationFix = QTransform(0, -1, 1, 0, 0, 0); break; - } - result = result.transformed(orientationFix); + if (auto exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size())) { + auto byteOrder = exif_data_get_byte_order(exifData); + if (auto exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION)) { + auto orientationFix = [exifEntry, byteOrder] { + auto orientation = exif_get_short(exifEntry->data, byteOrder); + switch (orientation) { + case 2: return QTransform(-1, 0, 0, 1, 0, 0); + case 3: return QTransform(-1, 0, 0, -1, 0, 0); + case 4: return QTransform(1, 0, 0, -1, 0, 0); + case 5: return QTransform(0, -1, -1, 0, 0, 0); + case 6: return QTransform(0, 1, -1, 0, 0, 0); + case 7: return QTransform(0, 1, 1, 0, 0, 0); + case 8: return QTransform(0, -1, 1, 0, 0, 0); + } + return QTransform(); + }; + result = result.transformed(orientationFix()); } exif_data_free(exifData); } @@ -2547,9 +2547,11 @@ namespace { if (animated) *animated = false; return QImage(); } - QByteArray img = f.readAll(); - QImage result = readImage(img, format, opaque, animated); - if (content && !result.isNull()) *content = img; + auto imageBytes = f.readAll(); + auto result = readImage(imageBytes, format, opaque, animated); + if (content && !result.isNull()) { + *content = imageBytes; + } return result; } diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 20d229417..c6f443b78 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -391,23 +391,24 @@ inline const QRegularExpression &cRussianLetters() { return regexp; } -inline QStringList cImgExtensions() { - static QStringList imgExtensions; - if (imgExtensions.isEmpty()) { - imgExtensions.reserve(4); - imgExtensions.push_back(qsl(".jpg")); - imgExtensions.push_back(qsl(".jpeg")); - imgExtensions.push_back(qsl(".png")); - imgExtensions.push_back(qsl(".gif")); +inline const QStringList &cImgExtensions() { + static QStringList result; + if (result.isEmpty()) { + result.reserve(4); + result.push_back(qsl(".jpg")); + result.push_back(qsl(".jpeg")); + result.push_back(qsl(".png")); + result.push_back(qsl(".gif")); } - return imgExtensions; + return result; } -inline QStringList cPhotoExtensions() { - static QStringList photoExtensions; - if (photoExtensions.isEmpty()) { - photoExtensions.push_back(qsl(".jpg")); - photoExtensions.push_back(qsl(".jpeg")); +inline const QStringList &cExtensionsForCompress() { + static QStringList result; + if (result.isEmpty()) { + result.push_back(qsl(".jpg")); + result.push_back(qsl(".jpeg")); + result.push_back(qsl(".png")); } - return photoExtensions; + return result; } diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index a0cbf9997..15c81fa88 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "core/utils.h" -#define BETA_VERSION_MACRO (10019012ULL) +#define BETA_VERSION_MACRO (10019013ULL) constexpr int AppVersion = 10020; constexpr str_const AppVersionStr = "0.10.20"; diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style index b64e72ba1..fc2c7b766 100644 --- a/Telegram/SourceFiles/history/history.style +++ b/Telegram/SourceFiles/history/history.style @@ -67,9 +67,6 @@ historyToDownBadgeSize: 22px; historyToDownShownAfter: 480px; historyToDownDuration: 150; -historyEmptyDog: icon {{ "history_empty_dog", #ffffff }}; -historyEmptySize: 128px; - membersInnerWidth: 310px; membersInnerHeightMax: 360px; membersInnerDropdown: InnerDropdown(defaultInnerDropdown) { diff --git a/Telegram/SourceFiles/history/history_service_layout.cpp b/Telegram/SourceFiles/history/history_service_layout.cpp index 02e8f6e8a..4560e266f 100644 --- a/Telegram/SourceFiles/history/history_service_layout.cpp +++ b/Telegram/SourceFiles/history/history_service_layout.cpp @@ -335,14 +335,6 @@ QVector ServiceMessagePainter::countLineWidths(const Text &text, const QRec } void paintEmpty(Painter &p, int width, int height) { - auto position = QPoint((width - st::historyEmptySize) / 2, ((height - st::historyEmptySize) * 4) / 9); - p.setPen(Qt::NoPen); - p.setBrush(st::msgServiceBg); - { - PainterHighQualityEnabler hq(p); - p.drawEllipse(rtlrect(position.x(), position.y(), st::historyEmptySize, st::historyEmptySize, width)); - } - st::historyEmptyDog.paint(p, position.x() + (st::historyEmptySize - st::historyEmptyDog.width()) / 2, position.y() + (st::historyEmptySize - st::historyEmptyDog.height()) / 2, width); } void serviceColorsUpdated() { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 6a3bdab90..3efcb1304 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -5551,9 +5551,7 @@ void HistoryWidget::step_recording(float64 ms, bool timer) { void HistoryWidget::chooseAttach() { if (!_history) return; - auto photoExtensions = cPhotoExtensions(); - auto imageExtensions = cImgExtensions(); - auto filter = filedialogAllFilesFilter() + qsl(";;Image files (*") + imageExtensions.join(qsl(" *")) + qsl(");;Photo files (*") + photoExtensions.join(qsl(" *")) + qsl(")"); + auto filter = filedialogAllFilesFilter() + qsl(";;Image files (*") + cImgExtensions().join(qsl(" *")) + qsl(")"); _attachFilesQueryId = FileDialog::queryReadFiles(lang(lng_choose_files), filter); } @@ -5578,7 +5576,7 @@ void HistoryWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update } } else { auto lists = getSendingFilesLists(update.filePaths); - if (lists.allFilesArePhotos) { + if (lists.allFilesForCompress) { confirmSendingFiles(lists); } else { validateSendingFiles(lists, [this](const QStringList &files) { @@ -6525,7 +6523,7 @@ bool HistoryWidget::confirmSendingFiles(const SendingFilesLists &lists, Compress auto insertTextOnCancel = QString(); auto prepareBox = [this, &files, &lists, compressed, &image] { if (files.size() > 1) { - return new SendFilesBox(files, lists.allFilesArePhotos ? compressed : CompressConfirm::None); + return new SendFilesBox(files, lists.allFilesForCompress ? compressed : CompressConfirm::None); } auto filepath = files.front(); auto animated = false; @@ -6610,8 +6608,8 @@ HistoryWidget::SendingFilesLists HistoryWidget::getSendingFilesLists(const QStri } void HistoryWidget::getSendingLocalFileInfo(SendingFilesLists &result, const QString &filepath) { - auto hasPhotoExtension = [](const QString &filepath) { - for_const (auto extension, cPhotoExtensions()) { + auto hasExtensionForCompress = [](const QString &filepath) { + for_const (auto extension, cExtensionsForCompress()) { if (filepath.right(extension.size()).compare(extension, Qt::CaseInsensitive) == 0) { return true; } @@ -6629,9 +6627,9 @@ void HistoryWidget::getSendingLocalFileInfo(SendingFilesLists &result, const QSt result.tooLargeFiles.push_back(filepath); } else { result.filesToSend.push_back(filepath); - if (result.allFilesArePhotos) { - if (filesize > App::kImageSizeLimit || !hasPhotoExtension(filepath)) { - result.allFilesArePhotos = false; + if (result.allFilesForCompress) { + if (filesize > App::kImageSizeLimit || !hasExtensionForCompress(filepath)) { + result.allFilesForCompress = false; } } } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index f7a5be999..af2fbb6c0 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -858,7 +858,7 @@ private: QStringList emptyFiles; QStringList tooLargeFiles; QStringList filesToSend; - bool allFilesArePhotos = true; + bool allFilesForCompress = true; }; SendingFilesLists getSendingFilesLists(const QList &files); SendingFilesLists getSendingFilesLists(const QStringList &files); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 6c9d2bd23..006e2e0b3 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4546,15 +4546,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateWebPage: { auto &d = update.c_updateWebPage(); - if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { - return; - } - - // update before applying skipped + // update web page anyway App::feedWebPage(d.vwebpage); _history->updatePreview(); webPagesOrGamesUpdate(); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { + return; + } ptsApplySkippedUpdates(); } break; @@ -4893,8 +4892,13 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateChannelWebPage: { auto &d = update.c_updateChannelWebPage(); - auto channel = App::channelLoaded(d.vchannel_id.v); + // update web page anyway + App::feedWebPage(d.vwebpage); + _history->updatePreview(); + webPagesOrGamesUpdate(); + + auto channel = App::channelLoaded(d.vchannel_id.v); if (channel && !_handlingChannelDifference) { if (channel->ptsRequesting()) { // skip global updates while getting channel difference return; @@ -4903,12 +4907,6 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } - - // update before applying skipped - App::feedWebPage(d.vwebpage); - _history->updatePreview(); - webPagesOrGamesUpdate(); - if (channel && !_handlingChannelDifference) { channel->ptsApplySkippedUpdates(); } diff --git a/Telegram/SourceFiles/media/player/media_player.style b/Telegram/SourceFiles/media/player/media_player.style index f2ae6476a..4dc8b7eec 100644 --- a/Telegram/SourceFiles/media/player/media_player.style +++ b/Telegram/SourceFiles/media/player/media_player.style @@ -238,17 +238,8 @@ mediaPlayerListMarginBottom: 10px; mediaPlayerScrollShadow: icon {{ "playlist_shadow", windowShadowFg }}; mediaPlayerListMarginTop: 8px; -mediaPlayerListIconFg: #ffffff; mediaPlayerFileLayout: OverviewFileLayout(overviewFileLayout) { maxWidth: 344px; - songPadding: margins(17px, 7px, 10px, 6px); - songThumbSize: 36px; - songNameTop: 7px; - songStatusTop: 25px; songIconBg: mediaPlayerActiveFg; songOverBg: mediaPlayerActiveFg; - songPause: icon {{ "playlist_pause", mediaPlayerListIconFg }}; - songPlay: icon {{ "playlist_play", mediaPlayerListIconFg }}; - songCancel: icon {{ "playlist_cancel", mediaPlayerListIconFg }}; - songDownload: icon {{ "playlist_download", mediaPlayerListIconFg }}; } diff --git a/Telegram/SourceFiles/mtproto/connection.cpp b/Telegram/SourceFiles/mtproto/connection.cpp index 98188ac58..7345c0c9a 100644 --- a/Telegram/SourceFiles/mtproto/connection.cpp +++ b/Telegram/SourceFiles/mtproto/connection.cpp @@ -2827,7 +2827,7 @@ void ConnectionPrivate::clearAuthKeyData() { if (!_authKeyStrings->dh_prime.isEmpty()) SecureZeroMemory(_authKeyStrings->dh_prime.data(), _authKeyStrings->dh_prime.size()); if (!_authKeyStrings->g_a.isEmpty()) SecureZeroMemory(_authKeyStrings->g_a.data(), _authKeyStrings->g_a.size()); #else - memset(authKeyData, 0, sizeof(AuthKeyCreateData)); + memset(_authKeyData.get(), 0, sizeof(AuthKeyCreateData)); if (!_authKeyStrings->dh_prime.isEmpty()) memset(_authKeyStrings->dh_prime.data(), 0, _authKeyStrings->dh_prime.size()); if (!_authKeyStrings->g_a.isEmpty()) memset(_authKeyStrings->g_a.data(), 0, _authKeyStrings->g_a.size()); #endif diff --git a/Telegram/SourceFiles/overview/overview.style b/Telegram/SourceFiles/overview/overview.style index 5739d1af3..8a4a5ed01 100644 --- a/Telegram/SourceFiles/overview/overview.style +++ b/Telegram/SourceFiles/overview/overview.style @@ -32,9 +32,13 @@ OverviewFileLayout { songIconBg: color; songOverBg: color; songPause: icon; + songPauseSelected: icon; songPlay: icon; + songPlaySelected: icon; songCancel: icon; + songCancelSelected: icon; songDownload: icon; + songDownloadSelected: icon; filePadding: margins; fileThumbSize: pixels; @@ -43,6 +47,9 @@ OverviewFileLayout { fileDateTop: pixels; } +overviewLeftMin: 28px; +overviewLeftMax: 42px; + overviewCheckBg: #00000040; overviewCheckFg: windowBg; overviewCheckFgActive: windowBg; @@ -70,18 +77,30 @@ overviewFileExtTop: 24px; overviewFileExtFg: #ffffff; overviewFileExtFont: font(18px semibold); +overviewSongPause: icon {{ "playlist_pause", msgInBg }}; +overviewSongPauseSelected: icon {{ "playlist_pause", msgInBgSelected }}; +overviewSongPlay: icon {{ "playlist_play", msgInBg }}; +overviewSongPlaySelected: icon {{ "playlist_play", msgInBgSelected }}; +overviewSongCancel: icon {{ "playlist_cancel", msgInBg }}; +overviewSongCancelSelected: icon {{ "playlist_cancel", msgInBgSelected }}; +overviewSongDownload: icon {{ "playlist_download", msgInBg }}; +overviewSongDownloadSelected: icon {{ "playlist_download", msgInBgSelected }}; overviewFileLayout: OverviewFileLayout { - maxWidth: 410px; - songPadding: msgFilePadding; - songThumbSize: msgFileSize; - songNameTop: msgFileNameTop; - songStatusTop: msgFileStatusTop; + maxWidth: 520px; + songPadding: margins(17px, 7px, 10px, 6px); + songThumbSize: 36px; + songNameTop: 7px; + songStatusTop: 25px; songIconBg: msgFileInBg; songOverBg: msgFileInBgOver; - songPause: historyFileInPause; - songPlay: historyFileInPlay; - songCancel: historyFileInCancel; - songDownload: historyFileInDownload; + songPause: overviewSongPause; + songPauseSelected: overviewSongPauseSelected; + songPlay: overviewSongPlay; + songPlaySelected: overviewSongPlaySelected; + songCancel: overviewSongCancel; + songCancelSelected: overviewSongCancelSelected; + songDownload: overviewSongDownload; + songDownloadSelected: overviewSongDownloadSelected; filePadding: margins(0px, 3px, 16px, 3px); fileThumbSize: 70px; @@ -97,7 +116,7 @@ overviewLoaderSkip: 4px; playlistHoverBg: windowBgOver; playlistPadding: 10px; -linksSearchMargin: margins(20px, 20px, 20px, 0px); +linksSearchTop: 30px; linksMaxWidth: 520px; linksLetterFg: #ffffff; linksLetterFont: font(24px); diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 9de617bf6..29f328b1c 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -466,9 +466,10 @@ void Video::updateStatusText() { } } -Voice::Voice(DocumentData *voice, HistoryItem *parent) : RadialProgressItem(parent) +Voice::Voice(DocumentData *voice, HistoryItem *parent, const style::OverviewFileLayout &st) : RadialProgressItem(parent) , _data(voice) -, _namel(new DocumentOpenClickHandler(_data)) { +, _namel(new DocumentOpenClickHandler(_data)) +, _st(st) { AddComponents(Info::Bit()); t_assert(_data->voice() != 0); @@ -483,8 +484,8 @@ Voice::Voice(DocumentData *voice, HistoryItem *parent) : RadialProgressItem(pare } void Voice::initDimensions() { - _maxw = st::overviewFileLayout.maxWidth; - _minh = st::overviewFileLayout.songPadding.top() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.bottom() + st::lineWidth; + _maxw = _st.maxWidth; + _minh = _st.songPadding.top() + _st.songThumbSize + _st.songPadding.bottom() + st::lineWidth; } void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) { @@ -508,16 +509,16 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1; - nameleft = st::overviewFileLayout.songPadding.left() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.right(); - nameright = st::overviewFileLayout.songPadding.left(); - nametop = st::overviewFileLayout.songNameTop; - statustop = st::overviewFileLayout.songStatusTop; + nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right(); + nameright = _st.songPadding.left(); + nametop = _st.songNameTop; + statustop = _st.songStatusTop; if (selected) { p.fillRect(clip.intersected(QRect(0, 0, _width, _height)), st::msgInBgSelected); } - QRect inner(rtlrect(st::overviewFileLayout.songPadding.left(), st::overviewFileLayout.songPadding.top(), st::overviewFileLayout.songThumbSize, st::overviewFileLayout.songThumbSize, _width)); + QRect inner(rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width)); if (clip.intersects(inner)) { p.setPen(Qt::NoPen); if (selected) { @@ -540,13 +541,13 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const auto icon = ([showPause, this, selected] { if (showPause) { - return &(selected ? st::historyFileInPauseSelected : st::historyFileInPause); + return &(selected ? _st.songPauseSelected : _st.songPause); } else if (_status.size() < 0 || _status.size() == FileStatusSizeLoaded) { - return &(selected ? st::historyFileInPlaySelected : st::historyFileInPlay); + return &(selected ? _st.songPlaySelected : _st.songPlay); } else if (_data->loading()) { - return &(selected ? st::historyFileInCancelSelected : st::historyFileInCancel); + return &(selected ? _st.songCancelSelected : _st.songCancel); } - return &(selected ? st::historyFileInDownloadSelected : st::historyFileInDownload); + return &(selected ? _st.songDownloadSelected : _st.songDownload); })(); icon->paintInCenter(p, inner); } @@ -589,12 +590,12 @@ void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, i int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; - nameleft = st::overviewFileLayout.songPadding.left() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.right(); - nameright = st::overviewFileLayout.songPadding.left(); - nametop = st::overviewFileLayout.songNameTop; - statustop = st::overviewFileLayout.songStatusTop; + nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right(); + nameright = _st.songPadding.left(); + nametop = _st.songNameTop; + statustop = _st.songStatusTop; - auto inner = rtlrect(st::overviewFileLayout.songPadding.left(), st::overviewFileLayout.songPadding.top(), st::overviewFileLayout.songThumbSize, st::overviewFileLayout.songThumbSize, _width); + auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); if (inner.contains(x, y)) { link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); return; @@ -747,13 +748,13 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con auto icon = ([showPause, loaded, this, selected] { if (showPause) { - return &(selected ? st::historyFileInPauseSelected : _st.songPause); + return &(selected ? _st.songPauseSelected : _st.songPause); } else if (loaded) { - return &(selected ? st::historyFileInPlaySelected : _st.songPlay); + return &(selected ? _st.songPlaySelected : _st.songPlay); } else if (_data->loading()) { - return &(selected ? st::historyFileInCancelSelected : _st.songCancel); + return &(selected ? _st.songCancelSelected : _st.songCancel); } - return &(selected ? st::historyFileInDownloadSelected : _st.songDownload); + return &(selected ? _st.songDownloadSelected : _st.songDownload); })(); icon->paintInCenter(p, inner); } diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index 8e23bb715..c5bc3de97 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -244,7 +244,7 @@ private: class Voice : public RadialProgressItem { public: - Voice(DocumentData *voice, HistoryItem *parent); + Voice(DocumentData *voice, HistoryItem *parent, const style::OverviewFileLayout &st); void initDimensions() override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; @@ -269,6 +269,8 @@ private: StatusText _status; ClickHandlerPtr _namel; + const style::OverviewFileLayout &_st; + Text _name, _details; int _nameVersion; diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 5f1510c7b..bb837c631 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -1276,14 +1276,21 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh if (_type == OverviewPhotos || _type == OverviewVideos) { _photosInRow = int32(_width - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip); _rowWidth = (int32(_width - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip; - } else if (_type == OverviewLinks) { - _rowWidth = qMin(_width - st::linksSearchMargin.left() - st::linksSearchMargin.right(), int32(st::linksMaxWidth)); + _rowsLeft = st::overviewPhotoSkip; } else { - _rowWidth = qMin(_width - st::profilePadding.left() - st::profilePadding.right(), st::overviewFileLayout.maxWidth); + auto contentLeftMin = st::overviewLeftMin; + auto contentLeftMax = st::overviewLeftMax; + if (_type == OverviewMusicFiles || _type == OverviewVoiceFiles) { + contentLeftMin -= st::overviewFileLayout.songPadding.left(); + contentLeftMax -= st::overviewFileLayout.songPadding.left(); + } + auto widthWithMin = st::windowMinWidth; + auto widthWithMax = st::overviewFileLayout.maxWidth + 2 * contentLeftMax; + _rowsLeft = anim::interpolate(contentLeftMax, contentLeftMin, qMax(widthWithMax - _width, 0) / float64(widthWithMax - widthWithMin)); + _rowWidth = qMin(_width - 2 * _rowsLeft, st::overviewFileLayout.maxWidth); } - _rowsLeft = (_width - _rowWidth) / 2; - _search->setGeometry(_rowsLeft, st::linksSearchMargin.top(), _rowWidth, _search->height()); + _search->setGeometry(_rowsLeft, st::linksSearchTop, _rowWidth, _search->height()); _cancelSearch->moveToLeft(_rowsLeft + _rowWidth - _cancelSearch->width(), _search->y()); if (_type == OverviewPhotos || _type == OverviewVideos) { @@ -1797,7 +1804,7 @@ void OverviewInner::recountMargins() { _marginTop = st::playlistPadding; _marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding)); } else if (_type == OverviewLinks || _type == OverviewFiles) { - _marginTop = st::linksSearchMargin.top() + _search->height() + st::linksSearchMargin.bottom(); + _marginTop = st::linksSearchTop + _search->height(); _marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding)); } else { _marginBottom = st::playlistPadding; @@ -1827,7 +1834,7 @@ Overview::Layout::ItemBase *OverviewInner::layoutPrepare(HistoryItem *item) { } else if (_type == OverviewVoiceFiles) { if (media && (media->type() == MediaTypeVoiceFile)) { if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { - i = _layoutItems.insert(item, new Overview::Layout::Voice(media->getDocument(), item)); + i = _layoutItems.insert(item, new Overview::Layout::Voice(media->getDocument(), item, st::overviewFileLayout)); i.value()->initDimensions(); } } diff --git a/Telegram/SourceFiles/profile/profile.style b/Telegram/SourceFiles/profile/profile.style index 58f24b1c2..946e7025c 100644 --- a/Telegram/SourceFiles/profile/profile.style +++ b/Telegram/SourceFiles/profile/profile.style @@ -144,3 +144,14 @@ profileVerifiedCheck: icon { { "profile_verified_star", windowBgActive, point(0px, 7px) }, { "profile_verified_check", windowFgActive, point(4px, 11px) } }; + +profileCommonGroupsSkip: 24px; +profileCommonGroupsLeftMin: 24px; +profileCommonGroupsLeftMax: 36px; +profileCommonGroupsWidthMax: 480px; +profileCommonGroupsPadding: margins(7px, 7px, 7px, 7px); +profileCommonGroupsPhotoSize: 42px; +profileCommonGroupsNameTop: 12px; +profileCommonGroupsNameLeft: 16px; +profileCommonGroupsBgOver: windowBgOver; +profileCommonGroupsRipple: defaultRippleAnimation; diff --git a/Telegram/SourceFiles/profile/profile_back_button.cpp b/Telegram/SourceFiles/profile/profile_back_button.cpp new file mode 100644 index 000000000..ea5f9fe11 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_back_button.cpp @@ -0,0 +1,72 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "profile/profile_back_button.h" + +#include "window/top_bar_widget.h" +#include "styles/style_widgets.h" +#include "styles/style_window.h" +#include "styles/style_profile.h" + +namespace Profile { + +BackButton::BackButton(QWidget *parent, const QString &text) : Ui::AbstractButton(parent) +, _text(text.toUpper()) { + setCursor(style::cur_pointer); + + subscribe(Adaptive::Changed(), [this] { updateAdaptiveLayout(); }); + updateAdaptiveLayout(); +} + +int BackButton::resizeGetHeight(int newWidth) { + return st::profileTopBarHeight; +} + +void BackButton::paintEvent(QPaintEvent *e) { + Painter p(this); + + p.fillRect(e->rect(), st::profileBg); + st::topBarBack.paint(p, (st::topBarArrowPadding.left() - st::topBarBack.width()) / 2, (st::topBarHeight - st::topBarBack.height()) / 2, width()); + + p.setFont(st::topBarButton.font); + p.setPen(st::topBarButton.textFg); + p.drawTextLeft(st::topBarArrowPadding.left(), st::topBarButton.padding.top() + st::topBarButton.textTop, width(), _text); + + Window::TopBarWidget::paintUnreadCounter(p, width()); +} + +void BackButton::onStateChanged(State was, StateChangeSource source) { + if (isDown() && !(was & StateFlag::Down)) { + emit clicked(); + } +} + +void BackButton::updateAdaptiveLayout() { + if (!Adaptive::OneColumn()) { + unsubscribe(base::take(_unreadCounterSubscription)); + } else if (!_unreadCounterSubscription) { + _unreadCounterSubscription = subscribe(Global::RefUnreadCounterUpdate(), [this] { + rtlupdate(0, 0, st::titleUnreadCounterRight, st::titleUnreadCounterTop); + }); + } +} + +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_back_button.h b/Telegram/SourceFiles/profile/profile_back_button.h new file mode 100644 index 000000000..4812b89db --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_back_button.h @@ -0,0 +1,45 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "ui/abstract_button.h" + +namespace Profile { + +class BackButton final : public Ui::AbstractButton, private base::Subscriber { +public: + BackButton(QWidget *parent, const QString &text); + +protected: + void paintEvent(QPaintEvent *e) override; + + int resizeGetHeight(int newWidth) override; + void onStateChanged(State was, StateChangeSource source) override; + +private: + void updateAdaptiveLayout(); + + int _unreadCounterSubscription = 0; + QString _text; + +}; + +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_block_common_groups.cpp b/Telegram/SourceFiles/profile/profile_block_common_groups.cpp deleted file mode 100644 index b77f993f6..000000000 --- a/Telegram/SourceFiles/profile/profile_block_common_groups.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop version of Telegram messaging app, see https://telegram.org - -Telegram Desktop is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -It is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org -*/ -#include "stdafx.h" -#include "profile/profile_block_common_groups.h" - -#include "profile/profile_section_memento.h" -#include "styles/style_widgets.h" -#include "observer_peer.h" -#include "apiwrap.h" -#include "lang.h" - -namespace Profile { -namespace { - -constexpr int kCommonGroupsPerPage = 20; - -} // namespace - -CommonGroupsWidget::CommonGroupsWidget(QWidget *parent, PeerData *peer) -: PeerListWidget(parent, peer, lang(lng_profile_common_groups_section)) { - refreshVisibility(); - - auto observeEvents = Notify::PeerUpdate::Flag::MembersChanged; - subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { - notifyPeerUpdated(update); - })); - - setSelectedCallback([this](PeerData *selectedPeer) { - Ui::showPeerHistory(selectedPeer, ShowAtUnreadMsgId, Ui::ShowWay::Forward); - }); - setPreloadMoreCallback([this] { - preloadMore(); - }); -} - -void CommonGroupsWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { - for_const (auto item, items()) { - if (item->peer == update.peer) { - updateStatusText(item); - this->update(); - return; - } - } -} - -int CommonGroupsWidget::resizeGetHeight(int newWidth) { - auto result = PeerListWidget::resizeGetHeight(newWidth); - return qRound(_height.current(result)); -} - -void CommonGroupsWidget::paintContents(Painter &p) { - _height.animating(getms()); - return PeerListWidget::paintContents(p); -} - -void CommonGroupsWidget::saveState(SectionMemento *memento) const { - if (auto count = itemsCount()) { - QList groups; - groups.reserve(count); - for_const (auto item, items()) { - groups.push_back(item->peer); - } - memento->setCommonGroups(groups); - } -} - -void CommonGroupsWidget::restoreState(const SectionMemento *memento) { - CommonGroupsEvent event; - event.groups = memento->getCommonGroups(); - if (!event.groups.empty()) { - onShowCommonGroups(event); - } -} - -void CommonGroupsWidget::onShowCommonGroups(const CommonGroupsEvent &event) { - for_const (auto group, event.groups) { - addItem(computeItem(group)); - _preloadGroupId = group->bareId(); - } - refreshVisibility(); - if (event.initialHeight >= 0) { - _height.start([this] { contentSizeUpdated(); }, event.initialHeight, resizeGetHeight(width()), st::widgetSlideDuration); - } - contentSizeUpdated(); - update(); -} - -void CommonGroupsWidget::preloadMore() { - if (_preloadRequestId || !_preloadGroupId) { - return; - } - auto user = peer()->asUser(); - t_assert(user != nullptr); - auto request = MTPmessages_GetCommonChats(user->inputUser, MTP_int(_preloadGroupId), MTP_int(kCommonGroupsPerPage)); - _preloadRequestId = MTP::send(request, ::rpcDone(base::lambda_guarded(this, [this](const MTPmessages_Chats &result) { - _preloadRequestId = 0; - _preloadGroupId = 0; - - if (auto chats = Api::getChatsFromMessagesChats(result)) { - auto &list = chats->c_vector().v; - if (!list.empty()) { - reserveItemsForSize(itemsCount() + list.size()); - for_const (auto &chatData, list) { - if (auto chat = App::feedChat(chatData)) { - addItem(computeItem(chat)); - _preloadGroupId = chat->bareId(); - } - } - contentSizeUpdated(); - } - } - }))); -} - -void CommonGroupsWidget::updateStatusText(Item *item) { - auto group = item->peer; - if (auto chat = group->asChat()) { - auto count = qMax(chat->count, chat->participants.size()); - item->statusText = count ? lng_chat_status_members(lt_count, count) : lang(lng_group_status); - } else if (auto megagroup = group->asMegagroup()) { - auto count = megagroup->membersCount(); - item->statusText = (count > 0) ? lng_chat_status_members(lt_count, count) : lang(lng_group_status); - - // Request members count. - if (!megagroup->wasFullUpdated()) App::api()->requestFullPeer(megagroup); - } else if (auto channel = group->asChannel()) { - auto count = channel->membersCount(); - item->statusText = (count > 0) ? lng_chat_status_members(lt_count, count) : lang(lng_channel_status); - - // Request members count. - if (!channel->wasFullUpdated()) App::api()->requestFullPeer(channel); - } else { - t_assert(!"Users should not get to CommonGroupsWidget::updateStatusText()"); - } -} - -CommonGroupsWidget::Item *CommonGroupsWidget::computeItem(PeerData *group) { - // Skip groups that migrated to supergroups. - if (group->migrateTo()) { - return nullptr; - } - - auto it = _dataMap.constFind(group); - if (it == _dataMap.cend()) { - it = _dataMap.insert(group, new Item(group)); - updateStatusText(it.value()); - } - return it.value(); -} - -CommonGroupsWidget::~CommonGroupsWidget() { - for (auto item : base::take(_dataMap)) { - delete item; - } -} - -} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_block_common_groups.h b/Telegram/SourceFiles/profile/profile_block_common_groups.h deleted file mode 100644 index b005668ca..000000000 --- a/Telegram/SourceFiles/profile/profile_block_common_groups.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop version of Telegram messaging app, see https://telegram.org - -Telegram Desktop is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -It is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org -*/ -#pragma once - -#include "profile/profile_block_peer_list.h" - -namespace Notify { -struct PeerUpdate; -} // namespace Notify - -namespace Profile { - -struct CommonGroupsEvent { - QList groups; - - // If initialHeight >= 0 the common groups widget will - // slide down starting from height() == initialHeight. - // Otherwise it will just show instantly. - int initialHeight = -1; -}; - -class CommonGroupsWidget : public PeerListWidget { -public: - CommonGroupsWidget(QWidget *parent, PeerData *peer); - - void setShowCommonGroupsObservable(base::Observable *observable) { - subscribe(observable, [this](const CommonGroupsEvent &event) { onShowCommonGroups(event); }); - } - - void saveState(SectionMemento *memento) const override; - void restoreState(const SectionMemento *memento) override; - - ~CommonGroupsWidget(); - -protected: - int resizeGetHeight(int newWidth) override; - void paintContents(Painter &p) override; - -private: - // Observed notifications. - void notifyPeerUpdated(const Notify::PeerUpdate &update); - - void updateStatusText(Item *item); - void onShowCommonGroups(const CommonGroupsEvent &event); - void preloadMore(); - - Item *computeItem(PeerData *group); - QMap _dataMap; - - Animation _height; - - int32 _preloadGroupId = 0; - mtpRequestId _preloadRequestId = 0; - -}; - -} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_block_info.cpp b/Telegram/SourceFiles/profile/profile_block_info.cpp index 01f032d7b..9872fea02 100644 --- a/Telegram/SourceFiles/profile/profile_block_info.cpp +++ b/Telegram/SourceFiles/profile/profile_block_info.cpp @@ -21,13 +21,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "profile/profile_block_info.h" -#include "profile/profile_block_common_groups.h" +#include "profile/profile_common_groups_section.h" #include "profile/profile_section_memento.h" #include "styles/style_profile.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/effects/widget_slide_wrap.h" #include "core/click_handler_types.h" +#include "mainwidget.h" #include "observer_peer.h" #include "apiwrap.h" #include "lang.h" @@ -69,12 +70,6 @@ void InfoWidget::slideCommonGroupsDown() { contentSizeUpdated(); } -void InfoWidget::restoreState(const SectionMemento *memento) { - if (!memento->getCommonGroups().isEmpty()) { - onForceHideCommonGroups(); - } -} - void InfoWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { if (update.peer != peer()) { return; @@ -253,7 +248,7 @@ int InfoWidget::getCommonGroupsCount() const { } void InfoWidget::refreshCommonGroups() { - if (auto count = (_forceHiddenCommonGroups ? 0 : getCommonGroupsCount())) { + if (auto count = getCommonGroupsCount()) { auto text = lng_profile_common_groups(lt_count, count); if (_commonGroups) { _commonGroups->setText(text); @@ -270,56 +265,15 @@ void InfoWidget::refreshCommonGroups() { } } -void InfoWidget::setShowCommonGroupsObservable(base::Observable *observable) { - _showCommonGroupsObservable = observable; - subscribe(_showCommonGroupsObservable, [this](const CommonGroupsEvent &event) { - onForceHideCommonGroups(); - }); -} - -void InfoWidget::onForceHideCommonGroups() { - if (_forceHiddenCommonGroups) { - return; - } - _forceHiddenCommonGroups = true; - _commonGroups.destroyDelayed(); - refreshVisibility(); - contentSizeUpdated(); -} - void InfoWidget::onShowCommonGroups() { auto count = getCommonGroupsCount(); if (count <= 0) { refreshCommonGroups(); return; } - if (_getCommonGroupsRequestId) { - return; + if (auto main = App::main()) { + main->showWideSection(Profile::CommonGroups::SectionMemento(peer())); } - auto user = peer()->asUser(); - t_assert(user != nullptr); - auto request = MTPmessages_GetCommonChats(user->inputUser, MTP_int(0), MTP_int(kCommonGroupsLimit)); - _getCommonGroupsRequestId = MTP::send(request, ::rpcDone(base::lambda_guarded(this, [this](const MTPmessages_Chats &result) { - _getCommonGroupsRequestId = 0; - - CommonGroupsEvent event; - if (auto chats = Api::getChatsFromMessagesChats(result)) { - auto &list = chats->c_vector().v; - event.groups.reserve(list.size()); - for_const (auto &chatData, list) { - if (auto chat = App::feedChat(chatData)) { - event.groups.push_back(chat); - } - } - } - - auto oldHeight = height(); - onForceHideCommonGroups(); - if (!event.groups.empty() && _showCommonGroupsObservable) { - event.initialHeight = oldHeight - (isHidden() ? 0 : height()); - _showCommonGroupsObservable->notify(event, true); - } - }))); } void InfoWidget::setLabeledText(ChildWidget *labelWidget, const QString &label, diff --git a/Telegram/SourceFiles/profile/profile_block_info.h b/Telegram/SourceFiles/profile/profile_block_info.h index 8736395f8..dd9956d92 100644 --- a/Telegram/SourceFiles/profile/profile_block_info.h +++ b/Telegram/SourceFiles/profile/profile_block_info.h @@ -36,17 +36,12 @@ class LeftOutlineButton; namespace Profile { -struct CommonGroupsEvent; class InfoWidget : public BlockWidget, public RPCSender { public: InfoWidget(QWidget *parent, PeerData *peer); - void setShowCommonGroupsObservable(base::Observable *observable); - void showFinished() override; - void restoreState(const SectionMemento *memento) override; - protected: // Resizes content and counts natural widget height for the desired width. int resizeGetHeight(int newWidth) override; @@ -66,7 +61,6 @@ private: void refreshVisibility(); int getCommonGroupsCount() const; - void onForceHideCommonGroups(); void onShowCommonGroups(); void slideCommonGroupsDown(); @@ -87,11 +81,6 @@ private: Animation _height; bool _showFinished = false; - bool _forceHiddenCommonGroups = false; - mtpRequestId _getCommonGroupsRequestId = 0; - - base::Observable *_showCommonGroupsObservable = nullptr; - }; } // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_common_groups_section.cpp b/Telegram/SourceFiles/profile/profile_common_groups_section.cpp new file mode 100644 index 000000000..274f9ce82 --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_common_groups_section.cpp @@ -0,0 +1,446 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "profile/profile_common_groups_section.h" + +#include "profile/profile_section_memento.h" +#include "profile/profile_back_button.h" +#include "styles/style_widgets.h" +#include "styles/style_profile.h" +#include "styles/style_window.h" +#include "styles/style_settings.h" +#include "ui/effects/ripple_animation.h" +#include "ui/widgets/scroll_area.h" +#include "ui/widgets/shadow.h" +#include "mainwidget.h" +#include "observer_peer.h" +#include "apiwrap.h" +#include "lang.h" + +namespace Profile { +namespace CommonGroups { +namespace { + +constexpr int kCommonGroupsPerPage = 40; + +} // namespace + +Window::SectionWidget *SectionMemento::createWidget(QWidget *parent, const QRect &geometry) const { + auto result = new Widget(parent, _peer); + result->setInternalState(geometry, this); + return result; +} + +FixedBar::FixedBar(QWidget *parent) : TWidget(parent) +, _backButton(this, lang(lng_profile_common_groups_section)) { + _backButton->moveToLeft(0, 0); + connect(_backButton, SIGNAL(clicked()), this, SLOT(onBack())); +} + +void FixedBar::onBack() { + App::main()->showBackFromStack(); +} + +int FixedBar::resizeGetHeight(int newWidth) { + auto newHeight = 0; + + auto buttonLeft = newWidth; + _backButton->resizeToWidth(newWidth); + _backButton->moveToLeft(0, 0); + newHeight += _backButton->height(); + + return newHeight; +} + +void FixedBar::setAnimatingMode(bool enabled) { + if (_animatingMode != enabled) { + _animatingMode = enabled; + setCursor(_animatingMode ? style::cur_pointer : style::cur_default); + if (_animatingMode) { + setAttribute(Qt::WA_OpaquePaintEvent, false); + hideChildren(); + } else { + setAttribute(Qt::WA_OpaquePaintEvent); + showChildren(); + } + show(); + } +} + +void FixedBar::mousePressEvent(QMouseEvent *e) { + if (e->button() == Qt::LeftButton) { + onBack(); + } else { + TWidget::mousePressEvent(e); + } +} + +InnerWidget::Item::Item(PeerData *peer) : peer(peer) { +} + +InnerWidget::Item::~Item() = default; + +InnerWidget::InnerWidget(QWidget *parent, PeerData *peer) : TWidget(parent) +, _peer(peer) { + setMouseTracking(true); + setAttribute(Qt::WA_OpaquePaintEvent); + _rowHeight = st::profileCommonGroupsPadding.top() + st::profileCommonGroupsPhotoSize + st::profileCommonGroupsPadding.bottom(); + _contentTop = st::profileCommonGroupsSkip; +} + +void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { + _visibleTop = visibleTop; + _visibleBottom = visibleBottom; + + checkPreloadMore(); +} + +void InnerWidget::checkPreloadMore() { + if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop) > height()) { + preloadMore(); + } +} + +void InnerWidget::saveState(SectionMemento *memento) const { + if (auto count = _items.size()) { + QList groups; + groups.reserve(count); + for_const (auto item, _items) { + groups.push_back(item->peer); + } + memento->setCommonGroups(groups); + } +} + +void InnerWidget::restoreState(const SectionMemento *memento) { + auto list = memento->getCommonGroups(); + _allLoaded = false; + if (!list.empty()) { + showInitial(list); + } +} + +void InnerWidget::showInitial(const QList &list) { + for_const (auto group, list) { + _items.push_back(computeItem(group)); + _preloadGroupId = group->bareId(); + } + updateSize(); +} + +void InnerWidget::preloadMore() { + if (_preloadRequestId || _allLoaded) { + return; + } + auto user = peer()->asUser(); + t_assert(user != nullptr); + auto request = MTPmessages_GetCommonChats(user->inputUser, MTP_int(_preloadGroupId), MTP_int(kCommonGroupsPerPage)); + _preloadRequestId = MTP::send(request, ::rpcDone(base::lambda_guarded(this, [this](const MTPmessages_Chats &result) { + _preloadRequestId = 0; + _preloadGroupId = 0; + _allLoaded = true; + if (auto chats = Api::getChatsFromMessagesChats(result)) { + auto &list = chats->c_vector().v; + if (!list.empty()) { + _items.reserve(_items.size() + list.size()); + for_const (auto &chatData, list) { + if (auto chat = App::feedChat(chatData)) { + auto found = false; + for_const (auto item, _items) { + if (item->peer == chat) { + found = true; + break; + } + } + if (!found) { + _items.push_back(computeItem(chat)); + } + _preloadGroupId = chat->bareId(); + _allLoaded = false; + } + } + updateSize(); + } + } + }))); +} + +void InnerWidget::updateSize() { + TWidget::resizeToWidth(width()); + checkPreloadMore(); +} + +int InnerWidget::resizeGetHeight(int newWidth) { + update(); + + auto contentLeftMin = st::profileCommonGroupsLeftMin; + auto contentLeftMax = st::profileCommonGroupsLeftMax; + auto widthWithMin = st::windowMinWidth; + auto widthWithMax = st::profileCommonGroupsWidthMax + 2 * contentLeftMax; + _contentLeft = anim::interpolate(contentLeftMax, contentLeftMin, qMax(widthWithMax - newWidth, 0) / float64(widthWithMax - widthWithMin)); + _contentWidth = qMin(newWidth - 2 * _contentLeft, st::profileCommonGroupsWidthMax); + + auto newHeight = _contentTop; + newHeight += _items.size() * _rowHeight; + newHeight += st::profileCommonGroupsSkip; + return qMax(newHeight, _minHeight); +} + +void InnerWidget::paintEvent(QPaintEvent *e) { + Painter p(this); + + auto ms = getms(); + auto clip = e->rect(); + p.fillRect(clip, st::profileBg); + + auto from = floorclamp(clip.y() - _contentTop, _rowHeight, 0, _items.size()); + auto to = ceilclamp(clip.y() + clip.height() - _contentTop, _rowHeight, 0, _items.size()); + for (auto i = from; i != to; ++i) { + paintRow(p, i, ms); + } +} + +void InnerWidget::paintRow(Painter &p, int index, TimeMs ms) { + auto item = _items[index]; + auto selected = (_pressed >= 0) ? (index == _pressed) : (index == _selected); + + auto x = _contentLeft; + auto y = _contentTop + index * _rowHeight; + if (selected) { + p.fillRect(myrtlrect(x, y, _contentWidth, _rowHeight), st::profileCommonGroupsBgOver); + } + if (auto &ripple = item->ripple) { + ripple->paint(p, x, y, width(), ms); + if (ripple->empty()) { + ripple.reset(); + } + } + + x += st::profileCommonGroupsPadding.left(); + y += st::profileCommonGroupsPadding.top(); + item->peer->paintUserpic(p, st::profileCommonGroupsPhotoSize, rtl() ? (width() - x - st::profileCommonGroupsPhotoSize) : x, y); + + x += st::profileCommonGroupsPhotoSize + st::profileCommonGroupsNameLeft; + y += st::profileCommonGroupsNameTop; + auto nameWidth = _contentWidth - (x - _contentLeft) - st::profileCommonGroupsPadding.right(); + if (item->name.isEmpty()) { + item->name.setText(st::semiboldFont, App::peerName(item->peer), _textNameOptions); + } + _items[index]->name.drawLeftElided(p, x, y, nameWidth, width()); +} + +void InnerWidget::keyPressEvent(QKeyEvent *e) { + +} + +void InnerWidget::updateSelected(QPoint localPos) { + auto selected = -1; + auto selectedKick = false; + + if (rtl()) localPos.setX(width() - localPos.x()); + if (localPos.x() >= _contentLeft && localPos.x() < _contentLeft + _contentWidth && localPos.y() >= _contentTop) { + selected = (localPos.y() - _contentTop) / _rowHeight; + if (selected >= _items.size()) { + selected = -1; + } + } + + if (_selected != selected) { + updateRow(_selected); + _selected = selected; + updateRow(_selected); + if (_pressed < 0) { + setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default); + } + } +} + +void InnerWidget::updateRow(int index) { + rtlupdate(_contentLeft, _contentTop + index * _rowHeight, _contentWidth, _rowHeight); +} + +void InnerWidget::mousePressEvent(QMouseEvent *e) { + _pressed = _selected; + if (_pressed >= 0) { + auto item = _items[_pressed]; + if (!item->ripple) { + auto mask = Ui::RippleAnimation::rectMask(QSize(_contentWidth, _rowHeight)); + item->ripple = std_::make_unique(st::profileCommonGroupsRipple, std_::move(mask), [this, index = _pressed] { + updateRow(index); + }); + } + auto left = _contentLeft; + auto top = _contentTop + _rowHeight * _pressed; + item->ripple->add(e->pos() - QPoint(left, top)); + } +} + +void InnerWidget::mouseMoveEvent(QMouseEvent *e) { + updateSelected(e->pos()); +} + +void InnerWidget::mouseReleaseEvent(QMouseEvent *e) { + updateRow(_pressed); + auto pressed = base::take(_pressed, -1); + if (pressed >= 0 && pressed < _items.size()) { + if (auto &ripple = _items[pressed]->ripple) { + ripple->lastStop(); + } + if (pressed == _selected) { + Ui::showPeerHistory(_items[pressed]->peer, ShowAtUnreadMsgId, Ui::ShowWay::Forward); + } + } + setCursor(_selected ? style::cur_pointer : style::cur_default); + updateRow(_selected); +} + +InnerWidget::Item *InnerWidget::computeItem(PeerData *group) { + // Skip groups that migrated to supergroups. + if (group->migrateTo()) { + return nullptr; + } + + auto it = _dataMap.constFind(group); + if (it == _dataMap.cend()) { + it = _dataMap.insert(group, new Item(group)); + } + return it.value(); +} + +InnerWidget::~InnerWidget() { + for (auto item : base::take(_dataMap)) { + delete item; + } +} + +Widget::Widget(QWidget *parent, PeerData *peer) : Window::SectionWidget(parent) +, _scroll(this, st::settingsScroll) +, _inner(this, peer) +, _fixedBar(this) +, _fixedBarShadow(this, st::shadowColor) { + _fixedBar->move(0, 0); + _fixedBar->resizeToWidth(width()); + _fixedBar->show(); + + _fixedBarShadow->raise(); + updateAdaptiveLayout(); + subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); }); + + _scroll->setOwnedWidget(_inner); + _scroll->move(0, _fixedBar->height()); + _scroll->show(); + + connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); + connect(_inner, SIGNAL(cancelled()), _fixedBar, SLOT(onBack())); +} + +void Widget::updateAdaptiveLayout() { + _fixedBarShadow->moveToLeft(Adaptive::OneColumn() ? 0 : st::lineWidth, _fixedBar->height()); +} + +PeerData *Widget::peer() const { + return _inner->peer(); +} + +QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) { + if (params.withTopBarShadow) _fixedBarShadow->hide(); + auto result = myGrab(this); + if (params.withTopBarShadow) _fixedBarShadow->show(); + return result; +} + +void Widget::setInnerFocus() { + _inner->setFocus(); +} + +bool Widget::showInternal(const Window::SectionMemento *memento) { + if (auto profileMemento = dynamic_cast(memento)) { + if (profileMemento->getPeer() == peer()) { + restoreState(profileMemento); + return true; + } + } + return false; +} + +void Widget::setInternalState(const QRect &geometry, const SectionMemento *memento) { + setGeometry(geometry); + myEnsureResized(this); + restoreState(memento); +} + +std_::unique_ptr Widget::createMemento() const { + auto result = std_::make_unique(peer()); + saveState(result.get()); + return std_::move(result); +} + +void Widget::saveState(SectionMemento *memento) const { + memento->setScrollTop(_scroll->scrollTop()); + _inner->saveState(memento); +} + +void Widget::restoreState(const SectionMemento *memento) { + _inner->restoreState(memento); + auto scrollTop = memento->getScrollTop(); + _scroll->scrollToY(scrollTop); + _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); +} + +void Widget::resizeEvent(QResizeEvent *e) { + if (!width() || !height()) { + return; + } + + int newScrollTop = _scroll->scrollTop() + topDelta(); + _fixedBar->resizeToWidth(width()); + _fixedBarShadow->resize(width(), st::lineWidth); + + QSize scrollSize(width(), height() - _fixedBar->height()); + if (_scroll->size() != scrollSize) { + _scroll->resize(scrollSize); + _inner->resizeToWidth(scrollSize.width(), _scroll->height()); + } + + if (!_scroll->isHidden()) { + if (topDelta()) { + _scroll->scrollToY(newScrollTop); + } + int scrollTop = _scroll->scrollTop(); + _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); + } +} + +void Widget::onScroll() { + int scrollTop = _scroll->scrollTop(); + _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); +} + +void Widget::showAnimatedHook() { + _fixedBar->setAnimatingMode(true); +} + +void Widget::showFinishedHook() { + _fixedBar->setAnimatingMode(false); +} + +} // namespace CommonGroups +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_common_groups_section.h b/Telegram/SourceFiles/profile/profile_common_groups_section.h new file mode 100644 index 000000000..b6abf408c --- /dev/null +++ b/Telegram/SourceFiles/profile/profile_common_groups_section.h @@ -0,0 +1,216 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "window/section_widget.h" +#include "window/section_memento.h" + +namespace Notify { +struct PeerUpdate; +} // namespace Notify + +namespace Ui { +class ScrollArea; +class PlainShadow; +} // namespace Ui + +namespace Profile { + +class BackButton; + +namespace CommonGroups { + +class SectionMemento : public Window::SectionMemento { +public: + SectionMemento(PeerData *peer) : _peer(peer) { + } + + Window::SectionWidget *createWidget(QWidget *parent, const QRect &geometry) const override; + + PeerData *getPeer() const { + return _peer; + } + void setScrollTop(int scrollTop) { + _scrollTop = scrollTop; + } + int getScrollTop() const { + return _scrollTop; + } + void setCommonGroups(const QList &groups) { + _commonGroups = groups; + } + const QList &getCommonGroups() const { + return _commonGroups; + } + +private: + PeerData *_peer; + int _scrollTop = 0; + QList _commonGroups; + +}; + +class FixedBar final : public TWidget, private base::Subscriber { + Q_OBJECT + +public: + FixedBar(QWidget *parent); + + // When animating mode is enabled the content is hidden and the + // whole fixed bar acts like a back button. + void setAnimatingMode(bool enabled); + +protected: + void mousePressEvent(QMouseEvent *e) override; + int resizeGetHeight(int newWidth) override; + +public slots: + void onBack(); + +private: + ChildWidget _backButton; + + bool _animatingMode = false; + +}; + +class InnerWidget final : public TWidget { + Q_OBJECT + +public: + InnerWidget(QWidget *parent, PeerData *peer); + + PeerData *peer() const { + return _peer; + } + + // Updates the area that is visible inside the scroll container. + void setVisibleTopBottom(int visibleTop, int visibleBottom) override; + + void resizeToWidth(int newWidth, int minHeight) { + _minHeight = minHeight; + return TWidget::resizeToWidth(newWidth); + } + + void saveState(SectionMemento *memento) const; + void restoreState(const SectionMemento *memento); + + ~InnerWidget(); + +signals: + void cancelled(); + +protected: + void paintEvent(QPaintEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + + // Resizes content and counts natural widget height for the desired width. + int resizeGetHeight(int newWidth) override; + +private: + void updateSelected(QPoint localPos); + void updateRow(int index); + void showInitial(const QList &list); + void checkPreloadMore(); + void preloadMore(); + void updateSize(); + void paintRow(Painter &p, int index, TimeMs ms); + + PeerData *_peer; + + int _minHeight = 0; + int _rowHeight = 0; + int _contentLeft = 0; + int _contentTop = 0; + int _contentWidth = 0; + int _visibleTop = 0; + int _visibleBottom = 0; + + struct Item { + explicit Item(PeerData *peer); + ~Item(); + + PeerData * const peer; + Text name; + std_::unique_ptr ripple; + }; + Item *computeItem(PeerData *group); + QMap _dataMap; + QList _items; + int _selected = -1; + int _pressed = -1; + + int32 _preloadGroupId = 0; + mtpRequestId _preloadRequestId = 0; + bool _allLoaded = true; + +}; + +class Widget final : public Window::SectionWidget { + Q_OBJECT + +public: + Widget(QWidget *parent, PeerData *peer); + + PeerData *peer() const; + PeerData *peerForDialogs() const override { + return peer(); + } + + bool hasTopBarShadow() const override { + return true; + } + + QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms) override; + + void setInnerFocus() override; + + bool showInternal(const Window::SectionMemento *memento) override; + std_::unique_ptr createMemento() const override; + + void setInternalState(const QRect &geometry, const SectionMemento *memento); + +protected: + void resizeEvent(QResizeEvent *e) override; + + void showAnimatedHook() override; + void showFinishedHook() override; + + private slots: + void onScroll(); + +private: + void updateAdaptiveLayout(); + void saveState(SectionMemento *memento) const; + void restoreState(const SectionMemento *memento); + + ChildWidget _scroll; + ChildWidget _inner; + ChildWidget _fixedBar; + ChildWidget _fixedBarShadow; + +}; + +} // namespace CommonGroups +} // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_fixed_bar.cpp b/Telegram/SourceFiles/profile/profile_fixed_bar.cpp index 77f73b739..934e86dc5 100644 --- a/Telegram/SourceFiles/profile/profile_fixed_bar.cpp +++ b/Telegram/SourceFiles/profile/profile_fixed_bar.cpp @@ -29,59 +29,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "boxes/addcontactbox.h" #include "boxes/confirmbox.h" #include "observer_peer.h" -#include "window/top_bar_widget.h" #include "styles/style_boxes.h" +#include "profile/profile_back_button.h" namespace Profile { - -class BackButton final : public Ui::AbstractButton, private base::Subscriber { -public: - BackButton(QWidget *parent) : Ui::AbstractButton(parent) - , _text(lang(lng_menu_back).toUpper()) { - setCursor(style::cur_pointer); - - subscribe(Adaptive::Changed(), [this] { updateAdaptiveLayout(); }); - updateAdaptiveLayout(); - } - -protected: - int resizeGetHeight(int newWidth) override { - return st::profileTopBarHeight; - } - void paintEvent(QPaintEvent *e) override { - Painter p(this); - - p.fillRect(e->rect(), st::profileBg); - st::topBarBack.paint(p, (st::topBarArrowPadding.left() - st::topBarBack.width()) / 2, (st::topBarHeight - st::topBarBack.height()) / 2, width()); - - p.setFont(st::topBarButton.font); - p.setPen(st::topBarButton.textFg); - p.drawTextLeft(st::topBarArrowPadding.left(), st::topBarButton.padding.top() + st::topBarButton.textTop, width(), _text); - - Window::TopBarWidget::paintUnreadCounter(p, width()); - } - void onStateChanged(State was, StateChangeSource source) override { - if (isDown() && !(was & StateFlag::Down)) { - emit clicked(); - } - } - -private: - void updateAdaptiveLayout() { - if (!Adaptive::OneColumn()) { - unsubscribe(base::take(_unreadCounterSubscription)); - } else if (!_unreadCounterSubscription) { - _unreadCounterSubscription = subscribe(Global::RefUnreadCounterUpdate(), [this] { - rtlupdate(0, 0, st::titleUnreadCounterRight, st::titleUnreadCounterTop); - }); - } - } - - int _unreadCounterSubscription = 0; - QString _text; - -}; - namespace { using UpdateFlag = Notify::PeerUpdate::Flag; @@ -98,7 +49,7 @@ FixedBar::FixedBar(QWidget *parent, PeerData *peer) : TWidget(parent) , _peerChat(peer->asChat()) , _peerChannel(peer->asChannel()) , _peerMegagroup(peer->isMegagroup() ? _peerChannel : nullptr) -, _backButton(this) { +, _backButton(this, lang(lng_menu_back)) { _backButton->moveToLeft(0, 0); connect(_backButton, SIGNAL(clicked()), this, SLOT(onBack())); diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.cpp b/Telegram/SourceFiles/profile/profile_inner_widget.cpp index 38322712e..c44dadd20 100644 --- a/Telegram/SourceFiles/profile/profile_inner_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_inner_widget.cpp @@ -24,7 +24,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "styles/style_profile.h" #include "styles/style_window.h" #include "profile/profile_cover.h" -#include "profile/profile_block_common_groups.h" #include "profile/profile_block_info.h" #include "profile/profile_block_settings.h" #include "profile/profile_block_invite_link.h" @@ -50,16 +49,7 @@ void InnerWidget::createBlocks() { auto channel = _peer->asChannel(); auto megagroup = _peer->isMegagroup() ? channel : nullptr; if (user || channel || megagroup) { - auto widget = new InfoWidget(this, _peer); - widget->setShowCommonGroupsObservable(&_showCommonGroupsObservable); - _blocks.push_back({ widget, BlockSide::Right }); - } - if (user) { - _commonGroupsWidget = new CommonGroupsWidget(this, _peer); - _commonGroupsWidget->setShowCommonGroupsObservable(&_showCommonGroupsObservable); - _blocks.push_back({ _commonGroupsWidget, BlockSide::Right }); - } else { - _commonGroupsWidget = nullptr; + _blocks.push_back({ new InfoWidget(this, _peer), BlockSide::Right }); } _blocks.push_back({ new SettingsWidget(this, _peer), BlockSide::Right }); if (chat || channel || megagroup) { diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.h b/Telegram/SourceFiles/profile/profile_inner_widget.h index 7230ecf90..877ec6612 100644 --- a/Telegram/SourceFiles/profile/profile_inner_widget.h +++ b/Telegram/SourceFiles/profile/profile_inner_widget.h @@ -20,13 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "profile/profile_block_common_groups.h" - namespace Profile { class CoverWidget; class BlockWidget; -struct CommonGroupsEvent; class SectionMemento; class InnerWidget final : public TWidget { @@ -117,12 +114,8 @@ private: }; QList _blocks; - // We need to save this pointer for getting common groups list for section memento. - CommonGroupsWidget *_commonGroupsWidget = nullptr; - Mode _mode = Mode::OneColumn; - base::Observable _showCommonGroupsObservable; }; } // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_section_memento.h b/Telegram/SourceFiles/profile/profile_section_memento.h index 680cb592b..73505f023 100644 --- a/Telegram/SourceFiles/profile/profile_section_memento.h +++ b/Telegram/SourceFiles/profile/profile_section_memento.h @@ -42,17 +42,10 @@ public: int getScrollTop() const { return _scrollTop; } - void setCommonGroups(const QList &groups) { - _commonGroups = groups; - } - const QList &getCommonGroups() const { - return _commonGroups; - } private: PeerData *_peer; int _scrollTop = 0; - QList _commonGroups; }; diff --git a/Telegram/SourceFiles/profile/profile_widget.cpp b/Telegram/SourceFiles/profile/profile_widget.cpp index 30c42d76c..54120e3b5 100644 --- a/Telegram/SourceFiles/profile/profile_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_widget.cpp @@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwindow.h" #include "application.h" #include "ui/widgets/scroll_area.h" +#include "ui/widgets/shadow.h" namespace Profile { @@ -61,6 +62,10 @@ PeerData *Widget::peer() const { return _inner->peer(); } +bool Widget::hasTopBarShadow() const { + return _fixedBarShadow->isFullyShown(); +} + QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) { if (params.withTopBarShadow) _fixedBarShadow->hide(); auto result = myGrab(this); diff --git a/Telegram/SourceFiles/profile/profile_widget.h b/Telegram/SourceFiles/profile/profile_widget.h index 850acbd32..d3cade576 100644 --- a/Telegram/SourceFiles/profile/profile_widget.h +++ b/Telegram/SourceFiles/profile/profile_widget.h @@ -21,10 +21,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "window/section_widget.h" -#include "ui/widgets/shadow.h" namespace Ui { class ScrollArea; +class ToggleableShadow; } // namespace Ui namespace Profile { @@ -43,9 +43,7 @@ public: return peer(); } - bool hasTopBarShadow() const override { - return _fixedBarShadow->isFullyShown(); - } + bool hasTopBarShadow() const override; QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms) override; diff --git a/Telegram/SourceFiles/ui/effects/send_action_animations.cpp b/Telegram/SourceFiles/ui/effects/send_action_animations.cpp index 54e5f1d23..18004ed1f 100644 --- a/Telegram/SourceFiles/ui/effects/send_action_animations.cpp +++ b/Telegram/SourceFiles/ui/effects/send_action_animations.cpp @@ -179,7 +179,7 @@ void CreateImplementationsMap() { Implementations.createIfNull(); Type recordTypes[] = { Type::RecordVideo, - Type::RecordVoice + Type::RecordVoice, }; for_const (auto type, recordTypes) { Implementations->insert(type, &RecordAnimation::kMeta); @@ -188,7 +188,7 @@ void CreateImplementationsMap() { Type::UploadFile, Type::UploadPhoto, Type::UploadVideo, - Type::UploadVoice + Type::UploadVoice, }; for_const (auto type, uploadTypes) { Implementations->insert(type, &UploadAnimation::kMeta); diff --git a/Telegram/SourceFiles/ui/widgets/widgets.style b/Telegram/SourceFiles/ui/widgets/widgets.style index 084c813b0..852605b1f 100644 --- a/Telegram/SourceFiles/ui/widgets/widgets.style +++ b/Telegram/SourceFiles/ui/widgets/widgets.style @@ -882,17 +882,17 @@ historySendActionTypingLargeNumerator: 28px; historySendActionTypingSmallNumerator: 16px; historySendActionTypingDenominator: 12.; -historySendActionRecordDuration: 300; +historySendActionRecordDuration: 500; historySendActionRecordPosition: point(1px, -4px); -historySendActionRecordDelta: 3px; -historySendActionRecordStrokeNumerator: 12px; +historySendActionRecordDelta: 4px; +historySendActionRecordStrokeNumerator: 16px; historySendActionRecordDenominator: 8.; historySendActionUploadDuration: 500; historySendActionUploadPosition: point(0px, -4px); historySendActionUploadDelta: 5px; -historySendActionUploadStrokeNumerator: 12px; -historySendActionUploadSizeNumerator: 28px; +historySendActionUploadStrokeNumerator: 16px; +historySendActionUploadSizeNumerator: 32px; historySendActionUploadDenominator: 8.; MediaPlayerButton { diff --git a/Telegram/build/version b/Telegram/build/version index da285d56d..112e9a899 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -3,4 +3,4 @@ AppVersionStrMajor 0.10 AppVersionStrSmall 0.10.20 AppVersionStr 0.10.20 AlphaChannel 0 -BetaVersion 10019012 +BetaVersion 10019013 diff --git a/Telegram/gyp/Telegram.gyp b/Telegram/gyp/Telegram.gyp index dd64f3347..b16993665 100644 --- a/Telegram/gyp/Telegram.gyp +++ b/Telegram/gyp/Telegram.gyp @@ -390,12 +390,12 @@ '<(src_loc)/platform/platform_main_window.h', '<(src_loc)/platform/platform_notifications_manager.h', '<(src_loc)/platform/platform_window_title.h', + '<(src_loc)/profile/profile_back_button.cpp', + '<(src_loc)/profile/profile_back_button.h', '<(src_loc)/profile/profile_block_actions.cpp', '<(src_loc)/profile/profile_block_actions.h', '<(src_loc)/profile/profile_block_channel_members.cpp', '<(src_loc)/profile/profile_block_channel_members.h', - '<(src_loc)/profile/profile_block_common_groups.cpp', - '<(src_loc)/profile/profile_block_common_groups.h', '<(src_loc)/profile/profile_block_info.cpp', '<(src_loc)/profile/profile_block_info.h', '<(src_loc)/profile/profile_block_invite_link.cpp', @@ -410,6 +410,8 @@ '<(src_loc)/profile/profile_block_shared_media.h', '<(src_loc)/profile/profile_block_widget.cpp', '<(src_loc)/profile/profile_block_widget.h', + '<(src_loc)/profile/profile_common_groups_section.cpp', + '<(src_loc)/profile/profile_common_groups_section.h', '<(src_loc)/profile/profile_cover_drop_area.cpp', '<(src_loc)/profile/profile_cover_drop_area.h', '<(src_loc)/profile/profile_cover.cpp',