Support distinct calling/invited states.

This commit is contained in:
John Preston 2025-04-06 17:21:24 +04:00
parent 55c05d1a6e
commit b036bedbc3
16 changed files with 221 additions and 105 deletions

View file

@ -4762,6 +4762,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_invite" = "Invite Members";
"lng_group_call_invite_conf" = "Add People";
"lng_group_call_invited_status" = "invited";
"lng_group_call_calling_status" = "calling...";
"lng_group_call_blockchain_only_status" = "listening";
"lng_group_call_muted_by_me_status" = "muted for you";
"lng_group_call_invite_title" = "Invite members";

View file

@ -893,6 +893,8 @@ groupCallMemberColoredCrossLine: CrossLineAnimation(groupCallMemberInactiveCross
fg: groupCallMemberMutedIcon;
icon: icon {{ "calls/group_calls_unmuted", groupCallMemberActiveIcon }};
}
groupCallMemberCalling: icon {{ "calls/call_answer", groupCallMemberInactiveIcon }};
groupCallMemberCallingPosition: point(0px, 8px);
groupCallMemberInvited: icon {{ "calls/group_calls_invited", groupCallMemberInactiveIcon }};
groupCallMemberInvitedPosition: point(2px, 12px);
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 }};
groupCallNarrowScreenIcon: icon {{ "calls/video_mini_screencast", groupCallMemberNotJoinedStatus }};
groupCallNarrowInvitedIcon: icon {{ "calls/video_mini_invited", groupCallMemberNotJoinedStatus }};
groupCallNarrowCallingIcon: icon {{ "calls/video_mini_invited", groupCallMemberNotJoinedStatus }};
groupCallNarrowIconPosition: point(-4px, 2px);
groupCallNarrowIconSkip: 15px;
groupCallOutline: 2px;

View file

@ -1542,7 +1542,8 @@ void Call::finish(
_user->owner().registerInvitedToCallUser(
migrateCall->id(),
migrateCall,
_user);
_user,
true);
}
const auto session = &_user->session();
const auto weak = base::make_weak(this);

View file

