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