From 02517f7221371a6ff52661775581302b36dacad8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 3 Mar 2021 19:29:33 +0400 Subject: [PATCH] Update API scheme to layer 125. --- Telegram/Resources/tl/api.tl | 39 +++-- Telegram/SourceFiles/boxes/url_auth_box.cpp | 12 +- .../SourceFiles/calls/calls_group_call.cpp | 89 ++++++----- Telegram/SourceFiles/calls/calls_group_call.h | 6 +- .../SourceFiles/calls/calls_group_common.h | 6 +- .../SourceFiles/calls/calls_group_members.cpp | 125 ++++++++-------- .../SourceFiles/calls/calls_group_members.h | 4 +- .../SourceFiles/calls/calls_group_panel.cpp | 12 +- Telegram/SourceFiles/data/data_group_call.cpp | 139 ++++++++++-------- Telegram/SourceFiles/data/data_group_call.h | 17 +-- Telegram/SourceFiles/data/data_session.cpp | 2 +- .../SourceFiles/export/export_api_wrap.cpp | 2 + .../admin_log/history_admin_log_item.cpp | 34 ++--- .../view/history_view_group_call_tracker.cpp | 44 ++++-- .../SourceFiles/ui/image/image_location.cpp | 30 ++++ .../SourceFiles/ui/image/image_location.h | 1 + 16 files changed, 331 insertions(+), 231 deletions(-) diff --git a/Telegram/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index 01457d6b9..f50130cb6 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -92,6 +92,7 @@ inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes th inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation; inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation; +inputGroupCallStream#d1cc2a5f call:InputGroupCall date:int = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; @@ -127,8 +128,8 @@ chatForbidden#7328bdb id:int title:string = Chat; channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; -chatFull#f06c4018 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int = ChatFull; -channelFull#2548c037 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector = ChatFull; +chatFull#8a1e2983 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer = ChatFull; +channelFull#548c3f93 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -370,9 +371,9 @@ updateChat#1330a196 chat_id:int = Update; updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; updateGroupCall#a45eb99b chat_id:int call:GroupCall = Update; updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#609a6ed4 flags:# chat_id:int date:int user_id:int prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant qts:int = Update; -updateChannelParticipant#65d2b464 flags:# channel_id:int date:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant qts:int = Update; -updateBotStopped#30ec6ebc user_id:int stopped:Bool qts:int = Update; +updateChatParticipant#f3b3781f flags:# chat_id:int date:int actor_id:int user_id:int prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; +updateChannelParticipant#7fecb1ec flags:# channel_id:int date:int actor_id:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; +updateBotStopped#7f9488a user_id:int date:int stopped:Bool qts:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -1202,15 +1203,15 @@ peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats; groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#55903081 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true id:long access_hash:long participants_count:int params:flags.0?DataJSON version:int = GroupCall; +groupCall#c0c2052e flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true id:long access_hash:long participants_count:int params:flags.0?DataJSON title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int version:int = GroupCall; inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -groupCallParticipant#64c62a15 flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true user_id:int date:int active_date:flags.3?int source:int volume:flags.7?int = GroupCallParticipant; +groupCallParticipant#d27d3adf flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string = GroupCallParticipant; -phone.groupCall#66ab0bfc call:GroupCall participants:Vector participants_next_offset:string users:Vector = phone.GroupCall; +phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; -phone.groupParticipants#9cfeb92d count:int participants:Vector next_offset:string users:Vector version:int = phone.GroupParticipants; +phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; @@ -1237,6 +1238,8 @@ chatAdminWithInvites#dfd2330f admin_id:int invites_count:int revoked_invites_cou messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; +messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1469,8 +1472,8 @@ messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector = Vector; -messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult; -messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult; +messages.requestUrlAuth#198fb446 flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; +messages.acceptUrlAuth#b12c7125 flags:# write_allowed:flags.0?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Messages; messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; @@ -1494,12 +1497,14 @@ messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:in messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; +messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; messages.editExportedChatInvite#2e4ffbe flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int = messages.ExportedChatInvite; messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; messages.getChatInviteImporters#26fb7289 peer:InputPeer link:string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; +messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; @@ -1563,7 +1568,7 @@ channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats; +channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_groupcall:flags.2?true = messages.Chats; channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; @@ -1606,16 +1611,18 @@ phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall durati phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#bd3dabe0 peer:InputPeer random_id:int = Updates; -phone.joinGroupCall#5f9c8e62 flags:# muted:flags.0?true call:InputGroupCall params:DataJSON = Updates; +phone.createGroupCall#1fd59252 flags:# peer:InputPeer join_as:flags.0?InputPeer random_id:int = Updates; +phone.joinGroupCall#2e8166b8 flags:# muted:flags.0?true call:InputGroupCall join_as:flags.1?InputPeer params:DataJSON = Updates; phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.editGroupCallMember#a5e76cd8 flags:# muted:flags.0?true call:InputGroupCall user_id:InputUser volume:flags.1?int = Updates; phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; phone.toggleGroupCallSettings#74bbb43d flags:# call:InputGroupCall join_muted:flags.0?Bool = Updates; phone.getGroupCall#c7cb017 call:InputGroupCall = phone.GroupCall; phone.getGroupParticipants#c9f1d285 call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; phone.checkGroupCall#b74a7bea call:InputGroupCall source:int = Bool; +phone.toggleGroupCallRecord#c02a66d7 flags:# start:flags.0?true call:InputGroupCall title:flags.1?string = Updates; +phone.editGroupCallParticipant#4713e7a3 flags:# muted:flags.0?true call:InputGroupCall participant:InputPeer volume:flags.1?int = Updates; +phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; @@ -1632,4 +1639,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -// LAYER 124 +// LAYER 125 diff --git a/Telegram/SourceFiles/boxes/url_auth_box.cpp b/Telegram/SourceFiles/boxes/url_auth_box.cpp index 0a4420aa8..8865193fa 100644 --- a/Telegram/SourceFiles/boxes/url_auth_box.cpp +++ b/Telegram/SourceFiles/boxes/url_auth_box.cpp @@ -41,10 +41,13 @@ void UrlAuthBox::Activate( const auto buttonId = button->buttonId; const auto url = QString::fromUtf8(button->data); + using Flag = MTPmessages_RequestUrlAuth::Flag; button->requestId = session->api().request(MTPmessages_RequestUrlAuth( + MTP_flags(Flag::f_peer | Flag::f_msg_id | Flag::f_button_id), inputPeer, MTP_int(itemId.msg), - MTP_int(buttonId) + MTP_int(buttonId), + MTPstring() // #TODO auth url )).done([=](const MTPUrlAuthResult &result) { const auto button = HistoryMessageMarkupButton::Get( &session->data(), @@ -111,11 +114,14 @@ void UrlAuthBox::Request( } else if (const auto msg = session->data().message(itemId)) { const auto allowWrite = (result == Result::AuthAndAllowWrite); using Flag = MTPmessages_AcceptUrlAuth::Flag; + const auto flags = (allowWrite ? Flag::f_write_allowed : Flag(0)) + | (Flag::f_peer | Flag::f_msg_id | Flag::f_button_id); session->api().request(MTPmessages_AcceptUrlAuth( - MTP_flags(allowWrite ? Flag::f_write_allowed : Flag(0)), + MTP_flags(flags), inputPeer, MTP_int(itemId.msg), - MTP_int(buttonId) + MTP_int(buttonId), + MTPstring() // #TODO auth url )).done([=](const MTPUrlAuthResult &result) { const auto to = result.match( [&](const MTPDurlAuthResultAccepted &data) { diff --git a/Telegram/SourceFiles/calls/calls_group_call.cpp b/Telegram/SourceFiles/calls/calls_group_call.cpp index 37a7c1967..039ef0be0 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/calls_group_call.cpp @@ -57,18 +57,18 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000); } [[nodiscard]] const Data::GroupCall::Participant *LookupParticipant( - not_null chat, + not_null peer, uint64 id, - not_null user) { - const auto call = chat->groupCall(); + not_null participantPeer) { + const auto call = peer->groupCall(); if (!id || !call || call->id() != id) { return nullptr; } const auto &participants = call->participants(); const auto i = ranges::find( participants, - user, - &Data::GroupCall::Participant::user); + participantPeer, + &Data::GroupCall::Participant::peer); return (i != end(participants)) ? &*i : nullptr; } @@ -76,7 +76,11 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000); [[nodiscard]] bool IsGroupCallAdmin( not_null peer, - not_null user) { + not_null participantPeer) { + const auto user = participantPeer->asUser(); + if (!user) { + return false; // #TODO calls + } if (const auto chat = peer->asChat()) { return chat->admins.contains(user) || (chat->creator == user->bareId()); @@ -240,7 +244,9 @@ void GroupCall::playConnectingSoundOnce() { void GroupCall::start() { _createRequestId = _api.request(MTPphone_CreateGroupCall( + MTP_flags(0), _peer->input, + MTPInputPeer(), // #TODO calls join_as MTP_int(openssl::RandomValue()) )).done([=](const MTPUpdates &result) { _acceptFields = true; @@ -343,11 +349,13 @@ void GroupCall::rejoin() { const auto json = QJsonDocument(root).toJson( QJsonDocument::Compact); const auto wasMuteState = muted(); + using Flag = MTPphone_JoinGroupCall::Flag; _api.request(MTPphone_JoinGroupCall( MTP_flags((wasMuteState != MuteState::Active) - ? MTPphone_JoinGroupCall::Flag::f_muted - : MTPphone_JoinGroupCall::Flag(0)), + ? Flag::f_muted + : Flag(0)), inputCall(), + MTPInputPeer(), // #TODO calls join_as MTP_dataJSON(MTP_bytes(json)) )).done([=](const MTPUpdates &updates) { _mySsrc = ssrc; @@ -392,7 +400,7 @@ void GroupCall::applySelfInCallLocally() { const auto i = ranges::find( participants, self, - &Data::GroupCall::Participant::user); + &Data::GroupCall::Participant::peer); const auto date = (i != end(participants)) ? i->date : base::unixtime::now(); @@ -406,6 +414,7 @@ void GroupCall::applySelfInCallLocally() { const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0)) | (lastActive ? Flag::f_active_date : Flag(0)) | (_mySsrc ? Flag(0) : Flag::f_left) + | Flag::f_self | Flag::f_volume // Without flag the volume is reset to 100%. | Flag::f_volume_by_admin // Self volume can only be set by admin. | ((muted() != MuteState::Active) ? Flag::f_muted : Flag(0)); @@ -416,19 +425,20 @@ void GroupCall::applySelfInCallLocally() { 1, MTP_groupCallParticipant( MTP_flags(flags), - MTP_int(self->bareId()), + peerToMTP(self->id), // #TODO calls channel or self MTP_int(date), MTP_int(lastActive), MTP_int(_mySsrc), - MTP_int(volume))), + MTP_int(volume), + MTPstring())), // #TODO calls about MTP_int(0)).c_updateGroupCallParticipants()); } void GroupCall::applyParticipantLocally( - not_null user, + not_null participantPeer, bool mute, std::optional volume) { - const auto participant = LookupParticipant(_peer, _id, user); + const auto participant = LookupParticipant(_peer, _id, participantPeer); if (!participant || !participant->ssrc) { return; } @@ -436,7 +446,7 @@ void GroupCall::applyParticipantLocally( const auto isMuted = participant->muted || (mute && canManageCall); const auto canSelfUnmute = !canManageCall ? participant->canSelfUnmute - : (!mute || IsGroupCallAdmin(_peer, user)); + : (!mute || IsGroupCallAdmin(_peer, participantPeer)); const auto isMutedByYou = mute && !canManageCall; const auto mutedCount = 0/*participant->mutedCount*/; using Flag = MTPDgroupCallParticipant::Flag; @@ -447,7 +457,7 @@ void GroupCall::applyParticipantLocally( : Flag(0)) | (participant->lastActive ? Flag::f_active_date : Flag(0)) | (isMuted ? Flag::f_muted : Flag(0)) - | (isMutedByYou ? Flag::f_muted_by_you : Flag(0)); + | (isMutedByYou ? Flag::f_muted_by_you : Flag(0)); // #TODO calls self? _peer->groupCall()->applyUpdateChecked( MTP_updateGroupCallParticipants( inputCall(), @@ -455,11 +465,12 @@ void GroupCall::applyParticipantLocally( 1, MTP_groupCallParticipant( MTP_flags(flags), - MTP_int(user->bareId()), + peerToMTP(participantPeer->id), MTP_int(participant->date), MTP_int(participant->lastActive), MTP_int(participant->ssrc), - MTP_int(volume.value_or(participant->volume)))), + MTP_int(volume.value_or(participant->volume)), + MTPstring())), // #TODO calls about MTP_int(0)).c_updateGroupCallParticipants()); } @@ -631,22 +642,25 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) { // No real information about mutedByMe or my custom volume. return; } - const auto user = _peer->owner().user(data.vuser_id().v); - const auto participant = LookupParticipant(_peer, _id, user); + const auto participantPeer = _peer->owner().peer( + peerFromMTP(data.vpeer())); + const auto participant = LookupParticipant( + _peer, + _id, + participantPeer); if (!participant) { return; } _otherParticipantStateValue.fire(Group::ParticipantState{ - .user = user, + .peer = participantPeer, .volume = data.vvolume().value_or_empty(), .mutedByMe = data.is_muted_by_you(), }); }; - const auto self = _peer->session().userId(); for (const auto &participant : data.vparticipants().v) { participant.match([&](const MTPDgroupCallParticipant &data) { - if (data.vuser_id().v != self) { + if (!data.is_self()) { handleOtherParticipants(data); return; } @@ -891,12 +905,11 @@ void GroupCall::maybeSendMutedUpdate(MuteState previous) { void GroupCall::sendMutedUpdate() { _api.request(_updateMuteRequestId).cancel(); - _updateMuteRequestId = _api.request(MTPphone_EditGroupCallMember( - MTP_flags((muted() != MuteState::Active) - ? MTPphone_EditGroupCallMember::Flag::f_muted - : MTPphone_EditGroupCallMember::Flag(0)), + using Flag = MTPphone_EditGroupCallParticipant::Flag; + _updateMuteRequestId = _api.request(MTPphone_EditGroupCallParticipant( + MTP_flags((muted() != MuteState::Active) ? Flag::f_muted : Flag(0)), inputCall(), - MTP_inputUserSelf(), + MTP_inputPeerSelf(), MTP_int(100000) // volume )).done([=](const MTPUpdates &result) { _updateMuteRequestId = 0; @@ -930,37 +943,37 @@ void GroupCall::setCurrentAudioDevice(bool input, const QString &deviceId) { void GroupCall::toggleMute(const Group::MuteRequest &data) { if (data.locallyOnly) { - applyParticipantLocally(data.user, data.mute, std::nullopt); + applyParticipantLocally(data.peer, data.mute, std::nullopt); } else { - editParticipant(data.user, data.mute, std::nullopt); + editParticipant(data.peer, data.mute, std::nullopt); } } void GroupCall::changeVolume(const Group::VolumeRequest &data) { if (data.locallyOnly) { - applyParticipantLocally(data.user, false, data.volume); + applyParticipantLocally(data.peer, false, data.volume); } else { - editParticipant(data.user, false, data.volume); + editParticipant(data.peer, false, data.volume); } } void GroupCall::editParticipant( - not_null user, + not_null participantPeer, bool mute, std::optional volume) { - const auto participant = LookupParticipant(_peer, _id, user); + const auto participant = LookupParticipant(_peer, _id, participantPeer); if (!participant) { return; } - applyParticipantLocally(user, mute, volume); + applyParticipantLocally(participantPeer, mute, volume); - using Flag = MTPphone_EditGroupCallMember::Flag; + using Flag = MTPphone_EditGroupCallParticipant::Flag; const auto flags = (mute ? Flag::f_muted : Flag(0)) | (volume.has_value() ? Flag::f_volume : Flag(0)); - _api.request(MTPphone_EditGroupCallMember( + _api.request(MTPphone_EditGroupCallParticipant( MTP_flags(flags), inputCall(), - user->inputUser, + participantPeer->input, MTP_int(std::clamp(volume.value_or(0), 1, Group::kMaxVolume)) )).done([=](const MTPUpdates &result) { _peer->session().api().applyUpdates(result); @@ -987,7 +1000,7 @@ std::variant> GroupCall::inviteUsers( return !invited.contains(user) && !ranges::contains( participants, user, - &Data::GroupCall::Participant::user); + &Data::GroupCall::Participant::peer); }); auto count = 0; diff --git a/Telegram/SourceFiles/calls/calls_group_call.h b/Telegram/SourceFiles/calls/calls_group_call.h index 90d18839d..9cd52633b 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.h +++ b/Telegram/SourceFiles/calls/calls_group_call.h @@ -56,7 +56,7 @@ enum class MuteState { [[nodiscard]] bool IsGroupCallAdmin( not_null peer, - not_null user); + not_null participantPeer); struct LevelUpdate { uint32 ssrc = 0; @@ -194,11 +194,11 @@ private: void playConnectingSoundOnce(); void editParticipant( - not_null user, + not_null participantPeer, bool mute, std::optional volume); void applyParticipantLocally( - not_null user, + not_null participantPeer, bool mute, std::optional volume); diff --git a/Telegram/SourceFiles/calls/calls_group_common.h b/Telegram/SourceFiles/calls/calls_group_common.h index 7f76fd398..a22cd9f62 100644 --- a/Telegram/SourceFiles/calls/calls_group_common.h +++ b/Telegram/SourceFiles/calls/calls_group_common.h @@ -15,20 +15,20 @@ constexpr auto kDefaultVolume = 10000; constexpr auto kMaxVolume = 20000; struct MuteRequest { - not_null user; + not_null peer; bool mute = false; bool locallyOnly = false; }; struct VolumeRequest { - not_null user; + not_null peer; int volume = kDefaultVolume; bool finalized = true; bool locallyOnly = false; }; struct ParticipantState { - not_null user; + not_null peer; std::optional volume; bool mutedByMe = false; bool locallyOnly = false; diff --git a/Telegram/SourceFiles/calls/calls_group_members.cpp b/Telegram/SourceFiles/calls/calls_group_members.cpp index 3f2ba724c..f26dbfb86 100644 --- a/Telegram/SourceFiles/calls/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/calls_group_members.cpp @@ -91,7 +91,9 @@ public: class Row final : public PeerListRow { public: - Row(not_null delegate, not_null user); + Row( + not_null delegate, + not_null participantPeer); enum class State { Active, @@ -266,8 +268,8 @@ public: } [[nodiscard]] rpl::producer toggleMuteRequests() const; [[nodiscard]] rpl::producer changeVolumeRequests() const; - [[nodiscard]] auto kickMemberRequests() const - -> rpl::producer>; + [[nodiscard]] auto kickParticipantRequests() const + -> rpl::producer>; bool rowCanMuteMembers() override; void rowUpdateRow(not_null row) override; @@ -284,7 +286,7 @@ private: [[nodiscard]] std::unique_ptr createRow( const Data::GroupCall::Participant &participant); [[nodiscard]] std::unique_ptr createInvitedRow( - not_null user); + not_null participantPeer); void prepareRows(not_null real); //void repaintByTimer(); @@ -294,8 +296,8 @@ private: not_null row); void addMuteActionsToContextMenu( not_null menu, - not_null user, - bool userIsCallAdmin, + not_null participantPeer, + bool participantIsCallAdmin, not_null row); void setupListChangeViewers(not_null call); void subscribeToChanges(not_null real); @@ -308,7 +310,7 @@ private: void removeRow(not_null row); void updateRowLevel(not_null row, float level); void checkSpeakingRowPosition(not_null row); - Row *findRow(not_null user) const; + Row *findRow(not_null participantPeer) const; [[nodiscard]] Data::GroupCall *resolvedRealCall() const; void appendInvitedUsers(); @@ -323,7 +325,7 @@ private: rpl::event_stream _toggleMuteRequests; rpl::event_stream _changeVolumeRequests; - rpl::event_stream> _kickMemberRequests; + rpl::event_stream> _kickParticipantRequests; rpl::variable _fullCount = 1; rpl::variable _fullCountMin = 0; rpl::variable _fullCountMax = std::numeric_limits::max(); @@ -345,8 +347,10 @@ private: }; -Row::Row(not_null delegate, not_null user) -: PeerListRow(user) +Row::Row( + not_null delegate, + not_null participantPeer) +: PeerListRow(participantPeer) , _delegate(delegate) { refreshStatus(); } @@ -872,11 +876,13 @@ void MembersController::subscribeToChanges(not_null real) { ) | rpl::start_with_next([=](const Update &update) { Expects(update.was.has_value() || update.now.has_value()); - const auto user = update.was ? update.was->user : update.now->user; + const auto participantPeer = update.was + ? update.was->peer + : update.now->peer; if (!update.now) { - if (const auto row = findRow(user)) { - const auto owner = &user->owner(); - if (user->isSelf()) { + if (const auto row = findRow(participantPeer)) { + const auto owner = &participantPeer->owner(); + if (participantPeer->isSelf()) { updateRow(row, nullptr); } else { removeRow(row); @@ -918,7 +924,7 @@ void MembersController::updateRow( const Data::GroupCall::Participant &now) { auto reorderIfInvitedBeforeIndex = 0; auto countChange = 0; - if (const auto row = findRow(now.user)) { + if (const auto row = findRow(now.peer)) { if (now.speaking && (!was || !was->speaking)) { checkSpeakingRowPosition(row); } @@ -1047,8 +1053,9 @@ void MembersController::updateRowLevel( row->updateLevel(level); } -Row *MembersController::findRow(not_null user) const { - return static_cast(delegate()->peerListFindRow(user->id)); +Row *MembersController::findRow(not_null participantPeer) const { + return static_cast( + delegate()->peerListFindRow(participantPeer->id)); } Data::GroupCall *MembersController::resolvedRealCall() const { @@ -1094,16 +1101,16 @@ void MembersController::prepareRows(not_null real) { auto count = delegate()->peerListFullRowsCount(); for (auto i = 0; i != count;) { auto row = delegate()->peerListRowAt(i); - auto user = row->peer()->asUser(); - if (user->isSelf()) { + auto participantPeer = row->peer(); + if (participantPeer->isSelf()) { // #TODO calls add self even if channel foundSelf = true; ++i; continue; } const auto contains = ranges::contains( participants, - not_null{ user }, - &Data::GroupCall::Participant::user); + participantPeer, + &Data::GroupCall::Participant::peer); if (contains) { ++fullCountMin; ++i; @@ -1117,8 +1124,8 @@ void MembersController::prepareRows(not_null real) { const auto self = _peer->session().user(); const auto i = ranges::find( participants, - _peer->session().user(), - &Data::GroupCall::Participant::user); + self, + &Data::GroupCall::Participant::peer); auto row = (i != end(participants)) ? createRow(*i) : createSelfRow(); if (row) { if (row->state() != Row::State::Invited) { @@ -1223,9 +1230,9 @@ void MembersController::rowPaintIcon( _inactiveCrossLine.paint(p, left, top, crossProgress, iconColor); } -auto MembersController::kickMemberRequests() const --> rpl::producer>{ - return _kickMemberRequests.events(); +auto MembersController::kickParticipantRequests() const +-> rpl::producer>{ + return _kickParticipantRequests.events(); } void MembersController::rowClicked(not_null row) { @@ -1235,7 +1242,7 @@ void MembersController::rowClicked(not_null row) { } auto saved = base::take(_menu); for (const auto peer : base::take(_menuCheckRowsAfterHidden)) { - if (const auto row = findRow(peer->asUser())) { + if (const auto row = findRow(peer)) { if (row->speaking()) { checkSpeakingRowPosition(row); } @@ -1270,21 +1277,19 @@ base::unique_qptr MembersController::rowContextMenu( base::unique_qptr MembersController::createRowContextMenu( QWidget *parent, not_null row) { - Expects(row->peer()->isUser()); - + const auto participantPeer = row->peer(); const auto real = static_cast(row.get()); - if (row->peer()->isSelf() + if (participantPeer->isSelf() && (!_peer->canManageGroupCall() || !real->ssrc())) { return nullptr; } - const auto user = row->peer()->asUser(); auto result = base::make_unique_q( parent, st::groupCallPopupMenu); const auto muteState = real->state(); - const auto admin = IsGroupCallAdmin(_peer, user); - const auto session = &user->session(); + const auto admin = IsGroupCallAdmin(_peer, participantPeer); + const auto session = &_peer->session(); const auto getCurrentWindow = [=]() -> Window::SessionController* { if (const auto window = Core::App().activeWindow()) { if (const auto controller = window->sessionController()) { @@ -1319,25 +1324,25 @@ base::unique_qptr MembersController::createRowContextMenu( }; const auto showProfile = [=] { performOnMainWindow([=](not_null window) { - window->showPeerInfo(user); + window->showPeerInfo(participantPeer); }); }; const auto showHistory = [=] { performOnMainWindow([=](not_null window) { window->showPeerHistory( - user, + participantPeer, Window::SectionShow::Way::Forward); }); }; const auto removeFromGroup = crl::guard(this, [=] { - _kickMemberRequests.fire_copy(user); + _kickParticipantRequests.fire_copy(participantPeer); }); if (real->ssrc() != 0) { - addMuteActionsToContextMenu(result, user, admin, real); + addMuteActionsToContextMenu(result, participantPeer, admin, real); } - if (!user->isSelf()) { + if (!participantPeer->isSelf()) { // #TODO calls correct check self result->addAction( tr::lng_context_view_profile(tr::now), showProfile); @@ -1345,13 +1350,17 @@ base::unique_qptr MembersController::createRowContextMenu( tr::lng_context_send_message(tr::now), showHistory); const auto canKick = [&] { + const auto user = participantPeer->asUser(); if (static_cast(row.get())->state() == Row::State::Invited) { return false; } else if (const auto chat = _peer->asChat()) { return chat->amCreator() - || (chat->canBanMembers() && !chat->admins.contains(user)); + || (user + && chat->canBanMembers() + && !chat->admins.contains(user)); // #TODO calls can kick } else if (const auto group = _peer->asMegagroup()) { - return group->canRestrictUser(user); + return group->amCreator() + || (user && group->canRestrictUser(user)); // #TODO calls can kick } return false; }(); @@ -1366,8 +1375,8 @@ base::unique_qptr MembersController::createRowContextMenu( void MembersController::addMuteActionsToContextMenu( not_null menu, - not_null user, - bool userIsCallAdmin, + not_null participantPeer, + bool participantIsCallAdmin, not_null row) { const auto muteString = [=] { return (_peer->canManageGroupCall() @@ -1383,7 +1392,7 @@ void MembersController::addMuteActionsToContextMenu( const auto toggleMute = crl::guard(this, [=](bool mute, bool local) { _toggleMuteRequests.fire(Group::MuteRequest{ - .user = user, + .peer = participantPeer, .mute = mute, .locallyOnly = local, }); @@ -1392,7 +1401,7 @@ void MembersController::addMuteActionsToContextMenu( int volume, bool local) { _changeVolumeRequests.fire(Group::VolumeRequest{ - .user = user, + .peer = participantPeer, .volume = std::clamp(volume, 1, Group::kMaxVolume), .locallyOnly = local, }); @@ -1404,12 +1413,12 @@ void MembersController::addMuteActionsToContextMenu( auto mutesFromVolume = rpl::never() | rpl::type_erased(); - if (!isMuted || user->isSelf()) { + if (!isMuted || participantPeer->isSelf()) { const auto call = _call.get(); auto otherParticipantStateValue = call ? call->otherParticipantStateValue( ) | rpl::filter([=](const Group::ParticipantState &data) { - return data.user == user; + return data.peer == participantPeer; }) : rpl::never() | rpl::type_erased(); @@ -1437,7 +1446,7 @@ void MembersController::addMuteActionsToContextMenu( volumeItem->toggleMuteLocallyRequests( ) | rpl::start_with_next([=](bool muted) { - if (!user->isSelf()) { + if (!participantPeer->isSelf()) { // #TODO calls check self toggleMute(muted, true); } }, volumeItem->lifetime()); @@ -1449,7 +1458,7 @@ void MembersController::addMuteActionsToContextMenu( volumeItem->changeVolumeLocallyRequests( ) | rpl::start_with_next([=](int volume) { - if (!user->isSelf()) { + if (!participantPeer->isSelf()) { // #TODO calls check self changeVolume(volume, true); } }, volumeItem->lifetime()); @@ -1459,9 +1468,9 @@ void MembersController::addMuteActionsToContextMenu( const auto muteAction = [&]() -> QAction* { if (muteState == Row::State::Invited - || user->isSelf() + || participantPeer->isSelf() // #TODO calls check self || (muteState == Row::State::Muted - && userIsCallAdmin + && participantIsCallAdmin && _peer->canManageGroupCall())) { return nullptr; } @@ -1486,7 +1495,7 @@ void MembersController::addMuteActionsToContextMenu( } std::unique_ptr MembersController::createSelfRow() { - const auto self = _peer->session().user(); + const auto self = _peer->session().user(); // #TODO calls check self auto result = std::make_unique(this, self); updateRow(result.get(), nullptr); return result; @@ -1494,17 +1503,17 @@ std::unique_ptr MembersController::createSelfRow() { std::unique_ptr MembersController::createRow( const Data::GroupCall::Participant &participant) { - auto result = std::make_unique(this, participant.user); + auto result = std::make_unique(this, participant.peer); updateRow(result.get(), &participant); return result; } std::unique_ptr MembersController::createInvitedRow( - not_null user) { - if (findRow(user)) { + not_null participantPeer) { + if (findRow(participantPeer)) { return nullptr; } - auto result = std::make_unique(this, user); + auto result = std::make_unique(this, participantPeer); updateRow(result.get(), nullptr); return result; } @@ -1538,10 +1547,10 @@ auto GroupMembers::changeVolumeRequests() const _listController.get())->changeVolumeRequests(); } -auto GroupMembers::kickMemberRequests() const --> rpl::producer> { +auto GroupMembers::kickParticipantRequests() const +-> rpl::producer> { return static_cast( - _listController.get())->kickMemberRequests(); + _listController.get())->kickParticipantRequests(); } int GroupMembers::desiredHeight() const { diff --git a/Telegram/SourceFiles/calls/calls_group_members.h b/Telegram/SourceFiles/calls/calls_group_members.h index a0e1e1dd3..88f459adc 100644 --- a/Telegram/SourceFiles/calls/calls_group_members.h +++ b/Telegram/SourceFiles/calls/calls_group_members.h @@ -42,8 +42,8 @@ public: -> rpl::producer; [[nodiscard]] auto changeVolumeRequests() const -> rpl::producer; - [[nodiscard]] auto kickMemberRequests() const - -> rpl::producer>; + [[nodiscard]] auto kickParticipantRequests() const + -> rpl::producer>; [[nodiscard]] rpl::producer<> addMembersRequests() const { return _addMemberRequests.events(); } diff --git a/Telegram/SourceFiles/calls/calls_group_panel.cpp b/Telegram/SourceFiles/calls/calls_group_panel.cpp index 93a00f41f..e43378189 100644 --- a/Telegram/SourceFiles/calls/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_group_panel.cpp @@ -520,9 +520,11 @@ void GroupPanel::initWithCall(GroupCall *call) { } }, _callLifetime); - _members->kickMemberRequests( - ) | rpl::start_with_next([=](not_null user) { - kickMember(user); + _members->kickParticipantRequests( + ) | rpl::start_with_next([=](not_null participantPeer) { + if (const auto user = participantPeer->asUser()) { + kickMember(user); // #TODO calls kick + } }, _callLifetime); _members->addMembersRequests( @@ -570,7 +572,9 @@ void GroupPanel::addMembers() { } auto alreadyIn = _peer->owner().invitedToCallUsers(real->id()); for (const auto &participant : real->participants()) { - alreadyIn.emplace(participant.user); + if (const auto user = participant.peer->asUser()) { + alreadyIn.emplace(user); + } } alreadyIn.emplace(_peer->session().user()); auto controller = std::make_unique( diff --git a/Telegram/SourceFiles/data/data_group_call.cpp b/Telegram/SourceFiles/data/data_group_call.cpp index 38ccd2e6a..9e3d88aa0 100644 --- a/Telegram/SourceFiles/data/data_group_call.cpp +++ b/Telegram/SourceFiles/data/data_group_call.cpp @@ -39,7 +39,7 @@ GroupCall::GroupCall( } GroupCall::~GroupCall() { - api().request(_unknownUsersRequestId).cancel(); + api().request(_unknownParticipantPeersRequestId).cancel(); api().request(_participantsRequestId).cancel(); api().request(_reloadRequestId).cancel(); } @@ -87,6 +87,7 @@ void GroupCall::requestParticipants() { result.match([&](const MTPDphone_groupParticipants &data) { _nextOffset = qs(data.vnext_offset()); _peer->owner().processUsers(data.vusers()); + _peer->owner().processChats(data.vchats()); applyParticipantsSlice( data.vparticipants().v, ApplySliceSource::SliceLoaded); @@ -154,9 +155,9 @@ bool GroupCall::participantsLoaded() const { return _allReceived; } -UserData *GroupCall::userBySsrc(uint32 ssrc) const { - const auto i = _userBySsrc.find(ssrc); - return (i != end(_userBySsrc)) ? i->second.get() : nullptr; +PeerData *GroupCall::participantPeerBySsrc(uint32 ssrc) const { + const auto i = _participantPeerBySsrc.find(ssrc); + return (i != end(_participantPeerBySsrc)) ? i->second.get() : nullptr; } rpl::producer<> GroupCall::participantsSliceAdded() { @@ -216,9 +217,10 @@ void GroupCall::reload() { ).done([=](const MTPphone_GroupCall &result) { result.match([&](const MTPDphone_groupCall &data) { _peer->owner().processUsers(data.vusers()); + _peer->owner().processChats(data.vchats()); _participants.clear(); _speakingByActiveFinishes.clear(); - _userBySsrc.clear(); + _participantPeerBySsrc.clear(); applyParticipantsSlice( data.vparticipants().v, ApplySliceSource::SliceLoaded); @@ -242,19 +244,20 @@ void GroupCall::applyParticipantsSlice( auto changedCount = _fullCount.current(); for (const auto &participant : list) { participant.match([&](const MTPDgroupCallParticipant &data) { - const auto userId = data.vuser_id().v; - const auto user = _peer->owner().user(userId); + const auto participantPeerId = peerFromMTP(data.vpeer()); + const auto participantPeer = _peer->owner().peer( + participantPeerId); const auto i = ranges::find( _participants, - user, - &Participant::user); + participantPeer, + &Participant::peer); if (data.is_left()) { if (i != end(_participants)) { auto update = ParticipantUpdate{ .was = *i, }; - _userBySsrc.erase(i->ssrc); - _speakingByActiveFinishes.remove(user); + _participantPeerBySsrc.erase(i->ssrc); + _speakingByActiveFinishes.remove(participantPeer); _participants.erase(i); if (sliceSource != ApplySliceSource::SliceLoaded) { _participantUpdates.fire(std::move(update)); @@ -290,7 +293,7 @@ void GroupCall::applyParticipantsSlice( const auto onlyMinLoaded = data.is_min() && (!was || was->onlyMinLoaded); const auto value = Participant{ - .user = user, + .peer = participantPeer, .date = data.vdate().v, .lastActive = lastActive, .ssrc = uint32(data.vsource().v), @@ -303,13 +306,17 @@ void GroupCall::applyParticipantsSlice( .onlyMinLoaded = onlyMinLoaded, }; if (i == end(_participants)) { - _userBySsrc.emplace(value.ssrc, user); + _participantPeerBySsrc.emplace(value.ssrc, participantPeer); _participants.push_back(value); - _peer->owner().unregisterInvitedToCallUser(_id, user); + if (const auto user = participantPeer->asUser()) { + _peer->owner().unregisterInvitedToCallUser(_id, user); + } } else { if (i->ssrc != value.ssrc) { - _userBySsrc.erase(i->ssrc); - _userBySsrc.emplace(value.ssrc, user); + _participantPeerBySsrc.erase(i->ssrc); + _participantPeerBySsrc.emplace( + value.ssrc, + participantPeer); } *i = value; } @@ -334,16 +341,19 @@ void GroupCall::applyLastSpoke( uint32 ssrc, LastSpokeTimes when, crl::time now) { - const auto i = _userBySsrc.find(ssrc); - if (i == end(_userBySsrc)) { + const auto i = _participantPeerBySsrc.find(ssrc); + if (i == end(_participantPeerBySsrc)) { _unknownSpokenSsrcs[ssrc] = when; requestUnknownParticipants(); return; } - const auto j = ranges::find(_participants, i->second, &Participant::user); + const auto j = ranges::find( + _participants, + i->second, + &Participant::peer); Assert(j != end(_participants)); - _speakingByActiveFinishes.remove(j->user); + _speakingByActiveFinishes.remove(j->peer); const auto sounding = (when.anything + kSoundStatusKeptFor >= now) && j->canSelfUnmute; const auto speaking = sounding @@ -360,22 +370,22 @@ void GroupCall::applyLastSpoke( } void GroupCall::applyActiveUpdate( - UserId userId, + PeerId participantPeerId, LastSpokeTimes when, - UserData *userLoaded) { + PeerData *participantPeerLoaded) { if (inCall()) { return; } - const auto i = userLoaded + const auto i = participantPeerLoaded ? ranges::find( _participants, - not_null{ userLoaded }, - &Participant::user) + not_null{ participantPeerLoaded }, + &Participant::peer) : _participants.end(); const auto notFound = (i == end(_participants)); const auto loadByUserId = notFound || i->onlyMinLoaded; if (loadByUserId) { - _unknownSpokenUids[userId] = when; + _unknownSpokenPeerIds[participantPeerId] = when; requestUnknownParticipants(); } if (notFound || !i->canSelfUnmute) { @@ -389,7 +399,7 @@ void GroupCall::applyActiveUpdate( if (lastActive <= i->lastActive || finishes <= now) { return; } - _speakingByActiveFinishes[i->user] = finishes; + _speakingByActiveFinishes[i->peer] = finishes; if (!_speakingByActiveFinishTimer.isActive()) { _speakingByActiveFinishTimer.callOnce(finishes - now); } @@ -408,8 +418,9 @@ void GroupCall::applyActiveUpdate( void GroupCall::checkFinishSpeakingByActive() { const auto now = crl::now(); auto nearest = 0; - auto stop = std::vector>(); - for (auto i = begin(_speakingByActiveFinishes); i != end(_speakingByActiveFinishes);) { + auto stop = std::vector>(); + for (auto i = begin(_speakingByActiveFinishes) + ; i != end(_speakingByActiveFinishes);) { const auto when = i->second; if (now >= when) { stop.push_back(i->first); @@ -421,8 +432,11 @@ void GroupCall::checkFinishSpeakingByActive() { ++i; } } - for (const auto user : stop) { - const auto i = ranges::find(_participants, user, &Participant::user); + for (const auto participantPeer : stop) { + const auto i = ranges::find( + _participants, + participantPeer, + &Participant::peer); if (i->speaking) { const auto was = *i; i->speaking = false; @@ -438,8 +452,8 @@ void GroupCall::checkFinishSpeakingByActive() { } void GroupCall::requestUnknownParticipants() { - if (_unknownUsersRequestId - || (_unknownSpokenSsrcs.empty() && _unknownSpokenUids.empty())) { + if (_unknownParticipantPeersRequestId + || (_unknownSpokenSsrcs.empty() && _unknownSpokenPeerIds.empty())) { return; } const auto ssrcs = [&] { @@ -455,18 +469,18 @@ void GroupCall::requestUnknownParticipants() { } return result; }(); - const auto uids = [&] { - if (_unknownSpokenUids.size() + ssrcs.size() < kRequestPerPage) { - return base::take(_unknownSpokenUids); + const auto peerIds = [&] { + if (_unknownSpokenPeerIds.size() + ssrcs.size() < kRequestPerPage) { + return base::take(_unknownSpokenPeerIds); } - auto result = base::flat_map(); + auto result = base::flat_map(); const auto available = (kRequestPerPage - int(ssrcs.size())); if (available > 0) { result.reserve(available); while (result.size() < available) { - const auto [userId, when] = _unknownSpokenUids.back(); + const auto [userId, when] = _unknownSpokenPeerIds.back(); result.emplace(userId, when); - _unknownSpokenUids.erase(_unknownSpokenUids.end() - 1); + _unknownSpokenPeerIds.erase(_unknownSpokenPeerIds.end() - 1); } } return result; @@ -477,62 +491,65 @@ void GroupCall::requestUnknownParticipants() { ssrcInputs.push_back(MTP_int(ssrc)); } auto uidInputs = QVector(); - uidInputs.reserve(uids.size()); - for (const auto [userId, when] : uids) { - uidInputs.push_back(MTP_int(userId)); + uidInputs.reserve(peerIds.size()); + for (const auto [peerId, when] : peerIds) { + Assert(peerIsUser(peerId)); // #TODO calls + uidInputs.push_back(MTP_int(peerToUser(peerId))); } - _unknownUsersRequestId = api().request(MTPphone_GetGroupParticipants( - input(), - MTP_vector(uidInputs), - MTP_vector(ssrcInputs), - MTP_string(QString()), - MTP_int(kRequestPerPage) - )).done([=](const MTPphone_GroupParticipants &result) { + _unknownParticipantPeersRequestId = api().request( + MTPphone_GetGroupParticipants( + input(), + MTP_vector(uidInputs), + MTP_vector(ssrcInputs), + MTP_string(QString()), + MTP_int(kRequestPerPage) + ) + ).done([=](const MTPphone_GroupParticipants &result) { result.match([&](const MTPDphone_groupParticipants &data) { _peer->owner().processUsers(data.vusers()); applyParticipantsSlice( data.vparticipants().v, ApplySliceSource::UnknownLoaded); }); - _unknownUsersRequestId = 0; + _unknownParticipantPeersRequestId = 0; const auto now = crl::now(); for (const auto [ssrc, when] : ssrcs) { applyLastSpoke(ssrc, when, now); _unknownSpokenSsrcs.remove(ssrc); } - for (const auto [userId, when] : uids) { - if (const auto user = _peer->owner().userLoaded(userId)) { + for (const auto [peerId, when] : peerIds) { + if (const auto participantPeer = _peer->owner().peerLoaded(peerId)) { const auto isParticipant = ranges::contains( _participants, - not_null{ user }, - &Participant::user); + not_null{ participantPeer }, + &Participant::peer); if (isParticipant) { - applyActiveUpdate(userId, when, user); + applyActiveUpdate(peerId, when, participantPeer); } } - _unknownSpokenUids.remove(userId); + _unknownSpokenPeerIds.remove(peerId); } requestUnknownParticipants(); }).fail([=](const RPCError &error) { - _unknownUsersRequestId = 0; + _unknownParticipantPeersRequestId = 0; for (const auto [ssrc, when] : ssrcs) { _unknownSpokenSsrcs.remove(ssrc); } - for (const auto [userId, when] : uids) { - _unknownSpokenUids.remove(userId); + for (const auto [peerId, when] : peerIds) { + _unknownSpokenPeerIds.remove(peerId); } requestUnknownParticipants(); }).send(); } void GroupCall::setInCall() { - _unknownSpokenUids.clear(); + _unknownSpokenPeerIds.clear(); if (_speakingByActiveFinishes.empty()) { return; } auto restartTimer = true; const auto latest = crl::now() + kActiveAfterJoined; - for (auto &[user, when] : _speakingByActiveFinishes) { + for (auto &[peer, when] : _speakingByActiveFinishes) { if (when > latest) { when = latest; } else { diff --git a/Telegram/SourceFiles/data/data_group_call.h b/Telegram/SourceFiles/data/data_group_call.h index b1d6bac88..8b7165d2c 100644 --- a/Telegram/SourceFiles/data/data_group_call.h +++ b/Telegram/SourceFiles/data/data_group_call.h @@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer.h" -class UserData; class PeerData; class ApiWrap; @@ -33,7 +32,7 @@ public: void setPeer(not_null peer); struct Participant { - not_null user; + not_null peer; TimeId date = 0; TimeId lastActive = 0; uint32 ssrc = 0; @@ -57,7 +56,7 @@ public: -> const std::vector &; void requestParticipants(); [[nodiscard]] bool participantsLoaded() const; - [[nodiscard]] UserData *userBySsrc(uint32 ssrc) const; + [[nodiscard]] PeerData *participantPeerBySsrc(uint32 ssrc) const; [[nodiscard]] rpl::producer<> participantsSliceAdded(); [[nodiscard]] rpl::producer participantUpdated() const; @@ -68,9 +67,9 @@ public: const MTPDupdateGroupCallParticipants &update); void applyLastSpoke(uint32 ssrc, LastSpokeTimes when, crl::time now); void applyActiveUpdate( - UserId userId, + PeerId participantPeerId, LastSpokeTimes when, - UserData *userLoaded); + PeerData *participantPeerLoaded); [[nodiscard]] int fullCount() const; [[nodiscard]] rpl::producer fullCountValue() const; @@ -108,15 +107,15 @@ private: mtpRequestId _reloadRequestId = 0; std::vector _participants; - base::flat_map> _userBySsrc; - base::flat_map, crl::time> _speakingByActiveFinishes; + base::flat_map> _participantPeerBySsrc; + base::flat_map, crl::time> _speakingByActiveFinishes; base::Timer _speakingByActiveFinishTimer; QString _nextOffset; rpl::variable _fullCount = 0; base::flat_map _unknownSpokenSsrcs; - base::flat_map _unknownSpokenUids; - mtpRequestId _unknownUsersRequestId = 0; + base::flat_map _unknownSpokenPeerIds; + mtpRequestId _unknownParticipantPeersRequestId = 0; rpl::event_stream _participantUpdates; rpl::event_stream<> _participantsSliceAdded; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 6f334d815..84b3bf328 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -832,7 +832,7 @@ void Session::registerInvitedToCallUser( const auto inCall = ranges::contains( call->participants(), user, - &Data::GroupCall::Participant::user); + &Data::GroupCall::Participant::peer); if (inCall) { return; } diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp index c16fb12c9..b74e4072a 100644 --- a/Telegram/SourceFiles/export/export_api_wrap.cpp +++ b/Telegram/SourceFiles/export/export_api_wrap.cpp @@ -88,6 +88,8 @@ LocationKey ComputeLocationKey(const Data::FileLocation &value) { result.type |= (9ULL << 24); result.type |= (uint64(uint32(data.vlocal_id().v)) << 32); result.id = data.vvolume_id().v; + }, [&](const MTPDinputGroupCallStream &data) { + result.type = (10ULL << 24); }); return result; } diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index f5e7f32c7..9a7d78bc5 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -946,9 +946,9 @@ void GenerateItems( addSimpleServiceMessage(text); }; - auto groupCallParticipantUser = [&](const MTPGroupCallParticipant &data) { + auto groupCallParticipantPeer = [&](const MTPGroupCallParticipant &data) { return data.match([&](const MTPDgroupCallParticipant &data) { - return history->owner().user(data.vuser_id().v); + return history->owner().peer(peerFromMTP(data.vpeer())); }); }; @@ -966,29 +966,29 @@ void GenerateItems( }; auto createParticipantMute = [&](const MTPDchannelAdminLogEventActionParticipantMute &data) { - const auto user = groupCallParticipantUser(data.vparticipant()); - const auto userLink = user->createOpenLink(); - const auto userLinkText = textcmdLink(2, user->name); + const auto participantPeer = groupCallParticipantPeer(data.vparticipant()); + const auto participantPeerLink = participantPeer->createOpenLink(); + const auto participantPeerLinkText = textcmdLink(2, participantPeer->name); auto text = tr::lng_admin_log_muted_participant( tr::now, lt_from, fromLinkText, lt_user, - userLinkText); - addServiceMessageWithLink(text, userLink); + participantPeerLinkText); + addServiceMessageWithLink(text, participantPeerLink); }; auto createParticipantUnmute = [&](const MTPDchannelAdminLogEventActionParticipantUnmute &data) { - const auto user = groupCallParticipantUser(data.vparticipant()); - const auto userLink = user->createOpenLink(); - const auto userLinkText = textcmdLink(2, user->name); + const auto participantPeer = groupCallParticipantPeer(data.vparticipant()); + const auto participantPeerLink = participantPeer->createOpenLink(); + const auto participantPeerLinkText = textcmdLink(2, participantPeer->name); auto text = tr::lng_admin_log_unmuted_participant( tr::now, lt_from, fromLinkText, lt_user, - userLinkText); - addServiceMessageWithLink(text, userLink); + participantPeerLinkText); + addServiceMessageWithLink(text, participantPeerLink); }; auto createToggleGroupCallSetting = [&](const MTPDchannelAdminLogEventActionToggleGroupCallSetting &data) { @@ -1069,9 +1069,9 @@ void GenerateItems( }; auto createParticipantVolume = [&](const MTPDchannelAdminLogEventActionParticipantVolume &data) { - const auto user = groupCallParticipantUser(data.vparticipant()); - const auto userLink = user->createOpenLink(); - const auto userLinkText = textcmdLink(2, user->name); + const auto participantPeer = groupCallParticipantPeer(data.vparticipant()); + const auto participantPeerLink = participantPeer->createOpenLink(); + const auto participantPeerLinkText = textcmdLink(2, participantPeer->name); const auto volume = data.vparticipant().match([&]( const MTPDgroupCallParticipant &data) { return data.vvolume().value_or(10000); @@ -1082,10 +1082,10 @@ void GenerateItems( lt_from, fromLinkText, lt_user, - userLinkText, + participantPeerLinkText, lt_percent, volumeText); - addServiceMessageWithLink(text, userLink); + addServiceMessageWithLink(text, participantPeerLink); }; auto createChangeHistoryTTL = [&](const MTPDchannelAdminLogEventActionChangeHistoryTTL &data) { diff --git a/Telegram/SourceFiles/history/view/history_view_group_call_tracker.cpp b/Telegram/SourceFiles/history/view/history_view_group_call_tracker.cpp index 038dc3da5..fe46bc4e8 100644 --- a/Telegram/SourceFiles/history/view/history_view_group_call_tracker.cpp +++ b/Telegram/SourceFiles/history/view/history_view_group_call_tracker.cpp @@ -99,7 +99,7 @@ rpl::producer GroupCallTracker::ContentByCall( for (const auto &participant : call->participants()) { const auto alreadyInList = ranges::contains( state->userpics, - participant.user, + participant.peer, &UserpicInRow::peer); if (alreadyInList) { continue; @@ -120,7 +120,7 @@ rpl::producer GroupCallTracker::ContentByCall( for (auto i = 0; i != kLimit - already; ++i) { if (adding[i]) { state->userpics.push_back(UserpicInRow{ - .peer = adding[i]->user, + .peer = adding[i]->peer, .speaking = adding[i]->speaking, }); } @@ -163,11 +163,11 @@ rpl::producer GroupCallTracker::ContentByCall( static const auto RemoveUserpic = []( not_null state, not_null call, - not_null user, + not_null participantPeer, int userpicSize) { const auto i = ranges::find( state->userpics, - user, + participantPeer, &UserpicInRow::peer); if (i == state->userpics.end()) { return false; @@ -180,7 +180,7 @@ rpl::producer GroupCallTracker::ContentByCall( static const auto CheckPushToFront = []( not_null state, not_null call, - not_null user, + not_null participantPeer, int userpicSize) { Expects(state->userpics.size() <= kLimit); @@ -189,7 +189,7 @@ rpl::producer GroupCallTracker::ContentByCall( // Find where to put a new speaking userpic. for (; i != end(state->userpics); ++i) { - if (i->peer == user) { + if (i->peer == participantPeer) { if (i->speaking) { return false; } @@ -199,8 +199,8 @@ rpl::producer GroupCallTracker::ContentByCall( } const auto j = ranges::find( participants, - not_null{ static_cast(i->peer.get()) }, - &Data::GroupCall::Participant::user); + i->peer, + &Data::GroupCall::Participant::peer); if (j == end(participants) || !j->speaking) { // Found a non-speaking one, put the new speaking one here. break; @@ -213,13 +213,13 @@ rpl::producer GroupCallTracker::ContentByCall( // Add the new speaking to the place we found. const auto added = state->userpics.insert(i, UserpicInRow{ - .peer = user, + .peer = participantPeer, .speaking = true, }); // Remove him from the tail, if he was there. for (auto i = added + 1; i != state->userpics.end(); ++i) { - if (i->peer == user) { + if (i->peer == participantPeer) { state->userpics.erase(i); break; } @@ -230,8 +230,8 @@ rpl::producer GroupCallTracker::ContentByCall( for (auto i = state->userpics.end() - 1; i != added; --i) { const auto j = ranges::find( participants, - not_null{ static_cast(i->peer.get()) }, - &Data::GroupCall::Participant::user); + i->peer, + &Data::GroupCall::Participant::peer); if (j == end(participants) || !j->speaking) { // Found a non-speaking one, remove. state->userpics.erase(i); @@ -263,14 +263,26 @@ rpl::producer GroupCallTracker::ContentByCall( using ParticipantUpdate = Data::GroupCall::ParticipantUpdate; call->participantUpdated( ) | rpl::start_with_next([=](const ParticipantUpdate &update) { - const auto user = update.now ? update.now->user : update.was->user; + const auto participantPeer = update.now + ? update.now->peer + : update.was->peer; if (!update.now) { - if (RemoveUserpic(state, call, user, userpicSize)) { + const auto removed = RemoveUserpic( + state, + call, + participantPeer, + userpicSize); + if (removed) { pushNext(); } } else if (update.now->speaking && (!update.was || !update.was->speaking)) { - if (CheckPushToFront(state, call, user, userpicSize)) { + const auto pushed = CheckPushToFront( + state, + call, + participantPeer, + userpicSize); + if (pushed) { pushNext(); } } else { @@ -279,7 +291,7 @@ rpl::producer GroupCallTracker::ContentByCall( if (updateSpeakingState) { const auto i = ranges::find( state->userpics, - user, + participantPeer, &UserpicInRow::peer); if (i != end(state->userpics)) { const auto index = i - begin(state->userpics); diff --git a/Telegram/SourceFiles/ui/image/image_location.cpp b/Telegram/SourceFiles/ui/image/image_location.cpp index 7b217e72b..3bfd5b385 100644 --- a/Telegram/SourceFiles/ui/image/image_location.cpp +++ b/Telegram/SourceFiles/ui/image/image_location.cpp @@ -166,6 +166,13 @@ StorageFileLocation::StorageFileLocation( }); _volumeId = data.vvolume_id().v; _localId = data.vlocal_id().v; + }, [&](const MTPDinputGroupCallStream &data) { + _type = Type::GroupCallStream; + data.vcall().match([&](const MTPDinputGroupCall &data) { + _id = data.vid().v; + _accessHash = data.vaccess_hash().v; + }); + _localId = data.vdate().v; }); } @@ -250,6 +257,11 @@ MTPInputFileLocation StorageFileLocation::tl(int32 self) const { MTP_long(_volumeId), MTP_int(_localId)); + case Type::GroupCallStream: + return MTP_inputGroupCallStream( + MTP_inputGroupCall(MTP_long(_id), MTP_long(_accessHash)), + MTP_int(_localId)); + } Unexpected("Type in StorageFileLocation::tl."); } @@ -358,6 +370,9 @@ bool StorageFileLocation::valid() const { case Type::PeerPhoto: case Type::StickerSetThumb: return (_dcId != 0) && (_id != 0); + + case Type::GroupCallStream: + return (_dcId != 0) && (_id != 0) && (_localId != 0); } return false; } @@ -401,6 +416,11 @@ Storage::Cache::Key StorageFileLocation::cacheKey() const { case Type::Takeout: return Key{ shifted, 0 }; + + case Type::GroupCallStream: + return Key{ + shifted | sliced | (uint64(uint32(_localId)) << 16), + _id }; } return Key(); } @@ -443,6 +463,7 @@ Storage::Cache::Key StorageFileLocation::bigFileBaseCacheKey() const { case Type::Encrypted: case Type::Secure: case Type::Takeout: + case Type::GroupCallStream: Unexpected("Not implemented file location type."); }; @@ -522,6 +543,11 @@ bool operator==(const StorageFileLocation &a, const StorageFileLocation &b) { && (a._volumeId == b._volumeId) && (a._localId == b._localId) && (a._id == b._id); + + case Type::GroupCallStream: + return (a._dcId == b._dcId) + && (a._id == b._id) + && (a._localId == b._localId); }; Unexpected("Type in StorageFileLocation::operator==."); } @@ -573,6 +599,10 @@ bool operator<(const StorageFileLocation &a, const StorageFileLocation &b) { case Type::StickerSetThumb: return std::tie(a._id, a._localId, a._volumeId, a._dcId) < std::tie(b._id, b._localId, b._volumeId, b._dcId); + + case Type::GroupCallStream: + return std::tie(a._id, a._localId, a._dcId) + < std::tie(b._id, b._localId, b._dcId); }; Unexpected("Type in StorageFileLocation::operator==."); } diff --git a/Telegram/SourceFiles/ui/image/image_location.h b/Telegram/SourceFiles/ui/image/image_location.h index fb3fb7299..d8574df54 100644 --- a/Telegram/SourceFiles/ui/image/image_location.h +++ b/Telegram/SourceFiles/ui/image/image_location.h @@ -59,6 +59,7 @@ public: Photo = 0x05, PeerPhoto = 0x06, StickerSetThumb = 0x07, + GroupCallStream = 0x08, }; StorageFileLocation() = default;