diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 520df38eed..4a3f1bc052 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4765,6 +4765,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_call_add_to_group_all" = "Those users aren't members of «{group}». Add them to the group?"; "lng_group_call_invite_members" = "Group members"; "lng_group_call_invite_search_results" = "Search results"; +"lng_group_call_invite_limit" = "This is currently the maximum allowed number of participants."; "lng_group_call_new_muted" = "Mute new participants"; "lng_group_call_speakers" = "Speakers"; "lng_group_call_microphone" = "Microphone"; @@ -4921,6 +4922,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_confcall_link_or" = "or"; "lng_confcall_link_join" = "Be the first to join the call and add people from there. {link}"; "lng_confcall_link_join_link" = "Open call {arrow}"; +"lng_confcall_invite_done_user" = "You invited {user} to join the call."; +"lng_confcall_invite_done_many#one" = "You invited **{count} person** to join the call."; +"lng_confcall_invite_done_many#other" = "You invited **{count} people** to join the call."; +"lng_confcall_invite_fail_user" = "You cannot call {user} because of their privacy settings."; +"lng_confcall_invite_fail_many#one" = "You cannot call **{count} person** because of their privacy settings."; +"lng_confcall_invite_fail_many#other" = "You cannot call **{count} people** because of their privacy settings."; "lng_no_mic_permission" = "Telegram needs microphone access so that you can make calls and record voice messages."; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index d74c67f79c..d67b208f9b 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -1538,3 +1538,20 @@ groupCallLinkPreview: InputField(defaultInputField) { style: defaultTextStyle; heightMin: 35px; } +groupCallInviteLink: SettingsButton(defaultSettingsButton) { + textFg: mediaviewTextLinkFg; + textFgOver: mediaviewTextLinkFg; + textBg: groupCallMembersBg; + textBgOver: groupCallMembersBgOver; + + style: TextStyle(defaultTextStyle) { + font: font(14px semibold); + } + + height: 20px; + padding: margins(63px, 8px, 8px, 9px); + + ripple: groupCallRipple; +} +groupCallInviteLinkIcon: icon {{ "info/edit/group_manage_links", mediaviewTextLinkFg }}; +groupCallInviteLinkIconPosition: point(23px, 2px); diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index 2a67b56673..19950598f4 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -3697,61 +3697,88 @@ void GroupCall::editParticipant( }).send(); } -std::variant> GroupCall::inviteUsers( - const std::vector> &users) { +void GroupCall::inviteUsers( + const std::vector> &users, + Fn done) { const auto real = lookupReal(); if (!real) { - return 0; + if (done) { + done({}); + } + return; } const auto owner = &_peer->owner(); - if (_conferenceCall) { + struct State { + InviteResult result; + int requests = 0; + }; + const auto state = std::make_shared(); + const auto finishRequest = [=] { + if (!--state->requests) { + if (done) { + done(std::move(state->result)); + } + } + }; + + if (const auto call = _conferenceCall.get()) { for (const auto &user : users) { _api.request(MTPphone_InviteConferenceCallParticipant( inputCallSafe(), user->inputUser - )).send(); + )).done([=](const MTPUpdates &result) { + owner->registerInvitedToCallUser(_id, call, user); + _peer->session().api().applyUpdates(result); + state->result.invited.push_back(user); + finishRequest(); + }).fail([=](const MTP::Error &error) { + const auto type = error.type(); + if (type == u"USER_PRIVACY_RESTRICTED"_q) { + state->result.privacyRestricted.push_back(user); + } else if (type == u"USER_ALREADY_PARTICIPANT"_q) { + state->result.alreadyIn.push_back(user); + } + finishRequest(); + }).send(); + ++state->requests; } - auto result = std::variant>(0); - if (users.size() != 1) { - result = int(users.size()); - } else { - result = users.front(); - } - return result; + return; } - auto count = 0; + auto usersSlice = std::vector>(); + usersSlice.reserve(kMaxInvitePerSlice); auto slice = QVector(); - auto result = std::variant>(0); slice.reserve(kMaxInvitePerSlice); const auto sendSlice = [&] { - count += slice.size(); _api.request(MTPphone_InviteToGroupCall( inputCall(), MTP_vector(slice) )).done([=](const MTPUpdates &result) { _peer->session().api().applyUpdates(result); + for (const auto &user : usersSlice) { + state->result.invited.push_back(user); + } + finishRequest(); + }).fail([=](const MTP::Error &error) { + finishRequest(); }).send(); + ++state->requests; + slice.clear(); + usersSlice.clear(); }; for (const auto &user : users) { - if (!count && slice.empty()) { - result = user; - } owner->registerInvitedToCallUser(_id, _peer, user); + usersSlice.push_back(user); slice.push_back(user->inputUser); if (slice.size() == kMaxInvitePerSlice) { sendSlice(); } } - if (count != 0 || slice.size() != 1) { - result = int(count + slice.size()); - } if (!slice.empty()) { sendSlice(); } - return result; } auto GroupCall::ensureGlobalShortcutManager() diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.h b/Telegram/SourceFiles/calls/group/calls_group_call.h index a1534fa72f..c81ada53c1 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.h +++ b/Telegram/SourceFiles/calls/group/calls_group_call.h @@ -416,8 +416,15 @@ public: void toggleMute(const Group::MuteRequest &data); void changeVolume(const Group::VolumeRequest &data); - std::variant> inviteUsers( - const std::vector> &users); + + struct InviteResult { + std::vector> invited; + std::vector> alreadyIn; + std::vector> privacyRestricted; + }; + void inviteUsers( + const std::vector> &users, + Fn done); std::shared_ptr ensureGlobalShortcutManager(); void applyGlobalShortcutChanges(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp index 1e13d45a82..05ef1fc92f 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp @@ -15,12 +15,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_session.h" #include "data/data_group_call.h" +#include "info/profile/info_profile_icon.h" #include "main/main_session.h" +#include "main/session/session_show.h" #include "ui/text/text_utilities.h" #include "ui/layers/generic_box.h" +#include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "apiwrap.h" #include "lang/lang_keys.h" +#include "styles/style_boxes.h" // membersMarginTop #include "styles/style_calls.h" #include "styles/style_dialogs.h" // searchedBarHeight @@ -61,38 +65,139 @@ public: ConfInviteController( not_null session, base::flat_set> alreadyIn, - Fn)> choose) - : ContactsBoxController(session) - , _alreadyIn(std::move(alreadyIn)) - , _choose(std::move(choose)) { - } + Fn shareLink); + + [[nodiscard]] rpl::producer hasSelectedValue() const; protected: - std::unique_ptr createRow( - not_null user) override { - if (user->isSelf() - || user->isBot() - || user->isServiceUser() - || user->isInaccessible()) { - return nullptr; - } - auto result = ContactsBoxController::createRow(user); - if (_alreadyIn.contains(user)) { - result->setDisabledState(PeerListRow::State::DisabledChecked); - } - return result; - } + void prepareViewHook() override; - void rowClicked(not_null row) override { - _choose(row->peer()); - } + std::unique_ptr createRow( + not_null user) override; + + void rowClicked(not_null row) override; private: - const base::flat_set> _alreadyIn; - const Fn)> _choose; + [[nodiscard]] int fullCount() const; + + base::flat_set> _alreadyIn; + const Fn _shareLink; + rpl::variable _hasSelected; }; +ConfInviteController::ConfInviteController( + not_null session, + base::flat_set> alreadyIn, + Fn shareLink) +: ContactsBoxController(session) +, _alreadyIn(std::move(alreadyIn)) +, _shareLink(std::move(shareLink)) { + _alreadyIn.remove(session->user()); +} + +rpl::producer ConfInviteController::hasSelectedValue() const { + return _hasSelected.value(); +} + +std::unique_ptr ConfInviteController::createRow( + not_null user) { + if (user->isSelf() + || user->isBot() + || user->isServiceUser() + || user->isInaccessible()) { + return nullptr; + } + auto result = ContactsBoxController::createRow(user); + if (_alreadyIn.contains(user)) { + result->setDisabledState(PeerListRow::State::DisabledChecked); + } + return result; +} + +int ConfInviteController::fullCount() const { + return _alreadyIn.size() + delegate()->peerListSelectedRowsCount(); +} + +void ConfInviteController::rowClicked(not_null row) { + auto count = fullCount(); + auto limit = Data::kMaxConferenceMembers; + if (count < limit || row->checked()) { + delegate()->peerListSetRowChecked(row, !row->checked()); + _hasSelected = (delegate()->peerListSelectedRowsCount() > 0); + } else { + delegate()->peerListUiShow()->showToast( + tr::lng_group_call_invite_limit(tr::now)); + } +} + +void ConfInviteController::prepareViewHook() { + auto button = object_ptr>( + nullptr, + object_ptr( + nullptr, + tr::lng_profile_add_via_link(), + st::groupCallInviteLink), + style::margins(0, st::membersMarginTop, 0, 0)); + + const auto icon = Ui::CreateChild( + button->entity(), + st::groupCallInviteLinkIcon, + QPoint()); + button->entity()->heightValue( + ) | rpl::start_with_next([=](int height) { + icon->moveToLeft( + st::groupCallInviteLinkIconPosition.x(), + (height - st::groupCallInviteLinkIcon.height()) / 2); + }, icon->lifetime()); + + button->entity()->setClickedCallback(_shareLink); + button->entity()->events( + ) | rpl::filter([=](not_null e) { + return (e->type() == QEvent::Enter); + }) | rpl::start_with_next([=] { + delegate()->peerListMouseLeftGeometry(); + }, button->lifetime()); + delegate()->peerListSetAboveWidget(std::move(button)); +} + +[[nodiscard]] TextWithEntities ComposeInviteResultToast( + const GroupCall::InviteResult &result) { + auto text = TextWithEntities(); + const auto invited = int(result.invited.size()); + const auto restricted = int(result.privacyRestricted.size()); + if (invited == 1) { + text.append(tr::lng_confcall_invite_done_user( + tr::now, + lt_user, + Ui::Text::Bold(result.invited.front()->shortName()), + Ui::Text::RichLangValue)); + } else if (invited > 1) { + text.append(tr::lng_confcall_invite_done_many( + tr::now, + lt_count, + invited, + Ui::Text::RichLangValue)); + } + if (invited && restricted) { + text.append(u"\n\n"_q); + } + if (restricted == 1) { + text.append(tr::lng_confcall_invite_fail_user( + tr::now, + lt_user, + Ui::Text::Bold(result.privacyRestricted.front()->shortName()), + Ui::Text::RichLangValue)); + } else if (restricted > 1) { + text.append(tr::lng_confcall_invite_fail_many( + tr::now, + lt_count, + restricted, + Ui::Text::RichLangValue)); + } + return text; +} + } // namespace InviteController::InviteController( @@ -204,7 +309,8 @@ std::unique_ptr InviteContactsController::createRow( object_ptr PrepareInviteBox( not_null call, - Fn showToast) { + Fn showToast, + Fn finished)> shareConferenceLink) { const auto real = call->lookupReal(); if (!real) { return nullptr; @@ -220,33 +326,44 @@ object_ptr PrepareInviteBox( alreadyIn.emplace(peer->session().user()); if (call->conference()) { const auto close = std::make_shared>(); - const auto invite = [=](not_null peer) { - Expects(peer->isUser()); - - const auto call = weak.get(); - if (!call) { - return; - } - const auto user = peer->asUser(); - call->inviteUsers({ user }); - showToast(tr::lng_group_call_invite_done_user( - tr::now, - lt_user, - Ui::Text::Bold(user->firstName), - Ui::Text::WithEntities)); - (*close)(); + const auto shareLink = [=] { + Assert(shareConferenceLink != nullptr); + shareConferenceLink([=](bool ok) { if (ok) (*close)(); }); }; auto controller = std::make_unique( &real->session(), alreadyIn, - invite); - controller->setStyleOverrides( + shareLink); + const auto raw = controller.get(); + raw->setStyleOverrides( &st::groupCallInviteMembersList, &st::groupCallMultiSelect); auto initBox = [=](not_null box) { - box->setTitle(tr::lng_group_call_invite_title()); - box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); - *close = [=] { box->closeBox(); }; + box->setTitle(tr::lng_group_call_invite_conf()); + raw->hasSelectedValue() | rpl::start_with_next([=](bool has) { + box->clearButtons(); + if (has) { + box->addButton(tr::lng_group_call_invite_button(), [=] { + const auto call = weak.get(); + if (!call) { + return; + } + auto peers = box->collectSelectedRows(); + auto users = ranges::views::all( + peers + ) | ranges::views::transform([](not_null peer) { + return not_null(peer->asUser()); + }) | ranges::to_vector; + const auto done = [=](GroupCall::InviteResult result) { + (*close)(); + showToast({ ComposeInviteResultToast(result) }); + }; + call->inviteUsers(users, done); + }); + } + box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); + }, box->lifetime()); + *close = crl::guard(box, [=] { box->closeBox(); }); }; return Box(std::move(controller), initBox); } @@ -270,24 +387,23 @@ object_ptr PrepareInviteBox( if (!call) { return; } - const auto result = call->inviteUsers(users); - if (const auto user = std::get_if>(&result)) { - showToast(tr::lng_group_call_invite_done_user( - tr::now, - lt_user, - Ui::Text::Bold((*user)->firstName), - Ui::Text::WithEntities)); - } else if (const auto count = std::get_if(&result)) { - if (*count > 0) { + call->inviteUsers(users, [=](GroupCall::InviteResult result) { + if (result.invited.size() == 1) { + showToast(tr::lng_group_call_invite_done_user( + tr::now, + lt_user, + Ui::Text::Bold(result.invited.front()->firstName), + Ui::Text::WithEntities)); + } else if (result.invited.size() > 1) { showToast(tr::lng_group_call_invite_done_many( tr::now, lt_count, - *count, + result.invited.size(), Ui::Text::RichLangValue)); + } else { + Unexpected("Result in GroupCall::inviteUsers."); } - } else { - Unexpected("Result in GroupCall::inviteUsers."); - } + }); }; const auto inviteWithAdd = [=]( std::shared_ptr show, diff --git a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.h b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.h index e1e10ff4e7..47508d131a 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.h +++ b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.h @@ -77,6 +77,7 @@ private: [[nodiscard]] object_ptr PrepareInviteBox( not_null call, - Fn showToast); + Fn showToast, + Fn finished)> shareConferenceLink = nullptr); } // namespace Calls::Group diff --git a/Telegram/SourceFiles/calls/group/calls_group_members.cpp b/Telegram/SourceFiles/calls/group/calls_group_members.cpp index 3416b4a014..03f9610706 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members.cpp @@ -1742,13 +1742,15 @@ void Members::setMode(PanelMode mode) { } QRect Members::getInnerGeometry() const { + const auto shareLink = _shareLinkButton.current(); const auto addMembers = _addMemberButton.current(); + const auto share = shareLink ? shareLink->height() : 0; const auto add = addMembers ? addMembers->height() : 0; return QRect( 0, -_scroll->scrollTop(), width(), - _list->y() + _list->height() + _bottomSkip->height() + add); + _list->y() + _list->height() + _bottomSkip->height() + add + share); } rpl::producer Members::fullCountValue() const { @@ -1923,16 +1925,22 @@ void Members::setupFakeRoundCorners() { const auto bottomleft = create({ 0, shift }); const auto bottomright = create({ shift, shift }); + const auto heightValue = [=](Ui::RpWidget *widget) { + topleft->raise(); + topright->raise(); + bottomleft->raise(); + bottomright->raise(); + return widget ? widget->heightValue() : rpl::single(0); + }; rpl::combine( _list->geometryValue(), - _addMemberButton.value() | rpl::map([=](Ui::RpWidget *widget) { - topleft->raise(); - topright->raise(); - bottomleft->raise(); - bottomright->raise(); - return widget ? widget->heightValue() : rpl::single(0); - }) | rpl::flatten_latest() - ) | rpl::start_with_next([=](QRect list, int addMembers) { + _addMemberButton.value() | rpl::map( + heightValue + ) | rpl::flatten_latest(), + _shareLinkButton.value() | rpl::map( + heightValue + ) | rpl::flatten_latest() + ) | rpl::start_with_next([=](QRect list, int addMembers, int shareLink) { const auto left = list.x(); const auto top = list.y() - _topSkip->height(); const auto right = left + list.width() - topright->width(); @@ -1941,6 +1949,7 @@ void Members::setupFakeRoundCorners() { + list.height() + _bottomSkip->height() + addMembers + + shareLink - bottomleft->height(); topleft->move(left, top); topright->move(right, top); diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 8dced0375a..31f55e304a 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -949,7 +949,9 @@ void Panel::setupMembers() { _members->addMembersRequests( ) | rpl::start_with_next([=] { - if (!_peer->isBroadcast() + if (_call->conference()) { + addMembers(); + } else if (!_peer->isBroadcast() && Data::CanSend(_peer, ChatRestriction::SendOther, false) && _call->joinAs()->isSelf()) { addMembers(); @@ -960,19 +962,9 @@ void Panel::setupMembers() { } }, _callLifetime); - const auto exporting = std::make_shared(); _members->shareLinkRequests( - ) | rpl::start_with_next([=] { - Expects(_call->conference()); - - if (*exporting) { - return; - } - *exporting = true; - ExportConferenceCallLink(uiShow(), _call->conferenceCall(), { - .st = DarkConferenceCallLinkStyle(), - .finished = [=](bool) { *exporting = false; }, - }); + ) | rpl::start_with_next([cb = shareConferenceLinkCallback()] { + cb(nullptr); }, _callLifetime); _call->videoEndpointLargeValue( @@ -984,6 +976,28 @@ void Panel::setupMembers() { }, _callLifetime); } +Fn finished)> Panel::shareConferenceLinkCallback() { + const auto exporting = std::make_shared(); + return [=](Fn finished) { + Expects(_call->conference()); + + if (*exporting) { + return; + } + *exporting = true; + const auto done = [=](bool ok) { + *exporting = false; + if (const auto onstack = finished) { + onstack(ok); + } + }; + ExportConferenceCallLink(uiShow(), _call->conferenceCall(), { + .finished = done, + .st = DarkConferenceCallLinkStyle(), + }); + }; +} + void Panel::enlargeVideo() { _lastSmallGeometry = window()->geometry(); @@ -1536,10 +1550,17 @@ void Panel::showMainMenu() { } void Panel::addMembers() { + if (_call->conference() + && _call->conferenceCall()->fullCount() >= Data::kMaxConferenceMembers) { + showToast({ tr::lng_group_call_invite_limit(tr::now) }); + } const auto showToastCallback = [=](TextWithEntities &&text) { showToast(std::move(text)); }; - if (auto box = PrepareInviteBox(_call, showToastCallback)) { + const auto link = _call->conference() + ? shareConferenceLinkCallback() + : nullptr; + if (auto box = PrepareInviteBox(_call, showToastCallback, link)) { showBox(std::move(box)); } } diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.h b/Telegram/SourceFiles/calls/group/calls_group_panel.h index a591273d06..05c399dea6 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.h +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.h @@ -193,6 +193,8 @@ private: void toggleWideControls(bool shown); void updateWideControlsVisibility(); [[nodiscard]] bool videoButtonInNarrowMode() const; + [[nodiscard]] auto shareConferenceLinkCallback() + -> Fn finished)>; void endCall(); diff --git a/Telegram/SourceFiles/data/data_group_call.cpp b/Telegram/SourceFiles/data/data_group_call.cpp index 47cdc4fabf..b90e0f24c3 100644 --- a/Telegram/SourceFiles/data/data_group_call.cpp +++ b/Telegram/SourceFiles/data/data_group_call.cpp @@ -27,7 +27,6 @@ constexpr auto kSpeakingAfterActive = crl::time(6000); constexpr auto kActiveAfterJoined = crl::time(1000); constexpr auto kWaitForUpdatesTimeout = 3 * crl::time(1000); constexpr auto kReloadStaleTimeout = 16 * crl::time(1000); -constexpr auto kMaxConferenceMembers = 50; [[nodiscard]] QString ExtractNextOffset(const MTPphone_GroupCall &call) { return call.match([&](const MTPDphone_groupCall &data) { @@ -245,7 +244,7 @@ void GroupCall::checkStaleRequest() { MTP_vector(), // ids MTP_vector(), // ssrcs MTP_string(QString()), - MTP_int(kMaxConferenceMembers) + MTP_int(kMaxConferenceMembers + 10) )).done([=](const MTPphone_GroupParticipants &result) { _checkStaleRequestId = 0; const auto &list = _participantsWithAccess.current(); diff --git a/Telegram/SourceFiles/data/data_group_call.h b/Telegram/SourceFiles/data/data_group_call.h index d9dfdb8559..f413f3f70b 100644 --- a/Telegram/SourceFiles/data/data_group_call.h +++ b/Telegram/SourceFiles/data/data_group_call.h @@ -30,6 +30,8 @@ namespace Data { [[nodiscard]] const std::string &RtmpEndpointId(); +inline constexpr auto kMaxConferenceMembers = 10; + struct LastSpokeTimes { crl::time anything = 0; crl::time voice = 0; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 098315878d..fd205d0e03 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1135,6 +1135,30 @@ GroupCall *Session::groupCall(CallId callId) const { return (i != end(_groupCalls)) ? i->second.get() : nullptr; } +std::shared_ptr Session::sharedConferenceCall( + CallId id, + uint64 accessHash) { + const auto i = _conferenceCalls.find(id); + if (i != end(_conferenceCalls)) { + if (auto result = i->second.lock()) { + return result; + } + } + auto result = std::make_shared( + session().user(), + id, + accessHash, + TimeId(), // scheduledDate + false, // rtmp + true); // conference + if (i != end(_conferenceCalls)) { + i->second = result; + } else { + _conferenceCalls.emplace(id, result); + } + return result; +} + void Session::watchForOffline(not_null user, TimeId now) { if (!now) { now = base::unixtime::now(); @@ -1205,7 +1229,13 @@ void Session::registerInvitedToCallUser( CallId callId, not_null peer, not_null user) { - const auto call = peer->groupCall(); + registerInvitedToCallUser(callId, peer->groupCall(), user); +} + +void Session::registerInvitedToCallUser( + CallId callId, + GroupCall *call, + not_null user) { if (call && call->id() == callId) { const auto inCall = ranges::contains( call->participants(), diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 108f42482b..011d98dd43 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -230,7 +230,11 @@ public: void registerGroupCall(not_null call); void unregisterGroupCall(not_null call); - GroupCall *groupCall(CallId callId) const; + [[nodiscard]] GroupCall *groupCall(CallId callId) const; + + [[nodiscard]] std::shared_ptr sharedConferenceCall( + CallId id, + uint64 accessHash); void watchForOffline(not_null user, TimeId now = 0); void maybeStopWatchForOffline(not_null user); @@ -241,7 +245,13 @@ public: CallId callId, not_null peer, not_null user); - void unregisterInvitedToCallUser(CallId callId, not_null user); + void registerInvitedToCallUser( + CallId callId, + GroupCall *call, + not_null user); + void unregisterInvitedToCallUser( + CallId callId, + not_null user); struct InviteToCall { CallId id = 0; @@ -1096,10 +1106,11 @@ private: base::flat_set> _heavyViewParts; - base::flat_map> _groupCalls; + base::flat_map> _groupCalls; + base::flat_map> _conferenceCalls; rpl::event_stream _invitesToCalls; base::flat_map< - uint64, + CallId, base::flat_set>> _invitedToCallUsers; base::flat_set> _shownSpoilers; diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index 361ed511e0..9620615dd8 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -135,13 +135,9 @@ constexpr auto kPlayStatusLimit = 2; MTP_int(*creating) )).done(crl::guard(controller, [=](const MTPphone_GroupCall &result) { result.data().vcall().match([&](const auto &data) { - const auto call = std::make_shared( - session->user(), + const auto call = session->data().sharedConferenceCall( data.vid().v, - data.vaccess_hash().v, - TimeId(), // scheduleDate - false, // rtmp - true); // conference + data.vaccess_hash().v); call->processFullCall(result); const auto finished = [=](bool ok) { if (!ok) { diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index d0a2eae995..648e498da9 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -896,13 +896,9 @@ void SessionNavigation::resolveConferenceCall( const auto inviteMsgId = base::take(_conferenceCallInviteMsgId); const auto finished = base::take(_conferenceCallResolveFinished); result.data().vcall().match([&](const auto &data) { - const auto call = std::make_shared( - session().user(), + const auto call = session().data().sharedConferenceCall( data.vid().v, - data.vaccess_hash().v, - TimeId(), // scheduleDate - false, // rtmp - true); // conference + data.vaccess_hash().v); call->processFullCall(result); const auto confirmed = std::make_shared(); const auto join = [=] {