mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 07:07:08 +02:00
Update API scheme to layer 125.
This commit is contained in:
parent
2734cab3f2
commit
02517f7221
16 changed files with 331 additions and 231 deletions
Telegram
Resources/tl
SourceFiles
boxes
calls
calls_group_call.cppcalls_group_call.hcalls_group_common.hcalls_group_members.cppcalls_group_members.hcalls_group_panel.cpp
data
export
history
ui/image
|
@ -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<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;
|
||||
|
||||
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;
|
||||
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;
|
||||
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#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;
|
||||
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;
|
||||
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<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;
|
||||
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.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<string> = Vector<EmojiLanguage>;
|
||||
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
|
||||
messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
|
||||
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<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.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<InputUser> =
|
|||
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<InputUser> 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<InputUser> = 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<int> sources:Vector<int> 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<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.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
|
||||
|
||||
// LAYER 124
|
||||
// LAYER 125
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -57,18 +57,18 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
|
|||
}
|
||||
|
||||
[[nodiscard]] const Data::GroupCall::Participant *LookupParticipant(
|
||||
not_null<PeerData*> chat,
|
||||
not_null<PeerData*> peer,
|
||||
uint64 id,
|
||||
not_null<UserData*> user) {
|
||||
const auto call = chat->groupCall();
|
||||
not_null<PeerData*> 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<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()) {
|
||||
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<int32>())
|
||||
)).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<UserData*> user,
|
||||
not_null<PeerData*> participantPeer,
|
||||
bool mute,
|
||||
std::optional<int> 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<UserData*> user,
|
||||
not_null<PeerData*> participantPeer,
|
||||
bool mute,
|
||||
std::optional<int> 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<int, not_null<UserData*>> GroupCall::inviteUsers(
|
|||
return !invited.contains(user) && !ranges::contains(
|
||||
participants,
|
||||
user,
|
||||
&Data::GroupCall::Participant::user);
|
||||
&Data::GroupCall::Participant::peer);
|
||||
});
|
||||
|
||||
auto count = 0;
|
||||
|
|
|
@ -56,7 +56,7 @@ enum class MuteState {
|
|||
|
||||
[[nodiscard]] bool IsGroupCallAdmin(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<UserData*> user);
|
||||
not_null<PeerData*> participantPeer);
|
||||
|
||||
struct LevelUpdate {
|
||||
uint32 ssrc = 0;
|
||||
|
@ -194,11 +194,11 @@ private:
|
|||
void playConnectingSoundOnce();
|
||||
|
||||
void editParticipant(
|
||||
not_null<UserData*> user,
|
||||
not_null<PeerData*> participantPeer,
|
||||
bool mute,
|
||||
std::optional<int> volume);
|
||||
void applyParticipantLocally(
|
||||
not_null<UserData*> user,
|
||||
not_null<PeerData*> participantPeer,
|
||||
bool mute,
|
||||
std::optional<int> volume);
|
||||
|
||||
|
|
|
@ -15,20 +15,20 @@ constexpr auto kDefaultVolume = 10000;
|
|||
constexpr auto kMaxVolume = 20000;
|
||||
|
||||
struct MuteRequest {
|
||||
not_null<UserData*> user;
|
||||
not_null<PeerData*> peer;
|
||||
bool mute = false;
|
||||
bool locallyOnly = false;
|
||||
};
|
||||
|
||||
struct VolumeRequest {
|
||||
not_null<UserData*> user;
|
||||
not_null<PeerData*> peer;
|
||||
int volume = kDefaultVolume;
|
||||
bool finalized = true;
|
||||
bool locallyOnly = false;
|
||||
};
|
||||
|
||||
struct ParticipantState {
|
||||
not_null<UserData*> user;
|
||||
not_null<PeerData*> peer;
|
||||
std::optional<int> volume;
|
||||
bool mutedByMe = false;
|
||||
bool locallyOnly = false;
|
||||
|
|
|
@ -91,7 +91,9 @@ public:
|
|||
|
||||
class Row final : public PeerListRow {
|
||||
public:
|
||||
Row(not_null<RowDelegate*> delegate, not_null<UserData*> user);
|
||||
Row(
|
||||
not_null<RowDelegate*> delegate,
|
||||
not_null<PeerData*> participantPeer);
|
||||
|
||||
enum class State {
|
||||
Active,
|
||||
|
@ -266,8 +268,8 @@ public:
|
|||
}
|
||||
[[nodiscard]] rpl::producer<MuteRequest> toggleMuteRequests() const;
|
||||
[[nodiscard]] rpl::producer<VolumeRequest> changeVolumeRequests() const;
|
||||
[[nodiscard]] auto kickMemberRequests() const
|
||||
-> rpl::producer<not_null<UserData*>>;
|
||||
[[nodiscard]] auto kickParticipantRequests() const
|
||||
-> rpl::producer<not_null<PeerData*>>;
|
||||
|
||||
bool rowCanMuteMembers() override;
|
||||
void rowUpdateRow(not_null<Row*> row) override;
|
||||
|
@ -284,7 +286,7 @@ private:
|
|||
[[nodiscard]] std::unique_ptr<Row> createRow(
|
||||
const Data::GroupCall::Participant &participant);
|
||||
[[nodiscard]] std::unique_ptr<Row> createInvitedRow(
|
||||
not_null<UserData*> user);
|
||||
not_null<PeerData*> participantPeer);
|
||||
|
||||
void prepareRows(not_null<Data::GroupCall*> real);
|
||||
//void repaintByTimer();
|
||||
|
@ -294,8 +296,8 @@ private:
|
|||
not_null<PeerListRow*> row);
|
||||
void addMuteActionsToContextMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<UserData*> user,
|
||||
bool userIsCallAdmin,
|
||||
not_null<PeerData*> participantPeer,
|
||||
bool participantIsCallAdmin,
|
||||
not_null<Row*> row);
|
||||
void setupListChangeViewers(not_null<GroupCall*> call);
|
||||
void subscribeToChanges(not_null<Data::GroupCall*> real);
|
||||
|
@ -308,7 +310,7 @@ private:
|
|||
void removeRow(not_null<Row*> row);
|
||||
void updateRowLevel(not_null<Row*> row, float level);
|
||||
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;
|
||||
void appendInvitedUsers();
|
||||
|
@ -323,7 +325,7 @@ private:
|
|||
|
||||
rpl::event_stream<MuteRequest> _toggleMuteRequests;
|
||||
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> _fullCountMin = 0;
|
||||
rpl::variable<int> _fullCountMax = std::numeric_limits<int>::max();
|
||||
|
@ -345,8 +347,10 @@ private:
|
|||
|
||||
};
|
||||
|
||||
Row::Row(not_null<RowDelegate*> delegate, not_null<UserData*> user)
|
||||
: PeerListRow(user)
|
||||
Row::Row(
|
||||
not_null<RowDelegate*> delegate,
|
||||
not_null<PeerData*> participantPeer)
|
||||
: PeerListRow(participantPeer)
|
||||
, _delegate(delegate) {
|
||||
refreshStatus();
|
||||
}
|
||||
|
@ -872,11 +876,13 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> 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<UserData*> user) const {
|
||||
return static_cast<Row*>(delegate()->peerListFindRow(user->id));
|
||||
Row *MembersController::findRow(not_null<PeerData*> participantPeer) const {
|
||||
return static_cast<Row*>(
|
||||
delegate()->peerListFindRow(participantPeer->id));
|
||||
}
|
||||
|
||||
Data::GroupCall *MembersController::resolvedRealCall() const {
|
||||
|
@ -1094,16 +1101,16 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> 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<Data::GroupCall*> 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<not_null<UserData*>>{
|
||||
return _kickMemberRequests.events();
|
||||
auto MembersController::kickParticipantRequests() const
|
||||
-> rpl::producer<not_null<PeerData*>>{
|
||||
return _kickParticipantRequests.events();
|
||||
}
|
||||
|
||||
void MembersController::rowClicked(not_null<PeerListRow*> row) {
|
||||
|
@ -1235,7 +1242,7 @@ void MembersController::rowClicked(not_null<PeerListRow*> 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<Ui::PopupMenu> MembersController::rowContextMenu(
|
|||
base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
|
||||
QWidget *parent,
|
||||
not_null<PeerListRow*> row) {
|
||||
Expects(row->peer()->isUser());
|
||||
|
||||
const auto participantPeer = row->peer();
|
||||
const auto real = static_cast<Row*>(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<Ui::PopupMenu>(
|
||||
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<Ui::PopupMenu> MembersController::createRowContextMenu(
|
|||
};
|
||||
const auto showProfile = [=] {
|
||||
performOnMainWindow([=](not_null<Window::SessionController*> window) {
|
||||
window->showPeerInfo(user);
|
||||
window->showPeerInfo(participantPeer);
|
||||
});
|
||||
};
|
||||
const auto showHistory = [=] {
|
||||
performOnMainWindow([=](not_null<Window::SessionController*> 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<Ui::PopupMenu> MembersController::createRowContextMenu(
|
|||
tr::lng_context_send_message(tr::now),
|
||||
showHistory);
|
||||
const auto canKick = [&] {
|
||||
const auto user = participantPeer->asUser();
|
||||
if (static_cast<Row*>(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<Ui::PopupMenu> MembersController::createRowContextMenu(
|
|||
|
||||
void MembersController::addMuteActionsToContextMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<UserData*> user,
|
||||
bool userIsCallAdmin,
|
||||
not_null<PeerData*> participantPeer,
|
||||
bool participantIsCallAdmin,
|
||||
not_null<Row*> 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<bool>() | 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<Group::ParticipantState>() | 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<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);
|
||||
updateRow(result.get(), nullptr);
|
||||
return result;
|
||||
|
@ -1494,17 +1503,17 @@ std::unique_ptr<Row> MembersController::createSelfRow() {
|
|||
|
||||
std::unique_ptr<Row> MembersController::createRow(
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Row> MembersController::createInvitedRow(
|
||||
not_null<UserData*> user) {
|
||||
if (findRow(user)) {
|
||||
not_null<PeerData*> participantPeer) {
|
||||
if (findRow(participantPeer)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = std::make_unique<Row>(this, user);
|
||||
auto result = std::make_unique<Row>(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<not_null<UserData*>> {
|
||||
auto GroupMembers::kickParticipantRequests() const
|
||||
-> rpl::producer<not_null<PeerData*>> {
|
||||
return static_cast<MembersController*>(
|
||||
_listController.get())->kickMemberRequests();
|
||||
_listController.get())->kickParticipantRequests();
|
||||
}
|
||||
|
||||
int GroupMembers::desiredHeight() const {
|
||||
|
|
|
@ -42,8 +42,8 @@ public:
|
|||
-> rpl::producer<Group::MuteRequest>;
|
||||
[[nodiscard]] auto changeVolumeRequests() const
|
||||
-> rpl::producer<Group::VolumeRequest>;
|
||||
[[nodiscard]] auto kickMemberRequests() const
|
||||
-> rpl::producer<not_null<UserData*>>;
|
||||
[[nodiscard]] auto kickParticipantRequests() const
|
||||
-> rpl::producer<not_null<PeerData*>>;
|
||||
[[nodiscard]] rpl::producer<> addMembersRequests() const {
|
||||
return _addMemberRequests.events();
|
||||
}
|
||||
|
|
|
@ -520,9 +520,11 @@ void GroupPanel::initWithCall(GroupCall *call) {
|
|||
}
|
||||
}, _callLifetime);
|
||||
|
||||
_members->kickMemberRequests(
|
||||
) | rpl::start_with_next([=](not_null<UserData*> user) {
|
||||
kickMember(user);
|
||||
_members->kickParticipantRequests(
|
||||
) | rpl::start_with_next([=](not_null<PeerData*> 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<InviteController>(
|
||||
|
|
|
@ -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<not_null<UserData*>>();
|
||||
for (auto i = begin(_speakingByActiveFinishes); i != end(_speakingByActiveFinishes);) {
|
||||
auto stop = std::vector<not_null<PeerData*>>();
|
||||
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<UserId, LastSpokeTimes>();
|
||||
auto result = base::flat_map<PeerId, LastSpokeTimes>();
|
||||
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<MTPint>();
|
||||
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<MTPint>(uidInputs),
|
||||
MTP_vector<MTPint>(ssrcInputs),
|
||||
MTP_string(QString()),
|
||||
MTP_int(kRequestPerPage)
|
||||
)).done([=](const MTPphone_GroupParticipants &result) {
|
||||
_unknownParticipantPeersRequestId = api().request(
|
||||
MTPphone_GetGroupParticipants(
|
||||
input(),
|
||||
MTP_vector<MTPint>(uidInputs),
|
||||
MTP_vector<MTPint>(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 {
|
||||
|
|
|
@ -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<PeerData*> peer);
|
||||
|
||||
struct Participant {
|
||||
not_null<UserData*> user;
|
||||
not_null<PeerData*> peer;
|
||||
TimeId date = 0;
|
||||
TimeId lastActive = 0;
|
||||
uint32 ssrc = 0;
|
||||
|
@ -57,7 +56,7 @@ public:
|
|||
-> const std::vector<Participant> &;
|
||||
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<ParticipantUpdate> 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<int> fullCountValue() const;
|
||||
|
@ -108,15 +107,15 @@ private:
|
|||
mtpRequestId _reloadRequestId = 0;
|
||||
|
||||
std::vector<Participant> _participants;
|
||||
base::flat_map<uint32, not_null<UserData*>> _userBySsrc;
|
||||
base::flat_map<not_null<UserData*>, crl::time> _speakingByActiveFinishes;
|
||||
base::flat_map<uint32, not_null<PeerData*>> _participantPeerBySsrc;
|
||||
base::flat_map<not_null<PeerData*>, crl::time> _speakingByActiveFinishes;
|
||||
base::Timer _speakingByActiveFinishTimer;
|
||||
QString _nextOffset;
|
||||
rpl::variable<int> _fullCount = 0;
|
||||
|
||||
base::flat_map<uint32, LastSpokeTimes> _unknownSpokenSsrcs;
|
||||
base::flat_map<UserId, LastSpokeTimes> _unknownSpokenUids;
|
||||
mtpRequestId _unknownUsersRequestId = 0;
|
||||
base::flat_map<PeerId, LastSpokeTimes> _unknownSpokenPeerIds;
|
||||
mtpRequestId _unknownParticipantPeersRequestId = 0;
|
||||
|
||||
rpl::event_stream<ParticipantUpdate> _participantUpdates;
|
||||
rpl::event_stream<> _participantsSliceAdded;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -99,7 +99,7 @@ rpl::producer<Ui::GroupCallBarContent> 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<Ui::GroupCallBarContent> 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<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
|||
static const auto RemoveUserpic = [](
|
||||
not_null<State*> state,
|
||||
not_null<Data::GroupCall*> call,
|
||||
not_null<UserData*> user,
|
||||
not_null<PeerData*> 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<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
|||
static const auto CheckPushToFront = [](
|
||||
not_null<State*> state,
|
||||
not_null<Data::GroupCall*> call,
|
||||
not_null<UserData*> user,
|
||||
not_null<PeerData*> participantPeer,
|
||||
int userpicSize) {
|
||||
Expects(state->userpics.size() <= kLimit);
|
||||
|
||||
|
@ -189,7 +189,7 @@ rpl::producer<Ui::GroupCallBarContent> 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<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
|||
}
|
||||
const auto j = ranges::find(
|
||||
participants,
|
||||
not_null{ static_cast<UserData*>(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<Ui::GroupCallBarContent> 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<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
|||
for (auto i = state->userpics.end() - 1; i != added; --i) {
|
||||
const auto j = ranges::find(
|
||||
participants,
|
||||
not_null{ static_cast<UserData*>(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<Ui::GroupCallBarContent> 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<Ui::GroupCallBarContent> 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);
|
||||
|
|
|
@ -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==.");
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
Photo = 0x05,
|
||||
PeerPhoto = 0x06,
|
||||
StickerSetThumb = 0x07,
|
||||
GroupCallStream = 0x08,
|
||||
};
|
||||
|
||||
StorageFileLocation() = default;
|
||||
|
|
Loading…
Add table
Reference in a new issue