From 021115b463c4dda447c464d0af9e31e991e25ec0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 1 Apr 2025 00:28:01 +0500 Subject: [PATCH] Nice join confcall confirm box. --- .../Resources/icons/calls/group_call_logo.png | Bin 0 -> 1092 bytes .../icons/calls/group_call_logo@2x.png | Bin 0 -> 2052 bytes .../icons/calls/group_call_logo@3x.png | Bin 0 -> 3149 bytes Telegram/Resources/langs/lang.strings | 6 + Telegram/SourceFiles/boxes/boxes.style | 6 + .../boxes/peers/add_participants_box.cpp | 1 + .../boxes/peers/replace_boost_box.cpp | 43 +++--- .../boxes/peers/replace_boost_box.h | 5 + Telegram/SourceFiles/calls/calls.style | 16 ++ .../calls/group/calls_group_common.cpp | 137 +++++++++++++++++- .../calls/group/calls_group_common.h | 1 + .../SourceFiles/core/local_url_handlers.cpp | 3 +- .../history/view/media/history_view_call.cpp | 4 +- .../bot/starref/info_bot_starref_common.h | 2 +- Telegram/SourceFiles/ui/effects/premium.style | 5 + .../window/window_session_controller.cpp | 27 ++-- .../window/window_session_controller.h | 8 +- 17 files changed, 217 insertions(+), 47 deletions(-) create mode 100644 Telegram/Resources/icons/calls/group_call_logo.png create mode 100644 Telegram/Resources/icons/calls/group_call_logo@2x.png create mode 100644 Telegram/Resources/icons/calls/group_call_logo@3x.png diff --git a/Telegram/Resources/icons/calls/group_call_logo.png b/Telegram/Resources/icons/calls/group_call_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b083149297bd7ee81d1e4ef1fb2aaba860574049 GIT binary patch literal 1092 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 Is#u2o2ZTDv=Kufz literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 4d5aafe974..8b340596dc 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4916,6 +4916,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_confcall_join_title" = "Group Call"; "lng_confcall_join_text" = "You are invited to join a Telegram Call."; +"lng_confcall_join_text_inviter" = "{user} is inviting you to join a Telegram Call."; +"lng_confcall_already_joined_one" = "{user} already joined this call."; +"lng_confcall_already_joined_two" = "{user} and {other} already joined this call."; +"lng_confcall_already_joined_three" = "{user}, {other} and {third} already joined this call."; +"lng_confcall_already_joined_many#one" = "{user}, {other} and **{count}** other person already joined this call."; +"lng_confcall_already_joined_many#other" = "{user}, {other} and **{count}** other people already joined this call."; "lng_confcall_join_button" = "Join Group Call"; "lng_confcall_create_link" = "Create Call Link"; "lng_confcall_create_link_description" = "You can create a link that will allow your friends on Telegram to join the call."; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index f77b417432..1e3b7f740d 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -24,6 +24,12 @@ UserpicButton { uploadIcon: icon; uploadIconPosition: point; } +UserpicsRow { + button: UserpicButton; + shift: pixels; + stroke: pixels; + invert: bool; +} ShortInfoBox { label: FlatLabel; labeled: FlatLabel; diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp index ad0bb57e77..25853e0f85 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp @@ -179,6 +179,7 @@ void FillUpgradeToPremiumCover( CreateUserpicsWithMoreBadge( container, rpl::single(std::move(userpicPeers)), + st::boostReplaceUserpicsRow, kUserpicsLimit), st::inviteForbiddenUserpicsPadding) )->entity()->setAttribute(Qt::WA_TransparentForMouseEvents); diff --git a/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp b/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp index 634e4a2480..f132e82e94 100644 --- a/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp @@ -550,13 +550,13 @@ object_ptr CreateUserpicsTransfer( rpl::variable count = 0; bool painting = false; }; - const auto full = st::boostReplaceUserpic.size.height() + const auto st = &st::boostReplaceUserpicsRow; + const auto full = st->button.size.height() + st::boostReplaceIconAdd.y() + st::lineWidth; auto result = object_ptr(parent, full); const auto raw = result.data(); - const auto &st = st::boostReplaceUserpic; - const auto right = CreateChild(raw, to, st); + const auto right = CreateChild(raw, to, st->button); const auto overlay = CreateChild(raw); const auto state = raw->lifetime().make_state(); @@ -564,7 +564,6 @@ object_ptr CreateUserpicsTransfer( from ) | rpl::start_with_next([=]( const std::vector> &list) { - const auto &st = st::boostReplaceUserpic; auto was = base::take(state->from); auto buttons = base::take(state->buttons); state->from.reserve(list.size()); @@ -578,7 +577,7 @@ object_ptr CreateUserpicsTransfer( state->buttons.push_back(std::move(buttons[index])); } else { state->buttons.push_back( - std::make_unique(raw, peer, st)); + std::make_unique(raw, peer, st->button)); const auto raw = state->buttons.back().get(); base::install_event_filter(raw, [=](not_null e) { return (e->type() == QEvent::Paint && !state->painting) @@ -598,7 +597,7 @@ object_ptr CreateUserpicsTransfer( const auto skip = st::boostReplaceUserpicsSkip; const auto left = width - 2 * right->width() - skip; const auto shift = std::min( - st::boostReplaceUserpicsShift, + st->shift, (count > 1 ? (left / (count - 1)) : width)); const auto total = right->width() + (count ? (skip + right->width() + (count - 1) * shift) : 0); @@ -630,7 +629,7 @@ object_ptr CreateUserpicsTransfer( auto q = QPainter(&state->layer); auto hq = PainterHighQualityEnabler(q); - const auto stroke = st::boostReplaceIconOutline; + const auto stroke = st->stroke; const auto half = stroke / 2.; auto pen = st::windowBg->p; pen.setWidthF(stroke * 2.); @@ -684,6 +683,7 @@ object_ptr CreateUserpicsTransfer( object_ptr CreateUserpicsWithMoreBadge( not_null parent, rpl::producer>> peers, + const style::UserpicsRow &st, int limit) { struct State { std::vector> from; @@ -693,7 +693,7 @@ object_ptr CreateUserpicsWithMoreBadge( rpl::variable count = 0; bool painting = false; }; - const auto full = st::boostReplaceUserpic.size.height() + const auto full = st.button.size.height() + st::boostReplaceIconAdd.y() + st::lineWidth; auto result = object_ptr(parent, full); @@ -703,9 +703,8 @@ object_ptr CreateUserpicsWithMoreBadge( const auto state = raw->lifetime().make_state(); std::move( peers - ) | rpl::start_with_next([=]( + ) | rpl::start_with_next([=, &st]( const std::vector> &list) { - const auto &st = st::boostReplaceUserpic; auto was = base::take(state->from); auto buttons = base::take(state->buttons); state->from.reserve(list.size()); @@ -719,7 +718,7 @@ object_ptr CreateUserpicsWithMoreBadge( state->buttons.push_back(std::move(buttons[index])); } else { state->buttons.push_back( - std::make_unique(raw, peer, st)); + std::make_unique(raw, peer, st.button)); const auto raw = state->buttons.back().get(); base::install_event_filter(raw, [=](not_null e) { return (e->type() == QEvent::Paint && !state->painting) @@ -735,13 +734,12 @@ object_ptr CreateUserpicsWithMoreBadge( rpl::combine( raw->widthValue(), state->count.value() - ) | rpl::start_with_next([=](int width, int count) { - const auto &st = st::boostReplaceUserpic; - const auto single = st.size.width(); + ) | rpl::start_with_next([=, &st](int width, int count) { + const auto single = st.button.size.width(); const auto left = width - single; const auto used = std::min(count, int(state->buttons.size())); const auto shift = std::min( - st::boostReplaceUserpicsShift, + st.shift, (used > 1 ? (left / (used - 1)) : width)); const auto total = used ? (single + (used - 1) * shift) : 0; auto x = (width - total) / 2; @@ -755,7 +753,7 @@ object_ptr CreateUserpicsWithMoreBadge( overlay->paintRequest( ) | rpl::filter([=] { return !state->buttons.empty(); - }) | rpl::start_with_next([=] { + }) | rpl::start_with_next([=, &st] { const auto outerw = overlay->width(); const auto ratio = style::DevicePixelRatio(); if (state->layer.size() != QSize(outerw, full) * ratio) { @@ -768,17 +766,26 @@ object_ptr CreateUserpicsWithMoreBadge( auto q = QPainter(&state->layer); auto hq = PainterHighQualityEnabler(q); - const auto stroke = st::boostReplaceIconOutline; + const auto stroke = st.stroke; const auto half = stroke / 2.; auto pen = st::windowBg->p; pen.setWidthF(stroke * 2.); state->painting = true; - for (const auto &button : state->buttons) { + const auto paintOne = [&](not_null button) { q.setPen(pen); q.setBrush(Qt::NoBrush); q.drawEllipse(button->geometry()); const auto position = button->pos(); button->render(&q, position, QRegion(), QWidget::DrawChildren); + }; + if (st.invert) { + for (const auto &button : ranges::views::reverse(state->buttons)) { + paintOne(button.get()); + } + } else { + for (const auto &button : state->buttons) { + paintOne(button.get()); + } } state->painting = false; const auto last = state->buttons.back().get(); diff --git a/Telegram/SourceFiles/boxes/peers/replace_boost_box.h b/Telegram/SourceFiles/boxes/peers/replace_boost_box.h index 6e622479dc..71f5bab64d 100644 --- a/Telegram/SourceFiles/boxes/peers/replace_boost_box.h +++ b/Telegram/SourceFiles/boxes/peers/replace_boost_box.h @@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/object_ptr.h" +namespace style { +struct UserpicsRow; +} // namespace style + class ChannelData; namespace Main { @@ -66,4 +70,5 @@ enum class UserpicsTransferType { [[nodiscard]] object_ptr CreateUserpicsWithMoreBadge( not_null parent, rpl::producer>> peers, + const style::UserpicsRow &st, int limit); diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 89fc1a1da0..3fbdecc1cc 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -1527,6 +1527,22 @@ confcallLinkFooterOr: FlatLabel(confcallLinkCenteredText) { confcallLinkFooterOrTop: 12px; confcallLinkFooterOrSkip: 8px; confcallLinkFooterOrLineTop: 9px; +confcallJoinBox: Box(confcallLinkBox) { + buttonPadding: margins(24px, 24px, 24px, 24px); +} +confcallJoinLogo: icon {{ "calls/group_call_logo", windowFgActive }}; +confcallJoinLogoPadding: margins(8px, 8px, 8px, 8px); +confcallJoinSepPadding: margins(0px, 8px, 0px, 8px); +confcallJoinUserpics: UserpicsRow { + button: UserpicButton(defaultUserpicButton) { + size: size(36px, 36px); + photoSize: 36px; + } + shift: 16px; + stroke: 2px; + invert: true; +} +confcallJoinUserpicsPadding: margins(0px, 0px, 0px, 16px); groupCallLinkBox: Box(confcallLinkBox) { bg: groupCallMembersBg; diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.cpp b/Telegram/SourceFiles/calls/group/calls_group_common.cpp index f0dbb9628f..e1ac887e00 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_common.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "base/platform/base_platform_info.h" #include "base/random.h" +#include "boxes/peers/replace_boost_box.h" // CreateUserpicsWithMoreBadge #include "boxes/share_box.h" #include "calls/calls_instance.h" #include "core/application.h" @@ -22,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/labels.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" +#include "ui/painter.h" #include "ui/vertical_list.h" #include "lang/lang_keys.h" #include "main/main_session.h" @@ -90,25 +92,144 @@ object_ptr ScreenSharingPrivacyRequestBox() { void ConferenceCallJoinConfirm( not_null box, std::shared_ptr call, + UserData *maybeInviter, Fn join) { - box->setTitle(tr::lng_confcall_join_title()); + box->setStyle(st::confcallJoinBox); + box->setWidth(st::boxWideWidth); + box->setNoContentMargin(true); + box->addTopButton(st::boxTitleClose, [=] { + box->closeBox(); + }); + const auto logoSize = st::confcallJoinLogo.size(); + const auto logoOuter = logoSize.grownBy(st::confcallJoinLogoPadding); + const auto logo = box->addRow( + object_ptr(box), + st::boxRowPadding + st::confcallLinkHeaderIconPadding); + logo->resize(logo->width(), logoOuter.height()); + logo->paintRequest() | rpl::start_with_next([=] { + if (logo->width() < logoOuter.width()) { + return; + } + auto p = QPainter(logo); + auto hq = PainterHighQualityEnabler(p); + const auto x = (logo->width() - logoOuter.width()) / 2; + const auto outer = QRect(QPoint(x, 0), logoOuter); + p.setBrush(st::windowBgActive); + p.setPen(Qt::NoPen); + p.drawEllipse(outer); + st::confcallJoinLogo.paintInCenter(p, outer); + }, logo->lifetime()); + + box->addRow( + object_ptr>( + box, + object_ptr( + box, + tr::lng_confcall_join_title(), + st::boxTitle)), + st::boxRowPadding + st::confcallLinkTitlePadding); + const auto wrapName = [&](not_null peer) { + return rpl::single(Ui::Text::Bold(peer->shortName())); + }; box->addRow( object_ptr( box, - tr::lng_confcall_join_text(), - st::boxLabel)); + (maybeInviter + ? tr::lng_confcall_join_text_inviter( + lt_user, + wrapName(maybeInviter), + Ui::Text::RichLangValue) + : tr::lng_confcall_join_text(Ui::Text::RichLangValue)), + st::confcallLinkCenteredText), + st::boxRowPadding + )->setTryMakeSimilarLines(true); - box->addButton(tr::lng_confcall_join_button(), [=] { + const auto &participants = call->participants(); + const auto known = int(participants.size()); + if (known) { + const auto sep = box->addRow( + object_ptr(box), + st::boxRowPadding + st::confcallJoinSepPadding); + sep->resize(sep->width(), st::normalFont->height); + sep->paintRequest() | rpl::start_with_next([=] { + auto p = QPainter(sep); + const auto line = st::lineWidth; + const auto top = st::confcallLinkFooterOrLineTop; + const auto fg = st::windowSubTextFg->b; + p.setOpacity(0.2); + p.fillRect(0, top, sep->width(), line, fg); + }, sep->lifetime()); + + auto peers = std::vector>(); + for (const auto &participant : participants) { + peers.push_back(participant.peer); + if (peers.size() == 3) { + break; + } + } + box->addRow( + CreateUserpicsWithMoreBadge( + box, + rpl::single(peers), + st::confcallJoinUserpics, + known), + st::boxRowPadding + st::confcallJoinUserpicsPadding); + + const auto wrapByIndex = [&](int index) { + Expects(index >= 0 && index < known); + + return wrapName(participants[index].peer); + }; + auto text = (known == 1) + ? tr::lng_confcall_already_joined_one( + lt_user, + wrapByIndex(0), + Ui::Text::RichLangValue) + : (known == 2) + ? tr::lng_confcall_already_joined_two( + lt_user, + wrapByIndex(0), + lt_other, + wrapByIndex(1), + Ui::Text::RichLangValue) + : (known == 3) + ? tr::lng_confcall_already_joined_three( + lt_user, + wrapByIndex(0), + lt_other, + wrapByIndex(1), + lt_third, + wrapByIndex(2), + Ui::Text::RichLangValue) + : tr::lng_confcall_already_joined_many( + lt_count, + rpl::single(1. * (std::max(known, call->fullCount()) - 2)), + lt_user, + wrapByIndex(0), + lt_other, + wrapByIndex(1), + Ui::Text::RichLangValue); + box->addRow( + object_ptr( + box, + std::move(text), + st::confcallLinkCenteredText), + st::boxRowPadding + )->setTryMakeSimilarLines(true); + } + const auto joinAndClose = [=] { const auto weak = Ui::MakeWeak(box); join(); if (const auto strong = weak.data()) { strong->closeBox(); } - }); - box->addButton(tr::lng_cancel(), [=] { - box->closeBox(); - }); + }; + Info::BotStarRef::AddFullWidthButton( + box, + tr::lng_confcall_join_button(), + joinAndClose, + &st::confcallLinkButton); } ConferenceCallLinkStyleOverrides DarkConferenceCallLinkStyle() { diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.h b/Telegram/SourceFiles/calls/group/calls_group_common.h index 03c0770d47..0d40b1f14d 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.h +++ b/Telegram/SourceFiles/calls/group/calls_group_common.h @@ -129,6 +129,7 @@ using StickedTooltips = base::flags; void ConferenceCallJoinConfirm( not_null box, std::shared_ptr call, + UserData *maybeInviter, Fn join); struct ConferenceCallLinkStyleOverrides { diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index f689603ec9..9092ba251b 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -1459,8 +1459,9 @@ bool ResolveConferenceCall( if (slug.isEmpty()) { return false; } + const auto myContext = context.value(); controller->window().activate(); - controller->resolveConferenceCall(match->captured(1)); + controller->resolveConferenceCall(match->captured(1), myContext.itemId); return true; } } // namespace diff --git a/Telegram/SourceFiles/history/view/media/history_view_call.cpp b/Telegram/SourceFiles/history/view/media/history_view_call.cpp index d136b733d4..cd12e9bc45 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_call.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_call.cpp @@ -65,13 +65,15 @@ QSize Call::countOptimalSize() { const auto user = _parent->history()->peer->asUser(); const auto conference = _conference; const auto video = _video; + const auto contextId = _parent->data()->fullId(); const auto id = _parent->data()->id; _link = std::make_shared([=](ClickContext context) { if (conference) { const auto my = context.other.value(); const auto weak = my.sessionWindow; if (const auto strong = weak.get()) { - strong->resolveConferenceCall(id); + QSize(); + strong->resolveConferenceCall(id, contextId); } } else if (user) { Core::App().calls().startOutgoingCall(user, video); diff --git a/Telegram/SourceFiles/info/bot/starref/info_bot_starref_common.h b/Telegram/SourceFiles/info/bot/starref/info_bot_starref_common.h index d69864bf15..a48586b1be 100644 --- a/Telegram/SourceFiles/info/bot/starref/info_bot_starref_common.h +++ b/Telegram/SourceFiles/info/bot/starref/info_bot_starref_common.h @@ -55,7 +55,7 @@ using ConnectedBots = std::vector; rpl::producer subtitle, bool newBadge = false); -[[nodiscard]] not_null AddFullWidthButton( +not_null AddFullWidthButton( not_null box, rpl::producer text, Fn callback = nullptr, diff --git a/Telegram/SourceFiles/ui/effects/premium.style b/Telegram/SourceFiles/ui/effects/premium.style index 261beffafa..daeece6ce2 100644 --- a/Telegram/SourceFiles/ui/effects/premium.style +++ b/Telegram/SourceFiles/ui/effects/premium.style @@ -311,6 +311,11 @@ boostReplaceIconSkip: 3px; boostReplaceIconOutline: 2px; boostReplaceIconAdd: point(4px, 2px); boostReplaceArrow: icon{{ "mediaview/next", windowSubTextFg }}; +boostReplaceUserpicsRow: UserpicsRow { + button: boostReplaceUserpic; + shift: boostReplaceUserpicsShift; + stroke: boostReplaceIconOutline; +} showOrIconLastSeen: icon{{ "settings/premium/large_lastseen", windowFgActive }}; showOrIconReadTime: icon{{ "settings/premium/large_readtime", windowFgActive }}; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index c689c9e9aa..c2e69511ae 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -842,21 +842,21 @@ void SessionNavigation::resolveCollectible( void SessionNavigation::resolveConferenceCall( QString slug, - Fn finished) { - resolveConferenceCall(std::move(slug), 0, std::move(finished)); + FullMsgId contextId) { + resolveConferenceCall(std::move(slug), 0, contextId); } void SessionNavigation::resolveConferenceCall( MsgId inviteMsgId, - Fn finished) { - resolveConferenceCall({}, inviteMsgId, std::move(finished)); + FullMsgId contextId) { + resolveConferenceCall({}, inviteMsgId, contextId); } void SessionNavigation::resolveConferenceCall( QString slug, MsgId inviteMsgId, - Fn finished) { - _conferenceCallResolveFinished = std::move(finished); + FullMsgId contextId) { + _conferenceCallResolveContextId = contextId; if (_conferenceCallSlug == slug && _conferenceCallInviteMsgId == inviteMsgId) { return; @@ -875,7 +875,7 @@ void SessionNavigation::resolveConferenceCall( _conferenceCallRequestId = 0; const auto slug = base::take(_conferenceCallSlug); const auto inviteMsgId = base::take(_conferenceCallInviteMsgId); - const auto finished = base::take(_conferenceCallResolveFinished); + const auto contextId = base::take(_conferenceCallResolveContextId); result.data().vcall().match([&](const auto &data) { const auto call = session().data().sharedConferenceCall( data.vid().v, @@ -888,22 +888,21 @@ void SessionNavigation::resolveConferenceCall( .joinMessageId = inviteMsgId, }); }; + const auto context = session().data().message(contextId); + const auto inviter = context + ? context->from()->asUser() + : nullptr; uiShow()->show(Box( Calls::Group::ConferenceCallJoinConfirm, call, + (inviter && !inviter->isSelf()) ? inviter : nullptr, join)); - if (finished) { - finished(true); - } }); }).fail([=] { _conferenceCallRequestId = 0; _conferenceCallSlug = QString(); - const auto finished = base::take(_conferenceCallResolveFinished); + _conferenceCallResolveContextId = FullMsgId(); showToast(tr::lng_group_invite_bad_link(tr::now)); - if (finished) { - finished(false); - } }).send(); } diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index ceb30f1bd3..040739589d 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -266,10 +266,10 @@ public: Fn fail = nullptr); void resolveConferenceCall( QString slug, - Fn finished = nullptr); + FullMsgId contextId); void resolveConferenceCall( MsgId inviteMsgId, - Fn finished = nullptr); + FullMsgId contextId); base::weak_ptr showToast( Ui::Toast::Config &&config); @@ -299,7 +299,7 @@ private: void resolveConferenceCall( QString slug, MsgId inviteMsgId, - Fn finished); + FullMsgId contextId); void resolveDone( const MTPcontacts_ResolvedPeer &result, @@ -341,7 +341,7 @@ private: QString _conferenceCallSlug; MsgId _conferenceCallInviteMsgId; - Fn _conferenceCallResolveFinished; + FullMsgId _conferenceCallResolveContextId; mtpRequestId _conferenceCallRequestId = 0; };