diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 1957187894..4d5aafe974 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4805,6 +4805,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_call_context_pin_screen" = "Pin screencast"; "lng_group_call_context_unpin_screen" = "Unpin screencast"; "lng_group_call_context_remove" = "Remove"; +"lng_group_call_context_cancel_invite" = "Cancel invitation"; "lng_group_call_remove_channel" = "Remove {channel} from the video chat and ban them?"; "lng_group_call_remove_channel_from_channel" = "Remove {channel} from the live stream?"; "lng_group_call_mac_access" = "Telegram Desktop does not have access to system wide keyboard input required for Push to Talk."; diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 02f3516871..4f81f6f37f 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -1489,8 +1489,12 @@ void Call::finish( || state == State::Failed) { return; } else if (conferenceInvite()) { - Core::App().calls().declineIncomingConferenceInvites(_conferenceId); - setState(finalState); + if (migrateCall) { + _delegate->callFinished(this); + } else { + Core::App().calls().declineIncomingConferenceInvites(_conferenceId); + setState(finalState); + } return; } else if (!_id) { setState(finalState); diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index 0e122b7c4c..f3e9365fd3 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -976,6 +976,33 @@ void Instance::declineIncomingConferenceInvites(CallId conferenceId) { } } +void Instance::declineOutgoingConferenceInvite( + CallId conferenceId, + not_null user) { + const auto i = _conferenceInvites.find(conferenceId); + if (i == end(_conferenceInvites)) { + return; + } + const auto j = i->second.users.find(user); + if (j == end(i->second.users)) { + return; + } + const auto api = &user->session().api(); + for (const auto &messageId : base::take(j->second.outgoing)) { + api->request(MTPphone_DeclineConferenceCallInvite( + MTP_int(messageId.bare) + )).send(); + } + if (!j->second.incoming.empty()) { + return; + } + i->second.users.erase(j); + if (i->second.users.empty()) { + _conferenceInvites.erase(i); + } + user->owner().unregisterInvitedToCallUser(conferenceId, user); +} + void Instance::showConferenceInvite( not_null user, MsgId conferenceInviteMsgId) { diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index f2fb73ee96..9936c69c92 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -147,6 +147,9 @@ public: not_null user, MsgId conferenceInviteMsgId); void declineIncomingConferenceInvites(CallId conferenceId); + void declineOutgoingConferenceInvite( + CallId conferenceId, + not_null user); [[nodiscard]] FnMut addAsyncWaiter(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index c2209c7102..057177db83 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -3739,6 +3739,7 @@ void GroupCall::inviteUsers( if (const auto call = _conferenceCall.get()) { for (const auto &user : users) { _api.request(MTPphone_InviteConferenceCallParticipant( + MTP_flags(0), inputCallSafe(), user->inputUser )).done([=](const MTPUpdates &result) { @@ -3752,6 +3753,8 @@ void GroupCall::inviteUsers( state->result.privacyRestricted.push_back(user); } else if (type == u"USER_ALREADY_PARTICIPANT"_q) { state->result.alreadyIn.push_back(user); + } else if (type == u"GROUPCALL_FORBIDDEN"_q) { + startRejoin(); } finishRequest(); }).send(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp index 6182597c1c..c8b2601270 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp @@ -319,6 +319,10 @@ object_ptr PrepareInviteBox( }) | ranges::to_vector; const auto done = [=](GroupCall::InviteResult result) { (*close)(); + if (result.invited.empty() + && result.privacyRestricted.empty()) { + return; + } showToast({ ComposeInviteResultToast(result) }); }; call->inviteUsers(users, done); diff --git a/Telegram/SourceFiles/calls/group/calls_group_members.cpp b/Telegram/SourceFiles/calls/group/calls_group_members.cpp index b1b1fa0c2b..0e3d2eb1d7 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/calls_volume_item.h" #include "calls/group/calls_group_members_row.h" #include "calls/group/calls_group_viewport.h" +#include "calls/calls_instance.h" #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_user.h" @@ -1308,6 +1309,9 @@ base::unique_qptr Members::Controller::createRowContextMenu( const auto participantPeer = row->peer(); const auto real = static_cast(row.get()); const auto muteState = real->state(); + if (muteState == Row::State::WithAccess) { + return nullptr; + } const auto muted = (muteState == Row::State::Muted) || (muteState == Row::State::RaisedHand); const auto addCover = !_call->rtmp(); @@ -1459,6 +1463,20 @@ base::unique_qptr Members::Controller::createRowContextMenu( removeHand); } } else { + const auto conference = _call->conferenceCall().get(); + if (muteState == Row::State::Invited + && participantPeer->isUser() + && conference) { + const auto id = conference->id(); + const auto cancelInvite = [=] { + Core::App().calls().declineOutgoingConferenceInvite( + id, + participantPeer->asUser()); + }; + result->addAction( + tr::lng_group_call_context_cancel_invite(tr::now), + cancelInvite); + } result->addAction( (participantPeer->isUser() ? tr::lng_context_view_profile(tr::now) @@ -1473,9 +1491,8 @@ base::unique_qptr Members::Controller::createRowContextMenu( } const auto canKick = [&] { const auto user = participantPeer->asUser(); - const auto state = static_cast(row.get())->state(); - if (state == Row::State::Invited - || state == Row::State::WithAccess) { + if (muteState == Row::State::Invited + || muteState == Row::State::WithAccess) { return false; } else if (const auto chat = _peer->asChat()) { return chat->amCreator() diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp index fd91ebbcb0..7dddb9240a 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp @@ -639,6 +639,7 @@ void MembersRow::paintComplexStatusText( const auto &font = st::normalFont; const auto useAbout = !_about.isEmpty() && (_state != State::WithAccess) + && (_state != State::Invited) && (style != MembersRowStyle::Video) && ((_state == State::RaisedHand && !_raisedHandStatus) || (_state != State::RaisedHand && !_speaking)); diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index 5761f160c0..51e38326f9 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -187,7 +187,7 @@ messageActionStarGift#4717e8a4 flags:# name_hidden:flags.0?true saved:flags.2?tr messageActionStarGiftUnique#acdfcb81 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long = MessageAction; messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; messageActionPaidMessagesPrice#bcd71419 stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; +messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -2610,7 +2610,7 @@ phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; phone.createConferenceCall#fbcefee6 random_id:int = phone.GroupCall; phone.deleteConferenceCallParticipants#f9231114 call:InputGroupCall ids:Vector block:bytes = Updates; phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#3e9cf7ee call:InputGroupCall user_id:InputUser = Updates; +phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates;