From a02876562a0d96f4d36f2960a4e7cb87f5071ef1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 17 May 2023 15:51:04 +0400 Subject: [PATCH] Finish improved stories reply area theming. --- Telegram/CMakeLists.txt | 1 + .../Resources/icons/emoji/stickers_add.png | Bin 470 -> 0 bytes .../Resources/icons/emoji/stickers_add@2x.png | Bin 899 -> 0 bytes .../Resources/icons/emoji/stickers_add@3x.png | Bin 1345 -> 0 bytes .../icons/emoji/stickers_add_dot.png | Bin 255 -> 0 bytes .../icons/emoji/stickers_add_dot@2x.png | Bin 312 -> 0 bytes .../icons/emoji/stickers_add_dot@3x.png | Bin 494 -> 0 bytes .../icons/emoji/stickers_add_unread.png | Bin 527 -> 0 bytes .../icons/emoji/stickers_add_unread@2x.png | Bin 1007 -> 0 bytes .../icons/emoji/stickers_add_unread@3x.png | Bin 1430 -> 0 bytes .../SourceFiles/boxes/sticker_set_box.cpp | 1 + Telegram/SourceFiles/boxes/translate_box.cpp | 4 +- .../chat_helpers/chat_helpers.style | 198 ++++++++++++------ .../chat_helpers/compose/compose_features.h | 27 +++ .../chat_helpers/emoji_list_widget.cpp | 47 +++-- .../chat_helpers/emoji_list_widget.h | 3 + .../chat_helpers/emoji_suggestions_widget.cpp | 149 +++++++++++-- .../chat_helpers/emoji_suggestions_widget.h | 119 +---------- .../chat_helpers/field_autocomplete.cpp | 7 +- .../chat_helpers/gifs_list_widget.cpp | 18 +- .../chat_helpers/gifs_list_widget.h | 7 +- .../chat_helpers/message_field.cpp | 12 +- .../SourceFiles/chat_helpers/message_field.h | 4 +- .../chat_helpers/stickers_list_footer.cpp | 63 +++--- .../chat_helpers/stickers_list_footer.h | 8 +- .../chat_helpers/stickers_list_widget.cpp | 87 ++++---- .../chat_helpers/stickers_list_widget.h | 7 +- .../SourceFiles/chat_helpers/tabbed_panel.cpp | 8 +- .../chat_helpers/tabbed_selector.cpp | 10 +- .../chat_helpers/tabbed_selector.h | 6 +- .../SourceFiles/history/history_widget.cpp | 2 +- .../history_view_compose_controls.cpp | 15 +- .../controls/history_view_compose_controls.h | 17 +- .../info_userpic_emoji_builder_widget.cpp | 2 +- .../media/stories/media_stories_reply.cpp | 35 +++- .../SourceFiles/media/view/media_view.style | 110 +++++++++- Telegram/SourceFiles/menu/menu_send.cpp | 13 +- Telegram/SourceFiles/menu/menu_send.h | 7 +- 38 files changed, 638 insertions(+), 349 deletions(-) delete mode 100644 Telegram/Resources/icons/emoji/stickers_add.png delete mode 100644 Telegram/Resources/icons/emoji/stickers_add@2x.png delete mode 100644 Telegram/Resources/icons/emoji/stickers_add@3x.png delete mode 100644 Telegram/Resources/icons/emoji/stickers_add_dot.png delete mode 100644 Telegram/Resources/icons/emoji/stickers_add_dot@2x.png delete mode 100644 Telegram/Resources/icons/emoji/stickers_add_dot@3x.png delete mode 100644 Telegram/Resources/icons/emoji/stickers_add_unread.png delete mode 100644 Telegram/Resources/icons/emoji/stickers_add_unread@2x.png delete mode 100644 Telegram/Resources/icons/emoji/stickers_add_unread@3x.png create mode 100644 Telegram/SourceFiles/chat_helpers/compose/compose_features.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 5c559e8a5d..3ed0b31c80 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -348,6 +348,7 @@ PRIVATE calls/calls_video_bubble.h calls/calls_video_incoming.cpp calls/calls_video_incoming.h + chat_helpers/compose/compose_features.h chat_helpers/compose/compose_show.cpp chat_helpers/compose/compose_show.h chat_helpers/bot_command.cpp diff --git a/Telegram/Resources/icons/emoji/stickers_add.png b/Telegram/Resources/icons/emoji/stickers_add.png deleted file mode 100644 index d4c77a202c4fe31fcf48f38f030c8f0df0d2be25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf%)!&eF~maf z?i9nURtJH$_@uss<-O_w0;?Mm-m>m#*}h@>3E8IQ7ra>39$~(*V(QkZM}I$R3$1bU zFmT;;)adj1?VC4mUbp@Bep!EYbz|SlpKW5VC+=EzdefS9uZ909Jo#OB+2pg0xa-G# zJUlTjPVC%rs;+^LEaolK>{1F1-Oiw=q{y%#_r(D=skVdL-ZtM*5@cfd&GqAg=4@X7 zO&v!W64KL`u!`)z{i;;bT9Btgy>8dE)Qjh0<2&~1CU0lsnUOv9*XAudUaneotZ>Sy zPDZvfLMQilcwgSKEqCeZ#wLXWrLogzZkjP!<>coWg9DF*h2KR@{7`SRUi53Nzo?O* zb@y3U-9(8~6AX9`Yn%@1%6841W!3ljMowoQuR(&`*|3bP0l+XkK$!@e| diff --git a/Telegram/Resources/icons/emoji/stickers_add@2x.png b/Telegram/Resources/icons/emoji/stickers_add@2x.png deleted file mode 100644 index f188f440d5c88257b522c9abcd0c829c02f5d77b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 899 zcmV-}1AP36P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NE?MXyIR9Fe^n7@i5K@i5(UDiaw zR1-B=A3+QS1<^pC!w2vg6!s1DDOB)JU}R=ys4T1pi{@%%a`(F{wpX@$#%X80n*%41 zw&ts^zNzZ2?wL^Ne%&*0&%kXn5cW?Wi^Wo@6g=DQ_INz{C$we=hr@+Jq1|pTm&^Tr z|MTqPFGg+w0A@{X>+tya*laf6-`~$PI1YgU#>Fa%#Y5EV^_Q2ITrMX84u`{dJYFmo zRBE@|VN52I)GnXTSF6={JT9>HdfjTZ27`f>tP9{sB+}`0R4V54IU%2(o}Apc1pt_G z!5tDOyq%pnI~)#$`t|jdJbCvAjEnd}0+n}PGm^(rYNpd^B9SoToUORvs5JS_ld4p= z+kJR=aE|MC2ghEoCz>F1gSy`%;ljcrUadw#;I8syRrF7VEZ5a)g&-!u6_xrV`WQhX z^9fqpUhtcP79#2K@<7pO)Me3qND8TxL#~XT1~ggeek|RK4oLa&=klUSdI98ieVoQG z>7kum6hx~Oui={o+J#ZWR;Db6>#4yy3{ z{Cr*=N;a8HKvpUh%A{PJN~UO4AmzfqAc(rMGO4kgl+V#JMia*_-HrmI{R>iP31OT- z=90a=y}`oS?+e$r{1sXWp%a<~jYcD&?#Du%%Zr6+F5O>3=q_eK{eB-PRV$TBx{n`A zxm=c>A|bp|1#WXixYhB4LU3Jt-0P1YPzUaSh9>nufjGiS{)2VMM^oTlgU}SL7ey%? zc~Z4wqrT~@^#A#>LGr{ey@397)6X#~mc@WRe!CA=7A13%%&h;%pY)uR-R<`b+%sUx Zz%Qq1$)w8hFSq~z002ovPDHLkV1nQ&jgbHV diff --git a/Telegram/Resources/icons/emoji/stickers_add@3x.png b/Telegram/Resources/icons/emoji/stickers_add@3x.png deleted file mode 100644 index 48de8115e323951613e07414864f0ccc3f964d3f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1345 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1SD_us|Wxo#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz1|Sip>6gA`6MbbHUhz_QxY#W5s< z_3bQMeUm_uept zOZ0rd^l?LL>+kR0%#A(&#P8ru>*s&Y|DR)79KSq(Bm9H|GTdtvaOOnd$`C18Sy@R* zNjW(=8JV2?{QT_f!`DB5{(SlJ<)=@d9zA;W=g*%vZ{ECpJK9aA=8&1W`T29_-o1T$ z_x}C;)-fv<_Hee@RaP8%G;__`wYGM4RxQGdn-rflR4fV64hasv{O8Y~w{LTK?ypzV znsDo}(~qp~pZpvF4A)MrEc?B3rDoiWqQ2|buS-iyKYsjpPx7<3Lh*l=OpMl85SGWS zuwhYr{=x_yJzZVb3|kwUHEY&f$lbBoQBs)4RK%9+!H$CC9~a-ebm@@y`jvb3?OV5g zeR)~gvf>7y?HN8X4>V*Gq*mX%7q=_(Y(jng{`Kqid9V3PJ2YH6VR7iL|Jt0oiB7Vj zrki){cyV2{;ec1gj?;g327cMa6dxD2Z29uPZmAau4?sF{%oiWvjPDP0&b^S;FLN#nZogFMZ6Abf4tQ@k4(1Oo0w&E4{bY z*^%ETU-F{Zf6HZmbwPd6s7BtH}2jQ?VmNtBust7q3K%< zyn9~tO#OE8;zUhXma8#yHL_(i9CdEqD4K2R>h9j&XklUDaqQHubpj2ON>fw#eO>_5 zM%NtyN8uHw2Ge#4F*EN!!7FIO=&LiW=V>P|4^PL(u#9I*#@)ubn*E`SR?I1g}fK z_oy%4a7JjAP|UHs3<;kO)z2HJByIYbzb{+URdfHmd2-njSA?vldTm_2x_ftddHM3? z%bx};6FGfbS=Y(A!&M}v{@t559+s}#*kcv#zV6|3a9D*S1N5n|H6~ z%t+cOr`!0_?(nU{$E-fwSOF5y(`hWcq?{%!EUaYia)HHUqe)7UHD_A>iyuF3ENM~Q zRoXU9tuoJS$246|P*9x<>XHCv749Qv&h(rp72A^St7+T&za;yB=7XBNX98Bn=W6oy z3r5?S`*7-PkG^x{*vtkyr4uI?vNRSx{VdUWps4zTd(KarRev>(J1Nd@f30RVZ?;`e z+TZEz=M{Z&_T+z2z2rY@t8Ti|>C>k}&rS_|#w=!e!O-FW)4aEhyEqqLia*96ws}*M zc%v=P=aUyNTnI?E6Pby>nF!|clyQ1RvI>gTe~DWM4fuGm(L diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot.png b/Telegram/Resources/icons/emoji/stickers_add_dot.png deleted file mode 100644 index 1bb4078f4ef84939c06077e904c5366a51d5576d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUWqP_ehFAzD zCrE5-m>DwvgcUiWqsHizux`05aBSM%e8JkPIRzXXJqZ2I*1v*I#_li%Op zSI$m%dM1!!U-Ls?9otM^ag}KYPn_WRB6vYpTrbAJ#6%_R_KIB>1tfSIFA6M3=U`xv WbkX?w=dQy|kma7PelF{r5}E)nyGHQ< diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png b/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png deleted file mode 100644 index 1723a7f362b4ee19c6fa27df5984115e19a03e46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@HgnjK|#PZP}w$E#P%i|8GSGb1PPOgx&J_{FpB;g6kqY)l*q0@@RTPFZfh zc1*(RRgC8wA?~YN%GQ3J**@uh)uiKh&Xg~$NsMj`{@QbV@gfF)*I1soU{S6gA`6MbbAj}7UAjQ7?Q#I z_L^Z)feo{VZjw2Y+mvc=N+{ zsSk#q_szF@{Pa*O0~3cr1CW@b`l0Na)A_Z@kzpdPjsg~a#yrlk*B@KhnYT7xO_bP{ z`+MWgX{jeSo!OSly!-05Da%$KxzSR^Gke)b8-MGGfu*0;d<&|5uHAKLMO*0E6XjnY z^VZm`Is2k&@2X|S%QgBQ`~KhUeAC0kc7Jx)xs?-b12#|CbY?-qy4P7vCm9!L8f!${ z|30hlX~g9zk|I8K^Gaj+XRllJYQwP|OqQ+X=Dq8sFPr?_mmhP#o%iJa);WjjQ@kfV zDG+kzesX`2&guI%pG590SY^F!&Y@2y@8)fCb;u?;og^V}p1P>_=jV5Av*b Yj0WeW+@f@u!$4u}>FVdQ&MBb@0G5=r5C8xG diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread.png b/Telegram/Resources/icons/emoji/stickers_add_unread.png deleted file mode 100644 index d8172e22b3195555a73c7c591972c1e2013eb6b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 527 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgftkToPF~maf zZpg;2W(R?@vG0V}m~ez?^0KUM?%0;8`a}3%>)xY(oj+)AndIQa#ko?nC(Kh?vE$Be zoi)c|g&*$n*?4A8t+BPS_3p(NZ=X6o`BX@#sc-P4CA-#b)`?z!efsI8{r^wijnJFk zemHUe{q#s%F7~=8OQXM3lag1U$mgFm96P5scTG55 zzgWTMS5ueO^P2lhnGd->R#!!Pc6 zIplijuCK19XS^q=Tyb&SmU}oxM=WBZSlIpVi#3$yJpO1g)2E|v>&Xr$=Bb->3|CCK zlQQMG<)#JF7Bgl1iV9`g^8{T3r@SrmKB%@>fy2Z%dA9G$Tvn3_hYfO?d+q-GGE`MC zpC_C9z~Rv~!|e*?cjV7Z_h$+G(B@EGkld@@FIMa5dV)33A-UF)#%i#b3 diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png b/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png deleted file mode 100644 index c48562529e6a2a6b2ec9a4de5c4217d7da2cb14c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1007 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFSxH1eR9Fe^m_17~K@i6^hNLl~ z=?wUiLb0;2kTilMg0JZ3$OrHCdput79Kq0r&sp>jpBSlry) zj6@ zeVs5V6R(gdShbNdVW1(@Xf#N8j!`0!aH^^?oNjM#)l>~&pp`2H83-&}u+g6-ruvZG z-`}&gyu9o-u$Ks|Y~e=J6S};-M70-fA;(;*zieSj=PbYykA!%w)m-HHb(l-|$8Spvk`NbZlM}iH@8b+yfh+ z+U;b%=J!>ajHCKVhO0;!`bN_tc@gFBw)xnA6}Kk$6gLBGr1~M`cH7_IKR-YBg0+&9 zt|p&j#4A)klmlkCFPaotuMbvyzv3$v-?C8fU5lF}e1y!4G)GlB3i=yuN8x2SkPkdC d@IYTY@E<*jYW#(_g^K_H002ovPDHLkV1fgd%1HnK diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png b/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png deleted file mode 100644 index 46a03b994c2f7388e781560a87777fe89a82ce12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1430 zcmV;H1!?+;P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=07*naRA>e5n!7JOK@`W`OGF|f zo&||#LP?@j2o;405nBHNy(q+^Qz(CbfPzFsB^nZiLLwm~qVZ}Z;!UB!?-LW}PWIlr zb9c?|`u(!E;Oy+oIp1^U%$YN1HZL#!#TJMy5L+O&Kx~270%5qg`T6(Z*MPaEFF4nZ7r|H#>Q%DYV6{% zz%7wTOixdXCW?4?c$l4?C2Uv_5DAOo;$k9%uGQPy+rq*^d3kvxc0%d__S}ie%E~`q zKZx8%1>2L8h~(^KO#X5Ulv1XF@C~=KvvX-_X?%Q~UB@?*)IiQxGF>w>GpQF|sLjny z#RS63xKv;4%OO=U85$Z&y~si(v$Ut0M@L8Hf!$f?kO{)FoD%x``;F2KigCj4?(SAx zIM0(z894^jfr0|ZImNuEr^hJ8pcn^`va&M8Wqp0!$S%+h+uPfUe_dT&b91x1EVE)V zeq&=p=tzjItu2w;)zu|*M#7*N=U*8{<{@+>#NOVX$TjYz2E`g18-*A3385n)ZfYBpC?E_8Qyx4*xiZV}~*>Ftgdfg!*g9ddnKSy>T}l8ryt!CJqc zr&KTlfPev*#y$gSa78`Di?uSa38hH~paaV&+@P2qGxX4(kyp@-IshG5M!5#XxaN^z zeSLjGM?&ZTbYOnK5QXGIi1qD<#n%`sYYYHtjR8r*V>U>J8KW8{sV7-XghhEoOBw|v zfMrujwHp+p)AI7Nuoxa57CK}?7p+6`592qK2B=3+l~8_2odQVy_0dO0Ud*9_Bs&;j zbZkGOqbmIo-;1A=;)U4ql;M{4rO$R@5`?RDT`%=#L>>)v~U{ z1DP?3nF!S}1VsmTxlUx)W1!LsaY1R4&e!_q5abr@!m?kfrG*EEG*`NYI6Vtm_ZiTT z_;7LIDOaX5-@M3$j#3G>Fb{lP>H0Wm<0nTgEiI0k0*^HE$r0Zq$w@@%qyDmA1sK^K z3b;J7Y3BHm7{^}y3o%_8MUyeXDv({+MFIC$q;UQ|>r*P>iVU}$2f8En^p*pKrw=hX z3lkw2V(ldI4L9*kSpLt^ov6T%YYmDpOodu$xFQ#m=jZ3RB^wk!;)G?{F}v6Tu?1oa k#1@Dx5L+O&K*$#O3zAGWa{bB&;{X5v07*qoM6N<$f?oQH@c;k- diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index 0f661181a0..82e4e3deba 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -606,6 +606,7 @@ void StickerSetBox::updateButtons() { const auto session = &_show->session(); auto box = ChatHelpers::MakeConfirmRemoveSetBox( session, + st::boxLabel, _inner->setId()); if (box) { _show->showBox(std::move(box)); diff --git a/Telegram/SourceFiles/boxes/translate_box.cpp b/Telegram/SourceFiles/boxes/translate_box.cpp index 662cf51e59..066ba855b2 100644 --- a/Telegram/SourceFiles/boxes/translate_box.cpp +++ b/Telegram/SourceFiles/boxes/translate_box.cpp @@ -63,7 +63,7 @@ ShowButton::ShowButton(not_null parent) _button.sizeValue( ) | rpl::start_with_next([=](const QSize &s) { resize( - s.width() + st::emojiSuggestionsFadeRight.width(), + s.width() + st::defaultEmojiSuggestions.fadeRight.width(), s.height()); _button.moveToRight(0, 0); }, lifetime()); @@ -74,7 +74,7 @@ void ShowButton::paintEvent(QPaintEvent *e) { auto p = QPainter(this); const auto clip = e->rect(); - const auto &icon = st::emojiSuggestionsFadeRight; + const auto &icon = st::defaultEmojiSuggestions.fadeRight; const auto fade = QRect(0, 0, icon.width(), height()); if (fade.intersects(clip)) { icon.fill(p, fade); diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index ceec7e3ecf..ba786876fc 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -10,6 +10,7 @@ using "ui/basic.style"; using "boxes/boxes.style"; using "ui/layers/layers.style"; using "ui/widgets/widgets.style"; +using "ui/menu_icons.style"; GroupCallUserpics { size: pixels; @@ -36,9 +37,50 @@ TabbedSearch { height: pixels; } +ComposeIcons { + settings: icon; + + recent: icon; + recentActive: icon; + people: icon; + peopleActive: icon; + nature: icon; + natureActive: icon; + food: icon; + foodActive: icon; + activity: icon; + activityActive: icon; + travel: icon; + travelActive: icon; + objects: icon; + objectsActive: icon; + symbols: icon; + symbolsActive: icon; + + menuFave: icon; + menuUnfave: icon; + menuStickerSet: icon; + menuRecentRemove: icon; + menuGifAdd: icon; + menuGifRemove: icon; + menuMute: icon; + menuSchedule: icon; + menuWhenOnline: icon; +} + +EmojiSuggestions { + dropdown: InnerDropdown; + bg: color; + overBg: color; + textFg: color; + fadeLeft: icon; + fadeRight: icon; +} + EmojiPan { margin: margins; padding: margins; + showAnimation: PanelAnimation; desiredSize: pixels; verticalSizeSub: pixels; header: pixels; @@ -51,8 +93,12 @@ EmojiPan { iconWidth: pixels; iconArea: pixels; bg: color; + headerFg: color; + trendingHeaderFg: color; + trendingSubheaderFg: color; + trendingUnreadFg: color; + trendingInstalled: icon; overBg: color; - expandBg: color; pathBg: color; pathFg: color; textFg: color; @@ -60,9 +106,14 @@ EmojiPan { categoriesBgOver: color; fadeLeft: icon; fadeRight: icon; + menu: PopupMenu; tabs: SettingsSlider; search: TabbedSearch; searchMargin: margins; + removeSet: IconButton; + boxLabel: FlatLabel; + icons: ComposeIcons; + autocompleteBottomSkip: pixels; } MessageBar { @@ -96,6 +147,7 @@ ComposeControls { send: SendButton; attach: IconButton; emoji: EmojiButton; + suggestions: EmojiSuggestions; tabbed: EmojiPan; } @@ -191,12 +243,6 @@ stickersScroll: ScrollArea(boxScroll) { stickersRowDisabledOpacity: 0.4; stickersRowDuration: 200; -stickersSettings: icon {{ "emoji/emoji_settings", emojiIconFg }}; -stickersTrending: icon {{ "emoji/stickers_add", emojiIconFg }}; -stickersTrendingUnread: icon { - { "emoji/stickers_add_unread", emojiIconFg }, - { "emoji/stickers_add_dot", dialogsUnreadBg } -}; emojiStatusDefault: icon {{ "emoji/stickers_premium", emojiIconFg }}; filtersRemove: IconButton(stickersRemove) { @@ -210,22 +256,6 @@ emojiTabs: SettingsSlider(defaultTabsSlider) { barTop: 40px; labelTop: 12px; } -emojiRecent: icon {{ "emoji/emoji_recent", emojiIconFg }}; -emojiRecentActive: icon {{ "emoji/emoji_recent", emojiSubIconFgActive }}; -emojiPeople: icon {{ "emoji/emoji_smile", emojiIconFg }}; -emojiPeopleActive: icon {{ "emoji/emoji_smile", emojiSubIconFgActive }}; -emojiNature: icon {{ "emoji/emoji_nature", emojiIconFg }}; -emojiNatureActive: icon {{ "emoji/emoji_nature", emojiSubIconFgActive }}; -emojiFood: icon {{ "emoji/emoji_food", emojiIconFg }}; -emojiFoodActive: icon {{ "emoji/emoji_food", emojiSubIconFgActive }}; -emojiActivity: icon {{ "emoji/emoji_activities", emojiIconFg }}; -emojiActivityActive: icon {{ "emoji/emoji_activities", emojiSubIconFgActive }}; -emojiTravel: icon {{ "emoji/emoji_travel", emojiIconFg }}; -emojiTravelActive: icon {{ "emoji/emoji_travel", emojiSubIconFgActive }}; -emojiObjects: icon {{ "emoji/emoji_objects", emojiIconFg }}; -emojiObjectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }}; -emojiSymbols: icon {{ "emoji/emoji_love", emojiIconFg }}; -emojiSymbolsActive: icon {{ "emoji/emoji_love", emojiSubIconFgActive }}; emojiCategoryIconTop: 6px; emojiPanAnimation: PanelAnimation(defaultPanelAnimation) { @@ -297,40 +327,6 @@ defaultTabbedSearch: TabbedSearch { groupSkip: 2px; height: 33px; } -defaultEmojiPan: EmojiPan { - margin: margins(7px, 0px, 7px, 0px); - padding: margins(7px, 0px, 4px, 7px); - desiredSize: 37px; - verticalSizeSub: 1px; - header: 33px; - headerLeft: 14px; - headerLockLeft: 7px; - headerLockedLeft: 26px; - headerTop: 10px; - footer: 36px; - iconSkip: 3px; - iconWidth: 30px; - iconArea: 28px; - bg: emojiPanBg; - overBg: emojiPanHover; - expandBg: emojiPanHeaderFg; - pathBg: windowBgRipple; - pathFg: windowBgOver; - textFg: windowFg; - categoriesBg: emojiPanCategories; - categoriesBgOver: windowBgRipple; - fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }}; - fadeRight: icon {{ "fade_horizontal", emojiPanCategories }}; - tabs: emojiTabs; - search: defaultTabbedSearch; - searchMargin: margins(1px, 11px, 2px, 5px); -} -statusEmojiPan: EmojiPan(defaultEmojiPan) { - categoriesBg: windowBg; - categoriesBgOver: windowBgOver; - fadeLeft: icon {{ "fade_horizontal-flip_horizontal", windowBg }}; - fadeRight: icon {{ "fade_horizontal", windowBg }}; -} inlineResultsMinHeight: 278px; inlineResultsMaxHeight: 640px; @@ -394,6 +390,81 @@ stickersToast: Toast(defaultToast) { stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }}; emojiEmpty: icon {{ "emoji_empty", windowSubTextFg }}; +defaultComposeIcons: ComposeIcons { + settings: icon {{ "emoji/emoji_settings", emojiIconFg }}; + + recent: icon {{ "emoji/emoji_recent", emojiIconFg }}; + recentActive: icon {{ "emoji/emoji_recent", emojiSubIconFgActive }}; + people: icon {{ "emoji/emoji_smile", emojiIconFg }}; + peopleActive: icon {{ "emoji/emoji_smile", emojiSubIconFgActive }}; + nature: icon {{ "emoji/emoji_nature", emojiIconFg }}; + natureActive: icon {{ "emoji/emoji_nature", emojiSubIconFgActive }}; + food: icon {{ "emoji/emoji_food", emojiIconFg }}; + foodActive: icon {{ "emoji/emoji_food", emojiSubIconFgActive }}; + activity: icon {{ "emoji/emoji_activities", emojiIconFg }}; + activityActive: icon {{ "emoji/emoji_activities", emojiSubIconFgActive }}; + travel: icon {{ "emoji/emoji_travel", emojiIconFg }}; + travelActive: icon {{ "emoji/emoji_travel", emojiSubIconFgActive }}; + objects: icon {{ "emoji/emoji_objects", emojiIconFg }}; + objectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }}; + symbols: icon {{ "emoji/emoji_love", emojiIconFg }}; + symbolsActive: icon {{ "emoji/emoji_love", emojiSubIconFgActive }}; + + menuFave: menuIconFave; + menuUnfave: menuIconUnfave; + menuStickerSet: menuIconStickers; + menuRecentRemove: menuIconDelete; + menuGifAdd: menuIconGif; + menuGifRemove: menuIconDelete; + menuMute: menuIconMute; + menuSchedule: menuIconSchedule; + menuWhenOnline: menuIconWhenOnline; +} +defaultEmojiPan: EmojiPan { + margin: margins(7px, 0px, 7px, 0px); + padding: margins(7px, 0px, 4px, 7px); + showAnimation: emojiPanAnimation; + desiredSize: 37px; + verticalSizeSub: 1px; + header: 33px; + headerLeft: 14px; + headerLockLeft: 7px; + headerLockedLeft: 26px; + headerTop: 10px; + footer: 36px; + iconSkip: 3px; + iconWidth: 30px; + iconArea: 28px; + bg: emojiPanBg; + headerFg: emojiPanHeaderFg; + trendingHeaderFg: stickersTrendingHeaderFg; + trendingSubheaderFg: stickersTrendingSubheaderFg; + trendingUnreadFg: stickersFeaturedUnreadBg; + trendingInstalled: stickersFeaturedInstalled; + overBg: emojiPanHover; + pathBg: windowBgRipple; + pathFg: windowBgOver; + textFg: windowFg; + categoriesBg: emojiPanCategories; + categoriesBgOver: windowBgRipple; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }}; + fadeRight: icon {{ "fade_horizontal", emojiPanCategories }}; + menu: popupMenuWithIcons; + tabs: emojiTabs; + search: defaultTabbedSearch; + searchMargin: margins(1px, 11px, 2px, 5px); + removeSet: stickerPanRemoveSet; + boxLabel: boxLabel; + icons: defaultComposeIcons; + autocompleteBottomSkip: 0px; +} +statusEmojiPan: EmojiPan(defaultEmojiPan) { + categoriesBg: windowBg; + categoriesBgOver: windowBgOver; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", windowBg }}; + fadeRight: icon {{ "fade_horizontal", windowBg }}; +} + inlineBotsScroll: ScrollArea(defaultSolidScroll) { deltat: stickerPanPadding; deltab: stickerPanPadding; @@ -410,6 +481,15 @@ emojiSuggestionsScrolledWidth: 240px; emojiSuggestionsPadding: margins(emojiColorsPadding, 0px, emojiColorsPadding, 0px); emojiSuggestionsFadeAfter: 20px; +defaultEmojiSuggestions: EmojiSuggestions { + dropdown: emojiSuggestionsDropdown; + bg: menuBg; + overBg: emojiPanHover; + textFg: windowFg; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }}; + fadeRight: icon {{ "fade_horizontal", boxBg }}; +} + mentionHeight: 40px; mentionPadding: margins(8px, 5px, 8px, 5px); mentionTop: 11px; @@ -479,9 +559,6 @@ reactPanelScroll: ScrollArea(emojiScroll) { deltab: 7px; } -emojiSuggestionsFadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }}; -emojiSuggestionsFadeRight: icon {{ "fade_horizontal", boxBg }}; - choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }}; choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }}; choosePeerCreateIconLeft: 25px; @@ -857,5 +934,6 @@ defaultComposeControls: ComposeControls { send: historySend; attach: historyAttach; emoji: historyAttachEmoji; + suggestions: defaultEmojiSuggestions; tabbed: defaultEmojiPan; } diff --git a/Telegram/SourceFiles/chat_helpers/compose/compose_features.h b/Telegram/SourceFiles/chat_helpers/compose/compose_features.h new file mode 100644 index 0000000000..2f99156799 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/compose/compose_features.h @@ -0,0 +1,27 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace ChatHelpers { + +struct ComposeFeatures { + bool sendAs = true; + bool ttlInfo = true; + bool botCommandSend = true; + bool silentBroadcastToggle = true; + bool attachBotsMenu = true; + bool inlineBots = true; + bool megagroupSet = true; + bool stickersSettings = true; + bool openStickerSets = true; + bool autocompleteHashtags = true; + bool autocompleteMentions = true; + bool autocompleteCommands = true; +}; + +} // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index a6ff9af754..3d5f35c57f 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -99,6 +99,7 @@ private: QSize _singleSize; QPoint _areaPosition; QPoint _innerPosition; + Ui::RoundRect _backgroundRect; Ui::RoundRect _overBg; bool _hiding = false; @@ -125,6 +126,7 @@ EmojiColorPicker::EmojiColorPicker( const style::EmojiPan &st) : RpWidget(parent) , _st(st) +, _backgroundRect(st::emojiPanRadius, _st.bg) , _overBg(st::emojiPanRadius, _st.overBg) { setMouseTracking(true); } @@ -181,8 +183,8 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) { p.drawPixmap(0, 0, _cache); return; } - Ui::Shadow::paint(p, inner, width(), st::emojiPanAnimation.shadow); - Ui::FillRoundRect(p, inner, st::boxBg, Ui::BoxCorners); + Ui::Shadow::paint(p, inner, width(), _st.showAnimation.shadow); + _backgroundRect.paint(p, inner); auto x = st::emojiPanMargins.left() + 2 * st::emojiColorsPadding + _singleSize.width(); if (rtl()) x = width() - x - st::emojiColorsSep; @@ -393,6 +395,7 @@ EmojiListWidget::EmojiListWidget( descriptor.show, std::move(descriptor.paused)) , _show(std::move(descriptor.show)) +, _features(descriptor.features) , _mode(descriptor.mode) , _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1) , _premiumIcon(_mode == Mode::EmojiStatus @@ -402,7 +405,7 @@ EmojiListWidget::EmojiListWidget( std::make_unique(&session())) , _customRecentFactory(std::move(descriptor.customRecentFactory)) , _overBg(st::emojiPanRadius, st().overBg) -, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg) +, _collapsedBg(st::emojiPanExpand.height / 2, st().headerFg) , _picker(this, st()) , _showPickerTimer([=] { showPicker(); }) { setMouseTracking(true); @@ -1072,7 +1075,7 @@ void EmojiListWidget::paint( - paintButtonGetWidth(p, info, buttonSelected, clip); if (info.section > 0 && clip.top() < info.rowsTop) { p.setFont(st::emojiPanHeaderFont); - p.setPen(st::emojiPanHeaderFg); + p.setPen(st().headerFg); auto titleText = (info.section < _staticCount) ? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now) : _custom[info.section - _staticCount].title; @@ -1091,7 +1094,7 @@ void EmojiListWidget::paint( } const auto textBaseline = top + st::emojiPanHeaderFont->ascent; p.setFont(st::emojiPanHeaderFont); - p.setPen(st::emojiPanHeaderFg); + p.setPen(st().headerFg); p.drawText(titleLeft, textBaseline, titleText); } if (clip.top() + clip.height() > info.rowsTop) { @@ -1459,7 +1462,8 @@ void EmojiListWidget::displaySet(uint64 setId) { } void EmojiListWidget::removeSet(uint64 setId) { - if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) { + const auto &labelSt = st().boxLabel; + if (auto box = MakeConfirmRemoveSetBox(&session(), labelSt, setId)) { checkHideWithBox(std::move(box)); } } @@ -1532,9 +1536,10 @@ QRect EmojiListWidget::removeButtonRect(const SectionInfo &info) const { if (_mode != Mode::Full) { return QRect(); } - const auto buttonw = st::stickerPanRemoveSet.rippleAreaPosition.x() - + st::stickerPanRemoveSet.rippleAreaSize; - const auto buttonh = st::stickerPanRemoveSet.height; + const auto &removeSt = st().removeSet; + const auto buttonw = removeSt.rippleAreaPosition.x() + + removeSt.rippleAreaSize; + const auto buttonh = removeSt.height; const auto buttonx = emojiRight() - st::emojiPanRemoveSkip - buttonw; const auto buttony = info.top + st::emojiPanRemoveTop; return QRect(buttonx, buttony, buttonw, buttonh); @@ -1966,19 +1971,18 @@ int EmojiListWidget::paintButtonGetWidth( if (remove.isEmpty()) { return 0; } else if (remove.intersects(clip)) { + const auto &removeSt = st().removeSet; if (custom.ripple) { custom.ripple->paint( p, - remove.x() + st::stickerPanRemoveSet.rippleAreaPosition.x(), - remove.y() + st::stickerPanRemoveSet.rippleAreaPosition.y(), + remove.x() + removeSt.rippleAreaPosition.x(), + remove.y() + removeSt.rippleAreaPosition.y(), width()); if (custom.ripple->empty()) { custom.ripple.reset(); } } - const auto &icon = selected - ? st::stickerPanRemoveSet.iconOver - : st::stickerPanRemoveSet.icon; + const auto &icon = selected ? removeSt.iconOver : removeSt.icon; icon.paint( p, (remove.topLeft() @@ -2045,7 +2049,9 @@ void EmojiListWidget::updateSelected() { if (hasButton(section) && myrtlrect(buttonRect(section)).contains(p.x(), p.y())) { newSelected = OverButton{ section }; - } else if (section >= _staticCount && _mode == Mode::Full) { + } else if (_features.openStickerSets + && section >= _staticCount + && _mode == Mode::Full) { newSelected = OverSet{ section }; } } else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) { @@ -2159,13 +2165,12 @@ std::unique_ptr EmojiListWidget::createButtonRipple( && section < _staticCount + _custom.size()); const auto remove = hasRemoveButton(section); - const auto &st = remove - ? st::stickerPanRemoveSet.ripple - : st::emojiPanButton.ripple; + const auto &removeSt = st().removeSet; + const auto &st = remove ? removeSt.ripple : st::emojiPanButton.ripple; auto mask = remove ? Ui::RippleAnimation::EllipseMask(QSize( - st::stickerPanRemoveSet.rippleAreaSize, - st::stickerPanRemoveSet.rippleAreaSize)) + removeSt.rippleAreaSize, + removeSt.rippleAreaSize)) : rightButton(section).rippleMask; return std::make_unique( st, @@ -2179,7 +2184,7 @@ QPoint EmojiListWidget::buttonRippleTopLeft(int section) const { return myrtlrect(buttonRect(section)).topLeft() + (hasRemoveButton(section) - ? st::stickerPanRemoveSet.rippleAreaPosition + ? st().removeSet.rippleAreaPosition : QPoint()); } diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h index fd307eda8c..cc97d64db3 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "chat_helpers/compose/compose_features.h" #include "chat_helpers/tabbed_selector.h" #include "ui/widgets/tooltip.h" #include "ui/round_rect.h" @@ -84,6 +85,7 @@ struct EmojiListDescriptor { DocumentId, Fn)> customRecentFactory; const style::EmojiPan *st = nullptr; + ComposeFeatures features; }; class EmojiListWidget final @@ -345,6 +347,7 @@ private: void applyNextSearchQuery(); const std::shared_ptr _show; + const ComposeFeatures _features; Mode _mode = Mode::Full; std::unique_ptr _search; const int _staticCount = 0; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp index b74e377087..ccd2353556 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/emoji_config.h" #include "ui/ui_utility.h" #include "ui/cached_round_corners.h" +#include "ui/round_rect.h" #include "platform/platform_specific.h" #include "core/application.h" #include "base/event_filter.h" @@ -41,15 +42,133 @@ constexpr auto kAnimationDuration = crl::time(120); } // namespace +class SuggestionsWidget final : public Ui::RpWidget { +public: + SuggestionsWidget( + QWidget *parent, + const style::EmojiSuggestions &st, + not_null session, + bool suggestCustomEmoji, + Fn)> allowCustomWithoutPremium); + ~SuggestionsWidget(); + + void showWithQuery(SuggestionsQuery query, bool force = false); + void selectFirstResult(); + bool handleKeyEvent(int key); + + [[nodiscard]] rpl::producer toggleAnimated() const; + + struct Chosen { + QString emoji; + QString customData; + }; + [[nodiscard]] rpl::producer triggered() const; + +private: + struct Row { + Row(not_null emoji, const QString &replacement); + + Ui::Text::CustomEmoji *custom = nullptr; + DocumentData *document = nullptr; + not_null emoji; + QString replacement; + }; + struct Custom { + not_null document; + not_null emoji; + QString replacement; + }; + + bool eventHook(QEvent *e) override; + void paintEvent(QPaintEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void enterEventHook(QEnterEvent *e) override; + void leaveEventHook(QEvent *e) override; + + void scrollByWheelEvent(not_null e); + void paintFadings(QPainter &p) const; + + [[nodiscard]] std::vector getRowsByQuery(const QString &text) const; + [[nodiscard]] base::flat_multi_map lookupCustom( + const std::vector &rows) const; + [[nodiscard]] std::vector appendCustom( + std::vector rows); + [[nodiscard]] std::vector appendCustom( + std::vector rows, + const base::flat_multi_map &custom); + void resizeToRows(); + void setSelected( + int selected, + anim::type animated = anim::type::instant); + void setPressed(int pressed); + void clearMouseSelection(); + void clearSelection(); + void updateSelectedItem(); + void updateItem(int index); + [[nodiscard]] QRect inner() const; + [[nodiscard]] QPoint innerShift() const; + [[nodiscard]] QPoint mapToInner(QPoint globalPosition) const; + void selectByMouse(QPoint globalPosition); + bool triggerSelectedRow() const; + void triggerRow(const Row &row) const; + + [[nodiscard]] int scrollCurrent() const; + void scrollTo(int value, anim::type animated = anim::type::instant); + void stopAnimations(); + + [[nodiscard]] not_null resolveCustomEmoji( + not_null document); + void customEmojiRepaint(); + + const style::EmojiSuggestions &_st; + const not_null _session; + SuggestionsQuery _query; + std::vector _rows; + bool _suggestCustomEmoji = false; + Fn)> _allowCustomWithoutPremium; + + Ui::RoundRect _overRect; + + base::flat_map< + not_null, + std::unique_ptr> _customEmoji; + bool _repaintScheduled = false; + + std::optional _lastMousePosition; + bool _mouseSelection = false; + int _selected = -1; + int _pressed = -1; + + int _scrollValue = 0; + Ui::Animations::Simple _scrollAnimation; + Ui::Animations::Simple _selectedAnimation; + int _scrollMax = 0; + int _oneWidth = 0; + QMargins _padding; + + QPoint _mousePressPosition; + int _dragScrollStart = -1; + + rpl::event_stream _toggleAnimated; + rpl::event_stream _triggered; + +}; + SuggestionsWidget::SuggestionsWidget( QWidget *parent, + const style::EmojiSuggestions &st, not_null session, bool suggestCustomEmoji, Fn)> allowCustomWithoutPremium) : RpWidget(parent) +, _st(st) , _session(session) , _suggestCustomEmoji(suggestCustomEmoji) , _allowCustomWithoutPremium(std::move(allowCustomWithoutPremium)) +, _overRect(st::roundRadiusSmall, _st.overBg) , _oneWidth(st::emojiSuggestionSize) , _padding(st::emojiSuggestionsPadding) { resize( @@ -284,7 +403,7 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) { _repaintScheduled = false; const auto clip = e->rect(); - p.fillRect(clip, st::boxBg); + p.fillRect(clip, _st.bg); const auto shift = innerShift(); p.translate(-shift); @@ -298,15 +417,13 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) { ? _pressed : _selectedAnimation.value(_selected); if (selected > -1.) { - Ui::FillRoundRect( + _overRect.paint( p, - QRect(selected * _oneWidth, 0, _oneWidth, _oneWidth), - st::emojiPanHover, - Ui::StickerHoverCorners); + QRect(selected * _oneWidth, 0, _oneWidth, _oneWidth)); } auto context = Ui::CustomEmoji::Context{ - .textColor = st::windowFg->c, + .textColor = _st.textFg->c, .now = crl::now(), }; for (auto i = from; i != till; ++i) { @@ -338,9 +455,9 @@ void SuggestionsWidget::paintFadings(QPainter &p) const { const auto rect = myrtlrect( shift.x(), 0, - st::emojiSuggestionsFadeLeft.width(), + _st.fadeLeft.width(), height()); - st::emojiSuggestionsFadeLeft.fill(p, rect); + _st.fadeLeft.fill(p, rect); p.setOpacity(1.); } const auto o_right = std::clamp( @@ -350,11 +467,11 @@ void SuggestionsWidget::paintFadings(QPainter &p) const { if (o_right > 0.) { p.setOpacity(o_right); const auto rect = myrtlrect( - shift.x() + width() - st::emojiSuggestionsFadeRight.width(), + shift.x() + width() - _st.fadeRight.width(), 0, - st::emojiSuggestionsFadeRight.width(), + _st.fadeRight.width(), height()); - st::emojiSuggestionsFadeRight.fill(p, rect); + _st.fadeRight.fill(p, rect); p.setOpacity(1.); } } @@ -601,17 +718,17 @@ SuggestionsController::SuggestionsController( not_null field, not_null session, const Options &options) -: _field(field) +: _st(options.st ? *options.st : st::defaultEmojiSuggestions) +, _field(field) , _session(session) , _showExactTimer([=] { showWithQuery(getEmojiQuery()); }) , _options(options) { - _container = base::make_unique_q( - outer, - st::emojiSuggestionsDropdown); + _container = base::make_unique_q(outer, _st.dropdown); _container->setAutoHiding(false); _suggestions = _container->setOwnedWidget( object_ptr( _container, + _st, session, _options.suggestCustomEmoji, _options.allowCustomWithoutPremium)); @@ -910,7 +1027,7 @@ void SuggestionsController::updateGeometry() { auto boundingRect = _container->parentWidget()->rect(); auto origin = rtl() ? PanelAnimation::Origin::BottomRight : PanelAnimation::Origin::BottomLeft; auto point = rtl() ? (aroundRect.topLeft() + QPoint(aroundRect.width(), 0)) : aroundRect.topLeft(); - const auto padding = st::emojiSuggestionsDropdown.padding; + const auto padding = _st.dropdown.padding; const auto shift = std::min(_container->width() - padding.left() - padding.right(), st::emojiSuggestionSize) / 2; point -= rtl() ? QPoint(_container->width() - padding.right() - shift, _container->height()) : QPoint(padding.left() + shift, _container->height()); if (rtl()) { diff --git a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.h index 513fb518d4..b89de0ad94 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.h @@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +namespace style { +struct EmojiSuggestions; +} // namespace style + namespace Main { class Session; } // namespace Main @@ -29,125 +33,17 @@ class CustomEmoji; namespace Ui::Emoji { +class SuggestionsWidget; + using SuggestionsQuery = std::variant; -class SuggestionsWidget final : public Ui::RpWidget { -public: - SuggestionsWidget( - QWidget *parent, - not_null session, - bool suggestCustomEmoji, - Fn)> allowCustomWithoutPremium); - ~SuggestionsWidget(); - - void showWithQuery(SuggestionsQuery query, bool force = false); - void selectFirstResult(); - bool handleKeyEvent(int key); - - [[nodiscard]] rpl::producer toggleAnimated() const; - - struct Chosen { - QString emoji; - QString customData; - }; - [[nodiscard]] rpl::producer triggered() const; - -private: - struct Row { - Row(not_null emoji, const QString &replacement); - - Ui::Text::CustomEmoji *custom = nullptr; - DocumentData *document = nullptr; - not_null emoji; - QString replacement; - }; - struct Custom { - not_null document; - not_null emoji; - QString replacement; - }; - - bool eventHook(QEvent *e) override; - void paintEvent(QPaintEvent *e) override; - void keyPressEvent(QKeyEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void enterEventHook(QEnterEvent *e) override; - void leaveEventHook(QEvent *e) override; - - void scrollByWheelEvent(not_null e); - void paintFadings(QPainter &p) const; - - [[nodiscard]] std::vector getRowsByQuery(const QString &text) const; - [[nodiscard]] base::flat_multi_map lookupCustom( - const std::vector &rows) const; - [[nodiscard]] std::vector appendCustom( - std::vector rows); - [[nodiscard]] std::vector appendCustom( - std::vector rows, - const base::flat_multi_map &custom); - void resizeToRows(); - void setSelected( - int selected, - anim::type animated = anim::type::instant); - void setPressed(int pressed); - void clearMouseSelection(); - void clearSelection(); - void updateSelectedItem(); - void updateItem(int index); - [[nodiscard]] QRect inner() const; - [[nodiscard]] QPoint innerShift() const; - [[nodiscard]] QPoint mapToInner(QPoint globalPosition) const; - void selectByMouse(QPoint globalPosition); - bool triggerSelectedRow() const; - void triggerRow(const Row &row) const; - - [[nodiscard]] int scrollCurrent() const; - void scrollTo(int value, anim::type animated = anim::type::instant); - void stopAnimations(); - - [[nodiscard]] not_null resolveCustomEmoji( - not_null document); - void customEmojiRepaint(); - - const not_null _session; - SuggestionsQuery _query; - std::vector _rows; - bool _suggestCustomEmoji = false; - Fn)> _allowCustomWithoutPremium; - - base::flat_map< - not_null, - std::unique_ptr> _customEmoji; - bool _repaintScheduled = false; - - std::optional _lastMousePosition; - bool _mouseSelection = false; - int _selected = -1; - int _pressed = -1; - - int _scrollValue = 0; - Ui::Animations::Simple _scrollAnimation; - Ui::Animations::Simple _selectedAnimation; - int _scrollMax = 0; - int _oneWidth = 0; - QMargins _padding; - - QPoint _mousePressPosition; - int _dragScrollStart = -1; - - rpl::event_stream _toggleAnimated; - rpl::event_stream _triggered; - -}; - class SuggestionsController { public: struct Options { bool suggestExactFirstWord = true; bool suggestCustomEmoji = false; Fn)> allowCustomWithoutPremium; + const style::EmojiSuggestions *st = nullptr; }; SuggestionsController( @@ -189,6 +85,7 @@ private: bool fieldFilter(not_null event); bool outerFilter(not_null event); + const style::EmojiSuggestions &_st; bool _shown = false; bool _forceHidden = false; int _queryStartPosition = 0; diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index b786157218..6f312926f0 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -685,6 +685,7 @@ void FieldAutocomplete::recount(bool resetScroll) { } else if (!_brows.empty()) { h = _brows.size() * st::mentionHeight; } + h += _st.autocompleteBottomSkip; if (_inner->width() != _boundings.width() || _inner->height() != h) { _inner->resize(_boundings.width(), h); @@ -1375,8 +1376,10 @@ void FieldAutocomplete::Inner::setSel(int sel, bool scroll) { int32 row = _sel / _stickersPerRow; const auto padding = st::stickerPanPadding; _scrollToRequested.fire({ - padding + row * st::stickerPanSize.height(), - padding + (row + 1) * st::stickerPanSize.height() }); + (row ? padding : 0) + row * st::stickerPanSize.height(), + (padding + + (row + 1) * st::stickerPanSize.height() + + _st.autocompleteBottomSkip) }); } } } diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 9ff10845d4..48a0e98009 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -57,7 +57,8 @@ constexpr auto kMinAfterScrollDelay = crl::time(33); void AddGifAction( Fn &&, const style::icon*)> callback, std::shared_ptr show, - not_null document) { + not_null document, + const style::ComposeIcons *iconsOverride) { if (!document->isGifv()) { return; } @@ -67,6 +68,9 @@ void AddGifAction( const auto text = (saved ? tr::lng_context_delete_gif : tr::lng_context_save_gif)(tr::now); + const auto &icons = iconsOverride + ? *iconsOverride + : st::defaultComposeIcons; callback(text, [=] { Api::ToggleSavedGif( show, @@ -80,7 +84,7 @@ void AddGifAction( document->session().local().writeSavedGifs(); } data.stickers().notifySavedGifsUpdated(); - }, saved ? &st::menuIconDelete : &st::menuIconGif); + }, saved ? &icons.menuGifRemove : &icons.menuGifAdd); } GifsListWidget::GifsListWidget( @@ -380,18 +384,18 @@ base::unique_qptr GifsListWidget::fillContextMenu( return nullptr; } - auto menu = base::make_unique_q( - this, - st::popupMenuWithIcons); + auto menu = base::make_unique_q(this, st().menu); const auto send = [=, selected = _selected](Api::SendOptions options) { selectInlineResult(selected, options, true); }; + const auto icons = &st().icons; SendMenu::FillSendMenu( menu, type, SendMenu::DefaultSilentCallback(send), SendMenu::DefaultScheduleCallback(this, type, send), - SendMenu::DefaultWhenOnlineCallback(send)); + SendMenu::DefaultWhenOnlineCallback(send), + icons); if (const auto item = _mosaic.maybeItemAt(_selected)) { const auto document = item->getDocument() @@ -404,7 +408,7 @@ base::unique_qptr GifsListWidget::fillContextMenu( const style::icon *icon) { menu->addAction(text, std::move(done), icon); }; - AddGifAction(std::move(callback), _show, document); + AddGifAction(std::move(callback), _show, document, icons); } } return menu; diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h index d21c8e5315..84e20c8646 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h @@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +namespace style { +struct ComposeIcons; +} // namespace style + namespace Api { struct SendOptions; } // namespace Api @@ -48,7 +52,8 @@ namespace ChatHelpers { void AddGifAction( Fn &&, const style::icon*)> callback, std::shared_ptr show, - not_null document); + not_null document, + const style::ComposeIcons *iconsOverride = nullptr); class StickersListFooter; struct StickerIcon; diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 03430e3abe..b0e263c4a4 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -498,7 +498,8 @@ InlineBotQuery ParseInlineBotQuery( } AutocompleteQuery ParseMentionHashtagBotCommandQuery( - not_null field) { + not_null field, + ChatHelpers::ComposeFeatures features) { auto result = AutocompleteQuery(); const auto cursor = field->textCursor(); @@ -530,6 +531,9 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery( const auto text = fragment.text(); for (auto i = position - fragmentPosition; i != 0; --i) { if (text[i - 1] == '@') { + if (!features.autocompleteMentions) { + return {}; + } if ((position - fragmentPosition - i < 1 || text[i].isLetter()) && (i < 2 || !(text[i - 2].isLetterOrNumber() || text[i - 2] == '_'))) { result.fromStart = (i == 1) && (fragmentPosition == 0); result.query = text.mid(i - 1, position - fragmentPosition - i + 1); @@ -540,12 +544,18 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery( } return result; } else if (text[i - 1] == '#') { + if (!features.autocompleteHashtags) { + return {}; + } if (i < 2 || !(text[i - 2].isLetterOrNumber() || text[i - 2] == '_')) { result.fromStart = (i == 1) && (fragmentPosition == 0); result.query = text.mid(i - 1, position - fragmentPosition - i + 1); } return result; } else if (text[i - 1] == '/') { + if (!features.autocompleteCommands) { + return {}; + } if (i < 2 && !fragmentPosition) { result.fromStart = (i == 1) && (fragmentPosition == 0); result.query = text.mid(i - 1, position - fragmentPosition - i + 1); diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h index 727e51a5b5..13012557b1 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.h +++ b/Telegram/SourceFiles/chat_helpers/message_field.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/input_fields.h" #include "base/timer.h" #include "base/qt_connection.h" +#include "chat_helpers/compose/compose_features.h" #ifndef TDESKTOP_DISABLE_SPELLCHECK #include "boxes/dictionaries_manager.h" @@ -90,7 +91,8 @@ struct AutocompleteQuery { bool fromStart = false; }; AutocompleteQuery ParseMentionHashtagBotCommandQuery( - not_null field); + not_null field, + ChatHelpers::ComposeFeatures features); class MessageLinksParser : private QObject { public: diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp index a9aa598d60..15e2e8c341 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp @@ -292,7 +292,7 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor) descriptor.st ? *descriptor.st : st::defaultEmojiPan) , _session(descriptor.session) , _paused(descriptor.paused) -, _settingsButtonVisible(descriptor.settingsButtonVisible) +, _features(descriptor.features) , _iconState([=] { update(); }) , _subiconState([=] { update(); }) , _selectionBg(st::emojiPanRadius, st().categoriesBgOver) @@ -300,7 +300,7 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor) setMouseTracking(true); _iconsLeft = st().iconSkip - + (_settingsButtonVisible ? st().iconWidth : 0); + + (_features.stickersSettings ? st().iconWidth : 0); _iconsRight = st().iconSkip; _session->downloaderTaskFinished( @@ -618,7 +618,7 @@ void StickersListFooter::paint( return; } - if (_settingsButtonVisible && !hasOnlyFeaturedSets()) { + if (_features.stickersSettings) { paintStickerSettingsIcon(p); } @@ -1012,12 +1012,12 @@ void StickersListFooter::updateSelected() { if (rtl()) x = width() - x; const auto settingsLeft = _iconsLeft - _singleWidth; auto newOver = OverState(SpecialOver::None); - if (_settingsButtonVisible + if (_features.stickersSettings && x >= settingsLeft && x < settingsLeft + _singleWidth && y >= _iconsTop && y < _iconsTop + st().footer) { - if (!_icons.empty() && !hasOnlyFeaturedSets()) { + if (!_icons.empty()) { newOver = SpecialOver::Settings; } } else if (!_icons.empty()) { @@ -1161,17 +1161,11 @@ void StickersListFooter::refreshSubiconsGeometry() { updateEmojiWidthCallback(); } -bool StickersListFooter::hasOnlyFeaturedSets() const { - return (_icons.size() == 1) - && (_icons[0].setId == Data::Stickers::FeaturedSetId); -} - void StickersListFooter::paintStickerSettingsIcon(QPainter &p) const { const auto settingsLeft = _iconsLeft - _singleWidth; - st::stickersSettings.paint( + st().icons.settings.paint( p, - settingsLeft - + (_singleWidth - st::stickersSettings.width()) / 2, + (settingsLeft + (_singleWidth - st().icons.settings.width()) / 2), _iconsTop + st::emojiCategoryIconTop, width()); } @@ -1411,22 +1405,22 @@ void StickersListFooter::paintSetIconToCache( using Section = Ui::Emoji::Section; const auto sectionIcon = [&](Section section, bool active) { const auto icons = std::array{ - &st::emojiRecent, - &st::emojiRecentActive, - &st::emojiPeople, - &st::emojiPeopleActive, - &st::emojiNature, - &st::emojiNatureActive, - &st::emojiFood, - &st::emojiFoodActive, - &st::emojiActivity, - &st::emojiActivityActive, - &st::emojiTravel, - &st::emojiTravelActive, - &st::emojiObjects, - &st::emojiObjectsActive, - &st::emojiSymbols, - &st::emojiSymbolsActive, + &st().icons.recent, + &st().icons.recentActive, + &st().icons.people, + &st().icons.peopleActive, + &st().icons.nature, + &st().icons.natureActive, + &st().icons.food, + &st().icons.foodActive, + &st().icons.activity, + &st().icons.activityActive, + &st().icons.travel, + &st().icons.travelActive, + &st().icons.objects, + &st().icons.objectsActive, + &st().icons.symbols, + &st().icons.symbolsActive, }; const auto index = int(section) * 2 + (active ? 1 : 0); @@ -1464,15 +1458,8 @@ void StickersListFooter::paintSetIconToCache( } else { paintOne(0, [&] { const auto selected = (info.index == _iconState.selected); - if (icon.setId == Data::Stickers::FeaturedSetId) { - const auto &stickers = _session->data().stickers(); - return stickers.featuredSetsUnreadCount() - ? &st::stickersTrendingUnread - : &st::stickersTrending; - //} else if (setId == Stickers::FavedSetId) { - // return &st::stickersFaved; - } else if (icon.setId == AllEmojiSectionSetId()) { - return &st::emojiPeople; + if (icon.setId == AllEmojiSectionSetId()) { + return &st().icons.people; } else if (const auto section = SetIdEmojiSection(icon.setId)) { return sectionIcon(*section, selected); } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h index 1a08f68535..f7a0afc1d4 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h @@ -7,8 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "media/clip/media_clip_reader.h" +#include "chat_helpers/compose/compose_features.h" #include "chat_helpers/tabbed_selector.h" +#include "media/clip/media_clip_reader.h" #include "mtproto/sender.h" #include "ui/dpr/dpr_image.h" #include "ui/round_rect.h" @@ -116,8 +117,8 @@ public: not_null session; Fn paused; not_null parent; - bool settingsButtonVisible = false; const style::EmojiPan *st = nullptr; + ComposeFeatures features; }; explicit StickersListFooter(Descriptor &&descriptor); @@ -130,7 +131,6 @@ public: uint64 activeSetId, Fn()> renderer, ValidateIconAnimations animations); - [[nodiscard]] bool hasOnlyFeaturedSets() const; void leaveToChildEvent(QEvent *e, QWidget *child) override; @@ -270,7 +270,7 @@ private: const not_null _session; const Fn _paused; - const bool _settingsButtonVisible = false; + const ComposeFeatures _features; static constexpr auto kVisibleIconsCount = 8; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index 40aae70eb8..cf0dda5eb7 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -184,12 +184,12 @@ StickersListWidget::StickersListWidget( descriptor.paused) , _mode(descriptor.mode) , _show(std::move(descriptor.show)) +, _features(descriptor.features) , _overBg(st::roundRadiusSmall, st().overBg) , _api(&session().mtp()) , _localSetsManager(std::make_unique(&session())) , _section(Section::Stickers) , _isMasks(_mode == Mode::Masks) -, _settingsHidden(descriptor.settingsHidden) , _updateItemsTimer([=] { updateItems(); }) , _updateSetsTimer([=] { updateSets(); }) , _trendingAddBgOver( @@ -286,8 +286,8 @@ object_ptr StickersListWidget::createFooter() { .session = &session(), .paused = footerPaused, .parent = this, - .settingsButtonVisible = !_settingsHidden, .st = &st(), + .features = _features, }); _footer = result; @@ -298,7 +298,7 @@ object_ptr StickersListWidget::createFooter() { _footer->openSettingsRequests( ) | rpl::start_with_next([=] { - const auto onlyFeatured = _footer->hasOnlyFeaturedSets(); + const auto onlyFeatured = !_isMasks && _mySets.empty(); _show->showBox(Box( _show, (onlyFeatured @@ -908,7 +908,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { auto add = featuredAddRect(info); int checkx = add.left() + (add.width() - st::stickersFeaturedInstalled.width()) / 2; int checky = add.top() + (add.height() - st::stickersFeaturedInstalled.height()) / 2; - st::stickersFeaturedInstalled.paint(p, QPoint(checkx, checky), width()); + st().trendingInstalled.paint(p, QPoint(checkx, checky), width()); } if (set.flags & SetFlag::Unread) { widthForTitle -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; @@ -921,12 +921,12 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { titleWidth = st::stickersTrendingHeaderFont->width(titleText); } p.setFont(st::stickersTrendingHeaderFont); - p.setPen(st::stickersTrendingHeaderFg); + p.setPen(st().trendingHeaderFg); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st::stickersTrendingHeaderTop, width(), titleText, titleWidth); if (set.flags & SetFlag::Unread) { p.setPen(Qt::NoPen); - p.setBrush(st::stickersFeaturedUnreadBg); + p.setBrush(st().trendingUnreadFg); { PainterHighQualityEnabler hq(p); @@ -936,7 +936,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { auto statusText = (count > 0) ? tr::lng_stickers_count(tr::now, lt_count, count) : tr::lng_contacts_loading(tr::now); p.setFont(st::stickersTrendingSubheaderFont); - p.setPen(st::stickersTrendingSubheaderFg); + p.setPen(st().trendingSubheaderFg); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st::stickersTrendingSubheaderTop, width(), statusText); if (info.rowsTop >= clip.y() + clip.height()) { @@ -963,13 +963,14 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { if (hasRemoveButton(info.section)) { auto remove = removeButtonRect(info); auto selected = selectedButton ? (selectedButton->section == info.section) : false; + const auto &removeSt = st().removeSet; if (set.ripple) { - set.ripple->paint(p, remove.x() + st::stickerPanRemoveSet.rippleAreaPosition.x(), remove.y() + st::stickerPanRemoveSet.rippleAreaPosition.y(), width()); + set.ripple->paint(p, remove.x() + removeSt.rippleAreaPosition.x(), remove.y() + removeSt.rippleAreaPosition.y(), width()); if (set.ripple->empty()) { set.ripple.reset(); } } - const auto &icon = selected ? st::stickerPanRemoveSet.iconOver : st::stickerPanRemoveSet.icon; + const auto &icon = selected ? removeSt.iconOver : removeSt.icon; icon.paint( p, remove.x() + (remove.width() - icon.width()) / 2, @@ -983,7 +984,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { titleWidth = st::stickersTrendingHeaderFont->width(titleText); } p.setFont(st::emojiPanHeaderFont); - p.setPen(st::emojiPanHeaderFg); + p.setPen(st().headerFg); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st().headerTop, width(), titleText, titleWidth); } if (clip.top() + clip.height() <= info.rowsTop) { @@ -1108,7 +1109,7 @@ int StickersListWidget::megagroupSetInfoLeft() const { } void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected) { - p.setPen(st::emojiPanHeaderFg); + p.setPen(st().headerFg); auto infoLeft = megagroupSetInfoLeft(); _megagroupSetAbout.drawLeft(p, infoLeft, y, width() - infoLeft, width()); @@ -1483,8 +1484,9 @@ QRect StickersListWidget::removeButtonRect(int index) const { } QRect StickersListWidget::removeButtonRect(const SectionInfo &info) const { - auto buttonw = st::stickerPanRemoveSet.width; - auto buttonh = st::stickerPanRemoveSet.height; + const auto &removeSt = st().removeSet; + auto buttonw = removeSt.width; + auto buttonh = removeSt.height; auto buttonx = stickersRight() - buttonw; auto buttony = info.top + (st().header - buttonh) / 2; return QRect(buttonx, buttony, buttonw, buttonh); @@ -1561,10 +1563,11 @@ std::unique_ptr StickersListWidget::createButtonRipple(int std::move(mask), [this, section] { rtlupdate(featuredAddRect(section)); }); } - auto maskSize = QSize(st::stickerPanRemoveSet.rippleAreaSize, st::stickerPanRemoveSet.rippleAreaSize); + const auto &removeSt = st().removeSet; + auto maskSize = QSize(removeSt.rippleAreaSize, removeSt.rippleAreaSize); auto mask = Ui::RippleAnimation::EllipseMask(maskSize); return std::make_unique( - st::stickerPanRemoveSet.ripple, + removeSt.ripple, std::move(mask), [this, section] { rtlupdate(removeButtonRect(section)); }); } @@ -1575,7 +1578,8 @@ QPoint StickersListWidget::buttonRippleTopLeft(int section) const { if (shownSets()[section].externalLayout) { return myrtlrect(featuredAddRect(section)).topLeft(); } - return myrtlrect(removeButtonRect(section)).topLeft() + st::stickerPanRemoveSet.rippleAreaPosition; + return myrtlrect(removeButtonRect(section)).topLeft() + + st().removeSet.rippleAreaPosition; } void StickersListWidget::showStickerSetBox(not_null document) { @@ -1604,9 +1608,7 @@ base::unique_qptr StickersListWidget::fillContextMenu( auto &set = sets[section]; Assert(index >= 0 && index < set.stickers.size()); - auto menu = base::make_unique_q( - this, - st::popupMenuWithIcons); + auto menu = base::make_unique_q(this, st().menu); const auto document = set.stickers[sticker->index].document; const auto send = [=](Api::SendOptions options) { @@ -1618,12 +1620,14 @@ base::unique_qptr StickersListWidget::fillContextMenu( : messageSentAnimationInfo(section, index, document), }); }; + const auto icons = &st().icons; SendMenu::FillSendMenu( menu, type, SendMenu::DefaultSilentCallback(send), SendMenu::DefaultScheduleCallback(this, type, send), - SendMenu::DefaultWhenOnlineCallback(send)); + SendMenu::DefaultWhenOnlineCallback(send), + icons); const auto show = _show; const auto toggleFavedSticker = [=] { @@ -1638,11 +1642,13 @@ base::unique_qptr StickersListWidget::fillContextMenu( ? tr::lng_faved_stickers_remove : tr::lng_faved_stickers_add)(tr::now), toggleFavedSticker, - isFaved ? &st::menuIconUnfave : &st::menuIconFave); + isFaved ? &icons->menuUnfave : &icons->menuFave); - menu->addAction(tr::lng_context_pack_info(tr::now), [=] { - showStickerSetBox(document); - }, &st::menuIconStickers); + if (_features.openStickerSets) { + menu->addAction(tr::lng_context_pack_info(tr::now), [=] { + showStickerSetBox(document); + }, &icons->menuStickerSet); + } if (const auto id = set.id; id == Data::Stickers::RecentSetId) { menu->addAction(tr::lng_recent_stickers_remove(tr::now), [=] { @@ -1650,7 +1656,7 @@ base::unique_qptr StickersListWidget::fillContextMenu( document, Data::FileOriginStickerSet(id, 0), false); - }, &st::menuIconDelete); + }, &icons->menuRecentRemove); } return menu; } @@ -1708,7 +1714,8 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) { return; } const auto document = set.stickers[sticker->index].document; - if (e->modifiers() & Qt::ControlModifier) { + if (_features.openStickerSets + && (e->modifiers() & Qt::ControlModifier)) { showStickerSetBox(document); } else { _chosen.fire({ @@ -1859,12 +1866,6 @@ void StickersListWidget::processPanelHideFinished() { if (_footer) { _footer->clearHeavyData(); } - // Preserve panel state through visibility toggles. - //// Reset to the recent stickers section. - //if (_section == Section::Featured && (!_footer || !_footer->hasOnlyFeaturedSets())) { - // setSection(Section::Stickers); - // validateSelectedIcon(ValidateIconAnimations::None); - //} } void StickersListWidget::setSection(Section section) { @@ -1994,9 +1995,6 @@ void StickersListWidget::refreshSettingsVisibility() { void StickersListWidget::refreshFooterIcons() { refreshIcons(ValidateIconAnimations::None); - if (_footer->hasOnlyFeaturedSets() && _section != Section::Featured) { - showStickerSet(Data::Stickers::FeaturedSetId); - } } void StickersListWidget::preloadImages() { @@ -2064,9 +2062,6 @@ void StickersListWidget::refreshRecent() { if (_section == Section::Stickers) { refreshRecentStickers(); } - if (_footer && _footer->hasOnlyFeaturedSets() && _section != Section::Featured) { - showStickerSet(Data::Stickers::FeaturedSetId); - } } auto StickersListWidget::collectRecentStickers() -> std::vector { @@ -2201,7 +2196,7 @@ void StickersListWidget::refreshFavedStickers() { } void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) { - if (!_megagroupSet || _isMasks) { + if (!_features.megagroupSet || !_megagroupSet || _isMasks) { return; } auto canEdit = _megagroupSet->canEditStickers(); @@ -2354,10 +2349,12 @@ void StickersListWidget::updateSelected() { newSelected = OverButton{ section }; } else if (featuredHasAddButton(section) && myrtlrect(featuredAddRect(info)).contains(p.x(), p.y())) { newSelected = OverButton{ section }; - } else if (!(sets[section].flags & SetFlag::Special)) { + } else if (_features.openStickerSets + && !(sets[section].flags & SetFlag::Special)) { newSelected = OverSet{ section }; - } else if (sets[section].id == Data::Stickers::MegagroupSetId - && (_megagroupSet->canEditStickers() || !sets[section].stickers.empty())) { + } else if ((sets[section].id == Data::Stickers::MegagroupSetId) + && (_megagroupSet->canEditStickers() + || !sets[section].stickers.empty())) { newSelected = OverSet{ section }; } } else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom && sx >= 0) { @@ -2624,10 +2621,12 @@ void StickersListWidget::removeMegagroupSet(bool locally) { close(); }), .cancelled = [](Fn &&close) { close(); }, + .labelStyle = &st().boxLabel, })); } void StickersListWidget::removeSet(uint64 setId) { + const auto &st = this->st().boxLabel; if (setId == Data::Stickers::MegagroupSetId) { const auto &sets = shownSets(); const auto i = ranges::find(sets, setId, &Set::id); @@ -2635,7 +2634,7 @@ void StickersListWidget::removeSet(uint64 setId) { const auto removeLocally = i->stickers.empty() || !_megagroupSet->canEditStickers(); removeMegagroupSet(removeLocally); - } else if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) { + } else if (auto box = MakeConfirmRemoveSetBox(&session(), st, setId)) { checkHideWithBox(std::move(box)); } } @@ -2660,6 +2659,7 @@ StickersListWidget::~StickersListWidget() = default; object_ptr MakeConfirmRemoveSetBox( not_null session, + const style::FlatLabel &st, uint64 setId) { const auto &sets = session->data().stickers().sets(); const auto it = sets.find(setId); @@ -2726,6 +2726,7 @@ object_ptr MakeConfirmRemoveSetBox( } }, .confirmText = tr::lng_stickers_remove_pack_confirm(), + .labelStyle = &st, }); } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index dc4e7dc449..6e2c2fa04a 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "chat_helpers/compose/compose_features.h" #include "chat_helpers/tabbed_selector.h" #include "data/stickers/data_stickers.h" #include "ui/round_rect.h" @@ -50,6 +51,7 @@ enum class Notification; namespace style { struct EmojiPan; +struct FlatLabel; } // namespace style namespace ChatHelpers { @@ -70,7 +72,7 @@ struct StickersListDescriptor { StickersListMode mode = StickersListMode::Full; Fn paused; const style::EmojiPan *st = nullptr; - bool settingsHidden = false; + ComposeFeatures features; }; class StickersListWidget final : public TabbedSelector::Inner { @@ -352,6 +354,7 @@ private: const Mode _mode; const std::shared_ptr _show; + const ComposeFeatures _features; Ui::RoundRect _overBg; std::unique_ptr _search; MTP::Sender _api; @@ -375,7 +378,6 @@ private: Section _section = Section::Stickers; const bool _isMasks; - bool _settingsHidden = false; base::Timer _updateItemsTimer; base::Timer _updateSetsTimer; @@ -426,6 +428,7 @@ private: [[nodiscard]] object_ptr MakeConfirmRemoveSetBox( not_null session, + const style::FlatLabel &st, uint64 setId); } // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp index 5321e649e4..e8ec060fb6 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp @@ -240,7 +240,7 @@ void TabbedPanel::paintEvent(QPaintEvent *e) { hideFinished(); } else { if (!_cache.isNull()) _cache = QPixmap(); - Ui::Shadow::paint(p, innerRect(), width(), st::emojiPanAnimation.shadow); + Ui::Shadow::paint(p, innerRect(), width(), _selector->st().showAnimation.shadow); } } @@ -362,7 +362,11 @@ void TabbedPanel::startShowAnimation() { if (!_a_show.animating()) { auto image = grabForAnimation(); - _showAnimation = std::make_unique(st::emojiPanAnimation, _dropDown ? Ui::PanelAnimation::Origin::TopRight : Ui::PanelAnimation::Origin::BottomRight); + _showAnimation = std::make_unique( + _selector->st().showAnimation, + (_dropDown + ? Ui::PanelAnimation::Origin::TopRight + : Ui::PanelAnimation::Origin::BottomRight)); auto inner = rect().marginsRemoved(st::emojiPanMargins); _showAnimation->setFinalImage(std::move(image), QRect(inner.topLeft() * cIntRetinaFactor(), inner.size() * cIntRetinaFactor())); _showAnimation->setCornerMasks(Images::CornersMask(st::emojiPanRadius)); diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index 5131c9f9bd..43b08c4a42 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -344,6 +344,7 @@ TabbedSelector::TabbedSelector( TabbedSelectorDescriptor &&descriptor) : RpWidget(parent) , _st(descriptor.st) +, _features(descriptor.features) , _show(std::move(descriptor.show)) , _level(descriptor.level) , _mode(descriptor.mode) @@ -377,7 +378,6 @@ TabbedSelector::TabbedSelector( : SelectorTab::Emoji) , _hasEmojiTab(ranges::contains(_tabs, SelectorTab::Emoji, &Tab::type)) , _hasStickersTab(ranges::contains(_tabs, SelectorTab::Stickers, &Tab::type)) -, _stickersSettingsHidden(descriptor.stickersSettingsHidden) , _hasGifsTab(ranges::contains(_tabs, SelectorTab::Gifs, &Tab::type)) , _hasMasksTab(ranges::contains(_tabs, SelectorTab::Masks, &Tab::type)) , _tabbed(_tabs.size() > 1) { @@ -487,6 +487,10 @@ TabbedSelector::TabbedSelector( TabbedSelector::~TabbedSelector() = default; +const style::EmojiPan &TabbedSelector::st() const { + return _st; +} + Main::Session &TabbedSelector::session() const { return _show->session(); } @@ -511,6 +515,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) { : EmojiMode::Full), .paused = paused, .st = &_st, + .features = _features, }); } case SelectorTab::Stickers: { @@ -521,7 +526,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) { .mode = StickersMode::Full, .paused = paused, .st = &_st, - .settingsHidden = _stickersSettingsHidden, + .features = _features, }); } case SelectorTab::Gifs: { @@ -540,6 +545,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) { .mode = StickersMode::Masks, .paused = paused, .st = &_st, + .features = _features, }); } } diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h index bcaa4fdeee..d41aebb809 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "api/api_common.h" +#include "chat_helpers/compose/compose_features.h" #include "ui/rp_widget.h" #include "ui/effects/animations.h" #include "ui/effects/message_sending_animation_common.h" @@ -87,7 +88,7 @@ struct TabbedSelectorDescriptor { const style::EmojiPan &st; PauseReason level = {}; TabbedSelectorMode mode = TabbedSelectorMode::Full; - bool stickersSettingsHidden = false; + ComposeFeatures features; }; [[nodiscard]] std::unique_ptr MakeSearch( @@ -117,6 +118,7 @@ public: TabbedSelectorDescriptor &&descriptor); ~TabbedSelector(); + [[nodiscard]] const style::EmojiPan &st() const; [[nodiscard]] Main::Session &session() const; [[nodiscard]] PauseReason level() const; @@ -267,6 +269,7 @@ private: not_null masks() const; const style::EmojiPan &_st; + const ComposeFeatures _features; const std::shared_ptr _show; const PauseReason _level = {}; @@ -291,7 +294,6 @@ private: const bool _hasEmojiTab; const bool _hasStickersTab; - const bool _stickersSettingsHidden; const bool _hasGifsTab; const bool _hasMasksTab; const bool _tabbed; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 87da53703c..ec4aa4d077 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1388,7 +1388,7 @@ AutocompleteQuery HistoryWidget::parseMentionHashtagBotCommandQuery() const { const auto result = (isChoosingTheme() || (_inlineBot && !_inlineLookingUpBot)) ? AutocompleteQuery() - : ParseMentionHashtagBotCommandQuery(_field); + : ParseMentionHashtagBotCommandQuery(_field, {}); if (result.query.isEmpty()) { return result; } else if (result.query[0] == '#' diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index a3fd8b3c81..1f4fb79b04 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -956,7 +956,7 @@ ComposeControls::ComposeControls( .st = _st.tabbed, .level = Window::GifPauseReason::TabbedPanel, .mode = ChatHelpers::TabbedSelector::Mode::Full, - .stickersSettingsHidden = !_features.stickersSettings, + .features = _features, })) , _selector(_regularWindow ? _regularWindow->tabbedSelector() @@ -982,7 +982,10 @@ ComposeControls::ComposeControls( _wrap.get(), st::historyBotCommandStart) : nullptr) -, _autocomplete(std::make_unique(parent, _show)) +, _autocomplete(std::make_unique( + parent, + _show, + &_st.tabbed)) , _header(std::make_unique(_wrap.get(), _show)) , _voiceRecordBar(std::make_unique( _wrap.get(), @@ -1389,7 +1392,7 @@ void ComposeControls::checkAutocomplete() { const auto peer = _history->peer; const auto autocomplete = _isInlineBot ? AutocompleteQuery() - : ParseMentionHashtagBotCommandQuery(_field); + : ParseMentionHashtagBotCommandQuery(_field, _features); if (!autocomplete.query.isEmpty()) { if (autocomplete.query[0] == '#' && cRecentWriteHashtags().isEmpty() @@ -1656,7 +1659,11 @@ void ComposeControls::initField() { _parent, _field, _session, - { .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow }); + { + .suggestCustomEmoji = true, + .allowCustomWithoutPremium = allow, + .st = &_st.suggestions, + }); _raiseEmojiSuggestions = [=] { suggestions->raise(); }; const auto rawTextEdit = _field->rawTextEdit().get(); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index d5749bfcb9..223940671b 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -7,10 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "base/required.h" #include "api/api_common.h" +#include "base/required.h" #include "base/unique_qptr.h" #include "base/timer.h" +#include "chat_helpers/compose/compose_features.h" #include "dialogs/dialogs_key.h" #include "history/view/controls/compose_controls_common.h" #include "ui/round_rect.h" @@ -93,16 +94,6 @@ enum class ComposeControlsMode { Scheduled, }; -struct ComposeControlsFeatures { - bool sendAs = true; - bool ttlInfo = true; - bool botCommandSend = true; - bool silentBroadcastToggle = true; - bool attachBotsMenu = true; - bool inlineBots = true; - bool stickersSettings = true; -}; - struct ComposeControlsDescriptor { const style::ComposeControls *stOverride = nullptr; std::shared_ptr show; @@ -111,7 +102,7 @@ struct ComposeControlsDescriptor { SendMenu::Type sendMenuType = {}; Window::SessionController *regularWindow = nullptr; rpl::producer stickerOrEmojiChosen; - ComposeControlsFeatures features; + ChatHelpers::ComposeFeatures features; }; class ComposeControls final { @@ -329,7 +320,7 @@ private: void changeFocusedControl(); const style::ComposeControls &_st; - const ComposeControlsFeatures _features; + const ChatHelpers::ComposeFeatures _features; const not_null _parent; const std::shared_ptr _show; const not_null _session; diff --git a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp index 6f91868822..3ce74ef555 100644 --- a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp +++ b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp @@ -321,7 +321,7 @@ void EmojiSelector::createSelector(Type type) { if (isEmoji) { st::userpicBuilderEmojiToggleStickersIcon.paintInCenter(p, r); } else { - st::emojiPeople.paintInCenter(p, r); + st::defaultEmojiPan.icons.people.paintInCenter(p, r); } }, toggleButton->lifetime()); } diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp index f800f192c8..1b44b8fa27 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "inline_bots/inline_bot_result.h" #include "media/stories/media_stories_controller.h" #include "menu/menu_send.h" +#include "styles/style_chat_helpers.h" #include "styles/style_media_view.h" namespace Media::Stories { @@ -41,6 +42,12 @@ ReplyArea::ReplyArea(not_null controller) .silentBroadcastToggle = false, .attachBotsMenu = false, .inlineBots = false, + .megagroupSet = false, + .stickersSettings = false, + .openStickerSets = false, + .autocompleteHashtags = false, + .autocompleteMentions = false, + .autocompleteCommands = false, }, } )) { @@ -52,13 +59,27 @@ ReplyArea::~ReplyArea() { } void ReplyArea::initGeometry() { - _controller->layoutValue( - ) | rpl::start_with_next([=](const Layout &layout) { - _controls->resizeToWidth(layout.content.width()); - const auto position = layout.controlsBottomPosition - - QPoint(0, _controls->heightCurrent()); - _controls->move(position.x(), position.y()); - _controls->setAutocompleteBoundingRect(layout.autocompleteRect); + rpl::combine( + _controller->layoutValue(), + _controls->height() + ) | rpl::start_with_next([=](const Layout &layout, int height) { + const auto content = layout.content; + _controls->resizeToWidth(content.width()); + if (_controls->heightCurrent() == height) { + const auto position = layout.controlsBottomPosition + - QPoint(0, height); + _controls->move(position.x(), position.y()); + const auto &tabbed = st::storiesComposeControls.tabbed; + const auto upper = QRect( + content.x(), + content.y(), + content.width(), + (position.y() + + tabbed.autocompleteBottomSkip + - content.y())); + _controls->setAutocompleteBoundingRect( + layout.autocompleteRect.intersected(upper)); + } }, _lifetime); } diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 7e01278eb9..aa9377f09d 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -407,7 +407,7 @@ pipVolumeIcon2Over: icon {{ "player/player_volume_on", mediaviewPipControlsFgOve speedSliderDividerSize: size(2px, 8px); -storiesMaxSize: size(405px, 720px); +storiesMaxSize: size(540px, 960px); storiesMaxNameFontSize: 17px; storiesRadius: 8px; storiesControlSize: 64px; @@ -460,6 +460,53 @@ storiesAttach: IconButton(historyAttach) { } storiesRecordVoice: icon {{ "chat/input_record", storiesComposeGrayIcon }}; storiesRecordVoiceOver: icon {{ "chat/input_record", storiesComposeGrayIcon }}; +storiesRemoveSet: IconButton(stickerPanRemoveSet) { + icon: icon {{ "simple_close", storiesComposeGrayIcon }}; + iconOver: icon {{ "simple_close", storiesComposeGrayIcon }}; + ripple: RippleAnimation(defaultRippleAnimation) { + color: storiesComposeBgOver; + } +} +storiesMenu: Menu(defaultMenu) { + itemBg: groupCallMenuBg; + itemBgOver: groupCallMenuBgOver; + itemFg: groupCallMembersFg; + itemFgOver: groupCallMembersFg; + itemFgDisabled: groupCallMemberNotJoinedStatus; + itemFgShortcut: groupCallMemberNotJoinedStatus; + itemFgShortcutOver: groupCallMemberNotJoinedStatus; + itemFgShortcutDisabled: groupCallMemberNotJoinedStatus; + + separator: MenuSeparator(defaultMenuSeparator) { + fg: groupCallMenuBgOver; + } + arrow: icon {{ "menu/submenu_arrow", groupCallMemberNotJoinedStatus }}; + + ripple: RippleAnimation(defaultRippleAnimation) { + color: groupCallMenuBgRipple; + } +} +storiesMenuShadow: Shadow(defaultEmptyShadow) { + fallback: groupCallMenuBg; +} +storiesMenuAnimation: PanelAnimation(defaultPanelAnimation) { + fadeBg: groupCallMenuBg; + shadow: storiesMenuShadow; +} +storiesPopupMenu: PopupMenu(defaultPopupMenu) { + shadow: storiesMenuShadow; + menu: storiesMenu; + animation: storiesMenuAnimation; +} +storiesMenuWithIcons: Menu(storiesMenu) { + itemIconPosition: point(15px, 5px); + itemPadding: margins(54px, 8px, 17px, 8px); +} +storiesPopupMenuWithIcons: PopupMenu(storiesPopupMenu) { + scrollPadding: margins(0px, 5px, 0px, 5px); + menu: storiesMenuWithIcons; +} + storiesComposeControls: ComposeControls(defaultComposeControls) { bg: storiesComposeBg; radius: storiesRadius; @@ -469,6 +516,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { placeholderFg: storiesComposeGrayText; placeholderFgActive: storiesComposeGrayText; placeholderFgError: storiesComposeGrayText; + menu: storiesPopupMenu; } send: SendButton(historySend) { inner: IconButton(storiesAttach) { @@ -489,10 +537,30 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { lineFg: storiesComposeGrayIcon; lineFgOver: storiesComposeGrayIcon; } - tabbed: EmojiPan(defaultEmojiPan) { + suggestions: EmojiSuggestions(defaultEmojiSuggestions) { + dropdown: InnerDropdown(emojiSuggestionsDropdown) { + animation: PanelAnimation(defaultPanelAnimation) { + fadeBg: storiesComposeBg; + } + bg: storiesComposeBg; + } bg: storiesComposeBg; overBg: storiesComposeBgOver; - expandBg: storiesComposeGrayText; + textFg: storiesComposeWhiteText; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }}; + fadeRight: icon {{ "fade_horizontal", storiesComposeBg }}; + } + tabbed: EmojiPan(defaultEmojiPan) { + showAnimation: PanelAnimation(emojiPanAnimation) { + fadeBg: storiesComposeBg; + } + bg: storiesComposeBg; + headerFg: storiesComposeGrayText; + trendingHeaderFg: storiesComposeWhiteText; + trendingSubheaderFg: storiesComposeGrayText; + trendingUnreadFg: storiesComposeBlue; + trendingInstalled: icon {{ "chat/input_save", storiesComposeBlue }}; + overBg: storiesComposeBgOver; pathBg: storiesComposeBgRipple; pathFg: storiesComposeBgOver; textFg: storiesComposeWhiteText; @@ -500,6 +568,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { categoriesBgOver: storiesComposeBgOver; fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }}; fadeRight: icon {{ "fade_horizontal", storiesComposeBg }}; + menu: storiesPopupMenuWithIcons; tabs: SettingsSlider(emojiTabs) { barFgActive: storiesComposeBlue; labelFg: storiesComposeGrayText; @@ -536,5 +605,40 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { ripple: emptyRippleAnimation; } } + removeSet: storiesRemoveSet; + boxLabel: FlatLabel(boxLabel) { + textFg: groupCallMembersFg; + } + icons: ComposeIcons { + settings: icon {{ "emoji/emoji_settings", storiesComposeGrayIcon }}; + + recent: icon {{ "emoji/emoji_recent", storiesComposeGrayIcon }}; + recentActive: icon {{ "emoji/emoji_recent", storiesComposeWhiteText }}; + people: icon {{ "emoji/emoji_smile", storiesComposeGrayIcon }}; + peopleActive: icon {{ "emoji/emoji_smile", storiesComposeWhiteText }}; + nature: icon {{ "emoji/emoji_nature", storiesComposeGrayIcon }}; + natureActive: icon {{ "emoji/emoji_nature", storiesComposeWhiteText }}; + food: icon {{ "emoji/emoji_food", storiesComposeGrayIcon }}; + foodActive: icon {{ "emoji/emoji_food", storiesComposeWhiteText }}; + activity: icon {{ "emoji/emoji_activities", storiesComposeGrayIcon }}; + activityActive: icon {{ "emoji/emoji_activities", storiesComposeWhiteText }}; + travel: icon {{ "emoji/emoji_travel", storiesComposeGrayIcon }}; + travelActive: icon {{ "emoji/emoji_travel", storiesComposeWhiteText }}; + objects: icon {{ "emoji/emoji_objects", storiesComposeGrayIcon }}; + objectsActive: icon {{ "emoji/emoji_objects", storiesComposeWhiteText }}; + symbols: icon {{ "emoji/emoji_love", storiesComposeGrayIcon }}; + symbolsActive: icon {{ "emoji/emoji_love", storiesComposeWhiteText }}; + + menuFave: icon {{ "menu/favorite", storiesComposeWhiteText }}; + menuUnfave: icon {{ "menu/unfavorite", storiesComposeWhiteText }}; + menuStickerSet: icon {{ "menu/stickers", storiesComposeWhiteText }}; + menuRecentRemove: icon {{ "menu/delete", storiesComposeWhiteText }}; + menuGifAdd: icon {{ "menu/gif", storiesComposeWhiteText }}; + menuGifRemove: icon {{ "menu/delete", storiesComposeWhiteText }}; + menuMute: icon {{ "menu/mute", storiesComposeWhiteText }}; + menuSchedule: icon {{ "menu/calendar", storiesComposeWhiteText }}; + menuWhenOnline: icon {{ "menu/send_when_online", storiesComposeWhiteText }}; + } + autocompleteBottomSkip: 10px; } } diff --git a/Telegram/SourceFiles/menu/menu_send.cpp b/Telegram/SourceFiles/menu/menu_send.cpp index 2d5ca31945..02ab8ed4bc 100644 --- a/Telegram/SourceFiles/menu/menu_send.cpp +++ b/Telegram/SourceFiles/menu/menu_send.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history.h" #include "history/history_unread_things.h" #include "apiwrap.h" +#include "styles/style_chat_helpers.h" #include "styles/style_menu_icons.h" #include @@ -56,10 +57,14 @@ FillMenuResult FillSendMenu( Type type, Fn silent, Fn schedule, - Fn whenOnline) { + Fn whenOnline, + const style::ComposeIcons *iconsOverride) { if (!silent && !schedule) { return FillMenuResult::None; } + const auto &icons = iconsOverride + ? *iconsOverride + : st::defaultComposeIcons; const auto now = type; if (now == Type::Disabled || (!silent && now == Type::SilentOnly)) { @@ -70,7 +75,7 @@ FillMenuResult FillSendMenu( menu->addAction( tr::lng_send_silent_message(tr::now), silent, - &st::menuIconMute); + &icons.menuMute); } if (schedule && now != Type::SilentOnly) { menu->addAction( @@ -78,13 +83,13 @@ FillMenuResult FillSendMenu( ? tr::lng_reminder_message(tr::now) : tr::lng_schedule_message(tr::now)), schedule, - &st::menuIconSchedule); + &icons.menuSchedule); } if (whenOnline && now == Type::ScheduledToUser) { menu->addAction( tr::lng_scheduled_send_until_online(tr::now), whenOnline, - &st::menuIconWhenOnline); + &icons.menuWhenOnline); } return FillMenuResult::Success; } diff --git a/Telegram/SourceFiles/menu/menu_send.h b/Telegram/SourceFiles/menu/menu_send.h index 0676de49e9..79edc38404 100644 --- a/Telegram/SourceFiles/menu/menu_send.h +++ b/Telegram/SourceFiles/menu/menu_send.h @@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +namespace style { +struct ComposeIcons; +} // namespace style + namespace Api { struct SendOptions; } // namespace Api @@ -47,7 +51,8 @@ FillMenuResult FillSendMenu( Type type, Fn silent, Fn schedule, - Fn whenOnline); + Fn whenOnline, + const style::ComposeIcons *iconsOverride = nullptr); void SetupMenuAndShortcuts( not_null button,