diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 788df16212..1c234f6755 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4762,6 +4762,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_call_invite" = "Invite Members"; "lng_group_call_invite_conf" = "Add People"; "lng_group_call_invited_status" = "invited"; +"lng_group_call_calling_status" = "calling..."; "lng_group_call_blockchain_only_status" = "listening"; "lng_group_call_muted_by_me_status" = "muted for you"; "lng_group_call_invite_title" = "Invite members"; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 09aad20fce..b3b6595030 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -893,6 +893,8 @@ groupCallMemberColoredCrossLine: CrossLineAnimation(groupCallMemberInactiveCross fg: groupCallMemberMutedIcon; icon: icon {{ "calls/group_calls_unmuted", groupCallMemberActiveIcon }}; } +groupCallMemberCalling: icon {{ "calls/call_answer", groupCallMemberInactiveIcon }}; +groupCallMemberCallingPosition: point(0px, 8px); groupCallMemberInvited: icon {{ "calls/group_calls_invited", groupCallMemberInactiveIcon }}; groupCallMemberInvitedPosition: point(2px, 12px); groupCallMemberRaisedHand: icon {{ "calls/group_calls_raised_hand", groupCallMemberInactiveStatus }}; @@ -1327,6 +1329,7 @@ groupCallNarrowRaisedHand: icon {{ "calls/video_mini_speak", groupCallMemberInac groupCallNarrowCameraIcon: icon {{ "calls/video_mini_video", groupCallMemberNotJoinedStatus }}; groupCallNarrowScreenIcon: icon {{ "calls/video_mini_screencast", groupCallMemberNotJoinedStatus }}; groupCallNarrowInvitedIcon: icon {{ "calls/video_mini_invited", groupCallMemberNotJoinedStatus }}; +groupCallNarrowCallingIcon: icon {{ "calls/video_mini_invited", groupCallMemberNotJoinedStatus }}; groupCallNarrowIconPosition: point(-4px, 2px); groupCallNarrowIconSkip: 15px; groupCallOutline: 2px; diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 7455ea2be6..0ba4672931 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -1542,7 +1542,8 @@ void Call::finish( _user->owner().registerInvitedToCallUser( migrateCall->id(), migrateCall, - _user); + _user, + true); } const auto session = &_user->session(); const auto weak = base::make_weak(this); diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index 0b21caa06a..7e2ae032b0 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -930,7 +930,8 @@ void Instance::unregisterConferenceInvite( CallId conferenceId, not_null user, MsgId messageId, - bool incoming) { + bool incoming, + bool onlyStopCalling) { const auto i = _conferenceInvites.find(conferenceId); if (i == end(_conferenceInvites)) { return; @@ -940,9 +941,14 @@ void Instance::unregisterConferenceInvite( return; } auto &info = j->second; - (incoming ? info.incoming : info.outgoing).remove(messageId); + if (!(incoming ? info.incoming : info.outgoing).remove(messageId)) { + return; + } if (!incoming) { - user->owner().unregisterInvitedToCallUser(conferenceId, user); + user->owner().unregisterInvitedToCallUser( + conferenceId, + user, + onlyStopCalling); } if (info.incoming.empty() && info.outgoing.empty()) { i->second.users.erase(j); @@ -1010,6 +1016,11 @@ void Instance::declineOutgoingConferenceInvite( user->owner().history(user), std::move(inputs), true); + for (const auto &messageId : ids) { + if (const auto item = user->owner().message(user, messageId)) { + item->destroy(); + } + } } if (!j->second.incoming.empty()) { return; @@ -1018,7 +1029,7 @@ void Instance::declineOutgoingConferenceInvite( if (i->second.users.empty()) { _conferenceInvites.erase(i); } - user->owner().unregisterInvitedToCallUser(conferenceId, user); + user->owner().unregisterInvitedToCallUser(conferenceId, user, !discard); } void Instance::showConferenceInvite( diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index 39896cbc1c..1157c777a0 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -131,7 +131,8 @@ public: CallId conferenceId, not_null user, MsgId messageId, - bool incoming); + bool incoming, + bool onlyStopCalling = false); void showConferenceInvite( not_null user, MsgId conferenceInviteMsgId); diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index ce2d214f18..2ea46d9dd5 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -1623,6 +1623,9 @@ void GroupCall::sendJoinRequest() { if (const auto once = base::take(_migratedConferenceInfo)) { processMigration(*once); } + for (const auto &callback : base::take(_rejoinedCallbacks)) { + callback(); + } }).fail([=](const MTP::Error &error) { const auto type = error.type(); if (_e2e) { @@ -3775,6 +3778,45 @@ void GroupCall::editParticipant( }).send(); } + +void GroupCall::inviteToConference( + InviteRequest request, + Fn()> resultAddress, + Fn finishRequest) { + using Flag = MTPphone_InviteConferenceCallParticipant::Flag; + const auto user = request.user; + _api.request(MTPphone_InviteConferenceCallParticipant( + MTP_flags(request.video ? Flag::f_video : Flag()), + inputCall(), + user->inputUser + )).done([=](const MTPUpdates &result) { + const auto call = _conferenceCall.get(); + user->owner().registerInvitedToCallUser(_id, call, user, true); + _peer->session().api().applyUpdates(result); + resultAddress()->invited.push_back(user); + finishRequest(); + }).fail([=](const MTP::Error &error) { + const auto result = resultAddress(); + const auto type = error.type(); + if (type == u"USER_PRIVACY_RESTRICTED"_q) { + result->privacyRestricted.push_back(user); + } else if (type == u"USER_ALREADY_PARTICIPANT"_q) { + result->alreadyIn.push_back(user); + } else if (type == u"USER_WAS_KICKED"_q) { + result->kicked.push_back(user); + } else if (type == u"GROUPCALL_FORBIDDEN"_q) { + startRejoin(); + _rejoinedCallbacks.push_back([=] { + inviteToConference(request, resultAddress, finishRequest); + }); + return; + } else { + result->failed.push_back(user); + } + finishRequest(); + }).send(); +} + void GroupCall::inviteUsers( const std::vector &requests, Fn done) { @@ -3802,32 +3844,9 @@ void GroupCall::inviteUsers( if (const auto call = _conferenceCall.get()) { for (const auto &request : requests) { - using Flag = MTPphone_InviteConferenceCallParticipant::Flag; - const auto user = request.user; - _api.request(MTPphone_InviteConferenceCallParticipant( - MTP_flags(request.video ? Flag::f_video : Flag()), - inputCallSafe(), - user->inputUser - )).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); - } else if (type == u"USER_WAS_KICKED"_q) { - state->result.kicked.push_back(user); - } else if (type == u"GROUPCALL_FORBIDDEN"_q) { - startRejoin(); - } else { - state->result.failed.push_back(user); - } - finishRequest(); - }).send(); + inviteToConference(request, [=] { + return &state->result; + }, finishRequest); ++state->requests; } return; @@ -3857,7 +3876,7 @@ void GroupCall::inviteUsers( }; for (const auto &request : requests) { const auto user = request.user; - owner->registerInvitedToCallUser(_id, _peer, user); + owner->registerInvitedToCallUser(_id, _peer, user, false); usersSlice.push_back(user); slice.push_back(user->inputUser); if (slice.size() == kMaxInvitePerSlice) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.h b/Telegram/SourceFiles/calls/group/calls_group_call.h index 99c0a1e54c..c7f8368061 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.h +++ b/Telegram/SourceFiles/calls/group/calls_group_call.h @@ -625,6 +625,10 @@ private: void markTrackShown(const VideoEndpoint &endpoint, bool shown); void processMigration(StartConferenceInfo conference); + void inviteToConference( + InviteRequest request, + Fn()> resultAddress, + Fn finishRequest); [[nodiscard]] int activeVideoSendersCount() const; @@ -645,6 +649,7 @@ private: rpl::variable _state = State::Creating; base::flat_set _unresolvedSsrcs; rpl::event_stream _errors; + std::vector> _rejoinedCallbacks; bool _recordingStoppedByMe = false; bool _requestedVideoChannelsUpdateScheduled = false; diff --git a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp index 68182df06a..876e24de95 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp @@ -477,15 +477,23 @@ object_ptr PrepareInviteBox( return nullptr; } const auto peer = call->peer(); + const auto conference = call->conference(); const auto weak = base::make_weak(call); - auto alreadyIn = peer->owner().invitedToCallUsers(real->id()); + const auto &invited = peer->owner().invitedToCallUsers(real->id()); + auto alreadyIn = base::flat_set>(); + alreadyIn.reserve(invited.size() + real->participants().size() + 1); + alreadyIn.emplace(peer->session().user()); for (const auto &participant : real->participants()) { if (const auto user = participant.peer->asUser()) { alreadyIn.emplace(user); } } - alreadyIn.emplace(peer->session().user()); - if (call->conference()) { + for (const auto &[user, calling] : invited) { + if (!conference || calling) { + alreadyIn.emplace(user); + } + } + if (conference) { const auto close = std::make_shared>(); const auto shareLink = [=] { Assert(shareConferenceLink != nullptr); diff --git a/Telegram/SourceFiles/calls/group/calls_group_members.cpp b/Telegram/SourceFiles/calls/group/calls_group_members.cpp index 3ec4f87411..52d787421d 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members.cpp @@ -108,7 +108,8 @@ private: [[nodiscard]] std::unique_ptr createRow( const Data::GroupCallParticipant &participant); [[nodiscard]] std::unique_ptr createInvitedRow( - not_null participantPeer); + not_null participantPeer, + bool calling); [[nodiscard]] std::unique_ptr createWithAccessRow( not_null participantPeer); @@ -494,8 +495,9 @@ void Members::Controller::toggleVideoEndpointActive( bool Members::Controller::appendInvitedUsers() { auto changed = false; if (const auto id = _call->id()) { - for (const auto &user : _peer->owner().invitedToCallUsers(id)) { - if (auto row = createInvitedRow(user)) { + const auto &invited = _peer->owner().invitedToCallUsers(id); + for (const auto &[user, calling] : invited) { + if (auto row = createInvitedRow(user, calling)) { delegate()->peerListAppendRow(std::move(row)); changed = true; } @@ -514,14 +516,16 @@ void Members::Controller::setupInvitedUsers() { ) | rpl::filter([=](const Invite &invite) { return (invite.id == _call->id()); }) | rpl::start_with_next([=](const Invite &invite) { + const auto user = invite.user; if (invite.removed) { - if (const auto row = findRow(invite.user)) { - if (row->state() == Row::State::Invited) { + if (const auto row = findRow(user)) { + if (row->state() == Row::State::Invited + || row->state() == Row::State::Calling) { delegate()->peerListRemoveRow(row); delegate()->peerListRefreshRows(); } } - } else if (auto row = createInvitedRow(invite.user)) { + } else if (auto row = createInvitedRow(user, invite.calling)) { delegate()->peerListAppendRow(std::move(row)); delegate()->peerListRefreshRows(); } @@ -571,7 +575,8 @@ void Members::Controller::setupWithAccessUsers() { if (const auto count = delegate()->peerListFullRowsCount()) { const auto last = delegate()->peerListRowAt(count - 1); const auto state = static_cast(last.get())->state(); - if (state == Row::State::Invited) { + if (state == Row::State::Invited + || state == Row::State::Calling) { partition = true; } } @@ -584,7 +589,8 @@ void Members::Controller::setupWithAccessUsers() { if (partition) { delegate()->peerListPartitionRows([](const PeerListRow &row) { const auto state = static_cast(row).state(); - return (state != Row::State::Invited); + return (state != Row::State::Invited) + && (state != Row::State::Calling); }); } delegate()->peerListRefreshRows(); @@ -599,6 +605,7 @@ void Members::Controller::updateRow( auto addedToBottom = (Row*)nullptr; if (const auto row = findRow(now.peer)) { if (row->state() == Row::State::Invited + || row->state() == Row::State::Calling || row->state() == Row::State::WithAccess) { reorderIfNonRealBefore = row->absoluteIndex(); } @@ -631,7 +638,9 @@ void Members::Controller::updateRow( reorderIfNonRealBefore - 1).get(); using State = Row::State; const auto state = static_cast(row)->state(); - return (state == State::Invited) || (state == State::WithAccess); + return (state == State::Invited) + || (state == State::Calling) + || (state == State::WithAccess); }(); if (reorder) { partitionRows(); @@ -666,12 +675,15 @@ void Members::Controller::partitionRows() { if (state == State::WithAccess) { hadWithAccess = true; } - return (state != State::Invited) && (state != State::WithAccess); + return (state != State::Invited) + && (state != State::Calling) + && (state != State::WithAccess); }); if (hadWithAccess) { delegate()->peerListPartitionRows([](const PeerListRow &row) { const auto state = static_cast(row).state(); - return (state != Row::State::Invited); + return (state != Row::State::Invited) + && (state != Row::State::Calling); }); } } @@ -811,7 +823,7 @@ void Members::Controller::updateRow( } else if (noParticipantState == Row::State::WithAccess) { row->updateStateWithAccess(); } else { - row->updateStateInvited(); + row->updateStateInvited(noParticipantState == Row::State::Calling); } const auto wasNoSounding = _soundingRowBySsrc.empty(); @@ -1093,15 +1105,21 @@ void Members::Controller::rowPaintIcon( return; } const auto narrow = (state.style == MembersRowStyle::Narrow); - if (state.invited) { + if (state.invited || state.calling) { if (narrow) { - st::groupCallNarrowInvitedIcon.paintInCenter(p, rect); + (state.invited + ? st::groupCallNarrowInvitedIcon + : st::groupCallNarrowCallingIcon).paintInCenter(p, rect); } else { - st::groupCallMemberInvited.paintInCenter( + const auto &icon = state.invited + ? st::groupCallMemberInvited + : st::groupCallMemberCalling; + const auto shift = state.invited + ? st::groupCallMemberInvitedPosition + : st::groupCallMemberCallingPosition; + icon.paintInCenter( p, - QRect( - rect.topLeft() + st::groupCallMemberInvitedPosition, - st::groupCallMemberInvited.size())); + QRect(rect.topLeft() + shift, icon.size())); } return; } @@ -1464,9 +1482,10 @@ base::unique_qptr Members::Controller::createRowContextMenu( } } else { const auto conference = _call->conferenceCall().get(); - if (muteState == Row::State::Invited + if (conference && participantPeer->isUser() - && conference) { + && (muteState == Row::State::Invited + || muteState == Row::State::Calling)) { const auto id = conference->id(); const auto cancelInvite = [=](bool discard) { Core::App().calls().declineOutgoingConferenceInvite( @@ -1474,9 +1493,11 @@ base::unique_qptr Members::Controller::createRowContextMenu( participantPeer->asUser(), discard); }; - result->addAction( - tr::lng_group_call_context_stop_ringing(tr::now), - [=] { cancelInvite(false); }); + if (muteState == Row::State::Calling) { + result->addAction( + tr::lng_group_call_context_stop_ringing(tr::now), + [=] { cancelInvite(false); }); + } result->addAction( tr::lng_group_call_context_cancel_invite(tr::now), [=] { cancelInvite(true); }); @@ -1497,6 +1518,7 @@ base::unique_qptr Members::Controller::createRowContextMenu( const auto canKick = [&] { const auto user = participantPeer->asUser(); if (muteState == Row::State::Invited + || muteState == Row::State::Calling || muteState == Row::State::WithAccess) { return false; } else if (const auto chat = _peer->asChat()) { @@ -1626,6 +1648,7 @@ void Members::Controller::addMuteActionsToContextMenu( const auto muteAction = [&]() -> QAction* { if (muteState == Row::State::Invited + || muteState == Row::State::Calling || muteState == Row::State::WithAccess || _call->rtmp() || isMe(participantPeer) @@ -1681,12 +1704,19 @@ std::unique_ptr Members::Controller::createRow( } std::unique_ptr Members::Controller::createInvitedRow( - not_null participantPeer) { - if (findRow(participantPeer)) { + not_null participantPeer, + bool calling) { + if (const auto row = findRow(participantPeer)) { + if (row->state() == Row::State::Invited + || row->state() == Row::State::Calling) { + row->updateStateInvited(calling); + delegate()->peerListUpdateRow(row); + } return nullptr; } + const auto state = calling ? Row::State::Calling : Row::State::Invited; auto result = std::make_unique(this, participantPeer); - updateRow(result.get(), std::nullopt, nullptr); + updateRow(result.get(), std::nullopt, nullptr, state); return result; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp index 7dddb9240a..3f213d61d5 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp @@ -138,9 +138,9 @@ void MembersRow::setSkipLevelUpdate(bool value) { _skipLevelUpdate = value; } -void MembersRow::updateStateInvited() { +void MembersRow::updateStateInvited(bool calling) { setVolume(Group::kDefaultVolume); - setState(State::Invited); + setState(calling ? State::Calling : State::Invited); setSounding(false); setSpeaking(false); _mutedByMe = false; @@ -640,11 +640,13 @@ void MembersRow::paintComplexStatusText( const auto useAbout = !_about.isEmpty() && (_state != State::WithAccess) && (_state != State::Invited) + && (_state != State::Calling) && (style != MembersRowStyle::Video) && ((_state == State::RaisedHand && !_raisedHandStatus) || (_state != State::RaisedHand && !_speaking)); if (!useAbout && _state != State::Invited + && _state != State::Calling && _state != State::WithAccess && !_mutedByMe) { paintStatusIcon(p, x, y, st, font, selected, narrowMode); @@ -693,6 +695,8 @@ void MembersRow::paintComplexStatusText( ? tr::lng_status_connecting(tr::now) : (_state == State::WithAccess) ? tr::lng_group_call_blockchain_only_status(tr::now) + : (_state == State::Calling) + ? tr::lng_group_call_calling_status(tr::now) : tr::lng_group_call_invited_status(tr::now))); } } @@ -706,6 +710,7 @@ QSize MembersRow::rightActionSize() const { bool MembersRow::rightActionDisabled() const { return _delegate->rowIsMe(peer()) || (_state == State::Invited) + || (_state == State::Calling) || !_delegate->rowCanMuteMembers(); } @@ -731,7 +736,9 @@ void MembersRow::rightActionPaint( size.width(), size.height(), outerWidth); - if (_state == State::Invited) { + if (_state == State::Invited + || _state == State::Calling + || _state == State::WithAccess) { _actionRipple = nullptr; } if (_actionRipple) { @@ -761,6 +768,7 @@ MembersRowDelegate::IconState MembersRow::computeIconState( .mutedByMe = _mutedByMe, .raisedHand = (_state == State::RaisedHand), .invited = (_state == State::Invited), + .calling = (_state == State::Calling), .style = style, }; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.h b/Telegram/SourceFiles/calls/group/calls_group_members_row.h index ef59b2686c..2aab2ead48 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.h +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.h @@ -24,7 +24,7 @@ struct PeerUserpicView; namespace Calls::Group { -enum class MembersRowStyle { +enum class MembersRowStyle : uchar { Default, Narrow, Video, @@ -40,6 +40,7 @@ public: bool mutedByMe = false; bool raisedHand = false; bool invited = false; + bool calling = false; MembersRowStyle style = MembersRowStyle::Default; }; virtual bool rowIsMe(not_null participantPeer) = 0; @@ -75,13 +76,14 @@ public: Muted, RaisedHand, Invited, + Calling, WithAccess, }; void setAbout(const QString &about); void setSkipLevelUpdate(bool value); void updateState(const Data::GroupCallParticipant &participant); - void updateStateInvited(); + void updateStateInvited(bool calling); void updateStateWithAccess(); void updateLevel(float level); void updateBlobAnimation(crl::time now); diff --git a/Telegram/SourceFiles/data/data_group_call.cpp b/Telegram/SourceFiles/data/data_group_call.cpp index 0318001421..6747b01b98 100644 --- a/Telegram/SourceFiles/data/data_group_call.cpp +++ b/Telegram/SourceFiles/data/data_group_call.cpp @@ -791,7 +791,10 @@ void GroupCall::applyParticipantsSlice( } if (adding) { if (const auto user = participantPeer->asUser()) { - _peer->owner().unregisterInvitedToCallUser(_id, user); + _peer->owner().unregisterInvitedToCallUser( + _id, + user, + false); } } }); diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index f715cc0bb1..2686a39af9 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -1701,13 +1701,11 @@ MediaCall::MediaCall(not_null parent, const Call &call) const auto peer = parent->history()->peer; peer->owner().registerCallItem(parent); if (const auto user = _call.conferenceId ? peer->asUser() : nullptr) { - if (_call.state == CallState::Invitation) { - Core::App().calls().registerConferenceInvite( - _call.conferenceId, - user, - parent->id, - !parent->out()); - } + Core::App().calls().registerConferenceInvite( + _call.conferenceId, + user, + parent->id, + !parent->out()); } } @@ -1716,13 +1714,11 @@ MediaCall::~MediaCall() { const auto peer = parent->history()->peer; peer->owner().unregisterCallItem(parent); if (const auto user = _call.conferenceId ? peer->asUser() : nullptr) { - if (_call.state == CallState::Invitation) { - Core::App().calls().unregisterConferenceInvite( - _call.conferenceId, - user, - parent->id, - !parent->out()); - } + Core::App().calls().unregisterConferenceInvite( + _call.conferenceId, + user, + parent->id, + !parent->out()); } } diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 641845ae0e..6bc8eaca38 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1219,8 +1219,8 @@ void Session::checkLocalUsersWentOffline() { } auto Session::invitedToCallUsers(CallId callId) const --> const base::flat_set> & { - static const base::flat_set> kEmpty; +-> const base::flat_map, bool> & { + static const base::flat_map, bool> kEmpty; const auto i = _invitedToCallUsers.find(callId); return (i != _invitedToCallUsers.end()) ? i->second : kEmpty; } @@ -1228,14 +1228,16 @@ auto Session::invitedToCallUsers(CallId callId) const void Session::registerInvitedToCallUser( CallId callId, not_null peer, - not_null user) { - registerInvitedToCallUser(callId, peer->groupCall(), user); + not_null user, + bool calling) { + registerInvitedToCallUser(callId, peer->groupCall(), user, calling); } void Session::registerInvitedToCallUser( CallId callId, GroupCall *call, - not_null user) { + not_null user, + bool calling) { if (call && call->id() == callId) { const auto inCall = ranges::contains( call->participants(), @@ -1245,19 +1247,32 @@ void Session::registerInvitedToCallUser( return; } } - _invitedToCallUsers[callId].emplace(user); - _invitesToCalls.fire({ callId, user }); + _invitedToCallUsers[callId][user] = calling; + _invitesToCalls.fire({ callId, user, calling }); } void Session::unregisterInvitedToCallUser( CallId callId, - not_null user) { + not_null user, + bool onlyStopCalling) { const auto i = _invitedToCallUsers.find(callId); if (i != _invitedToCallUsers.end()) { - i->second.remove(user); - if (i->second.empty()) { - _invitedToCallUsers.erase(i); - _invitesToCalls.fire({ callId, user, true }); + const auto j = i->second.find(user); + if (j != end(i->second)) { + if (onlyStopCalling) { + if (!j->second) { + return; + } + j->second = false; + } else { + i->second.erase(j); + if (i->second.empty()) { + _invitedToCallUsers.erase(i); + } + } + const auto calling = false; + const auto removed = !onlyStopCalling; + _invitesToCalls.fire({ callId, user, calling, removed }); } } } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index e1563d8563..bb810a7e37 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -240,22 +240,26 @@ public: void maybeStopWatchForOffline(not_null user); [[nodiscard]] auto invitedToCallUsers(CallId callId) const - -> const base::flat_set> &; + -> const base::flat_map, bool> &; void registerInvitedToCallUser( CallId callId, not_null peer, - not_null user); + not_null user, + bool calling); void registerInvitedToCallUser( CallId callId, GroupCall *call, - not_null user); + not_null user, + bool calling); void unregisterInvitedToCallUser( CallId callId, - not_null user); + not_null user, + bool onlyStopCalling); struct InviteToCall { CallId id = 0; not_null user; + bool calling = false; bool removed = false; }; [[nodiscard]] rpl::producer invitesToCalls() const { @@ -1112,7 +1116,7 @@ private: rpl::event_stream _invitesToCalls; base::flat_map< CallId, - base::flat_set>> _invitedToCallUsers; + base::flat_map, bool>> _invitedToCallUsers; base::flat_set> _shownSpoilers; base::flat_map< diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index f93592c270..6309d4965a 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1902,12 +1902,21 @@ void HistoryItem::applyEdition(const MTPDmessageService &message) { _flags &= ~MessageFlag::DisplayFromChecked; } else if (message.vaction().type() == mtpc_messageActionConferenceCall) { removeFromSharedMediaIndex(); + const auto owner = &history()->owner(); + const auto &data = message.vaction().c_messageActionConferenceCall(); + const auto info = Data::ComputeCallData(owner, data); + if (const auto user = history()->peer->asUser()) { + if (const auto conferenceId = out() ? info.conferenceId : 0) { + Core::App().calls().unregisterConferenceInvite( + conferenceId, + user, + id, + !out(), + true); + } + } _media = nullptr; - _media = std::make_unique( - this, - Data::ComputeCallData( - &history()->owner(), - message.vaction().c_messageActionConferenceCall())); + _media = std::make_unique(this, info); addToSharedMediaIndex(); finishEdition(-1); _flags &= ~MessageFlag::DisplayFromChecked; @@ -4896,7 +4905,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { for (const auto &id : action.vusers().v) { const auto user = owner->user(id.v); if (callId) { - owner->registerInvitedToCallUser(callId, peer, user); + owner->registerInvitedToCallUser(callId, peer, user, false); } }; const auto linkCallId = PeerHasThisCall(peer, callId).value_or(false)