Update API scheme to layer 125.

This commit is contained in:
John Preston 2021-03-03 19:29:33 +04:00
parent 2734cab3f2
commit 02517f7221
16 changed files with 331 additions and 231 deletions

View file

@ -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; 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; 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; inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation;
inputGroupCallStream#d1cc2a5f call:InputGroupCall date:int = InputFileLocation;
peerUser#9db1bc6d user_id:int = Peer; peerUser#9db1bc6d user_id:int = Peer;
peerChat#bad0e5bb chat_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<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = 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<RestrictionReason> 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; 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<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int = 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<BotInfo> 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#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<BotInfo> 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<string> = 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<BotInfo> 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<string> groupcall_default_join_as:flags.26?Peer = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant;
@ -370,9 +371,9 @@ updateChat#1330a196 chat_id:int = Update;
updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<GroupCallParticipant> version:int = Update; updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<GroupCallParticipant> version:int = Update;
updateGroupCall#a45eb99b chat_id:int call:GroupCall = Update; updateGroupCall#a45eb99b chat_id:int call:GroupCall = Update;
updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = 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; 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#65d2b464 flags:# channel_id:int date:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant 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#30ec6ebc user_id:int stopped:Bool 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; 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; stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats;
groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; 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; 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<GroupCallParticipant> participants_next_offset:string users:Vector<User> = phone.GroupCall; phone.groupCall#9e727aad call:GroupCall participants:Vector<GroupCallParticipant> participants_next_offset:string chats:Vector<Chat> users:Vector<User> = phone.GroupCall;
phone.groupParticipants#9cfeb92d count:int participants:Vector<GroupCallParticipant> next_offset:string users:Vector<User> version:int = phone.GroupParticipants; phone.groupParticipants#f47751b6 count:int participants:Vector<GroupCallParticipant> next_offset:string chats:Vector<Chat> users:Vector<User> version:int = phone.GroupParticipants;
inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType;
inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType;
@ -1237,6 +1238,8 @@ chatAdminWithInvites#dfd2330f admin_id:int invites_count:int revoked_invites_cou
messages.chatAdminsWithInvites#b69b72d7 admins:Vector<ChatAdminWithInvites> users:Vector<User> = messages.ChatAdminsWithInvites; messages.chatAdminsWithInvites#b69b72d7 admins:Vector<ChatAdminWithInvites> users:Vector<User> = messages.ChatAdminsWithInvites;
messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer;
---functions--- ---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; 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<string> = Vector<EmojiLanguage>; messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector<string> = Vector<EmojiLanguage>;
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>; messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
messages.requestUrlAuth#e33f5613 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#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = 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.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool;
messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Messages; messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Messages;
messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector<int> = messages.Messages; messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector<int> = 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.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia;
messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; 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.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.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.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool;
messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool;
messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; 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.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.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates;
messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer;
updates.getState#edd4882a = updates.State; updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; 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<InputUser> =
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; 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.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.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<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; 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.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool;
phone.createGroupCall#bd3dabe0 peer:InputPeer random_id:int = Updates; phone.createGroupCall#1fd59252 flags:# peer:InputPeer join_as:flags.0?InputPeer random_id:int = Updates;
phone.joinGroupCall#5f9c8e62 flags:# muted:flags.0?true call:InputGroupCall params:DataJSON = 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.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<InputUser> = Updates; phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector<InputUser> = Updates;
phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; phone.discardGroupCall#7a777135 call:InputGroupCall = Updates;
phone.toggleGroupCallSettings#74bbb43d flags:# call:InputGroupCall join_muted:flags.0?Bool = Updates; phone.toggleGroupCallSettings#74bbb43d flags:# call:InputGroupCall join_muted:flags.0?Bool = Updates;
phone.getGroupCall#c7cb017 call:InputGroupCall = phone.GroupCall; phone.getGroupCall#c7cb017 call:InputGroupCall = phone.GroupCall;
phone.getGroupParticipants#c9f1d285 call:InputGroupCall ids:Vector<int> sources:Vector<int> offset:string limit:int = phone.GroupParticipants; phone.getGroupParticipants#c9f1d285 call:InputGroupCall ids:Vector<int> sources:Vector<int> offset:string limit:int = phone.GroupParticipants;
phone.checkGroupCall#b74a7bea call:InputGroupCall source:int = Bool; 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.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>; langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
@ -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.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; stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
// LAYER 124 // LAYER 125

View file