@ -930,7 +930,8 @@ void Instance::unregisterConferenceInvite(
CallId conferenceId,
not_null<UserData*> user,
MsgId messageId,
bool incoming) {
bool incoming,
bool onlyStopCalling) {
const auto i = _conferenceInvites.find(conferenceId);
if (i == end(_conferenceInvites)) {
return;
@ -940,9 +941,14 @@ void Instance::unregisterConferenceInvite(
return;
}
auto &info = j->second;
(incoming ? info.incoming : info.outgoing).remove(messageId);
if (!(incoming ? info.incoming : info.outgoing).remove(messageId)) {
return;
}
if (!incoming) {
user->owner().unregisterInvitedToCallUser(conferenceId, user);
user->owner().unregisterInvitedToCallUser(
conferenceId,
user,
onlyStopCalling);
}
if (info.incoming.empty() && info.outgoing.empty()) {
i->second.users.erase(j);
@ -1010,6 +1016,11 @@ void Instance::declineOutgoingConferenceInvite(
user->owner().history(user),
std::move(inputs),
true);
for (const auto &messageId : ids) {
if (const auto item = user->owner().message(user, messageId)) {
item->destroy();
}
}
}
if (!j->second.incoming.empty()) {
return;
@ -1018,7 +1029,7 @@ void Instance::declineOutgoingConferenceInvite(
if (i->second.users.empty()) {
_conferenceInvites.erase(i);
}
user->owner().unregisterInvitedToCallUser(conferenceId, user);
user->owner().unregisterInvitedToCallUser(conferenceId, user, !discard);
}
void Instance::showConferenceInvite(

View file

@ -131,7 +131,8 @@ public:
CallId conferenceId,
not_null<UserData*> user,
MsgId messageId,
bool incoming);
bool incoming,
bool onlyStopCalling = false);
void showConferenceInvite(
not_null<UserData*> user,
MsgId conferenceInviteMsgId);

View file

@ -1623,6 +1623,9 @@ void GroupCall::sendJoinRequest() {
if (const auto once = base::take(_migratedConferenceInfo)) {
processMigration(*once);
}
for (const auto &callback : base::take(_rejoinedCallbacks)) {
callback();
}
}).fail([=](const MTP::Error &error) {
const auto type = error.type();
if (_e2e) {
@ -3775,6 +3778,45 @@ void GroupCall::editParticipant(
}).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(
const std::vector<InviteRequest> &requests,
Fn<void(InviteResult)> done) {
@ -3802,32 +3844,9 @@ void GroupCall::inviteUsers(
if (const auto call = _conferenceCall.get()) {
for (const auto &request : requests) {
using Flag = MTPphone_InviteConferenceCallParticipant::Flag;
const auto user = request.user;
_api.request(MTPphone_InviteConferenceCallParticipant(
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();
inviteToConference(request, [=] {
return &state->result;
}, finishRequest);
++state->requests;
}
return;
@ -3857,7 +3876,7 @@ void GroupCall::inviteUsers(
};
for (const auto &request : requests) {
const auto user = request.user;
owner->registerInvitedToCallUser(_id, _peer, user);
owner->registerInvitedToCallUser(_id, _peer, user, false);
usersSlice.push_back(user);
slice.push_back(user->inputUser);
if (slice.size() == kMaxInvitePerSlice) {

View file

@ -625,6 +625,10 @@ private:
void markTrackShown(const VideoEndpoint &endpoint, bool shown);
void processMigration(StartConferenceInfo conference);
void inviteToConference(
InviteRequest request,
Fn<not_null<InviteResult*>()> resultAddress,
Fn<void()> finishRequest);
[[nodiscard]] int activeVideoSendersCount() const;
@ -645,6 +649,7 @@ private:
rpl::variable<State> _state = State::Creating;
base::flat_set<uint32> _unresolvedSsrcs;
rpl::event_stream<Error> _errors;
std::vector<Fn<void()>> _rejoinedCallbacks;
bool _recordingStoppedByMe = false;
bool _requestedVideoChannelsUpdateScheduled = false;

View file

@ -477,15 +477,23 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
return nullptr;
}
const auto peer = call->peer();
const auto conference = call->conference();
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()) {
if (const auto user = participant.peer->asUser()) {
alreadyIn.emplace(user);
}
}
alreadyIn.emplace(peer->session().user());
if (call->conference()) {
for (const auto &[user, calling] : invited) {
if (!conference || calling) {
alreadyIn.emplace(user);
}
}
if (conference) {
const auto close = std::make_shared<Fn<void()>>();
const auto shareLink = [=] {
Assert(shareConferenceLink != nullptr);

View file

@ -108,7 +108,8 @@ private:
[[nodiscard]] std::unique_ptr<Row> createRow(
const Data::GroupCallParticipant &participant);
[[nodiscard]] std::unique_ptr<Row> createInvitedRow(
not_null<PeerData*> participantPeer);
not_null<PeerData*> participantPeer,
bool calling);
[[nodiscard]] std::unique_ptr<Row> createWithAccessRow(
not_null<PeerData*> participantPeer);
@ -494,8 +495,9 @@ void Members::Controller::toggleVideoEndpointActive(
bool Members::Controller::appendInvitedUsers() {
auto changed = false;
if (const auto id = _call->id()) {
for (const auto &user : _peer->owner().invitedToCallUsers(id)) {
if (auto row = createInvitedRow(user)) {
const auto &invited = _peer->owner().invitedToCallUsers(id);
for (const auto &[user, calling] : invited) {
if (auto row = createInvitedRow(user, calling)) {
delegate()->peerListAppendRow(std::move(row));
changed = true;
}
@ -514,14 +516,16 @@ void Members::Controller::setupInvitedUsers() {
) | rpl::filter([=](const Invite &invite) {
return (invite.id == _call->id());
}) | rpl::start_with_next([=](const Invite &invite) {
const auto user = invite.user;
if (invite.removed) {
if (const auto row = findRow(invite.user)) {
if (row->state() == Row::State::Invited) {
if (const auto row = findRow(user)) {
if (row->state() == Row::State::Invited
|| row->state() == Row::State::Calling) {
delegate()->peerListRemoveRow(row);
delegate()->peerListRefreshRows();
}
}
} else if (auto row = createInvitedRow(invite.user)) {
} else if (auto row = createInvitedRow(user, invite.calling)) {
delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows();
}
@ -571,7 +575,8 @@ void Members::Controller::setupWithAccessUsers() {
if (const auto count = delegate()->peerListFullRowsCount()) {
const auto last = delegate()->peerListRowAt(count - 1);
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;
}
}
@ -584,7 +589,8 @@ void Members::Controller::setupWithAccessUsers() {
if (partition) {
delegate()->peerListPartitionRows([](const PeerListRow &row) {
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();
@ -599,6 +605,7 @@ void Members::Controller::updateRow(
auto addedToBottom = (Row*)nullptr;
if (const auto row = findRow(now.peer)) {
if (row->state() == Row::State::Invited
|| row->state() == Row::State::Calling
|| row->state() == Row::State::WithAccess) {
reorderIfNonRealBefore = row->absoluteIndex();
}
@ -631,7 +638,9 @@ void Members::Controller::updateRow(
reorderIfNonRealBefore - 1).get();
using State = 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) {
partitionRows();
@ -666,12 +675,15 @@ void Members::Controller::partitionRows() {
if (state == State::WithAccess) {
hadWithAccess = true;
}
return (state != State::Invited) && (state != State::WithAccess);
return (state != State::Invited)
&& (state != State::Calling)
&& (state != State::WithAccess);
});
if (hadWithAccess) {
delegate()->peerListPartitionRows([](const PeerListRow &row) {
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) {
row->updateStateWithAccess();
} else {
row->updateStateInvited();
row->updateStateInvited(noParticipantState == Row::State::Calling);
}
const auto wasNoSounding = _soundingRowBySsrc.empty();
@ -1093,15 +1105,21 @@ void Members::Controller::rowPaintIcon(
return;
}
const auto narrow = (state.style == MembersRowStyle::Narrow);
if (state.invited) {
if (state.invited || state.calling) {
if (narrow) {
st::groupCallNarrowInvitedIcon.paintInCenter(p, rect);
(state.invited
? st::groupCallNarrowInvitedIcon
: st::groupCallNarrowCallingIcon).paintInCenter(p, rect);
} 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,
QRect(
rect.topLeft() + st::groupCallMemberInvitedPosition,
st::groupCallMemberInvited.size()));
QRect(rect.topLeft() + shift, icon.size()));
}
return;
}
@ -1464,9 +1482,10 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
}
} else {
const auto conference = _call->conferenceCall().get();
if (muteState == Row::State::Invited
if (conference
&& participantPeer->isUser()
&& conference) {
&& (muteState == Row::State::Invited
|| muteState == Row::State::Calling)) {
const auto id = conference->id();
const auto cancelInvite = [=](bool discard) {
Core::App().calls().declineOutgoingConferenceInvite(
@ -1474,9 +1493,11 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
participantPeer->asUser(),
discard);
};
result->addAction(
tr::lng_group_call_context_stop_ringing(tr::now),
[=] { cancelInvite(false); });
if (muteState == Row::State::Calling) {
result->addAction(
tr::lng_group_call_context_stop_ringing(tr::now),
[=] { cancelInvite(false); });
}
result->addAction(
tr::lng_group_call_context_cancel_invite(tr::now),
[=] { cancelInvite(true); });
@ -1497,6 +1518,7 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
const auto canKick = [&] {
const auto user = participantPeer->asUser();
if (muteState == Row::State::Invited
|| muteState == Row::State::Calling
|| muteState == Row::State::WithAccess) {
return false;
} else if (const auto chat = _peer->asChat()) {
@ -1626,6 +1648,7 @@ void Members::Controller::addMuteActionsToContextMenu(
const auto muteAction = [&]() -> QAction* {
if (muteState == Row::State::Invited
|| muteState == Row::State::Calling
|| muteState == Row::State::WithAccess
|| _call->rtmp()
|| isMe(participantPeer)
@ -1681,12 +1704,19 @@ std::unique_ptr<Row> Members::Controller::createRow(
}
std::unique_ptr<Row> Members::Controller::createInvitedRow(
not_null<PeerData*> participantPeer) {
if (findRow(participantPeer)) {
not_null<PeerData*> 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;
}
const auto state = calling ? Row::State::Calling : Row::State::Invited;
auto result = std::make_unique<Row>(this, participantPeer);
updateRow(result.get(), std::nullopt, nullptr);
updateRow(result.get(), std::nullopt, nullptr, state);
return result;
}

View file

@ -138,9 +138,9 @@ void MembersRow::setSkipLevelUpdate(bool value) {
_skipLevelUpdate = value;
}
void MembersRow::updateStateInvited() {
void MembersRow::updateStateInvited(bool calling) {
setVolume(Group::kDefaultVolume);
setState(State::Invited);
setState(calling ? State::Calling : State::Invited);
setSounding(false);
setSpeaking(false);
_mutedByMe = false;
@ -640,11 +640,13 @@ void MembersRow::paintComplexStatusText(
const auto useAbout = !_about.isEmpty()
&& (_state != State::WithAccess)
&& (_state != State::Invited)
&& (_state != State::Calling)
&& (style != MembersRowStyle::Video)
&& ((_state == State::RaisedHand && !_raisedHandStatus)
|| (_state != State::RaisedHand && !_speaking));
if (!useAbout
&& _state != State::Invited
&& _state != State::Calling
&& _state != State::WithAccess
&& !_mutedByMe) {
paintStatusIcon(p, x, y, st, font, selected, narrowMode);
@ -693,6 +695,8 @@ void MembersRow::paintComplexStatusText(
? tr::lng_status_connecting(tr::now)
: (_state == State::WithAccess)
? 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)));
}
}
@ -706,6 +710,7 @@ QSize MembersRow::rightActionSize() const {
bool MembersRow::rightActionDisabled() const {
return _delegate->rowIsMe(peer())
|| (_state == State::Invited)
|| (_state == State::Calling)
|| !_delegate->rowCanMuteMembers();
}
@ -731,7 +736,9 @@ void MembersRow::rightActionPaint(
size.width(),
size.height(),
outerWidth);
if (_state == State::Invited) {
if (_state == State::Invited
|| _state == State::Calling
|| _state == State::WithAccess) {
_actionRipple = nullptr;
}
if (_actionRipple) {
@ -761,6 +768,7 @@ MembersRowDelegate::IconState MembersRow::computeIconState(
.mutedByMe = _mutedByMe,
.raisedHand = (_state == State::RaisedHand),
.invited = (_state == State::Invited),
.calling = (_state == State::Calling),
.style = style,
};
}

View file

@ -24,7 +24,7 @@ struct PeerUserpicView;
namespace Calls::Group {
enum class MembersRowStyle {
enum class MembersRowStyle : uchar {
Default,
Narrow,
Video,
@ -40,6 +40,7 @@ public:
bool mutedByMe = false;
bool raisedHand = false;
bool invited = false;
bool calling = false;
MembersRowStyle style = MembersRowStyle::Default;
};
virtual bool rowIsMe(not_null<PeerData*> participantPeer) = 0;
@ -75,13 +76,14 @@ public:
Muted,
RaisedHand,
Invited,
Calling,
WithAccess,
};
void setAbout(const QString &about);
void setSkipLevelUpdate(bool value);
void updateState(const Data::GroupCallParticipant &participant);
void updateStateInvited();
void updateStateInvited(bool calling);
void updateStateWithAccess();
void updateLevel(float level);
void updateBlobAnimation(crl::time now);

View file

@ -791,7 +791,10 @@ void GroupCall::applyParticipantsSlice(
}
if (adding) {
if (const auto user = participantPeer->asUser()) {
_peer->owner().unregisterInvitedToCallUser(_id, user);
_peer->owner().unregisterInvitedToCallUser(
_id,
user,
false);
}
}
});

View file

@ -1701,13 +1701,11 @@ MediaCall::MediaCall(not_null<HistoryItem*> parent, const Call &call)
const auto peer = parent->history()->peer;
peer->owner().registerCallItem(parent);
if (const auto user = _call.conferenceId ? peer->asUser() : nullptr) {
if (_call.state == CallState::Invitation) {
Core::App().calls().registerConferenceInvite(
_call.conferenceId,
user,
parent->id,
!parent->out());
}
Core::App().calls().registerConferenceInvite(
_call.conferenceId,
user,
parent->id,
!parent->out());
}
}
@ -1716,13 +1714,11 @@ MediaCall::~MediaCall() {
const auto peer = parent->history()->peer;
peer->owner().unregisterCallItem(parent);
if (const auto user = _call.conferenceId ? peer->asUser() : nullptr) {
if (_call.state == CallState::Invitation) {
Core::App().calls().unregisterConferenceInvite(
_call.conferenceId,
user,
parent->id,
!parent->out());
}
Core::App().calls().unregisterConferenceInvite(
_call.conferenceId,
user,
parent->id,
!parent->out());
}
}

View file

@ -1219,8 +1219,8 @@ void Session::checkLocalUsersWentOffline() {
}
auto Session::invitedToCallUsers(CallId callId) const
-> const base::flat_set<not_null<UserData*>> & {
static const base::flat_set<not_null<UserData*>> kEmpty;
-> const base::flat_map<not_null<UserData*>, bool> & {
static const base::flat_map<not_null<UserData*>, bool> kEmpty;
const auto i = _invitedToCallUsers.find(callId);
return (i != _invitedToCallUsers.end()) ? i->second : kEmpty;
}
@ -1228,14 +1228,16 @@ auto Session::invitedToCallUsers(CallId callId) const
void Session::registerInvitedToCallUser(
CallId callId,
not_null<PeerData*> peer,
not_null<UserData*> user) {
registerInvitedToCallUser(callId, peer->groupCall(), user);
not_null<UserData*> user,
bool calling) {
registerInvitedToCallUser(callId, peer->groupCall(), user, calling);
}
void Session::registerInvitedToCallUser(
CallId callId,
GroupCall *call,
not_null<UserData*> user) {
not_null<UserData*> user,
bool calling) {
if (call && call->id() == callId) {
const auto inCall = ranges::contains(
call->participants(),
@ -1245,19 +1247,32 @@ void Session::registerInvitedToCallUser(
return;
}
}
_invitedToCallUsers[callId].emplace(user);
_invitesToCalls.fire({ callId, user });
_invitedToCallUsers[callId][user] = calling;
_invitesToCalls.fire({ callId, user, calling });
}
void Session::unregisterInvitedToCallUser(
CallId callId,
not_null<UserData*> user) {
not_null<UserData*> user,
bool onlyStopCalling) {
const auto i = _invitedToCallUsers.find(callId);
if (i != _invitedToCallUsers.end()) {
i->second.remove(user);
if (i->second.empty()) {
_invitedToCallUsers.erase(i);
_invitesToCalls.fire({ callId, user, true });
const auto j = i->second.find(user);
if (j != end(i->second)) {
if (onlyStopCalling) {
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 });
}
}
}

View file

@ -240,22 +240,26 @@ public:
void maybeStopWatchForOffline(not_null<UserData*> user);
[[nodiscard]] auto invitedToCallUsers(CallId callId) const
-> const base::flat_set<not_null<UserData*>> &;
-> const base::flat_map<not_null<UserData*>, bool> &;
void registerInvitedToCallUser(
CallId callId,
not_null<PeerData*> peer,
not_null<UserData*> user);
not_null<UserData*> user,
bool calling);
void registerInvitedToCallUser(
CallId callId,
GroupCall *call,
not_null<UserData*> user);
not_null<UserData*> user,
bool calling);
void unregisterInvitedToCallUser(
CallId callId,
not_null<UserData*> user);
not_null<UserData*> user,
bool onlyStopCalling);
struct InviteToCall {
CallId id = 0;
not_null<UserData*> user;
bool calling = false;
bool removed = false;
};
[[nodiscard]] rpl::producer<InviteToCall> invitesToCalls() const {
@ -1112,7 +1116,7 @@ private:
rpl::event_stream<InviteToCall> _invitesToCalls;
base::flat_map<
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_map<

View file

@ -1902,12 +1902,21 @@ void HistoryItem::applyEdition(const MTPDmessageService &message) {
_flags &= ~MessageFlag::DisplayFromChecked;
} else if (message.vaction().type() == mtpc_messageActionConferenceCall) {
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 = std::make_unique<Data::MediaCall>(
this,
Data::ComputeCallData(
&history()->owner(),
message.vaction().c_messageActionConferenceCall()));
_media = std::make_unique<Data::MediaCall>(this, info);
addToSharedMediaIndex();
finishEdition(-1);
_flags &= ~MessageFlag::DisplayFromChecked;
@ -4896,7 +4905,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
for (const auto &id : action.vusers().v) {
const auto user = owner->user(id.v);
if (callId) {
owner->registerInvitedToCallUser(callId, peer, user);
owner->registerInvitedToCallUser(callId, peer, user, false);
}
};
const auto linkCallId = PeerHasThisCall(peer, callId).value_or(false)