From be1afb4781a1a4c11744b1e3fe1afbddeff6600a Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 15 Jan 2021 19:27:34 +0400 Subject: [PATCH] Show recently joined by permanent link userpics. --- .../Resources/icons/info/edit/links_link.png | Bin 0 -> 606 bytes .../icons/info/edit/links_link@2x.png | Bin 0 -> 1193 bytes .../icons/info/edit/links_link@3x.png | Bin 0 -> 1905 bytes .../icons/info/edit/roundbtn_plus.png | Bin 0 -> 289 bytes .../icons/info/edit/roundbtn_plus@2x.png | Bin 0 -> 460 bytes .../icons/info/edit/roundbtn_plus@3x.png | Bin 0 -> 752 bytes Telegram/Resources/langs/lang.strings | 1 - Telegram/SourceFiles/api/api_invite_links.cpp | 76 ++++++++++++++- Telegram/SourceFiles/api/api_invite_links.h | 35 ++++++- .../boxes/peers/edit_peer_invite_links.cpp | 87 +++++++++++++++++- Telegram/SourceFiles/info/info.style | 10 ++ .../ui/controls/invite_link_buttons.cpp | 87 ++++++++++++++++++ .../ui/controls/invite_link_buttons.h | 11 +++ 13 files changed, 300 insertions(+), 7 deletions(-) create mode 100644 Telegram/Resources/icons/info/edit/links_link.png create mode 100644 Telegram/Resources/icons/info/edit/links_link@2x.png create mode 100644 Telegram/Resources/icons/info/edit/links_link@3x.png create mode 100644 Telegram/Resources/icons/info/edit/roundbtn_plus.png create mode 100644 Telegram/Resources/icons/info/edit/roundbtn_plus@2x.png create mode 100644 Telegram/Resources/icons/info/edit/roundbtn_plus@3x.png diff --git a/Telegram/Resources/icons/info/edit/links_link.png b/Telegram/Resources/icons/info/edit/links_link.png new file mode 100644 index 0000000000000000000000000000000000000000..334eab0a28935a0fa08bc7ed13a3bb82aa58aa39 GIT binary patch literal 606 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZp5{cEZ!eF(iWX zZRp-phYUn~?dt>X+ubu6cPJ5L4;NopBDCI8 zJa~(IRxo$0l*i;dEpsLp*Jp7kdVD)`D?aT6|ARRW>wqweYs%@TE|PzR8{HNw##|SD z{yCDxQDNKdwGzE`tCA2`@_F={@ZW& zs!iq;?RI6$*?zmkMsDVb0*fARCCSFR{r)ckzwWxLCmgXh?Ekk#>GH2rSgxcl%M4n6 zne*VPt6IVqGJFet=hhk@Q)Za|zHImO@a<8$lNdd&zn+@4Rf_pg+qSs%mz5P3&t>Mb z3*V$&&~P@*m`!`C*Or?(2};KcFDWYo_v*VIa6Fc_`J{e(q22s;hs!UgoUfec-s+^d zW&gyuxAoG)X2k1=@qFRo6S%$2lJ)i1UAt_~{g~OXrr=HTlbuzZ3{`vMc7%Ov zd7RF)BP7hC&hXP8Nfx{IH_Znh9Q{|LcI=OJ0VV4@vAd%V5XGwtp2`-M_#ikWr-;Y{rU Y_N{Tr;zbb!3qWz}>FVdQ&MBb@0P*ha)Bpeg literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/info/edit/links_link@2x.png b/Telegram/Resources/icons/info/edit/links_link@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6c1174a8a9ad3d007d61891558761cef922f2006 GIT binary patch literal 1193 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^uz(rC1}St4blSkcz#{DF;uuoF z_%_1U`-_9XJ?r?uKt~;szzrJ$1&+Aove-viZryS0+_776TQ*#_S6ETd+S~d_{2voH zx8N0L?v0`>JDs>41CQ786~D=wboyvck^URLmYhj9&)S_ockYZ|m!aDqqp(ZIl>W2k zac&SxuwX9ZmdIl`6VK(zLk=ZS#tKQZ&gi=O5nVC^E9TPzIft<$DQKUd=>j{ZP~op`TqU;N_pqM-Mc5Z zb<36`t}dTgN=i#Fo;};E91;OWy;_q`SM)zyo?efzel)@jlt9Y$kg<1e2+Ih{X$-o(^Ylw--VWo_rqpH~$U z6BA?l-KqdI-@vfJYiW>Z^NAEAA;#UicZ+`KReB^J?h&)&F!$HMbj&TW31`msyB8$?mb0k^8pi zbKKtI4@g#b_X-pP}Nr}tTvb)@gLbLjnCP;uk)tCo-te24!1 ztDFAr)vHyXcUHtlMi#zY@wmO>nmfa#Xw$>Z+rwq&$^Yo>V@a{|9tzlt$W3`ZDzZ6?-p*?$y>{j5c;9wnlpo6Y1Xe*YLeOz?B!Yyy=@2o{oA*snSK3K_x(3-MtXk# z{CV;O{*L6Vtk;STHs_N!W#!phT52+CvCAF!_3IbMV~2wIvuAfR+Z^lhW0*5vgQNb{ zj>Cr!FY0=Ks{8M;1)b$Z3zpk$CPMLYr z>zv*%5vMHUI!<<-Q|=@ybN9xLh=lnI4F7+KiNLzHSS0tdb6Hd(ObK>$NI_%7T*KSGrs?p0b!WOBDT9IB@CvmGze&n*TktdV5Y) z)hu5hAA>0y15Q4CI4L$JX2ase%4M~+YyU4-bnltkFrj#5SJl<*rcg)SKUahlCM2d@ lj%t{ATCZW77*U*mj5?2lcAh@prVlD6JYD@<);T3K0RVT58Rh^0 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/info/edit/links_link@3x.png b/Telegram/Resources/icons/info/edit/links_link@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f4d797b7f1d6c644f0242fddb9641938588e199d GIT binary patch literal 1905 zcmbVNX*Aml7XK$ggF#SF$C{Ff<@HG`wG?BGMC!$sM@b|0B4R08)mm~oX)QzX>{J^| zt!YrT9zwNRO53MOT8h@bRBS~MuM=NpKFv9E=ELv)?()0$ocrb86ekCql!TH5002^W zJB*8vy^jGE6WW=A7-J!UqFiv+0Q;@VvM|5|xZ|%72!O88hXSCaU;uI~5kg4_01#n< z01+XBj&n@#zpLI%k^lI|!Wy)f0|1Ck;4xOe-2km!cC>SKJgJr#O!|sFn;YR%&CpJ+ z_G!~6NtCt>KZc*i*nR0u=Y4L5k=kINPx{W4*@Y@R{ll686+K7RAr&N!T7Kz2c*P0`it-3Iza?ehTEf z{SEXha1Q)p;gd)K;0sB9({$o2=miv394O-rPL_omzEkUgz%(ss5B^RUhhym<&29{R1YH225UV&tr(Gs+F>kRbaYfKFE5|@^XL$JBoTei)bwZb_yYtd z@rT}%rY76q;F_SIAlRjPib2a|4-eT?NMlC_m6hGE?EkIK%434Z;~6?oI~hqyN%L=t zjhYYG=E;rqT(slDu=xSBQA}d6u_kt8ezac~2g8J-mf4hnn7S{5_+1*_` zHz{a`nYrYgqXg-UKQt6;o1FCY@bU^5<)C9DBO~Xy^u+cEPwz_KiX=keKs-_;3!ikH$ zcx5iXva+)6y9wg3tx_6fE;cW&K_9~>CUyr-zz;XyVQnnp_{@m3T!BFFu@{m@J_XiC zqithj_XozO#Zb)%1>u(GTxD&ghd^k$Z44ahj zF)=angzXA+>CnRx>_RnwdeTnV6Ij=22c;s@pyuZ0QP)?`lVnP21KFOQp6oT+!F-dn z6v$*l718kFyAsCU-hOB(W_&ianS;lXNJRp{ew6>t$a+9Pz{~5%_^Wv%urEKkyj;$k zV0QMXD=9^W)=$Y+(QyeLBvNGP;#ie2?~WrNP5kw?DtiJsC@ILwl1+{|2CNBlx^aG%d=GU3*H{Fi-)X9gM~k(P%UlXrLH%H5}1pfc2@apIcj79q~P~ z{&Mt;#v~hhs{R9M^R2gqBy ztOfi{8+ck=7UDcO^ASsaZtX@&(Y~*b&$Bwx>#4nYeQM4kyME$ME&mqW)ai`D?6R`! zgp-UvQcKJ4ijMx6iHV8t>rlxEiAqBc>wxo6Gxi7StCryRA0$H;;1*t5{q8pJbF5!* zaf%bqT;%IiyE~w(hsx1rs(lYNGauH=`?F35zjm|8`@I9F6fIwo=e~Ct&Dns`uL>^o zBKqB!KS@%H#t>zBIO>k&)^UxgKguKdFrW{o_6HAYv>ZLWf{3OsZ)b(s5%}zoGHI zrbs4X{=6_<@sC-AF2&01p>YKb%&okC56ETztom6gA}f5OZp6?x;Yem>s@Kt8R0eB2%{N{Ya4nwT49J^YiTz?9P99E9tYjA@Iy5rmJe1JJaQ*octHAzwt#Z0BovEey!2&yZaK}ft=^*>gTe~DWM4f D{v%i~ literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/info/edit/roundbtn_plus@2x.png b/Telegram/Resources/icons/info/edit/roundbtn_plus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f2772af06d54919c3a6f59ad68860629bc761ec7 GIT binary patch literal 460 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(<^uz(rC1}St4blLz^X6EVQ7*fIb zcE&}%W(6MC#QNv|>zn?yXN#Nmwde5%_`Fk8Je-(QUEOszOEY!5rghw=iSmug3@jbm z4xAm#0SXLEM?@E}9ASJQu!Kc}v5*yr87jB~m^OPQL{8hZ?sfXFs%IbUT`wo_X*cg*q=@bgo+M3kpe3S3j3^P6-CxncH525KNM8)7|V*d%xeD9|(Gd4#~dupU7?(%^B zl<7Aw2gVP90S!zEOa*&n7ck6VkjZD)U{GT?ew&f2f%Cw}GRmYHzH{bmzx}kpLTCBq zm+x1tUv2h!RlWcGS5gP``&Vae-rM)O?s-%EY&rG+6aUBOx-rh4-TKkutkjpsaptqD zEQ@vX4{gwACFGuD*#i5ZbvMshUpG#B|EISquXpoxgHvwDc4RKGS)kA@lbU?_f>rJA zyYFr$=B=H7{(0*D``gp*9on#c!ELsEe+7jLY~;cZ&%4K6#4lm~(0lLqW&YcD<*`hS ztzNOW=W;{L4ciBkAKSAWjsGsZvE%3?Z6=_=)n)r$rgJsqYCA9*Fk0N>3t;eJ=-bXL z!XVu6_$>qL0hR|pG_4mr``)j8Rc`*~WAB%XOgMIYWHwX3E=VCEXl1%hQ=K@N*9MFcx2zY$s5 z;Iee%vIe&snqG{ZUdg_Uy&Hn3FbPdPHj7Crak&PoidL^FtH~k1KrW9Escf!{mbr^W cC@^qEyz4EmhSsecond.push_back(std::move(done)); @@ -250,6 +251,58 @@ void InviteLinks::requestLinks(not_null peer) { _firstSliceRequests.emplace(peer, requestId); } +JoinedByLinkSlice InviteLinks::lookupJoinedFirstSlice(LinkKey key) const { + const auto i = _firstJoined.find(key); + return (i != end(_firstJoined)) ? i->second : JoinedByLinkSlice(); +} + +rpl::producer InviteLinks::joinedFirstSliceValue( + not_null peer, + const QString &link, + int fullCount) { + const auto key = LinkKey{ peer, link }; + auto current = lookupJoinedFirstSlice(key); + if (current.count == fullCount + && (!fullCount || !current.users.empty())) { + return rpl::single(current); + } + current.count = fullCount; + const auto remove = int(current.users.size()) - current.count; + if (remove > 0) { + current.users.erase(end(current.users) - remove, end(current.users)); + } + requestJoinedFirstSlice(key); + using namespace rpl::mappers; + return rpl::single( + current + ) | rpl::then(_joinedFirstSliceLoaded.events( + ) | rpl::filter( + _1 == key + ) | rpl::map([=] { + return lookupJoinedFirstSlice(key); + })); +} + +void InviteLinks::requestJoinedFirstSlice(LinkKey key) { + if (_firstJoinedRequests.contains(key)) { + return; + } + const auto requestId = _api->request(MTPmessages_GetChatInviteImporters( + key.peer->input, + MTP_string(key.link), + MTP_int(0), // offset_date + MTP_inputUserEmpty(), // offset_user + MTP_int(kJoinedFirstPage) + )).done([=](const MTPmessages_ChatInviteImporters &result) { + _firstJoinedRequests.remove(key); + _firstJoined[key] = parseSlice(key.peer, result); + _joinedFirstSliceLoaded.fire_copy(key); + }).fail([=](const RPCError &error) { + _firstJoinedRequests.remove(key); + }).send(); + _firstJoinedRequests.emplace(key, requestId); +} + void InviteLinks::setPermanent( not_null peer, const MTPExportedChatInvite &invite) { @@ -320,6 +373,27 @@ auto InviteLinks::parseSlice( return result; } +JoinedByLinkSlice InviteLinks::parseSlice( + not_null peer, + const MTPmessages_ChatInviteImporters &slice) const { + auto result = JoinedByLinkSlice(); + slice.match([&](const MTPDmessages_chatInviteImporters &data) { + auto &owner = peer->session().data(); + owner.processUsers(data.vusers()); + result.count = data.vcount().v; + result.users.reserve(data.vimporters().v.size()); + for (const auto importer : data.vimporters().v) { + importer.match([&](const MTPDchatInviteImporter &data) { + result.users.push_back({ + .user = owner.user(data.vuser_id().v), + .date = data.vdate().v, + }); + }); + } + }); + return result; +} + auto InviteLinks::parse( not_null peer, const MTPExportedChatInvite &invite) const -> Link { diff --git a/Telegram/SourceFiles/api/api_invite_links.h b/Telegram/SourceFiles/api/api_invite_links.h index 6c53c9fbb..8d78a8f18 100644 --- a/Telegram/SourceFiles/api/api_invite_links.h +++ b/Telegram/SourceFiles/api/api_invite_links.h @@ -28,6 +28,16 @@ struct PeerInviteLinks { int count = 0; }; +struct JoinedByLinkUser { + not_null user; + TimeId date = 0; +}; + +struct JoinedByLinkSlice { + std::vector users; + int count = 0; +}; + class InviteLinks final { public: explicit InviteLinks(not_null api); @@ -59,21 +69,29 @@ public: void requestLinks(not_null peer); [[nodiscard]] const Links &links(not_null peer) const; + [[nodiscard]] rpl::producer joinedFirstSliceValue( + not_null peer, + const QString &link, + int fullCount); + void requestMoreLinks( not_null peer, const QString &last, Fn done); private: - struct EditKey { + struct LinkKey { not_null peer; QString link; - friend inline bool operator<(const EditKey &a, const EditKey &b) { + friend inline bool operator<(const LinkKey &a, const LinkKey &b) { return (a.peer == b.peer) ? (a.link < b.link) : (a.peer < b.peer); } + friend inline bool operator==(const LinkKey &a, const LinkKey &b) { + return (a.peer == b.peer) && (a.link == b.link); + } }; [[nodiscard]] Links parseSlice( @@ -82,6 +100,9 @@ private: [[nodiscard]] Link parse( not_null peer, const MTPExportedChatInvite &invite) const; + [[nodiscard]] JoinedByLinkSlice parseSlice( + not_null peer, + const MTPmessages_ChatInviteImporters &slice) const; [[nodiscard]] Link *lookupPermanent(not_null peer); [[nodiscard]] Link *lookupPermanent(Links &links); [[nodiscard]] const Link *lookupPermanent(const Links &links) const; @@ -108,15 +129,23 @@ private: TimeId expireDate = 0, int usageLimit = 0); + void requestJoinedFirstSlice(LinkKey key); + [[nodiscard]] JoinedByLinkSlice lookupJoinedFirstSlice( + LinkKey key) const; + const not_null _api; base::flat_map, Links> _firstSlices; base::flat_map, mtpRequestId> _firstSliceRequests; + base::flat_map _firstJoined; + base::flat_map _firstJoinedRequests; + rpl::event_stream _joinedFirstSliceLoaded; + base::flat_map< not_null, std::vector>> _createCallbacks; - base::flat_map>> _editCallbacks; + base::flat_map>> _editCallbacks; }; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp index a7e2fad86..482a9b91b 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp @@ -8,15 +8,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_peer_invite_links.h" #include "data/data_changes.h" -#include "data/data_peer.h" +#include "data/data_user.h" #include "main/main_session.h" #include "api/api_invite_links.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/padding_wrap.h" +#include "ui/abstract_button.h" #include "ui/widgets/popup_menu.h" #include "ui/controls/invite_link_label.h" #include "ui/controls/invite_link_buttons.h" #include "ui/toast/toast.h" +#include "history/view/history_view_group_call_tracker.h" // GenerateUs... #include "lang/lang_keys.h" #include "apiwrap.h" #include "styles/style_info.h" @@ -40,7 +42,8 @@ void AddPermanentLinkBlock( return link ? std::make_tuple(link->link, link->usage) : std::make_tuple(QString(), 0); - }) | rpl::start_spawning(container->lifetime()); + }) | rpl::distinct_until_changed( + ) | rpl::start_spawning(container->lifetime()); const auto copyLink = [=] { if (const auto link = computePermanentLink()) { @@ -95,4 +98,84 @@ void AddPermanentLinkBlock( container, copyLink, shareLink); + + struct JoinedState { + QImage cachedUserpics; + std::vector list; + int count = 0; + bool allUserpicsLoaded = false; + rpl::variable content; + rpl::lifetime lifetime; + }; + const auto state = container->lifetime().make_state(); + const auto push = [=] { + HistoryView::GenerateUserpicsInRow( + state->cachedUserpics, + state->list, + st::inviteLinkUserpics, + 0); + state->allUserpicsLoaded = ranges::all_of( + state->list, + [](const HistoryView::UserpicInRow &element) { + return !element.peer->hasUserpic() || element.view->image(); + }); + state->content = Ui::JoinedCountContent{ + .count = state->count, + .userpics = state->cachedUserpics + }; + }; + std::move( + value + ) | rpl::map([=](QString link, int usage) { + return peer->session().api().inviteLinks().joinedFirstSliceValue( + peer, + link, + usage); + }) | rpl::flatten_latest( + ) | rpl::start_with_next([=](const Api::JoinedByLinkSlice &slice) { + auto list = std::vector(); + list.reserve(slice.users.size()); + for (const auto &item : slice.users) { + const auto i = ranges::find( + state->list, + item.user, + &HistoryView::UserpicInRow::peer); + if (i != end(state->list)) { + list.push_back(std::move(*i)); + } else { + list.push_back({ item.user }); + } + } + state->count = slice.count; + state->list = std::move(list); + push(); + }, state->lifetime); + + peer->session().downloaderTaskFinished( + ) | rpl::filter([=] { + return !state->allUserpicsLoaded; + }) | rpl::start_with_next([=] { + auto pushing = false; + state->allUserpicsLoaded = true; + for (const auto &element : state->list) { + if (!element.peer->hasUserpic()) { + continue; + } else if (element.peer->userpicUniqueKey(element.view) + != element.uniqueKey) { + pushing = true; + } else if (!element.view->image()) { + state->allUserpicsLoaded = false; + } + } + if (pushing) { + push(); + } + }, state->lifetime); + + Ui::AddJoinedCountButton( + container, + state->content.value(), + st::inviteLinkJoinedRowPadding + )->setClickedCallback([=] { + }); } diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 534caccde..fd9997ef6 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -9,6 +9,7 @@ using "ui/basic.style"; using "boxes/boxes.style"; using "ui/widgets/widgets.style"; +using "ui/chat/chat.style"; // GroupCallUserpics. InfoToggle { color: color; @@ -865,3 +866,12 @@ inviteLinkShare: RoundButton(inviteLinkCopy) { icon: icon {{ "info/edit/links_share", activeButtonFg }}; iconOver: icon {{ "info/edit/links_share", activeButtonFgOver }}; } +inviteLinkUserpics: GroupCallUserpics { + size: 28px; + shift: 6px; + stroke: 2px; + align: align(left); +} +inviteLinkUserpicsSkip: 8px; +inviteLinkJoinedFont: font(14px); +inviteLinkJoinedRowPadding: margins(0px, 18px, 0px, 0px); diff --git a/Telegram/SourceFiles/ui/controls/invite_link_buttons.cpp b/Telegram/SourceFiles/ui/controls/invite_link_buttons.cpp index 233ee0f51..8b8fc3cd9 100644 --- a/Telegram/SourceFiles/ui/controls/invite_link_buttons.cpp +++ b/Telegram/SourceFiles/ui/controls/invite_link_buttons.cpp @@ -11,9 +11,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/vertical_layout.h" #include "ui/wrap/padding_wrap.h" #include "lang/lang_keys.h" +#include "styles/style_chat.h" #include "styles/style_info.h" namespace Ui { +namespace { + +class JoinedCountButton final : public AbstractButton { +public: + using AbstractButton::AbstractButton; + + void onStateChanged(State was, StateChangeSource source) override { + update(); + } +}; + +} // namespace void AddCopyShareLinkButtons( not_null container, @@ -47,4 +60,78 @@ void AddCopyShareLinkButtons( }, wrap->lifetime()); } +not_null AddJoinedCountButton( + not_null container, + rpl::producer content, + style::margins padding) { + struct State { + JoinedCountContent content; + QString phrase; + int addedWidth = 0; + }; + const auto wrap = container->add( + object_ptr( + container, + st::inviteLinkUserpics.size), + padding); + const auto result = CreateChild(wrap); + const auto state = result->lifetime().make_state(); + std::move( + content + ) | rpl::start_with_next([=](JoinedCountContent &&content) { + state->content = std::move(content); + result->setAttribute( + Qt::WA_TransparentForMouseEvents, + !state->content.count); + const auto &st = st::inviteLinkUserpics; + const auto imageWidth = !state->content.userpics.isNull() + ? state->content.userpics.width() / style::DevicePixelRatio() + : !state->content.count + ? 0 + : ((std::min(state->content.count, 3) - 1) * (st.size - st.shift) + + st.size); + state->addedWidth = imageWidth + ? (imageWidth + st::inviteLinkUserpicsSkip) + : 0; + state->phrase = state->content.count + ? tr::lng_group_invite_joined( + tr::now, + lt_count_decimal, + state->content.count) + : tr::lng_group_invite_no_joined(tr::now); + const auto fullWidth = st::inviteLinkJoinedFont->width(state->phrase) + + state->addedWidth; + result->resize(fullWidth, st.size); + result->move((wrap->width() - fullWidth) / 2, 0); + result->update(); + }, result->lifetime()); + + result->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(result); + if (!state->content.userpics.isNull()) { + p.drawImage(0, 0, state->content.userpics); + } + const auto &font = st::inviteLinkJoinedFont; + p.setPen(state->content.count + ? st::defaultLinkButton.color + : st::windowSubTextFg); + p.setFont((result->isOver() || result->isDown()) + ? font->underline() + : font); + const auto top = (result->height() - font->height) / 2; + p.drawText( + state->addedWidth, + top + font->ascent, + state->phrase); + }, result->lifetime()); + + wrap->widthValue( + ) | rpl::start_with_next([=](int width) { + result->move((width - result->width()) / 2, 0); + }, wrap->lifetime()); + + return result; +} + } // namespace Ui diff --git a/Telegram/SourceFiles/ui/controls/invite_link_buttons.h b/Telegram/SourceFiles/ui/controls/invite_link_buttons.h index aa637dbb9..c21195b76 100644 --- a/Telegram/SourceFiles/ui/controls/invite_link_buttons.h +++ b/Telegram/SourceFiles/ui/controls/invite_link_buttons.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { +class AbstractButton; class VerticalLayout; void AddCopyShareLinkButtons( @@ -16,4 +17,14 @@ void AddCopyShareLinkButtons( Fn copyLink, Fn shareLink); +struct JoinedCountContent { + int count = 0; + QImage userpics; +}; + +not_null AddJoinedCountButton( + not_null container, + rpl::producer content, + style::margins padding); + } // namespace Ui