@ -41,10 +41,13 @@ void UrlAuthBox::Activate(
const auto buttonId = button->buttonId; const auto buttonId = button->buttonId;
const auto url = QString::fromUtf8(button->data); const auto url = QString::fromUtf8(button->data);
using Flag = MTPmessages_RequestUrlAuth::Flag;
button->requestId = session->api().request(MTPmessages_RequestUrlAuth( button->requestId = session->api().request(MTPmessages_RequestUrlAuth(
MTP_flags(Flag::f_peer | Flag::f_msg_id | Flag::f_button_id),
inputPeer, inputPeer,
MTP_int(itemId.msg), MTP_int(itemId.msg),
MTP_int(buttonId) MTP_int(buttonId),
MTPstring() // #TODO auth url
)).done([=](const MTPUrlAuthResult &result) { )).done([=](const MTPUrlAuthResult &result) {
const auto button = HistoryMessageMarkupButton::Get( const auto button = HistoryMessageMarkupButton::Get(
&session->data(), &session->data(),
@ -111,11 +114,14 @@ void UrlAuthBox::Request(
} else if (const auto msg = session->data().message(itemId)) { } else if (const auto msg = session->data().message(itemId)) {
const auto allowWrite = (result == Result::AuthAndAllowWrite); const auto allowWrite = (result == Result::AuthAndAllowWrite);
using Flag = MTPmessages_AcceptUrlAuth::Flag; 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( session->api().request(MTPmessages_AcceptUrlAuth(
MTP_flags(allowWrite ? Flag::f_write_allowed : Flag(0)), MTP_flags(flags),
inputPeer, inputPeer,
MTP_int(itemId.msg), MTP_int(itemId.msg),
MTP_int(buttonId) MTP_int(buttonId),
MTPstring() // #TODO auth url
)).done([=](const MTPUrlAuthResult &result) { )).done([=](const MTPUrlAuthResult &result) {
const auto to = result.match( const auto to = result.match(
[&](const MTPDurlAuthResultAccepted &data) { [&](const MTPDurlAuthResultAccepted &data) {

View file

@ -57,18 +57,18 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
} }
[[nodiscard]] const Data::GroupCall::Participant *LookupParticipant( [[nodiscard]] const Data::GroupCall::Participant *LookupParticipant(
not_null<PeerData*> chat, not_null<PeerData*> peer,
uint64 id, uint64 id,
not_null<UserData*> user) { not_null<PeerData*> participantPeer) {
const auto call = chat->groupCall(); const auto call = peer->groupCall();
if (!id || !call || call->id() != id) { if (!id || !call || call->id() != id) {
return nullptr; return nullptr;
} }
const auto &participants = call->participants(); const auto &participants = call->participants();
const auto i = ranges::find( const auto i = ranges::find(
participants, participants,
user, participantPeer,
&Data::GroupCall::Participant::user); &Data::GroupCall::Participant::peer);
return (i != end(participants)) ? &*i : nullptr; return (i != end(participants)) ? &*i : nullptr;
} }
@ -76,7 +76,11 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
[[nodiscard]] bool IsGroupCallAdmin( [[nodiscard]] bool IsGroupCallAdmin(
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> user) { not_null<PeerData*> participantPeer) {
const auto user = participantPeer->asUser();
if (!user) {
return false; // #TODO calls
}
if (const auto chat = peer->asChat()) { if (const auto chat = peer->asChat()) {
return chat->admins.contains(user) return chat->admins.contains(user)
|| (chat->creator == user->bareId()); || (chat->creator == user->bareId());
@ -240,7 +244,9 @@ void GroupCall::playConnectingSoundOnce() {
void GroupCall::start() { void GroupCall::start() {
_createRequestId = _api.request(MTPphone_CreateGroupCall( _createRequestId = _api.request(MTPphone_CreateGroupCall(
MTP_flags(0),
_peer->input, _peer->input,
MTPInputPeer(), // #TODO calls join_as
MTP_int(openssl::RandomValue<int32>()) MTP_int(openssl::RandomValue<int32>())
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
_acceptFields = true; _acceptFields = true;
@ -343,11 +349,13 @@ void GroupCall::rejoin() {
const auto json = QJsonDocument(root).toJson( const auto json = QJsonDocument(root).toJson(
QJsonDocument::Compact); QJsonDocument::Compact);
const auto wasMuteState = muted(); const auto wasMuteState = muted();
using Flag = MTPphone_JoinGroupCall::Flag;
_api.request(MTPphone_JoinGroupCall( _api.request(MTPphone_JoinGroupCall(
MTP_flags((wasMuteState != MuteState::Active) MTP_flags((wasMuteState != MuteState::Active)
? MTPphone_JoinGroupCall::Flag::f_muted ? Flag::f_muted
: MTPphone_JoinGroupCall::Flag(0)), : Flag(0)),
inputCall(), inputCall(),
MTPInputPeer(), // #TODO calls join_as
MTP_dataJSON(MTP_bytes(json)) MTP_dataJSON(MTP_bytes(json))
)).done([=](const MTPUpdates &updates) { )).done([=](const MTPUpdates &updates) {
_mySsrc = ssrc; _mySsrc = ssrc;
@ -392,7 +400,7 @@ void GroupCall::applySelfInCallLocally() {
const auto i = ranges::find( const auto i = ranges::find(
participants, participants,
self, self,
&Data::GroupCall::Participant::user); &Data::GroupCall::Participant::peer);
const auto date = (i != end(participants)) const auto date = (i != end(participants))
? i->date ? i->date
: base::unixtime::now(); : base::unixtime::now();
@ -406,6 +414,7 @@ void GroupCall::applySelfInCallLocally() {
const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0)) const auto flags = (canSelfUnmute ? Flag::f_can_self_unmute : Flag(0))
| (lastActive ? Flag::f_active_date : Flag(0)) | (lastActive ? Flag::f_active_date : Flag(0))
| (_mySsrc ? Flag(0) : Flag::f_left) | (_mySsrc ? Flag(0) : Flag::f_left)
| Flag::f_self
| Flag::f_volume // Without flag the volume is reset to 100%. | Flag::f_volume // Without flag the volume is reset to 100%.
| Flag::f_volume_by_admin // Self volume can only be set by admin. | Flag::f_volume_by_admin // Self volume can only be set by admin.
| ((muted() != MuteState::Active) ? Flag::f_muted : Flag(0)); | ((muted() != MuteState::Active) ? Flag::f_muted : Flag(0));
@ -416,19 +425,20 @@ void GroupCall::applySelfInCallLocally() {
1, 1,
MTP_groupCallParticipant( MTP_groupCallParticipant(
MTP_flags(flags), MTP_flags(flags),
MTP_int(self->bareId()), peerToMTP(self->id), // #TODO calls channel or self
MTP_int(date), MTP_int(date),
MTP_int(lastActive), MTP_int(lastActive),
MTP_int(_mySsrc), MTP_int(_mySsrc),
MTP_int(volume))), MTP_int(volume),
MTPstring())), // #TODO calls about
MTP_int(0)).c_updateGroupCallParticipants()); MTP_int(0)).c_updateGroupCallParticipants());
} }
void GroupCall::applyParticipantLocally( void GroupCall::applyParticipantLocally(
not_null<UserData*> user, not_null<PeerData*> participantPeer,
bool mute, bool mute,
std::optional<int> volume) { std::optional<int> volume) {
const auto participant = LookupParticipant(_peer, _id, user); const auto participant = LookupParticipant(_peer, _id, participantPeer);
if (!participant || !participant->ssrc) { if (!participant || !participant->ssrc) {
return; return;
} }
@ -436,7 +446,7 @@ void GroupCall::applyParticipantLocally(
const auto isMuted = participant->muted || (mute && canManageCall); const auto isMuted = participant->muted || (mute && canManageCall);
const auto canSelfUnmute = !canManageCall const auto canSelfUnmute = !canManageCall
? participant->canSelfUnmute ? participant->canSelfUnmute
: (!mute || IsGroupCallAdmin(_peer, user)); : (!mute || IsGroupCallAdmin(_peer, participantPeer));
const auto isMutedByYou = mute && !canManageCall; const auto isMutedByYou = mute && !canManageCall;
const auto mutedCount = 0/*participant->mutedCount*/; const auto mutedCount = 0/*participant->mutedCount*/;
using Flag = MTPDgroupCallParticipant::Flag; using Flag = MTPDgroupCallParticipant::Flag;
@ -447,7 +457,7 @@ void GroupCall::applyParticipantLocally(
: Flag(0)) : Flag(0))
| (participant->lastActive ? Flag::f_active_date : Flag(0)) | (participant->lastActive ? Flag::f_active_date : Flag(0))
| (isMuted ? Flag::f_muted : 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( _peer->groupCall()->applyUpdateChecked(
MTP_updateGroupCallParticipants( MTP_updateGroupCallParticipants(
inputCall(), inputCall(),
@ -455,11 +465,12 @@ void GroupCall::applyParticipantLocally(
1, 1,
MTP_groupCallParticipant( MTP_groupCallParticipant(
MTP_flags(flags), MTP_flags(flags),
MTP_int(user->bareId()), peerToMTP(participantPeer->id),
MTP_int(participant->date), MTP_int(participant->date),
MTP_int(participant->lastActive), MTP_int(participant->lastActive),
MTP_int(participant->ssrc), 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()); MTP_int(0)).c_updateGroupCallParticipants());
} }
@ -631,22 +642,25 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) {
// No real information about mutedByMe or my custom volume. // No real information about mutedByMe or my custom volume.
return; return;
} }
const auto user = _peer->owner().user(data.vuser_id().v); const auto participantPeer = _peer->owner().peer(
const auto participant = LookupParticipant(_peer, _id, user); peerFromMTP(data.vpeer()));
const auto participant = LookupParticipant(
_peer,
_id,
participantPeer);
if (!participant) { if (!participant) {
return; return;
} }
_otherParticipantStateValue.fire(Group::ParticipantState{ _otherParticipantStateValue.fire(Group::ParticipantState{
.user = user, .peer = participantPeer,
.volume = data.vvolume().value_or_empty(), .volume = data.vvolume().value_or_empty(),
.mutedByMe = data.is_muted_by_you(), .mutedByMe = data.is_muted_by_you(),
}); });
}; };
const auto self = _peer->session().userId();
for (const auto &participant : data.vparticipants().v) { for (const auto &participant : data.vparticipants().v) {
participant.match([&](const MTPDgroupCallParticipant &data) { participant.match([&](const MTPDgroupCallParticipant &data) {
if (data.vuser_id().v != self) { if (!data.is_self()) {
handleOtherParticipants(data); handleOtherParticipants(data);
return; return;
} }
@ -891,12 +905,11 @@ void GroupCall::maybeSendMutedUpdate(MuteState previous) {
void GroupCall::sendMutedUpdate() { void GroupCall::sendMutedUpdate() {
_api.request(_updateMuteRequestId).cancel(); _api.request(_updateMuteRequestId).cancel();
_updateMuteRequestId = _api.request(MTPphone_EditGroupCallMember( using Flag = MTPphone_EditGroupCallParticipant::Flag;
MTP_flags((muted() != MuteState::Active) _updateMuteRequestId = _api.request(MTPphone_EditGroupCallParticipant(
? MTPphone_EditGroupCallMember::Flag::f_muted MTP_flags((muted() != MuteState::Active) ? Flag::f_muted : Flag(0)),
: MTPphone_EditGroupCallMember::Flag(0)),
inputCall(), inputCall(),
MTP_inputUserSelf(), MTP_inputPeerSelf(),
MTP_int(100000) // volume MTP_int(100000) // volume
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
_updateMuteRequestId = 0; _updateMuteRequestId = 0;
@ -930,37 +943,37 @@ void GroupCall::setCurrentAudioDevice(bool input, const QString &deviceId) {
void GroupCall::toggleMute(const Group::MuteRequest &data) { void GroupCall::toggleMute(const Group::MuteRequest &data) {
if (data.locallyOnly) { if (data.locallyOnly) {
applyParticipantLocally(data.user, data.mute, std::nullopt); applyParticipantLocally(data.peer, data.mute, std::nullopt);
} else { } else {
editParticipant(data.user, data.mute, std::nullopt); editParticipant(data.peer, data.mute, std::nullopt);
} }
} }
void GroupCall::changeVolume(const Group::VolumeRequest &data) { void GroupCall::changeVolume(const Group::VolumeRequest &data) {
if (data.locallyOnly) { if (data.locallyOnly) {
applyParticipantLocally(data.user, false, data.volume); applyParticipantLocally(data.peer, false, data.volume);
} else { } else {
editParticipant(data.user, false, data.volume); editParticipant(data.peer, false, data.volume);
} }
} }
void GroupCall::editParticipant( void GroupCall::editParticipant(
not_null<UserData*> user, not_null<PeerData*> participantPeer,
bool mute, bool mute,
std::optional<int> volume) { std::optional<int> volume) {
const auto participant = LookupParticipant(_peer, _id, user); const auto participant = LookupParticipant(_peer, _id, participantPeer);
if (!participant) { if (!participant) {
return; 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)) const auto flags = (mute ? Flag::f_muted : Flag(0))
| (volume.has_value() ? Flag::f_volume : Flag(0)); | (volume.has_value() ? Flag::f_volume : Flag(0));
_api.request(MTPphone_EditGroupCallMember( _api.request(MTPphone_EditGroupCallParticipant(
MTP_flags(flags), MTP_flags(flags),
inputCall(), inputCall(),
user->inputUser, participantPeer->input,
MTP_int(std::clamp(volume.value_or(0), 1, Group::kMaxVolume)) MTP_int(std::clamp(volume.value_or(0), 1, Group::kMaxVolume))
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result); _peer->session().api().applyUpdates(result);
@ -987,7 +1000,7 @@ std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
return !invited.contains(user) && !ranges::contains( return !invited.contains(user) && !ranges::contains(
participants, participants,
user, user,
&Data::GroupCall::Participant::user); &Data::GroupCall::Participant::peer);
}); });
auto count = 0; auto count = 0;

View file

@ -56,7 +56,7 @@ enum class MuteState {
[[nodiscard]] bool IsGroupCallAdmin( [[nodiscard]] bool IsGroupCallAdmin(
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> user); not_null<PeerData*> participantPeer);
struct LevelUpdate { struct LevelUpdate {
uint32 ssrc = 0; uint32 ssrc = 0;
@ -194,11 +194,11 @@ private:
void playConnectingSoundOnce(); void playConnectingSoundOnce();
void editParticipant( void editParticipant(
not_null<UserData*> user, not_null<PeerData*> participantPeer,
bool mute, bool mute,
std::optional<int> volume); std::optional<int> volume);
void applyParticipantLocally( void applyParticipantLocally(
not_null<UserData*> user, not_null<PeerData*> participantPeer,
bool mute, bool mute,
std::optional<int> volume); std::optional<int> volume);

View file

@ -15,20 +15,20 @@ constexpr auto kDefaultVolume = 10000;
constexpr auto kMaxVolume = 20000; constexpr auto kMaxVolume = 20000;
struct MuteRequest { struct MuteRequest {
not_null<UserData*> user; not_null<PeerData*> peer;
bool mute = false; bool mute = false;
bool locallyOnly = false; bool locallyOnly = false;
}; };
struct VolumeRequest { struct VolumeRequest {
not_null<UserData*> user; not_null<PeerData*> peer;
int volume = kDefaultVolume; int volume = kDefaultVolume;
bool finalized = true; bool finalized = true;
bool locallyOnly = false; bool locallyOnly = false;
}; };
struct ParticipantState { struct ParticipantState {
not_null<UserData*> user; not_null<PeerData*> peer;
std::optional<int> volume; std::optional<int> volume;
bool mutedByMe = false; bool mutedByMe = false;
bool locallyOnly = false; bool locallyOnly = false;

View file

@ -91,7 +91,9 @@ public:
class Row final : public PeerListRow { class Row final : public PeerListRow {
public: public:
Row(not_null<RowDelegate*> delegate, not_null<UserData*> user); Row(
not_null<RowDelegate*> delegate,
not_null<PeerData*> participantPeer);
enum class State { enum class State {
Active, Active,
@ -266,8 +268,8 @@ public:
} }
[[nodiscard]] rpl::producer<MuteRequest> toggleMuteRequests() const; [[nodiscard]] rpl::producer<MuteRequest> toggleMuteRequests() const;
[[nodiscard]] rpl::producer<VolumeRequest> changeVolumeRequests() const; [[nodiscard]] rpl::producer<VolumeRequest> changeVolumeRequests() const;
[[nodiscard]] auto kickMemberRequests() const [[nodiscard]] auto kickParticipantRequests() const
-> rpl::producer<not_null<UserData*>>; -> rpl::producer<not_null<PeerData*>>;
bool rowCanMuteMembers() override; bool rowCanMuteMembers() override;
void rowUpdateRow(not_null<Row*> row) override; void rowUpdateRow(not_null<Row*> row) override;
@ -284,7 +286,7 @@ private:
[[nodiscard]] std::unique_ptr<Row> createRow( [[nodiscard]] std::unique_ptr<Row> createRow(
const Data::GroupCall::Participant &participant); const Data::GroupCall::Participant &participant);
[[nodiscard]] std::unique_ptr<Row> createInvitedRow( [[nodiscard]] std::unique_ptr<Row> createInvitedRow(
not_null<UserData*> user); not_null<PeerData*> participantPeer);
void prepareRows(not_null<Data::GroupCall*> real); void prepareRows(not_null<Data::GroupCall*> real);
//void repaintByTimer(); //void repaintByTimer();
@ -294,8 +296,8 @@ private:
not_null<PeerListRow*> row); not_null<PeerListRow*> row);
void addMuteActionsToContextMenu( void addMuteActionsToContextMenu(
not_null<Ui::PopupMenu*> menu, not_null<Ui::PopupMenu*> menu,
not_null<UserData*> user, not_null<PeerData*> participantPeer,
bool userIsCallAdmin, bool participantIsCallAdmin,
not_null<Row*> row); not_null<Row*> row);
void setupListChangeViewers(not_null<GroupCall*> call); void setupListChangeViewers(not_null<GroupCall*> call);
void subscribeToChanges(not_null<Data::GroupCall*> real); void subscribeToChanges(not_null<Data::GroupCall*> real);
@ -308,7 +310,7 @@ private:
void removeRow(not_null<Row*> row); void removeRow(not_null<Row*> row);
void updateRowLevel(not_null<Row*> row, float level); void updateRowLevel(not_null<Row*> row, float level);
void checkSpeakingRowPosition(not_null<Row*> row); void checkSpeakingRowPosition(not_null<Row*> row);
Row *findRow(not_null<UserData*> user) const; Row *findRow(not_null<PeerData*> participantPeer) const;
[[nodiscard]] Data::GroupCall *resolvedRealCall() const; [[nodiscard]] Data::GroupCall *resolvedRealCall() const;
void appendInvitedUsers(); void appendInvitedUsers();
@ -323,7 +325,7 @@ private:
rpl::event_stream<MuteRequest> _toggleMuteRequests; rpl::event_stream<MuteRequest> _toggleMuteRequests;
rpl::event_stream<VolumeRequest> _changeVolumeRequests; rpl::event_stream<VolumeRequest> _changeVolumeRequests;
rpl::event_stream<not_null<UserData*>> _kickMemberRequests; rpl::event_stream<not_null<PeerData*>> _kickParticipantRequests;
rpl::variable<int> _fullCount = 1; rpl::variable<int> _fullCount = 1;
rpl::variable<int> _fullCountMin = 0; rpl::variable<int> _fullCountMin = 0;
rpl::variable<int> _fullCountMax = std::numeric_limits<int>::max(); rpl::variable<int> _fullCountMax = std::numeric_limits<int>::max();
@ -345,8 +347,10 @@ private:
}; };
Row::Row(not_null<RowDelegate*> delegate, not_null<UserData*> user) Row::Row(
: PeerListRow(user) not_null<RowDelegate*> delegate,
not_null<PeerData*> participantPeer)
: PeerListRow(participantPeer)
, _delegate(delegate) { , _delegate(delegate) {
refreshStatus(); refreshStatus();
} }
@ -872,11 +876,13 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
) | rpl::start_with_next([=](const Update &update) { ) | rpl::start_with_next([=](const Update &update) {
Expects(update.was.has_value() || update.now.has_value()); 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 (!update.now) {
if (const auto row = findRow(user)) { if (const auto row = findRow(participantPeer)) {
const auto owner = &user->owner(); const auto owner = &participantPeer->owner();
if (user->isSelf()) { if (participantPeer->isSelf()) {
updateRow(row, nullptr); updateRow(row, nullptr);
} else { } else {
removeRow(row); removeRow(row);
@ -918,7 +924,7 @@ void MembersController::updateRow(
const Data::GroupCall::Participant &now) { const Data::GroupCall::Participant &now) {
auto reorderIfInvitedBeforeIndex = 0; auto reorderIfInvitedBeforeIndex = 0;
auto countChange = 0; auto countChange = 0;
if (const auto row = findRow(now.user)) { if (const auto row = findRow(now.peer)) {
if (now.speaking && (!was || !was->speaking)) { if (now.speaking && (!was || !was->speaking)) {
checkSpeakingRowPosition(row); checkSpeakingRowPosition(row);
} }
@ -1047,8 +1053,9 @@ void MembersController::updateRowLevel(
row->updateLevel(level); row->updateLevel(level);
} }
Row *MembersController::findRow(not_null<UserData*> user) const { Row *MembersController::findRow(not_null<PeerData*> participantPeer) const {
return static_cast<Row*>(delegate()->peerListFindRow(user->id)); return static_cast<Row*>(
delegate()->peerListFindRow(participantPeer->id));
} }
Data::GroupCall *MembersController::resolvedRealCall() const { Data::GroupCall *MembersController::resolvedRealCall() const {
@ -1094,16 +1101,16 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
auto count = delegate()->peerListFullRowsCount(); auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count;) { for (auto i = 0; i != count;) {
auto row = delegate()->peerListRowAt(i); auto row = delegate()->peerListRowAt(i);
auto user = row->peer()->asUser(); auto participantPeer = row->peer();
if (user->isSelf()) { if (participantPeer->isSelf()) { // #TODO calls add self even if channel
foundSelf = true; foundSelf = true;
++i; ++i;
continue; continue;
} }
const auto contains = ranges::contains( const auto contains = ranges::contains(
participants, participants,
not_null{ user }, participantPeer,
&Data::GroupCall::Participant::user); &Data::GroupCall::Participant::peer);
if (contains) { if (contains) {
++fullCountMin; ++fullCountMin;
++i; ++i;
@ -1117,8 +1124,8 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
const auto self = _peer->session().user(); const auto self = _peer->session().user();
const auto i = ranges::find( const auto i = ranges::find(
participants, participants,
_peer->session().user(), self,
&Data::GroupCall::Participant::user); &Data::GroupCall::Participant::peer);
auto row = (i != end(participants)) ? createRow(*i) : createSelfRow(); auto row = (i != end(participants)) ? createRow(*i) : createSelfRow();
if (row) { if (row) {
if (row->state() != Row::State::Invited) { if (row->state() != Row::State::Invited) {
@ -1223,9 +1230,9 @@ void MembersController::rowPaintIcon(
_inactiveCrossLine.paint(p, left, top, crossProgress, iconColor); _inactiveCrossLine.paint(p, left, top, crossProgress, iconColor);
} }
auto MembersController::kickMemberRequests() const auto MembersController::kickParticipantRequests() const
-> rpl::producer<not_null<UserData*>>{ -> rpl::producer<not_null<PeerData*>>{
return _kickMemberRequests.events(); return _kickParticipantRequests.events();
} }
void MembersController::rowClicked(not_null<PeerListRow*> row) { void MembersController::rowClicked(not_null<PeerListRow*> row) {
@ -1235,7 +1242,7 @@ void MembersController::rowClicked(not_null<PeerListRow*> row) {
} }
auto saved = base::take(_menu); auto saved = base::take(_menu);
for (const auto peer : base::take(_menuCheckRowsAfterHidden)) { for (const auto peer : base::take(_menuCheckRowsAfterHidden)) {
if (const auto row = findRow(peer->asUser())) { if (const auto row = findRow(peer)) {
if (row->speaking()) { if (row->speaking()) {
checkSpeakingRowPosition(row); checkSpeakingRowPosition(row);
} }
@ -1270,21 +1277,19 @@ base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu( base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
QWidget *parent, QWidget *parent,
not_null<PeerListRow*> row) { not_null<PeerListRow*> row) {
Expects(row->peer()->isUser()); const auto participantPeer = row->peer();
const auto real = static_cast<Row*>(row.get()); const auto real = static_cast<Row*>(row.get());
if (row->peer()->isSelf() if (participantPeer->isSelf()
&& (!_peer->canManageGroupCall() || !real->ssrc())) { && (!_peer->canManageGroupCall() || !real->ssrc())) {
return nullptr; return nullptr;
} }
const auto user = row->peer()->asUser();
auto result = base::make_unique_q<Ui::PopupMenu>( auto result = base::make_unique_q<Ui::PopupMenu>(
parent, parent,
st::groupCallPopupMenu); st::groupCallPopupMenu);
const auto muteState = real->state(); const auto muteState = real->state();
const auto admin = IsGroupCallAdmin(_peer, user); const auto admin = IsGroupCallAdmin(_peer, participantPeer);
const auto session = &user->session(); const auto session = &_peer->session();
const auto getCurrentWindow = [=]() -> Window::SessionController* { const auto getCurrentWindow = [=]() -> Window::SessionController* {
if (const auto window = Core::App().activeWindow()) { if (const auto window = Core::App().activeWindow()) {
if (const auto controller = window->sessionController()) { if (const auto controller = window->sessionController()) {
@ -1319,25 +1324,25 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
}; };
const auto showProfile = [=] { const auto showProfile = [=] {
performOnMainWindow([=](not_null<Window::SessionController*> window) { performOnMainWindow([=](not_null<Window::SessionController*> window) {
window->showPeerInfo(user); window->showPeerInfo(participantPeer);
}); });
}; };
const auto showHistory = [=] { const auto showHistory = [=] {
performOnMainWindow([=](not_null<Window::SessionController*> window) { performOnMainWindow([=](not_null<Window::SessionController*> window) {
window->showPeerHistory( window->showPeerHistory(
user, participantPeer,
Window::SectionShow::Way::Forward); Window::SectionShow::Way::Forward);
}); });
}; };
const auto removeFromGroup = crl::guard(this, [=] { const auto removeFromGroup = crl::guard(this, [=] {
_kickMemberRequests.fire_copy(user); _kickParticipantRequests.fire_copy(participantPeer);
}); });
if (real->ssrc() != 0) { 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( result->addAction(
tr::lng_context_view_profile(tr::now), tr::lng_context_view_profile(tr::now),
showProfile); showProfile);
@ -1345,13 +1350,17 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
tr::lng_context_send_message(tr::now), tr::lng_context_send_message(tr::now),
showHistory); showHistory);
const auto canKick = [&] { const auto canKick = [&] {
const auto user = participantPeer->asUser();
if (static_cast<Row*>(row.get())->state() == Row::State::Invited) { if (static_cast<Row*>(row.get())->state() == Row::State::Invited) {
return false; return false;
} else if (const auto chat = _peer->asChat()) { } else if (const auto chat = _peer->asChat()) {
return chat->amCreator() 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()) { } else if (const auto group = _peer->asMegagroup()) {
return group->canRestrictUser(user); return group->amCreator()
|| (user && group->canRestrictUser(user)); // #TODO calls can kick
} }
return false; return false;
}(); }();
@ -1366,8 +1375,8 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
void MembersController::addMuteActionsToContextMenu( void MembersController::addMuteActionsToContextMenu(
not_null<Ui::PopupMenu*> menu, not_null<Ui::PopupMenu*> menu,
not_null<UserData*> user, not_null<PeerData*> participantPeer,
bool userIsCallAdmin, bool participantIsCallAdmin,
not_null<Row*> row) { not_null<Row*> row) {
const auto muteString = [=] { const auto muteString = [=] {
return (_peer->canManageGroupCall() return (_peer->canManageGroupCall()
@ -1383,7 +1392,7 @@ void MembersController::addMuteActionsToContextMenu(
const auto toggleMute = crl::guard(this, [=](bool mute, bool local) { const auto toggleMute = crl::guard(this, [=](bool mute, bool local) {
_toggleMuteRequests.fire(Group::MuteRequest{ _toggleMuteRequests.fire(Group::MuteRequest{
.user = user, .peer = participantPeer,
.mute = mute, .mute = mute,
.locallyOnly = local, .locallyOnly = local,
}); });
@ -1392,7 +1401,7 @@ void MembersController::addMuteActionsToContextMenu(
int volume, int volume,
bool local) { bool local) {
_changeVolumeRequests.fire(Group::VolumeRequest{ _changeVolumeRequests.fire(Group::VolumeRequest{
.user = user, .peer = participantPeer,
.volume = std::clamp(volume, 1, Group::kMaxVolume), .volume = std::clamp(volume, 1, Group::kMaxVolume),
.locallyOnly = local, .locallyOnly = local,
}); });
@ -1404,12 +1413,12 @@ void MembersController::addMuteActionsToContextMenu(
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased(); auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased();
if (!isMuted || user->isSelf()) { if (!isMuted || participantPeer->isSelf()) {
const auto call = _call.get(); const auto call = _call.get();
auto otherParticipantStateValue = call auto otherParticipantStateValue = call
? call->otherParticipantStateValue( ? call->otherParticipantStateValue(
) | rpl::filter([=](const Group::ParticipantState &data) { ) | rpl::filter([=](const Group::ParticipantState &data) {
return data.user == user; return data.peer == participantPeer;
}) })
: rpl::never<Group::ParticipantState>() | rpl::type_erased(); : rpl::never<Group::ParticipantState>() | rpl::type_erased();
@ -1437,7 +1446,7 @@ void MembersController::addMuteActionsToContextMenu(
volumeItem->toggleMuteLocallyRequests( volumeItem->toggleMuteLocallyRequests(
) | rpl::start_with_next([=](bool muted) { ) | rpl::start_with_next([=](bool muted) {
if (!user->isSelf()) { if (!participantPeer->isSelf()) { // #TODO calls check self
toggleMute(muted, true); toggleMute(muted, true);
} }
}, volumeItem->lifetime()); }, volumeItem->lifetime());
@ -1449,7 +1458,7 @@ void MembersController::addMuteActionsToContextMenu(
volumeItem->changeVolumeLocallyRequests( volumeItem->changeVolumeLocallyRequests(
) | rpl::start_with_next([=](int volume) { ) | rpl::start_with_next([=](int volume) {
if (!user->isSelf()) { if (!participantPeer->isSelf()) { // #TODO calls check self
changeVolume(volume, true); changeVolume(volume, true);
} }
}, volumeItem->lifetime()); }, volumeItem->lifetime());
@ -1459,9 +1468,9 @@ void MembersController::addMuteActionsToContextMenu(
const auto muteAction = [&]() -> QAction* { const auto muteAction = [&]() -> QAction* {
if (muteState == Row::State::Invited if (muteState == Row::State::Invited
|| user->isSelf() || participantPeer->isSelf() // #TODO calls check self
|| (muteState == Row::State::Muted || (muteState == Row::State::Muted
&& userIsCallAdmin && participantIsCallAdmin
&& _peer->canManageGroupCall())) { && _peer->canManageGroupCall())) {
return nullptr; return nullptr;
} }
@ -1486,7 +1495,7 @@ void MembersController::addMuteActionsToContextMenu(
} }
std::unique_ptr<Row> MembersController::createSelfRow() { std::unique_ptr<Row> MembersController::createSelfRow() {
const auto self = _peer->session().user(); const auto self = _peer->session().user(); // #TODO calls check self
auto result = std::make_unique<Row>(this, self); auto result = std::make_unique<Row>(this, self);
updateRow(result.get(), nullptr); updateRow(result.get(), nullptr);
return result; return result;
@ -1494,17 +1503,17 @@ std::unique_ptr<Row> MembersController::createSelfRow() {
std::unique_ptr<Row> MembersController::createRow( std::unique_ptr<Row> MembersController::createRow(
const Data::GroupCall::Participant &participant) { const Data::GroupCall::Participant &participant) {
auto result = std::make_unique<Row>(this, participant.user); auto result = std::make_unique<Row>(this, participant.peer);
updateRow(result.get(), &participant); updateRow(result.get(), &participant);
return result; return result;
} }
std::unique_ptr<Row> MembersController::createInvitedRow( std::unique_ptr<Row> MembersController::createInvitedRow(
not_null<UserData*> user) { not_null<PeerData*> participantPeer) {
if (findRow(user)) { if (findRow(participantPeer)) {
return nullptr; return nullptr;
} }
auto result = std::make_unique<Row>(this, user); auto result = std::make_unique<Row>(this, participantPeer);
updateRow(result.get(), nullptr); updateRow(result.get(), nullptr);
return result; return result;
} }
@ -1538,10 +1547,10 @@ auto GroupMembers::changeVolumeRequests() const
_listController.get())->changeVolumeRequests(); _listController.get())->changeVolumeRequests();
} }
auto GroupMembers::kickMemberRequests() const auto GroupMembers::kickParticipantRequests() const
-> rpl::producer<not_null<UserData*>> { -> rpl::producer<not_null<PeerData*>> {
return static_cast<MembersController*>( return static_cast<MembersController*>(
_listController.get())->kickMemberRequests(); _listController.get())->kickParticipantRequests();
} }
int GroupMembers::desiredHeight() const { int GroupMembers::desiredHeight() const {

View file

@ -42,8 +42,8 @@ public:
-> rpl::producer<Group::MuteRequest>; -> rpl::producer<Group::MuteRequest>;
[[nodiscard]] auto changeVolumeRequests() const [[nodiscard]] auto changeVolumeRequests() const
-> rpl::producer<Group::VolumeRequest>; -> rpl::producer<Group::VolumeRequest>;
[[nodiscard]] auto kickMemberRequests() const [[nodiscard]] auto kickParticipantRequests() const
-> rpl::producer<not_null<UserData*>>; -> rpl::producer<not_null<PeerData*>>;
[[nodiscard]] rpl::producer<> addMembersRequests() const { [[nodiscard]] rpl::producer<> addMembersRequests() const {
return _addMemberRequests.events(); return _addMemberRequests.events();
} }

View file

@ -520,9 +520,11 @@ void GroupPanel::initWithCall(GroupCall *call) {
} }
}, _callLifetime); }, _callLifetime);
_members->kickMemberRequests( _members->kickParticipantRequests(
) | rpl::start_with_next([=](not_null<UserData*> user) { ) | rpl::start_with_next([=](not_null<PeerData*> participantPeer) {
kickMember(user); if (const auto user = participantPeer->asUser()) {
kickMember(user); // #TODO calls kick
}
}, _callLifetime); }, _callLifetime);
_members->addMembersRequests( _members->addMembersRequests(
@ -570,7 +572,9 @@ void GroupPanel::addMembers() {
} }
auto alreadyIn = _peer->owner().invitedToCallUsers(real->id()); auto alreadyIn = _peer->owner().invitedToCallUsers(real->id());
for (const auto &participant : real->participants()) { 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()); alreadyIn.emplace(_peer->session().user());
auto controller = std::make_unique<InviteController>( auto controller = std::make_unique<InviteController>(

View file

@ -39,7 +39,7 @@ GroupCall::GroupCall(
} }
GroupCall::~GroupCall() { GroupCall::~GroupCall() {
api().request(_unknownUsersRequestId).cancel(); api().request(_unknownParticipantPeersRequestId).cancel();
api().request(_participantsRequestId).cancel(); api().request(_participantsRequestId).cancel();
api().request(_reloadRequestId).cancel(); api().request(_reloadRequestId).cancel();
} }
@ -87,6 +87,7 @@ void GroupCall::requestParticipants() {
result.match([&](const MTPDphone_groupParticipants &data) { result.match([&](const MTPDphone_groupParticipants &data) {
_nextOffset = qs(data.vnext_offset()); _nextOffset = qs(data.vnext_offset());
_peer->owner().processUsers(data.vusers()); _peer->owner().processUsers(data.vusers());
_peer->owner().processChats(data.vchats());
applyParticipantsSlice( applyParticipantsSlice(
data.vparticipants().v, data.vparticipants().v,
ApplySliceSource::SliceLoaded); ApplySliceSource::SliceLoaded);
@ -154,9 +155,9 @@ bool GroupCall::participantsLoaded() const {
return _allReceived; return _allReceived;
} }
UserData *GroupCall::userBySsrc(uint32 ssrc) const { PeerData *GroupCall::participantPeerBySsrc(uint32 ssrc) const {
const auto i = _userBySsrc.find(ssrc); const auto i = _participantPeerBySsrc.find(ssrc);
return (i != end(_userBySsrc)) ? i->second.get() : nullptr; return (i != end(_participantPeerBySsrc)) ? i->second.get() : nullptr;
} }
rpl::producer<> GroupCall::participantsSliceAdded() { rpl::producer<> GroupCall::participantsSliceAdded() {
@ -216,9 +217,10 @@ void GroupCall::reload() {
).done([=](const MTPphone_GroupCall &result) { ).done([=](const MTPphone_GroupCall &result) {
result.match([&](const MTPDphone_groupCall &data) { result.match([&](const MTPDphone_groupCall &data) {
_peer->owner().processUsers(data.vusers()); _peer->owner().processUsers(data.vusers());
_peer->owner().processChats(data.vchats());
_participants.clear(); _participants.clear();
_speakingByActiveFinishes.clear(); _speakingByActiveFinishes.clear();
_userBySsrc.clear(); _participantPeerBySsrc.clear();
applyParticipantsSlice( applyParticipantsSlice(
data.vparticipants().v, data.vparticipants().v,
ApplySliceSource::SliceLoaded); ApplySliceSource::SliceLoaded);
@ -242,19 +244,20 @@ void GroupCall::applyParticipantsSlice(
auto changedCount = _fullCount.current(); auto changedCount = _fullCount.current();
for (const auto &participant : list) { for (const auto &participant : list) {
participant.match([&](const MTPDgroupCallParticipant &data) { participant.match([&](const MTPDgroupCallParticipant &data) {
const auto userId = data.vuser_id().v; const auto participantPeerId = peerFromMTP(data.vpeer());
const auto user = _peer->owner().user(userId); const auto participantPeer = _peer->owner().peer(
participantPeerId);
const auto i = ranges::find( const auto i = ranges::find(
_participants, _participants,
user, participantPeer,
&Participant::user); &Participant::peer);
if (data.is_left()) { if (data.is_left()) {
if (i != end(_participants)) { if (i != end(_participants)) {
auto update = ParticipantUpdate{ auto update = ParticipantUpdate{
.was = *i, .was = *i,
}; };
_userBySsrc.erase(i->ssrc); _participantPeerBySsrc.erase(i->ssrc);
_speakingByActiveFinishes.remove(user); _speakingByActiveFinishes.remove(participantPeer);
_participants.erase(i); _participants.erase(i);
if (sliceSource != ApplySliceSource::SliceLoaded) { if (sliceSource != ApplySliceSource::SliceLoaded) {
_participantUpdates.fire(std::move(update)); _participantUpdates.fire(std::move(update));
@ -290,7 +293,7 @@ void GroupCall::applyParticipantsSlice(
const auto onlyMinLoaded = data.is_min() const auto onlyMinLoaded = data.is_min()
&& (!was || was->onlyMinLoaded); && (!was || was->onlyMinLoaded);
const auto value = Participant{ const auto value = Participant{
.user = user, .peer = participantPeer,
.date = data.vdate().v, .date = data.vdate().v,
.lastActive = lastActive, .lastActive = lastActive,
.ssrc = uint32(data.vsource().v), .ssrc = uint32(data.vsource().v),
@ -303,13 +306,17 @@ void GroupCall::applyParticipantsSlice(
.onlyMinLoaded = onlyMinLoaded, .onlyMinLoaded = onlyMinLoaded,
}; };
if (i == end(_participants)) { if (i == end(_participants)) {
_userBySsrc.emplace(value.ssrc, user); _participantPeerBySsrc.emplace(value.ssrc, participantPeer);
_participants.push_back(value); _participants.push_back(value);
_peer->owner().unregisterInvitedToCallUser(_id, user); if (const auto user = participantPeer->asUser()) {
_peer->owner().unregisterInvitedToCallUser(_id, user);
}
} else { } else {
if (i->ssrc != value.ssrc) { if (i->ssrc != value.ssrc) {
_userBySsrc.erase(i->ssrc); _participantPeerBySsrc.erase(i->ssrc);
_userBySsrc.emplace(value.ssrc, user); _participantPeerBySsrc.emplace(
value.ssrc,
participantPeer);
} }
*i = value; *i = value;
} }
@ -334,16 +341,19 @@ void GroupCall::applyLastSpoke(
uint32 ssrc, uint32 ssrc,
LastSpokeTimes when, LastSpokeTimes when,
crl::time now) { crl::time now) {
const auto i = _userBySsrc.find(ssrc); const auto i = _participantPeerBySsrc.find(ssrc);
if (i == end(_userBySsrc)) { if (i == end(_participantPeerBySsrc)) {
_unknownSpokenSsrcs[ssrc] = when; _unknownSpokenSsrcs[ssrc] = when;
requestUnknownParticipants(); requestUnknownParticipants();
return; 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)); Assert(j != end(_participants));
_speakingByActiveFinishes.remove(j->user); _speakingByActiveFinishes.remove(j->peer);
const auto sounding = (when.anything + kSoundStatusKeptFor >= now) const auto sounding = (when.anything + kSoundStatusKeptFor >= now)
&& j->canSelfUnmute; && j->canSelfUnmute;
const auto speaking = sounding const auto speaking = sounding
@ -360,22 +370,22 @@ void GroupCall::applyLastSpoke(
} }
void GroupCall::applyActiveUpdate( void GroupCall::applyActiveUpdate(
UserId userId, PeerId participantPeerId,
LastSpokeTimes when, LastSpokeTimes when,
UserData *userLoaded) { PeerData *participantPeerLoaded) {
if (inCall()) { if (inCall()) {
return; return;
} }
const auto i = userLoaded const auto i = participantPeerLoaded
? ranges::find( ? ranges::find(
_participants, _participants,
not_null{ userLoaded }, not_null{ participantPeerLoaded },
&Participant::user) &Participant::peer)
: _participants.end(); : _participants.end();
const auto notFound = (i == end(_participants)); const auto notFound = (i == end(_participants));
const auto loadByUserId = notFound || i->onlyMinLoaded; const auto loadByUserId = notFound || i->onlyMinLoaded;
if (loadByUserId) { if (loadByUserId) {
_unknownSpokenUids[userId] = when; _unknownSpokenPeerIds[participantPeerId] = when;
requestUnknownParticipants(); requestUnknownParticipants();
} }
if (notFound || !i->canSelfUnmute) { if (notFound || !i->canSelfUnmute) {
@ -389,7 +399,7 @@ void GroupCall::applyActiveUpdate(
if (lastActive <= i->lastActive || finishes <= now) { if (lastActive <= i->lastActive || finishes <= now) {
return; return;
} }
_speakingByActiveFinishes[i->user] = finishes; _speakingByActiveFinishes[i->peer] = finishes;
if (!_speakingByActiveFinishTimer.isActive()) { if (!_speakingByActiveFinishTimer.isActive()) {
_speakingByActiveFinishTimer.callOnce(finishes - now); _speakingByActiveFinishTimer.callOnce(finishes - now);
} }
@ -408,8 +418,9 @@ void GroupCall::applyActiveUpdate(
void GroupCall::checkFinishSpeakingByActive() { void GroupCall::checkFinishSpeakingByActive() {
const auto now = crl::now(); const auto now = crl::now();
auto nearest = 0; auto nearest = 0;
auto stop = std::vector<not_null<UserData*>>(); auto stop = std::vector<not_null<PeerData*>>();
for (auto i = begin(_speakingByActiveFinishes); i != end(_speakingByActiveFinishes);) { for (auto i = begin(_speakingByActiveFinishes)
; i != end(_speakingByActiveFinishes);) {
const auto when = i->second; const auto when = i->second;
if (now >= when) { if (now >= when) {
stop.push_back(i->first); stop.push_back(i->first);
@ -421,8 +432,11 @@ void GroupCall::checkFinishSpeakingByActive() {
++i; ++i;
} }
} }
for (const auto user : stop) { for (const auto participantPeer : stop) {
const auto i = ranges::find(_participants, user, &Participant::user); const auto i = ranges::find(
_participants,
participantPeer,
&Participant::peer);
if (i->speaking) { if (i->speaking) {
const auto was = *i; const auto was = *i;
i->speaking = false; i->speaking = false;
@ -438,8 +452,8 @@ void GroupCall::checkFinishSpeakingByActive() {
} }
void GroupCall::requestUnknownParticipants() { void GroupCall::requestUnknownParticipants() {
if (_unknownUsersRequestId if (_unknownParticipantPeersRequestId
|| (_unknownSpokenSsrcs.empty() && _unknownSpokenUids.empty())) { || (_unknownSpokenSsrcs.empty() && _unknownSpokenPeerIds.empty())) {
return; return;
} }
const auto ssrcs = [&] { const auto ssrcs = [&] {
@ -455,18 +469,18 @@ void GroupCall::requestUnknownParticipants() {
} }
return result; return result;
}(); }();
const auto uids = [&] { const auto peerIds = [&] {
if (_unknownSpokenUids.size() + ssrcs.size() < kRequestPerPage) { if (_unknownSpokenPeerIds.size() + ssrcs.size() < kRequestPerPage) {
return base::take(_unknownSpokenUids); return base::take(_unknownSpokenPeerIds);
} }
auto result = base::flat_map<UserId, LastSpokeTimes>(); auto result = base::flat_map<PeerId, LastSpokeTimes>();
const auto available = (kRequestPerPage - int(ssrcs.size())); const auto available = (kRequestPerPage - int(ssrcs.size()));
if (available > 0) { if (available > 0) {
result.reserve(available); result.reserve(available);
while (result.size() < available) { while (result.size() < available) {
const auto [userId, when] = _unknownSpokenUids.back(); const auto [userId, when] = _unknownSpokenPeerIds.back();
result.emplace(userId, when); result.emplace(userId, when);
_unknownSpokenUids.erase(_unknownSpokenUids.end() - 1); _unknownSpokenPeerIds.erase(_unknownSpokenPeerIds.end() - 1);
} }
} }
return result; return result;
@ -477,62 +491,65 @@ void GroupCall::requestUnknownParticipants() {
ssrcInputs.push_back(MTP_int(ssrc)); ssrcInputs.push_back(MTP_int(ssrc));
} }
auto uidInputs = QVector<MTPint>(); auto uidInputs = QVector<MTPint>();
uidInputs.reserve(uids.size()); uidInputs.reserve(peerIds.size());
for (const auto [userId, when] : uids) { for (const auto [peerId, when] : peerIds) {
uidInputs.push_back(MTP_int(userId)); Assert(peerIsUser(peerId)); // #TODO calls
uidInputs.push_back(MTP_int(peerToUser(peerId)));
} }
_unknownUsersRequestId = api().request(MTPphone_GetGroupParticipants( _unknownParticipantPeersRequestId = api().request(
input(), MTPphone_GetGroupParticipants(
MTP_vector<MTPint>(uidInputs), input(),
MTP_vector<MTPint>(ssrcInputs), MTP_vector<MTPint>(uidInputs),
MTP_string(QString()), MTP_vector<MTPint>(ssrcInputs),
MTP_int(kRequestPerPage) MTP_string(QString()),
)).done([=](const MTPphone_GroupParticipants &result) { MTP_int(kRequestPerPage)
)
).done([=](const MTPphone_GroupParticipants &result) {
result.match([&](const MTPDphone_groupParticipants &data) { result.match([&](const MTPDphone_groupParticipants &data) {
_peer->owner().processUsers(data.vusers()); _peer->owner().processUsers(data.vusers());
applyParticipantsSlice( applyParticipantsSlice(
data.vparticipants().v, data.vparticipants().v,
ApplySliceSource::UnknownLoaded); ApplySliceSource::UnknownLoaded);
}); });
_unknownUsersRequestId = 0; _unknownParticipantPeersRequestId = 0;
const auto now = crl::now(); const auto now = crl::now();
for (const auto [ssrc, when] : ssrcs) { for (const auto [ssrc, when] : ssrcs) {
applyLastSpoke(ssrc, when, now); applyLastSpoke(ssrc, when, now);
_unknownSpokenSsrcs.remove(ssrc); _unknownSpokenSsrcs.remove(ssrc);
} }
for (const auto [userId, when] : uids) { for (const auto [peerId, when] : peerIds) {
if (const auto user = _peer->owner().userLoaded(userId)) { if (const auto participantPeer = _peer->owner().peerLoaded(peerId)) {
const auto isParticipant = ranges::contains( const auto isParticipant = ranges::contains(
_participants, _participants,
not_null{ user }, not_null{ participantPeer },
&Participant::user); &Participant::peer);
if (isParticipant) { if (isParticipant) {
applyActiveUpdate(userId, when, user); applyActiveUpdate(peerId, when, participantPeer);
} }
} }
_unknownSpokenUids.remove(userId); _unknownSpokenPeerIds.remove(peerId);
} }
requestUnknownParticipants(); requestUnknownParticipants();
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
_unknownUsersRequestId = 0; _unknownParticipantPeersRequestId = 0;
for (const auto [ssrc, when] : ssrcs) { for (const auto [ssrc, when] : ssrcs) {
_unknownSpokenSsrcs.remove(ssrc); _unknownSpokenSsrcs.remove(ssrc);
} }
for (const auto [userId, when] : uids) { for (const auto [peerId, when] : peerIds) {
_unknownSpokenUids.remove(userId); _unknownSpokenPeerIds.remove(peerId);
} }
requestUnknownParticipants(); requestUnknownParticipants();
}).send(); }).send();
} }
void GroupCall::setInCall() { void GroupCall::setInCall() {
_unknownSpokenUids.clear(); _unknownSpokenPeerIds.clear();
if (_speakingByActiveFinishes.empty()) { if (_speakingByActiveFinishes.empty()) {
return; return;
} }
auto restartTimer = true; auto restartTimer = true;
const auto latest = crl::now() + kActiveAfterJoined; const auto latest = crl::now() + kActiveAfterJoined;
for (auto &[user, when] : _speakingByActiveFinishes) { for (auto &[peer, when] : _speakingByActiveFinishes) {
if (when > latest) { if (when > latest) {
when = latest; when = latest;
} else { } else {

View file

@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h" #include "base/timer.h"
class UserData;
class PeerData; class PeerData;
class ApiWrap; class ApiWrap;
@ -33,7 +32,7 @@ public:
void setPeer(not_null<PeerData*> peer); void setPeer(not_null<PeerData*> peer);
struct Participant { struct Participant {
not_null<UserData*> user; not_null<PeerData*> peer;
TimeId date = 0; TimeId date = 0;
TimeId lastActive = 0; TimeId lastActive = 0;
uint32 ssrc = 0; uint32 ssrc = 0;
@ -57,7 +56,7 @@ public:
-> const std::vector<Participant> &; -> const std::vector<Participant> &;
void requestParticipants(); void requestParticipants();
[[nodiscard]] bool participantsLoaded() const; [[nodiscard]] bool participantsLoaded() const;
[[nodiscard]] UserData *userBySsrc(uint32 ssrc) const; [[nodiscard]] PeerData *participantPeerBySsrc(uint32 ssrc) const;
[[nodiscard]] rpl::producer<> participantsSliceAdded(); [[nodiscard]] rpl::producer<> participantsSliceAdded();
[[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const; [[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const;
@ -68,9 +67,9 @@ public:
const MTPDupdateGroupCallParticipants &update); const MTPDupdateGroupCallParticipants &update);
void applyLastSpoke(uint32 ssrc, LastSpokeTimes when, crl::time now); void applyLastSpoke(uint32 ssrc, LastSpokeTimes when, crl::time now);
void applyActiveUpdate( void applyActiveUpdate(
UserId userId, PeerId participantPeerId,
LastSpokeTimes when, LastSpokeTimes when,
UserData *userLoaded); PeerData *participantPeerLoaded);
[[nodiscard]] int fullCount() const; [[nodiscard]] int fullCount() const;
[[nodiscard]] rpl::producer<int> fullCountValue() const; [[nodiscard]] rpl::producer<int> fullCountValue() const;
@ -108,15 +107,15 @@ private:
mtpRequestId _reloadRequestId = 0; mtpRequestId _reloadRequestId = 0;
std::vector<Participant> _participants; std::vector<Participant> _participants;
base::flat_map<uint32, not_null<UserData*>> _userBySsrc; base::flat_map<uint32, not_null<PeerData*>> _participantPeerBySsrc;
base::flat_map<not_null<UserData*>, crl::time> _speakingByActiveFinishes; base::flat_map<not_null<PeerData*>, crl::time> _speakingByActiveFinishes;
base::Timer _speakingByActiveFinishTimer; base::Timer _speakingByActiveFinishTimer;
QString _nextOffset; QString _nextOffset;
rpl::variable<int> _fullCount = 0; rpl::variable<int> _fullCount = 0;
base::flat_map<uint32, LastSpokeTimes> _unknownSpokenSsrcs; base::flat_map<uint32, LastSpokeTimes> _unknownSpokenSsrcs;
base::flat_map<UserId, LastSpokeTimes> _unknownSpokenUids; base::flat_map<PeerId, LastSpokeTimes> _unknownSpokenPeerIds;
mtpRequestId _unknownUsersRequestId = 0; mtpRequestId _unknownParticipantPeersRequestId = 0;
rpl::event_stream<ParticipantUpdate> _participantUpdates; rpl::event_stream<ParticipantUpdate> _participantUpdates;
rpl::event_stream<> _participantsSliceAdded; rpl::event_stream<> _participantsSliceAdded;

View file

@ -832,7 +832,7 @@ void Session::registerInvitedToCallUser(
const auto inCall = ranges::contains( const auto inCall = ranges::contains(
call->participants(), call->participants(),
user, user,
&Data::GroupCall::Participant::user); &Data::GroupCall::Participant::peer);
if (inCall) { if (inCall) {
return; return;
} }

View file

@ -88,6 +88,8 @@ LocationKey ComputeLocationKey(const Data::FileLocation &value) {
result.type |= (9ULL << 24); result.type |= (9ULL << 24);
result.type |= (uint64(uint32(data.vlocal_id().v)) << 32); result.type |= (uint64(uint32(data.vlocal_id().v)) << 32);
result.id = data.vvolume_id().v; result.id = data.vvolume_id().v;
}, [&](const MTPDinputGroupCallStream &data) {
result.type = (10ULL << 24);
}); });
return result; return result;
} }

View file

@ -946,9 +946,9 @@ void GenerateItems(
addSimpleServiceMessage(text); addSimpleServiceMessage(text);
}; };
auto groupCallParticipantUser = [&](const MTPGroupCallParticipant &data) { auto groupCallParticipantPeer = [&](const MTPGroupCallParticipant &data) {
return data.match([&](const MTPDgroupCallParticipant &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) { auto createParticipantMute = [&](const MTPDchannelAdminLogEventActionParticipantMute &data) {
const auto user = groupCallParticipantUser(data.vparticipant()); const auto participantPeer = groupCallParticipantPeer(data.vparticipant());
const auto userLink = user->createOpenLink(); const auto participantPeerLink = participantPeer->createOpenLink();
const auto userLinkText = textcmdLink(2, user->name); const auto participantPeerLinkText = textcmdLink(2, participantPeer->name);
auto text = tr::lng_admin_log_muted_participant( auto text = tr::lng_admin_log_muted_participant(
tr::now, tr::now,
lt_from, lt_from,
fromLinkText, fromLinkText,
lt_user, lt_user,
userLinkText); participantPeerLinkText);
addServiceMessageWithLink(text, userLink); addServiceMessageWithLink(text, participantPeerLink);
}; };
auto createParticipantUnmute = [&](const MTPDchannelAdminLogEventActionParticipantUnmute &data) { auto createParticipantUnmute = [&](const MTPDchannelAdminLogEventActionParticipantUnmute &data) {
const auto user = groupCallParticipantUser(data.vparticipant()); const auto participantPeer = groupCallParticipantPeer(data.vparticipant());
const auto userLink = user->createOpenLink(); const auto participantPeerLink = participantPeer->createOpenLink();
const auto userLinkText = textcmdLink(2, user->name); const auto participantPeerLinkText = textcmdLink(2, participantPeer->name);
auto text = tr::lng_admin_log_unmuted_participant( auto text = tr::lng_admin_log_unmuted_participant(
tr::now, tr::now,
lt_from, lt_from,
fromLinkText, fromLinkText,
lt_user, lt_user,
userLinkText); participantPeerLinkText);
addServiceMessageWithLink(text, userLink); addServiceMessageWithLink(text, participantPeerLink);
}; };
auto createToggleGroupCallSetting = [&](const MTPDchannelAdminLogEventActionToggleGroupCallSetting &data) { auto createToggleGroupCallSetting = [&](const MTPDchannelAdminLogEventActionToggleGroupCallSetting &data) {
@ -1069,9 +1069,9 @@ void GenerateItems(
}; };
auto createParticipantVolume = [&](const MTPDchannelAdminLogEventActionParticipantVolume &data) { auto createParticipantVolume = [&](const MTPDchannelAdminLogEventActionParticipantVolume &data) {
const auto user = groupCallParticipantUser(data.vparticipant()); const auto participantPeer = groupCallParticipantPeer(data.vparticipant());
const auto userLink = user->createOpenLink(); const auto participantPeerLink = participantPeer->createOpenLink();
const auto userLinkText = textcmdLink(2, user->name); const auto participantPeerLinkText = textcmdLink(2, participantPeer->name);
const auto volume = data.vparticipant().match([&]( const auto volume = data.vparticipant().match([&](
const MTPDgroupCallParticipant &data) { const MTPDgroupCallParticipant &data) {
return data.vvolume().value_or(10000); return data.vvolume().value_or(10000);
@ -1082,10 +1082,10 @@ void GenerateItems(
lt_from, lt_from,
fromLinkText, fromLinkText,
lt_user, lt_user,
userLinkText, participantPeerLinkText,
lt_percent, lt_percent,
volumeText); volumeText);
addServiceMessageWithLink(text, userLink); addServiceMessageWithLink(text, participantPeerLink);
}; };
auto createChangeHistoryTTL = [&](const MTPDchannelAdminLogEventActionChangeHistoryTTL &data) { auto createChangeHistoryTTL = [&](const MTPDchannelAdminLogEventActionChangeHistoryTTL &data) {

View file

@ -99,7 +99,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
for (const auto &participant : call->participants()) { for (const auto &participant : call->participants()) {
const auto alreadyInList = ranges::contains( const auto alreadyInList = ranges::contains(
state->userpics, state->userpics,
participant.user, participant.peer,
&UserpicInRow::peer); &UserpicInRow::peer);
if (alreadyInList) { if (alreadyInList) {
continue; continue;
@ -120,7 +120,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
for (auto i = 0; i != kLimit - already; ++i) { for (auto i = 0; i != kLimit - already; ++i) {
if (adding[i]) { if (adding[i]) {
state->userpics.push_back(UserpicInRow{ state->userpics.push_back(UserpicInRow{
.peer = adding[i]->user, .peer = adding[i]->peer,
.speaking = adding[i]->speaking, .speaking = adding[i]->speaking,
}); });
} }
@ -163,11 +163,11 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
static const auto RemoveUserpic = []( static const auto RemoveUserpic = [](
not_null<State*> state, not_null<State*> state,
not_null<Data::GroupCall*> call, not_null<Data::GroupCall*> call,
not_null<UserData*> user, not_null<PeerData*> participantPeer,
int userpicSize) { int userpicSize) {
const auto i = ranges::find( const auto i = ranges::find(
state->userpics, state->userpics,
user, participantPeer,
&UserpicInRow::peer); &UserpicInRow::peer);
if (i == state->userpics.end()) { if (i == state->userpics.end()) {
return false; return false;
@ -180,7 +180,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
static const auto CheckPushToFront = []( static const auto CheckPushToFront = [](
not_null<State*> state, not_null<State*> state,
not_null<Data::GroupCall*> call, not_null<Data::GroupCall*> call,
not_null<UserData*> user, not_null<PeerData*> participantPeer,
int userpicSize) { int userpicSize) {
Expects(state->userpics.size() <= kLimit); Expects(state->userpics.size() <= kLimit);
@ -189,7 +189,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
// Find where to put a new speaking userpic. // Find where to put a new speaking userpic.
for (; i != end(state->userpics); ++i) { for (; i != end(state->userpics); ++i) {
if (i->peer == user) { if (i->peer == participantPeer) {
if (i->speaking) { if (i->speaking) {
return false; return false;
} }
@ -199,8 +199,8 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
} }
const auto j = ranges::find( const auto j = ranges::find(
participants, participants,
not_null{ static_cast<UserData*>(i->peer.get()) }, i->peer,
&Data::GroupCall::Participant::user); &Data::GroupCall::Participant::peer);
if (j == end(participants) || !j->speaking) { if (j == end(participants) || !j->speaking) {
// Found a non-speaking one, put the new speaking one here. // Found a non-speaking one, put the new speaking one here.
break; break;
@ -213,13 +213,13 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
// Add the new speaking to the place we found. // Add the new speaking to the place we found.
const auto added = state->userpics.insert(i, UserpicInRow{ const auto added = state->userpics.insert(i, UserpicInRow{
.peer = user, .peer = participantPeer,
.speaking = true, .speaking = true,
}); });
// Remove him from the tail, if he was there. // Remove him from the tail, if he was there.
for (auto i = added + 1; i != state->userpics.end(); ++i) { for (auto i = added + 1; i != state->userpics.end(); ++i) {
if (i->peer == user) { if (i->peer == participantPeer) {
state->userpics.erase(i); state->userpics.erase(i);
break; break;
} }
@ -230,8 +230,8 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
for (auto i = state->userpics.end() - 1; i != added; --i) { for (auto i = state->userpics.end() - 1; i != added; --i) {
const auto j = ranges::find( const auto j = ranges::find(
participants, participants,
not_null{ static_cast<UserData*>(i->peer.get()) }, i->peer,
&Data::GroupCall::Participant::user); &Data::GroupCall::Participant::peer);
if (j == end(participants) || !j->speaking) { if (j == end(participants) || !j->speaking) {
// Found a non-speaking one, remove. // Found a non-speaking one, remove.
state->userpics.erase(i); state->userpics.erase(i);
@ -263,14 +263,26 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
using ParticipantUpdate = Data::GroupCall::ParticipantUpdate; using ParticipantUpdate = Data::GroupCall::ParticipantUpdate;
call->participantUpdated( call->participantUpdated(
) | rpl::start_with_next([=](const ParticipantUpdate &update) { ) | 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 (!update.now) {
if (RemoveUserpic(state, call, user, userpicSize)) { const auto removed = RemoveUserpic(
state,
call,
participantPeer,
userpicSize);
if (removed) {
pushNext(); pushNext();
} }
} else if (update.now->speaking } else if (update.now->speaking
&& (!update.was || !update.was->speaking)) { && (!update.was || !update.was->speaking)) {
if (CheckPushToFront(state, call, user, userpicSize)) { const auto pushed = CheckPushToFront(
state,
call,
participantPeer,
userpicSize);
if (pushed) {
pushNext(); pushNext();
} }
} else { } else {
@ -279,7 +291,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
if (updateSpeakingState) { if (updateSpeakingState) {
const auto i = ranges::find( const auto i = ranges::find(
state->userpics, state->userpics,
user, participantPeer,
&UserpicInRow::peer); &UserpicInRow::peer);
if (i != end(state->userpics)) { if (i != end(state->userpics)) {
const auto index = i - begin(state->userpics); const auto index = i - begin(state->userpics);

View file

@ -166,6 +166,13 @@ StorageFileLocation::StorageFileLocation(
}); });
_volumeId = data.vvolume_id().v; _volumeId = data.vvolume_id().v;
_localId = data.vlocal_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_long(_volumeId),
MTP_int(_localId)); 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."); Unexpected("Type in StorageFileLocation::tl.");
} }
@ -358,6 +370,9 @@ bool StorageFileLocation::valid() const {
case Type::PeerPhoto: case Type::PeerPhoto:
case Type::StickerSetThumb: case Type::StickerSetThumb:
return (_dcId != 0) && (_id != 0); return (_dcId != 0) && (_id != 0);
case Type::GroupCallStream:
return (_dcId != 0) && (_id != 0) && (_localId != 0);
} }
return false; return false;
} }
@ -401,6 +416,11 @@ Storage::Cache::Key StorageFileLocation::cacheKey() const {
case Type::Takeout: case Type::Takeout:
return Key{ shifted, 0 }; return Key{ shifted, 0 };
case Type::GroupCallStream:
return Key{
shifted | sliced | (uint64(uint32(_localId)) << 16),
_id };
} }
return Key(); return Key();
} }
@ -443,6 +463,7 @@ Storage::Cache::Key StorageFileLocation::bigFileBaseCacheKey() const {
case Type::Encrypted: case Type::Encrypted:
case Type::Secure: case Type::Secure:
case Type::Takeout: case Type::Takeout:
case Type::GroupCallStream:
Unexpected("Not implemented file location type."); Unexpected("Not implemented file location type.");
}; };
@ -522,6 +543,11 @@ bool operator==(const StorageFileLocation &a, const StorageFileLocation &b) {
&& (a._volumeId == b._volumeId) && (a._volumeId == b._volumeId)
&& (a._localId == b._localId) && (a._localId == b._localId)
&& (a._id == b._id); && (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==."); Unexpected("Type in StorageFileLocation::operator==.");
} }
@ -573,6 +599,10 @@ bool operator<(const StorageFileLocation &a, const StorageFileLocation &b) {
case Type::StickerSetThumb: case Type::StickerSetThumb:
return std::tie(a._id, a._localId, a._volumeId, a._dcId) return std::tie(a._id, a._localId, a._volumeId, a._dcId)
< std::tie(b._id, b._localId, b._volumeId, b._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==."); Unexpected("Type in StorageFileLocation::operator==.");
} }

View file

@ -59,6 +59,7 @@ public:
Photo = 0x05, Photo = 0x05,
PeerPhoto = 0x06, PeerPhoto = 0x06,
StickerSetThumb = 0x07, StickerSetThumb = 0x07,
GroupCallStream = 0x08,
}; };
StorageFileLocation() = default; StorageFileLocation() = default;