mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Support voice chats in legacy groups, with migration.
This commit is contained in:
parent
cd3b989e70
commit
1b624d67b8
30 changed files with 584 additions and 389 deletions
|
@ -237,18 +237,16 @@ Updates::Updates(not_null<Main::Session*> session)
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
base::ObservableViewer(
|
base::ObservableViewer(
|
||||||
api().fullPeerUpdated()
|
api().fullPeerUpdated()
|
||||||
) | rpl::map([=](not_null<PeerData*> peer) {
|
) | rpl::filter([](not_null<PeerData*> peer) {
|
||||||
return peer->asChannel();
|
return peer->isChat() || peer->isMegagroup();
|
||||||
}) | rpl::filter(
|
}) | rpl::start_with_next([=](not_null<PeerData*> peer) {
|
||||||
_1 != nullptr
|
if (const auto users = _pendingSpeakingCallMembers.take(peer)) {
|
||||||
) | rpl::start_with_next([=](not_null<ChannelData*> channel) {
|
if (const auto call = peer->groupCall()) {
|
||||||
if (const auto users = _pendingSpeakingCallMembers.take(channel)) {
|
|
||||||
if (const auto call = channel->call()) {
|
|
||||||
for (const auto [userId, when] : *users) {
|
for (const auto [userId, when] : *users) {
|
||||||
call->applyActiveUpdate(
|
call->applyActiveUpdate(
|
||||||
userId,
|
userId,
|
||||||
when,
|
when,
|
||||||
channel->owner().userLoaded(userId));
|
peer->owner().userLoaded(userId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -911,6 +909,52 @@ bool Updates::isQuitPrevent() {
|
||||||
updateOnline();
|
updateOnline();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
void Updates::handleSendActionUpdate(
|
||||||
|
PeerId peerId,
|
||||||
|
MsgId rootId,
|
||||||
|
UserId userId,
|
||||||
|
const MTPSendMessageAction &action) {
|
||||||
|
const auto history = session().data().historyLoaded(peerId);
|
||||||
|
if (!history) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto peer = history->peer;
|
||||||
|
const auto user = (userId == session().userId())
|
||||||
|
? session().user().get()
|
||||||
|
: session().data().userLoaded(userId);
|
||||||
|
const auto isSpeakingInCall = (action.type()
|
||||||
|
== mtpc_speakingInGroupCallAction);
|
||||||
|
if (isSpeakingInCall) {
|
||||||
|
const auto call = peer->groupCall();
|
||||||
|
const auto now = crl::now();
|
||||||
|
if (call) {
|
||||||
|
call->applyActiveUpdate(userId, now, user);
|
||||||
|
} else {
|
||||||
|
const auto chat = peer->asChat();
|
||||||
|
const auto channel = peer->asChannel();
|
||||||
|
const auto active = chat
|
||||||
|
? (chat->flags() & MTPDchat::Flag::f_call_active)
|
||||||
|
: (channel->flags() & MTPDchannel::Flag::f_call_active);
|
||||||
|
if (active) {
|
||||||
|
_pendingSpeakingCallMembers.emplace(
|
||||||
|
channel).first->second[userId] = now;
|
||||||
|
session().api().requestFullPeer(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!user || user->isSelf()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto when = requestingDifference()
|
||||||
|
? 0
|
||||||
|
: base::unixtime::now();
|
||||||
|
session().data().registerSendAction(
|
||||||
|
history,
|
||||||
|
rootId,
|
||||||
|
user,
|
||||||
|
action,
|
||||||
|
when);
|
||||||
|
}
|
||||||
|
|
||||||
void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||||
switch (updates.type()) {
|
switch (updates.type()) {
|
||||||
|
@ -1601,75 +1645,29 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
|
|
||||||
case mtpc_updateUserTyping: {
|
case mtpc_updateUserTyping: {
|
||||||
auto &d = update.c_updateUserTyping();
|
auto &d = update.c_updateUserTyping();
|
||||||
const auto userId = peerFromUser(d.vuser_id());
|
handleSendActionUpdate(
|
||||||
const auto history = session().data().historyLoaded(userId);
|
peerFromUser(d.vuser_id()),
|
||||||
const auto user = session().data().userLoaded(d.vuser_id().v);
|
0,
|
||||||
if (history && user) {
|
d.vuser_id().v,
|
||||||
const auto when = requestingDifference() ? 0 : base::unixtime::now();
|
d.vaction());
|
||||||
session().data().registerSendAction(
|
|
||||||
history,
|
|
||||||
MsgId(),
|
|
||||||
user,
|
|
||||||
d.vaction(),
|
|
||||||
when);
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updateChatUserTyping: {
|
case mtpc_updateChatUserTyping: {
|
||||||
auto &d = update.c_updateChatUserTyping();
|
auto &d = update.c_updateChatUserTyping();
|
||||||
const auto history = session().data().historyLoaded(
|
handleSendActionUpdate(
|
||||||
peerFromChat(d.vchat_id()));
|
peerFromChat(d.vchat_id()),
|
||||||
const auto user = (d.vuser_id().v == session().userId())
|
0,
|
||||||
? nullptr
|
d.vuser_id().v,
|
||||||
: session().data().userLoaded(d.vuser_id().v);
|
d.vaction());
|
||||||
if (history && user) {
|
|
||||||
const auto when = requestingDifference() ? 0 : base::unixtime::now();
|
|
||||||
session().data().registerSendAction(
|
|
||||||
history,
|
|
||||||
MsgId(),
|
|
||||||
user,
|
|
||||||
d.vaction(),
|
|
||||||
when);
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updateChannelUserTyping: {
|
case mtpc_updateChannelUserTyping: {
|
||||||
const auto &d = update.c_updateChannelUserTyping();
|
const auto &d = update.c_updateChannelUserTyping();
|
||||||
const auto history = session().data().historyLoaded(
|
handleSendActionUpdate(
|
||||||
peerFromChannel(d.vchannel_id()));
|
peerFromChannel(d.vchannel_id()),
|
||||||
if (history) {
|
d.vtop_msg_id().value_or_empty(),
|
||||||
const auto userId = d.vuser_id().v;
|
d.vuser_id().v,
|
||||||
const auto user = (userId == session().userId())
|
d.vaction());
|
||||||
? session().user().get()
|
|
||||||
: session().data().userLoaded(userId);
|
|
||||||
const auto isSpeakingInCall = (d.vaction().type()
|
|
||||||
== mtpc_speakingInGroupCallAction);
|
|
||||||
if (isSpeakingInCall) {
|
|
||||||
const auto channel = history->peer->asChannel();
|
|
||||||
const auto call = channel->call();
|
|
||||||
const auto now = crl::now();
|
|
||||||
if (call) {
|
|
||||||
call->applyActiveUpdate(userId, now, user);
|
|
||||||
} else if (channel->flags()
|
|
||||||
& MTPDchannel::Flag::f_call_active) {
|
|
||||||
_pendingSpeakingCallMembers.emplace(
|
|
||||||
channel).first->second[userId] = now;
|
|
||||||
session().api().requestFullPeer(channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (user && !user->isSelf()) {
|
|
||||||
const auto when = requestingDifference()
|
|
||||||
? 0
|
|
||||||
: base::unixtime::now();
|
|
||||||
const auto rootId = d.vtop_msg_id().value_or_empty();
|
|
||||||
session().data().registerSendAction(
|
|
||||||
history,
|
|
||||||
rootId,
|
|
||||||
user,
|
|
||||||
d.vaction(),
|
|
||||||
when);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updateChatParticipants: {
|
case mtpc_updateChatParticipants: {
|
||||||
|
|
|
@ -122,6 +122,12 @@ private:
|
||||||
base::flat_map<not_null<ChannelData*>, crl::time> &whenMap,
|
base::flat_map<not_null<ChannelData*>, crl::time> &whenMap,
|
||||||
crl::time &curTime);
|
crl::time &curTime);
|
||||||
|
|
||||||
|
void handleSendActionUpdate(
|
||||||
|
PeerId peerId,
|
||||||
|
MsgId rootId,
|
||||||
|
UserId userId,
|
||||||
|
const MTPSendMessageAction &action);
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
|
|
||||||
int32 _updatesDate = 0;
|
int32 _updatesDate = 0;
|
||||||
|
@ -161,7 +167,7 @@ private:
|
||||||
|
|
||||||
base::flat_map<int, ActiveChatTracker> _activeChats;
|
base::flat_map<int, ActiveChatTracker> _activeChats;
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
not_null<ChannelData*>,
|
not_null<PeerData*>,
|
||||||
base::flat_map<UserId, crl::time>> _pendingSpeakingCallMembers;
|
base::flat_map<UserId, crl::time>> _pendingSpeakingCallMembers;
|
||||||
|
|
||||||
mtpRequestId _onlineRequest = 0;
|
mtpRequestId _onlineRequest = 0;
|
||||||
|
|
|
@ -12,13 +12,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "lang/lang_hardcoded.h"
|
#include "lang/lang_hardcoded.h"
|
||||||
#include "boxes/confirm_box.h"
|
#include "boxes/peers/edit_participants_box.h" // SubscribeToMigration.
|
||||||
#include "ui/toasts/common_toasts.h"
|
#include "ui/toasts/common_toasts.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -46,12 +47,12 @@ constexpr auto kUpdateSendActionEach = crl::time(500);
|
||||||
|
|
||||||
GroupCall::GroupCall(
|
GroupCall::GroupCall(
|
||||||
not_null<Delegate*> delegate,
|
not_null<Delegate*> delegate,
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
const MTPInputGroupCall &inputCall)
|
const MTPInputGroupCall &inputCall)
|
||||||
: _delegate(delegate)
|
: _delegate(delegate)
|
||||||
, _channel(channel)
|
, _peer(peer)
|
||||||
, _history(channel->owner().history(channel))
|
, _history(peer->owner().history(peer))
|
||||||
, _api(&_channel->session().mtp())
|
, _api(&peer->session().mtp())
|
||||||
, _lastSpokeCheckTimer([=] { checkLastSpoke(); })
|
, _lastSpokeCheckTimer([=] { checkLastSpoke(); })
|
||||||
, _checkJoinedTimer([=] { checkJoined(); })
|
, _checkJoinedTimer([=] { checkJoined(); })
|
||||||
, _pushToTalkCancelTimer([=] { pushToTalkCancel(); }) {
|
, _pushToTalkCancelTimer([=] { pushToTalkCancel(); }) {
|
||||||
|
@ -70,8 +71,8 @@ GroupCall::GroupCall(
|
||||||
|
|
||||||
const auto id = inputCall.c_inputGroupCall().vid().v;
|
const auto id = inputCall.c_inputGroupCall().vid().v;
|
||||||
if (id) {
|
if (id) {
|
||||||
if (const auto call = _channel->call(); call && call->id() == id) {
|
if (const auto call = _peer->groupCall(); call && call->id() == id) {
|
||||||
if (!_channel->canManageCall() && call->joinMuted()) {
|
if (!_peer->canManageGroupCall() && call->joinMuted()) {
|
||||||
_muted = MuteState::ForceMuted;
|
_muted = MuteState::ForceMuted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +114,7 @@ void GroupCall::setState(State state) {
|
||||||
_pushToTalkStarted = true;
|
_pushToTalkStarted = true;
|
||||||
applyGlobalShortcutChanges();
|
applyGlobalShortcutChanges();
|
||||||
}
|
}
|
||||||
if (const auto call = _channel->call(); call && call->id() == _id) {
|
if (const auto call = _peer->groupCall(); call && call->id() == _id) {
|
||||||
call->setInCall();
|
call->setInCall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,11 +143,11 @@ void GroupCall::setState(State state) {
|
||||||
|
|
||||||
void GroupCall::start() {
|
void GroupCall::start() {
|
||||||
_createRequestId = _api.request(MTPphone_CreateGroupCall(
|
_createRequestId = _api.request(MTPphone_CreateGroupCall(
|
||||||
_channel->input,
|
_peer->input,
|
||||||
MTP_int(rand_value<int32>())
|
MTP_int(rand_value<int32>())
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
_acceptFields = true;
|
_acceptFields = true;
|
||||||
_channel->session().api().applyUpdates(result);
|
_peer->session().api().applyUpdates(result);
|
||||||
_acceptFields = false;
|
_acceptFields = false;
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
LOG(("Call Error: Could not create, error: %1"
|
LOG(("Call Error: Could not create, error: %1"
|
||||||
|
@ -162,7 +163,13 @@ void GroupCall::start() {
|
||||||
|
|
||||||
void GroupCall::join(const MTPInputGroupCall &inputCall) {
|
void GroupCall::join(const MTPInputGroupCall &inputCall) {
|
||||||
setState(State::Joining);
|
setState(State::Joining);
|
||||||
_channel->setCall(inputCall);
|
if (const auto chat = _peer->asChat()) {
|
||||||
|
chat->setGroupCall(inputCall);
|
||||||
|
} else if (const auto group = _peer->asMegagroup()) {
|
||||||
|
group->setGroupCall(inputCall);
|
||||||
|
} else {
|
||||||
|
Unexpected("Peer type in GroupCall::join.");
|
||||||
|
}
|
||||||
|
|
||||||
inputCall.match([&](const MTPDinputGroupCall &data) {
|
inputCall.match([&](const MTPDinputGroupCall &data) {
|
||||||
_id = data.vid().v;
|
_id = data.vid().v;
|
||||||
|
@ -171,7 +178,7 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) {
|
||||||
});
|
});
|
||||||
|
|
||||||
using Update = Data::GroupCall::ParticipantUpdate;
|
using Update = Data::GroupCall::ParticipantUpdate;
|
||||||
_channel->call()->participantUpdated(
|
_peer->groupCall()->participantUpdated(
|
||||||
) | rpl::filter([=](const Update &update) {
|
) | rpl::filter([=](const Update &update) {
|
||||||
return (_instance != nullptr) && !update.now;
|
return (_instance != nullptr) && !update.now;
|
||||||
}) | rpl::start_with_next([=](const Update &update) {
|
}) | rpl::start_with_next([=](const Update &update) {
|
||||||
|
@ -179,6 +186,10 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) {
|
||||||
|
|
||||||
_instance->removeSsrcs({ update.was->ssrc });
|
_instance->removeSsrcs({ update.was->ssrc });
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
|
SubscribeToMigration(_peer, _lifetime, [=](not_null<ChannelData*> group) {
|
||||||
|
_peer = group;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::rejoin() {
|
void GroupCall::rejoin() {
|
||||||
|
@ -234,7 +245,7 @@ void GroupCall::rejoin() {
|
||||||
: State::Connecting);
|
: State::Connecting);
|
||||||
applySelfInCallLocally();
|
applySelfInCallLocally();
|
||||||
maybeSendMutedUpdate(wasMuteState);
|
maybeSendMutedUpdate(wasMuteState);
|
||||||
_channel->session().api().applyUpdates(updates);
|
_peer->session().api().applyUpdates(updates);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
const auto type = error.type();
|
const auto type = error.type();
|
||||||
LOG(("Call Error: Could not join, error: %1").arg(type));
|
LOG(("Call Error: Could not join, error: %1").arg(type));
|
||||||
|
@ -260,13 +271,13 @@ void GroupCall::rejoin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::applySelfInCallLocally() {
|
void GroupCall::applySelfInCallLocally() {
|
||||||
const auto call = _channel->call();
|
const auto call = _peer->groupCall();
|
||||||
if (!call || call->id() != _id) {
|
if (!call || call->id() != _id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
using Flag = MTPDgroupCallParticipant::Flag;
|
using Flag = MTPDgroupCallParticipant::Flag;
|
||||||
const auto &participants = call->participants();
|
const auto &participants = call->participants();
|
||||||
const auto self = _channel->session().user();
|
const auto self = _peer->session().user();
|
||||||
const auto i = ranges::find(
|
const auto i = ranges::find(
|
||||||
participants,
|
participants,
|
||||||
self,
|
self,
|
||||||
|
@ -312,7 +323,7 @@ void GroupCall::discard() {
|
||||||
// Here 'this' could be destroyed by updates, so we set Ended after
|
// Here 'this' could be destroyed by updates, so we set Ended after
|
||||||
// updates being handled, but in a guarded way.
|
// updates being handled, but in a guarded way.
|
||||||
crl::on_main(this, [=] { hangup(); });
|
crl::on_main(this, [=] { hangup(); });
|
||||||
_channel->session().api().applyUpdates(result);
|
_peer->session().api().applyUpdates(result);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
hangup();
|
hangup();
|
||||||
}).send();
|
}).send();
|
||||||
|
@ -343,7 +354,7 @@ void GroupCall::finish(FinishType type) {
|
||||||
|
|
||||||
// We want to leave request still being sent and processed even if
|
// We want to leave request still being sent and processed even if
|
||||||
// the call is already destroyed.
|
// the call is already destroyed.
|
||||||
const auto session = &_channel->session();
|
const auto session = &_peer->session();
|
||||||
const auto weak = base::make_weak(this);
|
const auto weak = base::make_weak(this);
|
||||||
session->api().request(MTPphone_LeaveGroupCall(
|
session->api().request(MTPphone_LeaveGroupCall(
|
||||||
inputCall(),
|
inputCall(),
|
||||||
|
@ -458,7 +469,7 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto self = _channel->session().userId();
|
const auto self = _peer->session().userId();
|
||||||
for (const auto &participant : data.vparticipants().v) {
|
for (const auto &participant : data.vparticipants().v) {
|
||||||
participant.match([&](const MTPDgroupCallParticipant &data) {
|
participant.match([&](const MTPDgroupCallParticipant &data) {
|
||||||
if (data.vuser_id().v != self) {
|
if (data.vuser_id().v != self) {
|
||||||
|
@ -565,7 +576,7 @@ void GroupCall::handleLevelsUpdated(
|
||||||
&& (!_lastSendProgressUpdate
|
&& (!_lastSendProgressUpdate
|
||||||
|| _lastSendProgressUpdate + kUpdateSendActionEach < now)) {
|
|| _lastSendProgressUpdate + kUpdateSendActionEach < now)) {
|
||||||
_lastSendProgressUpdate = now;
|
_lastSendProgressUpdate = now;
|
||||||
_channel->session().sendProgressManager().update(
|
_peer->session().sendProgressManager().update(
|
||||||
_history,
|
_history,
|
||||||
Api::SendProgressType::Speaking);
|
Api::SendProgressType::Speaking);
|
||||||
}
|
}
|
||||||
|
@ -600,7 +611,7 @@ void GroupCall::audioLevelsUpdated(
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::checkLastSpoke() {
|
void GroupCall::checkLastSpoke() {
|
||||||
const auto real = _channel->call();
|
const auto real = _peer->groupCall();
|
||||||
if (!real || real->id() != _id) {
|
if (!real || real->id() != _id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -683,7 +694,7 @@ void GroupCall::sendMutedUpdate() {
|
||||||
MTP_inputUserSelf()
|
MTP_inputUserSelf()
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
_updateMuteRequestId = 0;
|
_updateMuteRequestId = 0;
|
||||||
_channel->session().api().applyUpdates(result);
|
_peer->session().api().applyUpdates(result);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
_updateMuteRequestId = 0;
|
_updateMuteRequestId = 0;
|
||||||
if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
|
if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
|
||||||
|
@ -716,7 +727,7 @@ void GroupCall::toggleMute(not_null<UserData*> user, bool mute) {
|
||||||
inputCall(),
|
inputCall(),
|
||||||
user->inputUser
|
user->inputUser
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
_channel->session().api().applyUpdates(result);
|
_peer->session().api().applyUpdates(result);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
|
if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
|
||||||
LOG(("Call Info: Rejoin after error '%1' in editGroupCallMember."
|
LOG(("Call Info: Rejoin after error '%1' in editGroupCallMember."
|
||||||
|
@ -728,11 +739,11 @@ void GroupCall::toggleMute(not_null<UserData*> user, bool mute) {
|
||||||
|
|
||||||
std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
|
std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
|
||||||
const std::vector<not_null<UserData*>> &users) {
|
const std::vector<not_null<UserData*>> &users) {
|
||||||
const auto real = _channel->call();
|
const auto real = _peer->groupCall();
|
||||||
if (!real || real->id() != _id) {
|
if (!real || real->id() != _id) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const auto owner = &_channel->owner();
|
const auto owner = &_peer->owner();
|
||||||
const auto &invited = owner->invitedToCallUsers(_id);
|
const auto &invited = owner->invitedToCallUsers(_id);
|
||||||
const auto &participants = real->participants();
|
const auto &participants = real->participants();
|
||||||
auto &&toInvite = users | ranges::view::filter([&](
|
auto &&toInvite = users | ranges::view::filter([&](
|
||||||
|
@ -753,7 +764,7 @@ std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
|
||||||
inputCall(),
|
inputCall(),
|
||||||
MTP_vector<MTPInputUser>(slice)
|
MTP_vector<MTPInputUser>(slice)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
_channel->session().api().applyUpdates(result);
|
_peer->session().api().applyUpdates(result);
|
||||||
}).send();
|
}).send();
|
||||||
slice.clear();
|
slice.clear();
|
||||||
};
|
};
|
||||||
|
@ -761,7 +772,7 @@ std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
|
||||||
if (!count && slice.empty()) {
|
if (!count && slice.empty()) {
|
||||||
result = user;
|
result = user;
|
||||||
}
|
}
|
||||||
owner->registerInvitedToCallUser(_id, _channel, user);
|
owner->registerInvitedToCallUser(_id, _peer, user);
|
||||||
slice.push_back(user->inputUser);
|
slice.push_back(user->inputUser);
|
||||||
if (slice.size() == kMaxInvitePerSlice) {
|
if (slice.size() == kMaxInvitePerSlice) {
|
||||||
sendSlice();
|
sendSlice();
|
||||||
|
@ -869,7 +880,7 @@ void GroupCall::handleControllerError(const QString &error) {
|
||||||
// "{user}",
|
// "{user}",
|
||||||
// _user->name)));
|
// _user->name)));
|
||||||
} else if (error == u"ERROR_AUDIO_IO"_q) {
|
} else if (error == u"ERROR_AUDIO_IO"_q) {
|
||||||
Ui::show(Box<InformBox>(tr::lng_call_error_audio_io(tr::now)));
|
//Ui::show(Box<InformBox>(tr::lng_call_error_audio_io(tr::now)));
|
||||||
}
|
}
|
||||||
//finish(FinishType::Failed);
|
//finish(FinishType::Failed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,15 +61,15 @@ public:
|
||||||
|
|
||||||
GroupCall(
|
GroupCall(
|
||||||
not_null<Delegate*> delegate,
|
not_null<Delegate*> delegate,
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
const MTPInputGroupCall &inputCall);
|
const MTPInputGroupCall &inputCall);
|
||||||
~GroupCall();
|
~GroupCall();
|
||||||
|
|
||||||
[[nodiscard]] uint64 id() const {
|
[[nodiscard]] uint64 id() const {
|
||||||
return _id;
|
return _id;
|
||||||
}
|
}
|
||||||
[[nodiscard]] not_null<ChannelData*> channel() const {
|
[[nodiscard]] not_null<PeerData*> peer() const {
|
||||||
return _channel;
|
return _peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
@ -161,8 +161,8 @@ private:
|
||||||
[[nodiscard]] MTPInputGroupCall inputCall() const;
|
[[nodiscard]] MTPInputGroupCall inputCall() const;
|
||||||
|
|
||||||
const not_null<Delegate*> _delegate;
|
const not_null<Delegate*> _delegate;
|
||||||
const not_null<ChannelData*> _channel;
|
not_null<PeerData*> _peer; // Can change in legacy group migration.
|
||||||
const not_null<History*> _history;
|
not_null<History*> _history; // Can change in legacy group migration.
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
rpl::variable<State> _state = State::Creating;
|
rpl::variable<State> _state = State::Creating;
|
||||||
bool _instanceConnected = false;
|
bool _instanceConnected = false;
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "calls/calls_group_call.h"
|
#include "calls/calls_group_call.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
|
@ -24,7 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_domain.h" // Core::App().domain().activate.
|
#include "main/main_domain.h" // Core::App().domain().activate.
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "boxes/peers/edit_participants_box.h"
|
#include "boxes/peers/edit_participants_box.h" // SubscribeToMigration.
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "window/window_controller.h" // Controller::sessionController.
|
#include "window/window_controller.h" // Controller::sessionController.
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
@ -237,7 +238,7 @@ private:
|
||||||
[[nodiscard]] Data::GroupCall *resolvedRealCall() const;
|
[[nodiscard]] Data::GroupCall *resolvedRealCall() const;
|
||||||
|
|
||||||
const base::weak_ptr<GroupCall> _call;
|
const base::weak_ptr<GroupCall> _call;
|
||||||
const not_null<ChannelData*> _channel;
|
not_null<PeerData*> _peer;
|
||||||
|
|
||||||
// Use only resolvedRealCall() method, not this value directly.
|
// Use only resolvedRealCall() method, not this value directly.
|
||||||
Data::GroupCall *_realCallRawValue = nullptr;
|
Data::GroupCall *_realCallRawValue = nullptr;
|
||||||
|
@ -518,7 +519,7 @@ MembersController::MembersController(
|
||||||
not_null<GroupCall*> call,
|
not_null<GroupCall*> call,
|
||||||
not_null<QWidget*> menuParent)
|
not_null<QWidget*> menuParent)
|
||||||
: _call(call)
|
: _call(call)
|
||||||
, _channel(call->channel())
|
, _peer(call->peer())
|
||||||
, _menuParent(menuParent)
|
, _menuParent(menuParent)
|
||||||
, _inactiveCrossLine(st::groupCallMemberInactiveCrossLine)
|
, _inactiveCrossLine(st::groupCallMemberInactiveCrossLine)
|
||||||
, _coloredCrossLine(st::groupCallMemberColoredCrossLine) {
|
, _coloredCrossLine(st::groupCallMemberColoredCrossLine) {
|
||||||
|
@ -573,12 +574,12 @@ MembersController::~MembersController() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
|
void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
|
||||||
const auto channel = call->channel();
|
const auto peer = call->peer();
|
||||||
channel->session().changes().peerFlagsValue(
|
peer->session().changes().peerFlagsValue(
|
||||||
channel,
|
peer,
|
||||||
Data::PeerUpdate::Flag::GroupCall
|
Data::PeerUpdate::Flag::GroupCall
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=] {
|
||||||
return channel->call();
|
return peer->groupCall();
|
||||||
}) | rpl::filter([=](Data::GroupCall *real) {
|
}) | rpl::filter([=](Data::GroupCall *real) {
|
||||||
const auto call = _call.get();
|
const auto call = _call.get();
|
||||||
return call && real && (real->id() == call->id());
|
return call && real && (real->id() == call->id());
|
||||||
|
@ -591,7 +592,7 @@ void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
|
||||||
call->stateValue(
|
call->stateValue(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
const auto call = _call.get();
|
const auto call = _call.get();
|
||||||
const auto real = channel->call();
|
const auto real = peer->groupCall();
|
||||||
if (call && real && (real->id() == call->id())) {
|
if (call && real && (real->id() == call->id())) {
|
||||||
//updateRow(channel->session().user());
|
//updateRow(channel->session().user());
|
||||||
}
|
}
|
||||||
|
@ -751,14 +752,14 @@ Row *MembersController::findRow(not_null<UserData*> user) const {
|
||||||
|
|
||||||
Data::GroupCall *MembersController::resolvedRealCall() const {
|
Data::GroupCall *MembersController::resolvedRealCall() const {
|
||||||
return (_realCallRawValue
|
return (_realCallRawValue
|
||||||
&& (_channel->call() == _realCallRawValue)
|
&& (_peer->groupCall() == _realCallRawValue)
|
||||||
&& (_realCallRawValue->id() == _realId))
|
&& (_realCallRawValue->id() == _realId))
|
||||||
? _realCallRawValue
|
? _realCallRawValue
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Main::Session &MembersController::session() const {
|
Main::Session &MembersController::session() const {
|
||||||
return _call->channel()->session();
|
return _call->peer()->session();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::prepare() {
|
void MembersController::prepare() {
|
||||||
|
@ -768,7 +769,7 @@ void MembersController::prepare() {
|
||||||
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
|
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
|
||||||
|
|
||||||
const auto call = _call.get();
|
const auto call = _call.get();
|
||||||
if (const auto real = _channel->call();
|
if (const auto real = _peer->groupCall();
|
||||||
real && call && real->id() == call->id()) {
|
real && call && real->id() == call->id()) {
|
||||||
prepareRows(real);
|
prepareRows(real);
|
||||||
} else if (auto row = createSelfRow()) {
|
} else if (auto row = createSelfRow()) {
|
||||||
|
@ -804,10 +805,10 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundSelf) {
|
if (!foundSelf) {
|
||||||
const auto self = _channel->session().user();
|
const auto self = _peer->session().user();
|
||||||
const auto i = ranges::find(
|
const auto i = ranges::find(
|
||||||
participants,
|
participants,
|
||||||
_channel->session().user(),
|
_peer->session().user(),
|
||||||
&Data::GroupCall::Participant::user);
|
&Data::GroupCall::Participant::user);
|
||||||
auto row = (i != end(participants)) ? createRow(*i) : createSelfRow();
|
auto row = (i != end(participants)) ? createRow(*i) : createSelfRow();
|
||||||
if (row) {
|
if (row) {
|
||||||
|
@ -827,7 +828,7 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::loadMoreRows() {
|
void MembersController::loadMoreRows() {
|
||||||
if (const auto real = _channel->call()) {
|
if (const auto real = _peer->groupCall()) {
|
||||||
real->requestParticipants();
|
real->requestParticipants();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -838,7 +839,7 @@ auto MembersController::toggleMuteRequests() const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MembersController::rowCanMuteMembers() {
|
bool MembersController::rowCanMuteMembers() {
|
||||||
return _channel->canManageCall();
|
return _peer->canManageGroupCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersController::rowUpdateRow(not_null<Row*> row) {
|
void MembersController::rowUpdateRow(not_null<Row*> row) {
|
||||||
|
@ -999,7 +1000,7 @@ base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
|
||||||
_kickMemberRequests.fire_copy(user);
|
_kickMemberRequests.fire_copy(user);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (_channel->canManageCall()) {
|
if (_peer->canManageGroupCall()) {
|
||||||
result->addAction(
|
result->addAction(
|
||||||
(mute
|
(mute
|
||||||
? tr::lng_group_call_context_mute(tr::now)
|
? tr::lng_group_call_context_mute(tr::now)
|
||||||
|
@ -1012,7 +1013,16 @@ base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
|
||||||
result->addAction(
|
result->addAction(
|
||||||
tr::lng_context_send_message(tr::now),
|
tr::lng_context_send_message(tr::now),
|
||||||
showHistory);
|
showHistory);
|
||||||
if (_channel->canRestrictUser(user)) {
|
const auto canKick = [&] {
|
||||||
|
if (const auto chat = _peer->asChat()) {
|
||||||
|
return chat->amCreator()
|
||||||
|
|| (chat->canBanMembers() && !chat->admins.contains(user));
|
||||||
|
} else if (const auto group = _peer->asMegagroup()) {
|
||||||
|
return group->canRestrictUser(user);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
if (canKick) {
|
||||||
result->addAction(
|
result->addAction(
|
||||||
tr::lng_context_remove_from_group(tr::now),
|
tr::lng_context_remove_from_group(tr::now),
|
||||||
removeFromGroup);
|
removeFromGroup);
|
||||||
|
@ -1021,7 +1031,7 @@ base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Row> MembersController::createSelfRow() {
|
std::unique_ptr<Row> MembersController::createSelfRow() {
|
||||||
const auto self = _channel->session().user();
|
const auto self = _peer->session().user();
|
||||||
auto result = std::make_unique<Row>(this, self);
|
auto result = std::make_unique<Row>(this, self);
|
||||||
updateRow(result.get(), nullptr);
|
updateRow(result.get(), nullptr);
|
||||||
return result;
|
return result;
|
||||||
|
@ -1075,7 +1085,7 @@ int GroupMembers::desiredHeight() const {
|
||||||
auto desired = _header ? _header->height() : 0;
|
auto desired = _header ? _header->height() : 0;
|
||||||
auto count = [&] {
|
auto count = [&] {
|
||||||
if (const auto call = _call.get()) {
|
if (const auto call = _call.get()) {
|
||||||
if (const auto real = call->channel()->call()) {
|
if (const auto real = call->peer()->groupCall()) {
|
||||||
if (call->id() == real->id()) {
|
if (call->id() == real->id()) {
|
||||||
return real->fullCount();
|
return real->fullCount();
|
||||||
}
|
}
|
||||||
|
@ -1138,9 +1148,15 @@ object_ptr<Ui::FlatLabel> GroupMembers::setupTitle(
|
||||||
void GroupMembers::setupButtons(not_null<GroupCall*> call) {
|
void GroupMembers::setupButtons(not_null<GroupCall*> call) {
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
_addMember->showOn(Data::CanWriteValue(
|
_canAddMembers = Data::CanWriteValue(call->peer().get());
|
||||||
call->channel().get()
|
SubscribeToMigration(
|
||||||
));
|
call->peer(),
|
||||||
|
lifetime(),
|
||||||
|
[=](not_null<ChannelData*> channel) {
|
||||||
|
_canAddMembers = Data::CanWriteValue(channel.get());
|
||||||
|
});
|
||||||
|
|
||||||
|
_addMember->showOn(_canAddMembers.value());
|
||||||
_addMember->addClickHandler([=] { // TODO throttle(ripple duration)
|
_addMember->addClickHandler([=] { // TODO throttle(ripple duration)
|
||||||
_addMemberRequests.fire({});
|
_addMemberRequests.fire({});
|
||||||
});
|
});
|
||||||
|
|
|
@ -86,6 +86,7 @@ private:
|
||||||
Ui::RpWidget *_titleWrap = nullptr;
|
Ui::RpWidget *_titleWrap = nullptr;
|
||||||
Ui::FlatLabel *_title = nullptr;
|
Ui::FlatLabel *_title = nullptr;
|
||||||
Ui::IconButton *_addMember = nullptr;
|
Ui::IconButton *_addMember = nullptr;
|
||||||
|
rpl::variable<bool> _canAddMembers;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -47,7 +48,7 @@ namespace {
|
||||||
class InviteController final : public ParticipantsBoxController {
|
class InviteController final : public ParticipantsBoxController {
|
||||||
public:
|
public:
|
||||||
InviteController(
|
InviteController(
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
base::flat_set<not_null<UserData*>> alreadyIn,
|
base::flat_set<not_null<UserData*>> alreadyIn,
|
||||||
int fullInCount);
|
int fullInCount);
|
||||||
|
|
||||||
|
@ -65,7 +66,6 @@ public:
|
||||||
not_null<GroupCall*> call) const;
|
not_null<GroupCall*> call) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateTitle() const;
|
|
||||||
[[nodiscard]] int alreadyInCount() const;
|
[[nodiscard]] int alreadyInCount() const;
|
||||||
[[nodiscard]] bool isAlreadyIn(not_null<UserData*> user) const;
|
[[nodiscard]] bool isAlreadyIn(not_null<UserData*> user) const;
|
||||||
[[nodiscard]] int fullCount() const;
|
[[nodiscard]] int fullCount() const;
|
||||||
|
@ -73,7 +73,7 @@ private:
|
||||||
std::unique_ptr<PeerListRow> createRow(
|
std::unique_ptr<PeerListRow> createRow(
|
||||||
not_null<UserData*> user) const override;
|
not_null<UserData*> user) const override;
|
||||||
|
|
||||||
const not_null<ChannelData*> _channel;
|
not_null<PeerData*> _peer;
|
||||||
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
||||||
const int _fullInCount = 0;
|
const int _fullInCount = 0;
|
||||||
mutable base::flat_set<not_null<UserData*>> _skippedUsers;
|
mutable base::flat_set<not_null<UserData*>> _skippedUsers;
|
||||||
|
@ -81,24 +81,27 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
InviteController::InviteController(
|
InviteController::InviteController(
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
base::flat_set<not_null<UserData*>> alreadyIn,
|
base::flat_set<not_null<UserData*>> alreadyIn,
|
||||||
int fullInCount)
|
int fullInCount)
|
||||||
: ParticipantsBoxController(CreateTag{}, nullptr, channel, Role::Members)
|
: ParticipantsBoxController(CreateTag{}, nullptr, peer, Role::Members)
|
||||||
, _channel(channel)
|
, _peer(peer)
|
||||||
, _alreadyIn(std::move(alreadyIn))
|
, _alreadyIn(std::move(alreadyIn))
|
||||||
, _fullInCount(std::max(fullInCount, int(_alreadyIn.size()))) {
|
, _fullInCount(std::max(fullInCount, int(_alreadyIn.size()))) {
|
||||||
_skippedUsers.emplace(channel->session().user());
|
_skippedUsers.emplace(peer->session().user());
|
||||||
|
SubscribeToMigration(
|
||||||
|
_peer,
|
||||||
|
lifetime(),
|
||||||
|
[=](not_null<ChannelData*> channel) { _peer = channel; });
|
||||||
}
|
}
|
||||||
|
|
||||||
void InviteController::prepare() {
|
void InviteController::prepare() {
|
||||||
ParticipantsBoxController::prepare();
|
ParticipantsBoxController::prepare();
|
||||||
updateTitle();
|
delegate()->peerListSetTitle(tr::lng_group_call_invite_title());
|
||||||
}
|
}
|
||||||
|
|
||||||
void InviteController::rowClicked(not_null<PeerListRow*> row) {
|
void InviteController::rowClicked(not_null<PeerListRow*> row) {
|
||||||
delegate()->peerListSetRowChecked(row, !row->checked());
|
delegate()->peerListSetRowChecked(row, !row->checked());
|
||||||
updateTitle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base::unique_qptr<Ui::PopupMenu> InviteController::rowContextMenu(
|
base::unique_qptr<Ui::PopupMenu> InviteController::rowContextMenu(
|
||||||
|
@ -108,7 +111,6 @@ base::unique_qptr<Ui::PopupMenu> InviteController::rowContextMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
void InviteController::itemDeselectedHook(not_null<PeerData*> peer) {
|
void InviteController::itemDeselectedHook(not_null<PeerData*> peer) {
|
||||||
updateTitle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int InviteController::alreadyInCount() const {
|
int InviteController::alreadyInCount() const {
|
||||||
|
@ -126,9 +128,7 @@ int InviteController::fullCount() const {
|
||||||
std::unique_ptr<PeerListRow> InviteController::createRow(
|
std::unique_ptr<PeerListRow> InviteController::createRow(
|
||||||
not_null<UserData*> user) const {
|
not_null<UserData*> user) const {
|
||||||
if (user->isSelf() || user->isBot()) {
|
if (user->isSelf() || user->isBot()) {
|
||||||
if (_skippedUsers.emplace(user).second) {
|
_skippedUsers.emplace(user);
|
||||||
updateTitle();
|
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto result = std::make_unique<PeerListRow>(user);
|
auto result = std::make_unique<PeerListRow>(user);
|
||||||
|
@ -138,20 +138,6 @@ std::unique_ptr<PeerListRow> InviteController::createRow(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InviteController::updateTitle() const {
|
|
||||||
const auto inOrInvited = fullCount() - 1; // minus self
|
|
||||||
const auto canBeInvited = std::max({
|
|
||||||
delegate()->peerListFullRowsCount(), // minus self and bots
|
|
||||||
_channel->membersCount() - int(_skippedUsers.size()), // self + bots
|
|
||||||
inOrInvited
|
|
||||||
});
|
|
||||||
const auto additional = canBeInvited
|
|
||||||
? qsl("%1 / %2").arg(inOrInvited).arg(canBeInvited)
|
|
||||||
: QString();
|
|
||||||
delegate()->peerListSetTitle(tr::lng_group_call_invite_title());
|
|
||||||
delegate()->peerListSetAdditionalTitle(rpl::single(additional));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::variant<int, not_null<UserData*>> InviteController::inviteSelectedUsers(
|
std::variant<int, not_null<UserData*>> InviteController::inviteSelectedUsers(
|
||||||
not_null<PeerListBox*> box,
|
not_null<PeerListBox*> box,
|
||||||
not_null<GroupCall*> call) const {
|
not_null<GroupCall*> call) const {
|
||||||
|
@ -180,7 +166,7 @@ void LeaveGroupCallBox(
|
||||||
box.get(),
|
box.get(),
|
||||||
tr::lng_group_call_leave_sure(),
|
tr::lng_group_call_leave_sure(),
|
||||||
(inCall ? st::groupCallBoxLabel : st::boxLabel)));
|
(inCall ? st::groupCallBoxLabel : st::boxLabel)));
|
||||||
const auto discard = call->channel()->canManageCall()
|
const auto discard = call->peer()->canManageGroupCall()
|
||||||
? box->addRow(object_ptr<Ui::Checkbox>(
|
? box->addRow(object_ptr<Ui::Checkbox>(
|
||||||
box.get(),
|
box.get(),
|
||||||
tr::lng_group_call_end(),
|
tr::lng_group_call_end(),
|
||||||
|
@ -211,7 +197,7 @@ void LeaveGroupCallBox(
|
||||||
|
|
||||||
GroupPanel::GroupPanel(not_null<GroupCall*> call)
|
GroupPanel::GroupPanel(not_null<GroupCall*> call)
|
||||||
: _call(call)
|
: _call(call)
|
||||||
, _channel(call->channel())
|
, _peer(call->peer())
|
||||||
, _window(std::make_unique<Ui::Window>(Core::App().getModalParent()))
|
, _window(std::make_unique<Ui::Window>(Core::App().getModalParent()))
|
||||||
, _layerBg(std::make_unique<Ui::LayerManager>(_window->body()))
|
, _layerBg(std::make_unique<Ui::LayerManager>(_window->body()))
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
@ -232,6 +218,11 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call)
|
||||||
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
|
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
|
||||||
_settings->setColorOverrides(_mute->colorOverrides());
|
_settings->setColorOverrides(_mute->colorOverrides());
|
||||||
|
|
||||||
|
SubscribeToMigration(
|
||||||
|
_peer,
|
||||||
|
_window->lifetime(),
|
||||||
|
[=](not_null<ChannelData*> channel) { migrate(channel); });
|
||||||
|
|
||||||
initWindow();
|
initWindow();
|
||||||
initWidget();
|
initWidget();
|
||||||
initControls();
|
initControls();
|
||||||
|
@ -260,6 +251,22 @@ void GroupPanel::showAndActivate() {
|
||||||
_window->setFocus();
|
_window->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GroupPanel::migrate(not_null<ChannelData*> channel) {
|
||||||
|
_peer = channel;
|
||||||
|
_peerLifetime.destroy();
|
||||||
|
subscribeToPeerChanges();
|
||||||
|
_title.destroy();
|
||||||
|
refreshTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupPanel::subscribeToPeerChanges() {
|
||||||
|
Info::Profile::NameValue(
|
||||||
|
_peer
|
||||||
|
) | rpl::start_with_next([=](const TextWithEntities &name) {
|
||||||
|
_window->setTitle(name.text);
|
||||||
|
}, _peerLifetime);
|
||||||
|
}
|
||||||
|
|
||||||
void GroupPanel::initWindow() {
|
void GroupPanel::initWindow() {
|
||||||
_window->setAttribute(Qt::WA_OpaquePaintEvent);
|
_window->setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
_window->setAttribute(Qt::WA_NoSystemBackground);
|
_window->setAttribute(Qt::WA_NoSystemBackground);
|
||||||
|
@ -267,11 +274,7 @@ void GroupPanel::initWindow() {
|
||||||
QIcon(QPixmap::fromImage(Image::Empty()->original(), Qt::ColorOnly)));
|
QIcon(QPixmap::fromImage(Image::Empty()->original(), Qt::ColorOnly)));
|
||||||
_window->setTitleStyle(st::callTitle);
|
_window->setTitleStyle(st::callTitle);
|
||||||
|
|
||||||
Info::Profile::NameValue(
|
subscribeToPeerChanges();
|
||||||
_channel
|
|
||||||
) | rpl::start_with_next([=](const TextWithEntities &name) {
|
|
||||||
_window->setTitle(name.text);
|
|
||||||
}, _window->lifetime());
|
|
||||||
|
|
||||||
base::install_event_filter(_window.get(), [=](not_null<QEvent*> e) {
|
base::install_event_filter(_window.get(), [=](not_null<QEvent*> e) {
|
||||||
if (e->type() == QEvent::Close && handleClose()) {
|
if (e->type() == QEvent::Close && handleClose()) {
|
||||||
|
@ -360,7 +363,7 @@ void GroupPanel::initWithCall(GroupCall *call) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_channel = _call->channel();
|
_peer = _call->peer();
|
||||||
|
|
||||||
call->stateValue(
|
call->stateValue(
|
||||||
) | rpl::filter([](State state) {
|
) | rpl::filter([](State state) {
|
||||||
|
@ -428,17 +431,17 @@ void GroupPanel::initWithCall(GroupCall *call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPanel::addMembers() {
|
void GroupPanel::addMembers() {
|
||||||
const auto real = _channel->call();
|
const auto real = _peer->groupCall();
|
||||||
if (!_call || !real || real->id() != _call->id()) {
|
if (!_call || !real || real->id() != _call->id()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto alreadyIn = _channel->owner().invitedToCallUsers(real->id());
|
auto alreadyIn = _peer->owner().invitedToCallUsers(real->id());
|
||||||
for (const auto &participant : real->participants()) {
|
for (const auto &participant : real->participants()) {
|
||||||
alreadyIn.emplace(participant.user);
|
alreadyIn.emplace(participant.user);
|
||||||
}
|
}
|
||||||
alreadyIn.emplace(_channel->session().user());
|
alreadyIn.emplace(_peer->session().user());
|
||||||
auto controller = std::make_unique<InviteController>(
|
auto controller = std::make_unique<InviteController>(
|
||||||
_channel,
|
_peer,
|
||||||
std::move(alreadyIn),
|
std::move(alreadyIn),
|
||||||
real->fullCount());
|
real->fullCount());
|
||||||
controller->setStyleOverrides(
|
controller->setStyleOverrides(
|
||||||
|
@ -511,17 +514,21 @@ void GroupPanel::kickMember(not_null<UserData*> user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPanel::kickMemberSure(not_null<UserData*> user) {
|
void GroupPanel::kickMemberSure(not_null<UserData*> user) {
|
||||||
const auto currentRestrictedRights = [&]() -> MTPChatBannedRights {
|
if (const auto chat = _peer->asChat()) {
|
||||||
const auto it = _channel->mgInfo->lastRestricted.find(user);
|
chat->session().api().kickParticipant(chat, user);
|
||||||
return (it != _channel->mgInfo->lastRestricted.cend())
|
} else if (const auto channel = _peer->asChannel()) {
|
||||||
? it->second.rights
|
const auto currentRestrictedRights = [&]() -> MTPChatBannedRights {
|
||||||
: MTP_chatBannedRights(MTP_flags(0), MTP_int(0));
|
const auto it = channel->mgInfo->lastRestricted.find(user);
|
||||||
}();
|
return (it != channel->mgInfo->lastRestricted.cend())
|
||||||
|
? it->second.rights
|
||||||
|
: MTP_chatBannedRights(MTP_flags(0), MTP_int(0));
|
||||||
|
}();
|
||||||
|
|
||||||
_channel->session().api().kickParticipant(
|
channel->session().api().kickParticipant(
|
||||||
_channel,
|
channel,
|
||||||
user,
|
user,
|
||||||
currentRestrictedRights);
|
currentRestrictedRights);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPanel::initLayout() {
|
void GroupPanel::initLayout() {
|
||||||
|
@ -612,7 +619,7 @@ void GroupPanel::refreshTitle() {
|
||||||
if (!_title) {
|
if (!_title) {
|
||||||
_title.create(
|
_title.create(
|
||||||
widget(),
|
widget(),
|
||||||
Info::Profile::NameValue(_channel),
|
Info::Profile::NameValue(_peer),
|
||||||
st::groupCallHeaderLabel);
|
st::groupCallHeaderLabel);
|
||||||
_title->setAttribute(Qt::WA_TransparentForMouseEvents);
|
_title->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,8 +99,11 @@ private:
|
||||||
[[nodiscard]] std::optional<QRect> computeTitleRect() const;
|
[[nodiscard]] std::optional<QRect> computeTitleRect() const;
|
||||||
void refreshTitle();
|
void refreshTitle();
|
||||||
|
|
||||||
|
void migrate(not_null<ChannelData*> channel);
|
||||||
|
void subscribeToPeerChanges();
|
||||||
|
|
||||||
GroupCall *_call = nullptr;
|
GroupCall *_call = nullptr;
|
||||||
not_null<ChannelData*> _channel;
|
not_null<PeerData*> _peer;
|
||||||
|
|
||||||
const std::unique_ptr<Ui::Window> _window;
|
const std::unique_ptr<Ui::Window> _window;
|
||||||
const std::unique_ptr<Ui::LayerManager> _layerBg;
|
const std::unique_ptr<Ui::LayerManager> _layerBg;
|
||||||
|
@ -118,6 +121,8 @@ private:
|
||||||
std::unique_ptr<Ui::CallMuteButton> _mute;
|
std::unique_ptr<Ui::CallMuteButton> _mute;
|
||||||
object_ptr<Ui::CallButton> _hangup;
|
object_ptr<Ui::CallButton> _hangup;
|
||||||
|
|
||||||
|
rpl::lifetime _peerLifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Calls
|
} // namespace Calls
|
||||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/global_shortcuts.h"
|
#include "base/global_shortcuts.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "boxes/single_choice_box.h"
|
#include "boxes/single_choice_box.h"
|
||||||
|
@ -44,19 +45,19 @@ constexpr auto kDelaysCount = 201;
|
||||||
constexpr auto kCheckAccessibilityInterval = crl::time(500);
|
constexpr auto kCheckAccessibilityInterval = crl::time(500);
|
||||||
|
|
||||||
void SaveCallJoinMuted(
|
void SaveCallJoinMuted(
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
uint64 callId,
|
uint64 callId,
|
||||||
bool joinMuted) {
|
bool joinMuted) {
|
||||||
const auto call = channel->call();
|
const auto call = peer->groupCall();
|
||||||
if (!call
|
if (!call
|
||||||
|| call->id() != callId
|
|| call->id() != callId
|
||||||
|| !channel->canManageCall()
|
|| !peer->canManageGroupCall()
|
||||||
|| !call->canChangeJoinMuted()
|
|| !call->canChangeJoinMuted()
|
||||||
|| call->joinMuted() == joinMuted) {
|
|| call->joinMuted() == joinMuted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
call->setJoinMutedLocally(joinMuted);
|
call->setJoinMutedLocally(joinMuted);
|
||||||
channel->session().api().request(MTPphone_ToggleGroupCallSettings(
|
peer->session().api().request(MTPphone_ToggleGroupCallSettings(
|
||||||
MTP_flags(MTPphone_ToggleGroupCallSettings::Flag::f_join_muted),
|
MTP_flags(MTPphone_ToggleGroupCallSettings::Flag::f_join_muted),
|
||||||
call->input(),
|
call->input(),
|
||||||
MTP_bool(joinMuted)
|
MTP_bool(joinMuted)
|
||||||
|
@ -101,8 +102,8 @@ void GroupCallSettingsBox(
|
||||||
};
|
};
|
||||||
const auto state = box->lifetime().make_state<State>();
|
const auto state = box->lifetime().make_state<State>();
|
||||||
|
|
||||||
const auto channel = call->channel();
|
const auto peer = call->peer();
|
||||||
const auto real = channel->call();
|
const auto real = peer->groupCall();
|
||||||
const auto id = call->id();
|
const auto id = call->id();
|
||||||
const auto goodReal = (real && real->id() == id);
|
const auto goodReal = (real && real->id() == id);
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ void GroupCallSettingsBox(
|
||||||
|
|
||||||
const auto joinMuted = goodReal ? real->joinMuted() : false;
|
const auto joinMuted = goodReal ? real->joinMuted() : false;
|
||||||
const auto canChangeJoinMuted = (goodReal && real->canChangeJoinMuted());
|
const auto canChangeJoinMuted = (goodReal && real->canChangeJoinMuted());
|
||||||
const auto addCheck = (channel->canManageCall() && canChangeJoinMuted);
|
const auto addCheck = (peer->canManageGroupCall() && canChangeJoinMuted);
|
||||||
if (addCheck) {
|
if (addCheck) {
|
||||||
AddSkip(layout);
|
AddSkip(layout);
|
||||||
}
|
}
|
||||||
|
@ -402,11 +403,24 @@ void GroupCallSettingsBox(
|
||||||
//AddSkip(layout);
|
//AddSkip(layout);
|
||||||
|
|
||||||
const auto lookupLink = [=] {
|
const auto lookupLink = [=] {
|
||||||
return channel->hasUsername()
|
if (const auto group = peer->asMegagroup()) {
|
||||||
? channel->session().createInternalLinkFull(channel->username)
|
return group->hasUsername()
|
||||||
: channel->inviteLink();
|
? group->session().createInternalLinkFull(group->username)
|
||||||
|
: group->inviteLink();
|
||||||
|
} else if (const auto chat = peer->asChat()) {
|
||||||
|
return chat->inviteLink();
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
};
|
};
|
||||||
if (!lookupLink().isEmpty() || channel->canHaveInviteLink()) {
|
const auto canCreateLink = [&] {
|
||||||
|
if (const auto chat = peer->asChat()) {
|
||||||
|
return chat->canHaveInviteLink();
|
||||||
|
} else if (const auto group = peer->asMegagroup()) {
|
||||||
|
return group->canHaveInviteLink();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if (!lookupLink().isEmpty() || canCreateLink()) {
|
||||||
const auto copyLink = [=] {
|
const auto copyLink = [=] {
|
||||||
const auto link = lookupLink();
|
const auto link = lookupLink();
|
||||||
if (link.isEmpty()) {
|
if (link.isEmpty()) {
|
||||||
|
@ -427,12 +441,17 @@ void GroupCallSettingsBox(
|
||||||
)->addClickHandler([=] {
|
)->addClickHandler([=] {
|
||||||
if (!copyLink() && !state->generatingLink) {
|
if (!copyLink() && !state->generatingLink) {
|
||||||
state->generatingLink = true;
|
state->generatingLink = true;
|
||||||
channel->session().api().request(MTPmessages_ExportChatInvite(
|
peer->session().api().request(MTPmessages_ExportChatInvite(
|
||||||
channel->input
|
peer->input
|
||||||
)).done([=](const MTPExportedChatInvite &result) {
|
)).done([=](const MTPExportedChatInvite &result) {
|
||||||
if (result.type() == mtpc_chatInviteExported) {
|
if (result.type() == mtpc_chatInviteExported) {
|
||||||
channel->setInviteLink(
|
const auto link = qs(
|
||||||
qs(result.c_chatInviteExported().vlink()));
|
result.c_chatInviteExported().vlink());
|
||||||
|
if (const auto chat = peer->asChat()) {
|
||||||
|
chat->setInviteLink(link);
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
|
channel->setInviteLink(link);
|
||||||
|
}
|
||||||
copyLink();
|
copyLink();
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
|
@ -440,7 +459,7 @@ void GroupCallSettingsBox(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel->canManageCall()) {
|
if (peer->canManageGroupCall()) {
|
||||||
AddButton(
|
AddButton(
|
||||||
layout,
|
layout,
|
||||||
tr::lng_group_call_end(),
|
tr::lng_group_call_end(),
|
||||||
|
@ -472,7 +491,7 @@ void GroupCallSettingsBox(
|
||||||
if (canChangeJoinMuted
|
if (canChangeJoinMuted
|
||||||
&& muteJoined
|
&& muteJoined
|
||||||
&& muteJoined->toggled() != joinMuted) {
|
&& muteJoined->toggled() != joinMuted) {
|
||||||
SaveCallJoinMuted(channel, id, muteJoined->toggled());
|
SaveCallJoinMuted(peer, id, muteJoined->toggled());
|
||||||
}
|
}
|
||||||
}, box->lifetime());
|
}, box->lifetime());
|
||||||
box->addButton(tr::lng_box_done(), [=] {
|
box->addButton(tr::lng_box_done(), [=] {
|
||||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "media/audio/media_audio_track.h"
|
#include "media/audio/media_audio_track.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
|
@ -58,12 +59,12 @@ void Instance::startOutgoingCall(not_null<UserData*> user, bool video) {
|
||||||
}), video);
|
}), video);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::startOrJoinGroupCall(not_null<ChannelData*> channel) {
|
void Instance::startOrJoinGroupCall(not_null<PeerData*> peer) {
|
||||||
destroyCurrentCall();
|
destroyCurrentCall();
|
||||||
|
|
||||||
const auto call = channel->call();
|
const auto call = peer->groupCall();
|
||||||
createGroupCall(
|
createGroupCall(
|
||||||
channel,
|
peer,
|
||||||
call ? call->input() : MTP_inputGroupCall(MTPlong(), MTPlong()));
|
call ? call->input() : MTP_inputGroupCall(MTPlong(), MTPlong()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,17 +184,17 @@ void Instance::destroyGroupCall(not_null<GroupCall*> call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::createGroupCall(
|
void Instance::createGroupCall(
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
const MTPInputGroupCall &inputCall) {
|
const MTPInputGroupCall &inputCall) {
|
||||||
destroyCurrentCall();
|
destroyCurrentCall();
|
||||||
|
|
||||||
auto call = std::make_unique<GroupCall>(
|
auto call = std::make_unique<GroupCall>(
|
||||||
getGroupCallDelegate(),
|
getGroupCallDelegate(),
|
||||||
channel,
|
peer,
|
||||||
inputCall);
|
inputCall);
|
||||||
const auto raw = call.get();
|
const auto raw = call.get();
|
||||||
|
|
||||||
channel->session().account().sessionChanges(
|
peer->session().account().sessionChanges(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
destroyGroupCall(raw);
|
destroyGroupCall(raw);
|
||||||
}, raw->lifetime());
|
}, raw->lifetime());
|
||||||
|
@ -387,7 +388,7 @@ void Instance::handleGroupCallUpdate(
|
||||||
existing->applyUpdate(call);
|
existing->applyUpdate(call);
|
||||||
}
|
}
|
||||||
if (_currentGroupCall
|
if (_currentGroupCall
|
||||||
&& (&_currentGroupCall->channel()->session() == session)) {
|
&& (&_currentGroupCall->peer()->session() == session)) {
|
||||||
_currentGroupCall->handleUpdate(call);
|
_currentGroupCall->handleUpdate(call);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,7 +403,7 @@ void Instance::handleGroupCallUpdate(
|
||||||
existing->applyUpdate(update);
|
existing->applyUpdate(update);
|
||||||
}
|
}
|
||||||
if (_currentGroupCall
|
if (_currentGroupCall
|
||||||
&& (&_currentGroupCall->channel()->session() == session)
|
&& (&_currentGroupCall->peer()->session() == session)
|
||||||
&& (_currentGroupCall->id() == callId)) {
|
&& (_currentGroupCall->id() == callId)) {
|
||||||
_currentGroupCall->handleUpdate(update);
|
_currentGroupCall->handleUpdate(update);
|
||||||
}
|
}
|
||||||
|
@ -458,7 +459,7 @@ bool Instance::hasActivePanel(not_null<Main::Session*> session) const {
|
||||||
return (&_currentCall->user()->session() == session)
|
return (&_currentCall->user()->session() == session)
|
||||||
&& _currentCallPanel->isActive();
|
&& _currentCallPanel->isActive();
|
||||||
} else if (inGroupCall()) {
|
} else if (inGroupCall()) {
|
||||||
return (&_currentGroupCall->channel()->session() == session)
|
return (&_currentGroupCall->peer()->session() == session)
|
||||||
&& _currentGroupCallPanel->isActive();
|
&& _currentGroupCallPanel->isActive();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
~Instance();
|
~Instance();
|
||||||
|
|
||||||
void startOutgoingCall(not_null<UserData*> user, bool video);
|
void startOutgoingCall(not_null<UserData*> user, bool video);
|
||||||
void startOrJoinGroupCall(not_null<ChannelData*> channel);
|
void startOrJoinGroupCall(not_null<PeerData*> peer);
|
||||||
void handleUpdate(
|
void handleUpdate(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPUpdate &update);
|
const MTPUpdate &update);
|
||||||
|
@ -94,7 +94,7 @@ private:
|
||||||
void destroyCall(not_null<Call*> call);
|
void destroyCall(not_null<Call*> call);
|
||||||
|
|
||||||
void createGroupCall(
|
void createGroupCall(
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
const MTPInputGroupCall &inputCall);
|
const MTPInputGroupCall &inputCall);
|
||||||
void destroyGroupCall(not_null<GroupCall*> call);
|
void destroyGroupCall(not_null<GroupCall*> call);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/view/history_view_group_call_tracker.h" // ContentByCall.
|
#include "history/view/history_view_group_call_tracker.h" // ContentByCall.
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "boxes/abstract_box.h"
|
#include "boxes/abstract_box.h"
|
||||||
|
@ -506,12 +506,12 @@ void TopBar::initBlobsUnder(
|
||||||
}
|
}
|
||||||
|
|
||||||
void TopBar::subscribeToMembersChanges(not_null<GroupCall*> call) {
|
void TopBar::subscribeToMembersChanges(not_null<GroupCall*> call) {
|
||||||
const auto channel = call->channel();
|
const auto peer = call->peer();
|
||||||
channel->session().changes().peerFlagsValue(
|
peer->session().changes().peerFlagsValue(
|
||||||
channel,
|
peer,
|
||||||
Data::PeerUpdate::Flag::GroupCall
|
Data::PeerUpdate::Flag::GroupCall
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=] {
|
||||||
return channel->call();
|
return peer->groupCall();
|
||||||
}) | rpl::filter([=](Data::GroupCall *real) {
|
}) | rpl::filter([=](Data::GroupCall *real) {
|
||||||
const auto call = _groupCall.get();
|
const auto call = _groupCall.get();
|
||||||
return call && real && (real->id() == call->id());
|
return call && real && (real->id() == call->id());
|
||||||
|
@ -550,6 +550,17 @@ void TopBar::subscribeToMembersChanges(not_null<GroupCall*> call) {
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
call->peer()->session().changes().peerUpdates(
|
||||||
|
Data::PeerUpdate::Flag::Name
|
||||||
|
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
||||||
|
// _peer may change for the same Panel.
|
||||||
|
const auto call = _groupCall.get();
|
||||||
|
return (call != nullptr) && (update.peer == call->peer());
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
updateInfoLabels();
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TopBar::generateUserpicsInRow() {
|
void TopBar::generateUserpicsInRow() {
|
||||||
|
@ -599,8 +610,8 @@ void TopBar::setInfoLabels() {
|
||||||
_fullInfoLabel->setText(fullName.toUpper());
|
_fullInfoLabel->setText(fullName.toUpper());
|
||||||
_shortInfoLabel->setText(shortName.toUpper());
|
_shortInfoLabel->setText(shortName.toUpper());
|
||||||
} else if (const auto group = _groupCall.get()) {
|
} else if (const auto group = _groupCall.get()) {
|
||||||
const auto channel = group->channel();
|
const auto peer = group->peer();
|
||||||
const auto name = channel->name;
|
const auto name = peer->name;
|
||||||
_fullInfoLabel->setText(name.toUpper());
|
_fullInfoLabel->setText(name.toUpper());
|
||||||
_shortInfoLabel->setText(name.toUpper());
|
_shortInfoLabel->setText(name.toUpper());
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,13 +104,9 @@ void ChannelData::setInviteLink(const QString &newInviteLink) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ChannelData::inviteLink() const {
|
|
||||||
return _inviteLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChannelData::canHaveInviteLink() const {
|
bool ChannelData::canHaveInviteLink() const {
|
||||||
return (adminRights() & AdminRight::f_invite_users)
|
return amCreator()
|
||||||
|| amCreator();
|
|| (adminRights() & AdminRight::f_invite_users);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelData::setLocation(const MTPChannelLocation &data) {
|
void ChannelData::setLocation(const MTPChannelLocation &data) {
|
||||||
|
@ -524,10 +520,6 @@ bool ChannelData::canRestrictUser(not_null<UserData*> user) const {
|
||||||
return adminRights() & AdminRight::f_ban_users;
|
return adminRights() & AdminRight::f_ban_users;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChannelData::canManageCall() const {
|
|
||||||
return amCreator() || (adminRights() & AdminRight::f_manage_call);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChannelData::setAdminRights(const MTPChatAdminRights &rights) {
|
void ChannelData::setAdminRights(const MTPChatAdminRights &rights) {
|
||||||
if (rights.c_chatAdminRights().vflags().v == adminRights()) {
|
if (rights.c_chatAdminRights().vflags().v == adminRights()) {
|
||||||
return;
|
return;
|
||||||
|
@ -677,14 +669,24 @@ void ChannelData::privateErrorReceived() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelData::setCall(const MTPInputGroupCall &call) {
|
void ChannelData::migrateCall(std::unique_ptr<Data::GroupCall> call) {
|
||||||
|
Expects(_call == nullptr);
|
||||||
|
Expects(call != nullptr);
|
||||||
|
|
||||||
|
_call = std::move(call);
|
||||||
|
_call->setPeer(this);
|
||||||
|
session().changes().peerUpdated(this, UpdateFlag::GroupCall);
|
||||||
|
addFlags(MTPDchannel::Flag::f_call_active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelData::setGroupCall(const MTPInputGroupCall &call) {
|
||||||
call.match([&](const MTPDinputGroupCall &data) {
|
call.match([&](const MTPDinputGroupCall &data) {
|
||||||
if (_call && _call->id() == data.vid().v) {
|
if (_call && _call->id() == data.vid().v) {
|
||||||
return;
|
return;
|
||||||
} else if (!_call && !data.vid().v) {
|
} else if (!_call && !data.vid().v) {
|
||||||
return;
|
return;
|
||||||
} else if (!data.vid().v) {
|
} else if (!data.vid().v) {
|
||||||
clearCall();
|
clearGroupCall();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto hasCall = (_call != nullptr);
|
const auto hasCall = (_call != nullptr);
|
||||||
|
@ -701,7 +703,7 @@ void ChannelData::setCall(const MTPInputGroupCall &call) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelData::clearCall() {
|
void ChannelData::clearGroupCall() {
|
||||||
if (!_call) {
|
if (!_call) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -744,9 +746,9 @@ void ApplyChannelUpdate(
|
||||||
auto canEditStickers = channel->canEditStickers();
|
auto canEditStickers = channel->canEditStickers();
|
||||||
|
|
||||||
if (const auto call = update.vcall()) {
|
if (const auto call = update.vcall()) {
|
||||||
channel->setCall(*call);
|
channel->setGroupCall(*call);
|
||||||
} else {
|
} else {
|
||||||
channel->clearCall();
|
channel->clearGroupCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
channel->setFullFlags(update.vflags().v);
|
channel->setFullFlags(update.vflags().v);
|
||||||
|
|
|
@ -11,10 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_pts_waiter.h"
|
#include "data/data_pts_waiter.h"
|
||||||
#include "data/data_location.h"
|
#include "data/data_location.h"
|
||||||
|
|
||||||
namespace Data {
|
|
||||||
class GroupCall;
|
|
||||||
} // namespace Data
|
|
||||||
|
|
||||||
struct ChannelLocation {
|
struct ChannelLocation {
|
||||||
QString address;
|
QString address;
|
||||||
Data::LocationPoint point;
|
Data::LocationPoint point;
|
||||||
|
@ -307,10 +303,11 @@ public:
|
||||||
[[nodiscard]] bool canDelete() const;
|
[[nodiscard]] bool canDelete() const;
|
||||||
[[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const;
|
[[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const;
|
||||||
[[nodiscard]] bool canRestrictUser(not_null<UserData*> user) const;
|
[[nodiscard]] bool canRestrictUser(not_null<UserData*> user) const;
|
||||||
[[nodiscard]] bool canManageCall() const;
|
|
||||||
|
|
||||||
void setInviteLink(const QString &newInviteLink);
|
void setInviteLink(const QString &newInviteLink);
|
||||||
[[nodiscard]] QString inviteLink() const;
|
[[nodiscard]] QString inviteLink() const {
|
||||||
|
return _inviteLink;
|
||||||
|
}
|
||||||
[[nodiscard]] bool canHaveInviteLink() const;
|
[[nodiscard]] bool canHaveInviteLink() const;
|
||||||
|
|
||||||
void setLocation(const MTPChannelLocation &data);
|
void setLocation(const MTPChannelLocation &data);
|
||||||
|
@ -399,11 +396,12 @@ public:
|
||||||
[[nodiscard]] QString invitePeekHash() const;
|
[[nodiscard]] QString invitePeekHash() const;
|
||||||
void privateErrorReceived();
|
void privateErrorReceived();
|
||||||
|
|
||||||
[[nodiscard]] Data::GroupCall *call() const {
|
[[nodiscard]] Data::GroupCall *groupCall() const {
|
||||||
return _call.get();
|
return _call.get();
|
||||||
}
|
}
|
||||||
void setCall(const MTPInputGroupCall &call);
|
void migrateCall(std::unique_ptr<Data::GroupCall> call);
|
||||||
void clearCall();
|
void setGroupCall(const MTPInputGroupCall &call);
|
||||||
|
void clearGroupCall();
|
||||||
|
|
||||||
// Still public data members.
|
// Still public data members.
|
||||||
uint64 access = 0;
|
uint64 access = 0;
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
#include "data/data_group_call.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
@ -24,6 +25,14 @@ using UpdateFlag = Data::PeerUpdate::Flag;
|
||||||
ChatData::ChatData(not_null<Data::Session*> owner, PeerId id)
|
ChatData::ChatData(not_null<Data::Session*> owner, PeerId id)
|
||||||
: PeerData(owner, id)
|
: PeerData(owner, id)
|
||||||
, inputChat(MTP_int(bareId())) {
|
, inputChat(MTP_int(bareId())) {
|
||||||
|
_flags.changes(
|
||||||
|
) | rpl::start_with_next([=](const Flags::Change &change) {
|
||||||
|
if (change.diff & MTPDchat::Flag::f_call_not_empty) {
|
||||||
|
if (const auto history = this->owner().historyLoaded(this)) {
|
||||||
|
history->updateChatListEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatData::setPhoto(const MTPChatPhoto &photo) {
|
void ChatData::setPhoto(const MTPChatPhoto &photo) {
|
||||||
|
@ -124,6 +133,11 @@ void ChatData::setInviteLink(const QString &newInviteLink) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChatData::canHaveInviteLink() const {
|
||||||
|
return amCreator()
|
||||||
|
|| (adminRights() & AdminRight::f_invite_users);
|
||||||
|
}
|
||||||
|
|
||||||
void ChatData::setAdminRights(const MTPChatAdminRights &rights) {
|
void ChatData::setAdminRights(const MTPChatAdminRights &rights) {
|
||||||
if (rights.c_chatAdminRights().vflags().v == adminRights()) {
|
if (rights.c_chatAdminRights().vflags().v == adminRights()) {
|
||||||
return;
|
return;
|
||||||
|
@ -176,6 +190,47 @@ void ChatData::setMigrateToChannel(ChannelData *channel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatData::setGroupCall(const MTPInputGroupCall &call) {
|
||||||
|
if (migrateTo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
call.match([&](const MTPDinputGroupCall &data) {
|
||||||
|
if (_call && _call->id() == data.vid().v) {
|
||||||
|
return;
|
||||||
|
} else if (!_call && !data.vid().v) {
|
||||||
|
return;
|
||||||
|
} else if (!data.vid().v) {
|
||||||
|
clearGroupCall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto hasCall = (_call != nullptr);
|
||||||
|
if (hasCall) {
|
||||||
|
owner().unregisterGroupCall(_call.get());
|
||||||
|
}
|
||||||
|
_call = std::make_unique<Data::GroupCall>(
|
||||||
|
this,
|
||||||
|
data.vid().v,
|
||||||
|
data.vaccess_hash().v);
|
||||||
|
owner().registerGroupCall(_call.get());
|
||||||
|
session().changes().peerUpdated(this, UpdateFlag::GroupCall);
|
||||||
|
addFlags(MTPDchat::Flag::f_call_active);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatData::clearGroupCall() {
|
||||||
|
if (!_call) {
|
||||||
|
return;
|
||||||
|
} else if (const auto group = migrateTo(); group && !group->groupCall()) {
|
||||||
|
group->migrateCall(base::take(_call));
|
||||||
|
} else {
|
||||||
|
owner().unregisterGroupCall(_call.get());
|
||||||
|
_call = nullptr;
|
||||||
|
}
|
||||||
|
session().changes().peerUpdated(this, UpdateFlag::GroupCall);
|
||||||
|
removeFlags(MTPDchat::Flag::f_call_active
|
||||||
|
| MTPDchat::Flag::f_call_not_empty);
|
||||||
|
}
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
void ApplyChatUpdate(
|
void ApplyChatUpdate(
|
||||||
|
@ -310,6 +365,12 @@ void ApplyChatUpdate(
|
||||||
void ApplyChatUpdate(not_null<ChatData*> chat, const MTPDchatFull &update) {
|
void ApplyChatUpdate(not_null<ChatData*> chat, const MTPDchatFull &update) {
|
||||||
ApplyChatUpdate(chat, update.vparticipants());
|
ApplyChatUpdate(chat, update.vparticipants());
|
||||||
|
|
||||||
|
if (const auto call = update.vcall()) {
|
||||||
|
chat->setGroupCall(*call);
|
||||||
|
} else {
|
||||||
|
chat->clearGroupCall();
|
||||||
|
}
|
||||||
|
|
||||||
if (const auto info = update.vbot_info()) {
|
if (const auto info = update.vbot_info()) {
|
||||||
for (const auto &item : info->v) {
|
for (const auto &item : info->v) {
|
||||||
item.match([&](const MTPDbotInfo &data) {
|
item.match([&](const MTPDbotInfo &data) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ public:
|
||||||
| MTPDchat::Flag::f_deactivated
|
| MTPDchat::Flag::f_deactivated
|
||||||
| MTPDchat::Flag::f_migrated_to
|
| MTPDchat::Flag::f_migrated_to
|
||||||
| MTPDchat::Flag::f_admin_rights
|
| MTPDchat::Flag::f_admin_rights
|
||||||
|
| MTPDchat::Flag::f_call_not_empty
|
||||||
| MTPDchat::Flag::f_default_banned_rights;
|
| MTPDchat::Flag::f_default_banned_rights;
|
||||||
using Flags = Data::Flags<
|
using Flags = Data::Flags<
|
||||||
MTPDchat::Flags,
|
MTPDchat::Flags,
|
||||||
|
@ -141,9 +142,10 @@ public:
|
||||||
void applyEditAdmin(not_null<UserData*> user, bool isAdmin);
|
void applyEditAdmin(not_null<UserData*> user, bool isAdmin);
|
||||||
|
|
||||||
void setInviteLink(const QString &newInviteLink);
|
void setInviteLink(const QString &newInviteLink);
|
||||||
QString inviteLink() const {
|
[[nodiscard]] QString inviteLink() const {
|
||||||
return _inviteLink;
|
return _inviteLink;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool canHaveInviteLink() const;
|
||||||
void refreshBotStatus();
|
void refreshBotStatus();
|
||||||
|
|
||||||
enum class UpdateStatus {
|
enum class UpdateStatus {
|
||||||
|
@ -162,6 +164,12 @@ public:
|
||||||
ChannelData *getMigrateToChannel() const;
|
ChannelData *getMigrateToChannel() const;
|
||||||
void setMigrateToChannel(ChannelData *channel);
|
void setMigrateToChannel(ChannelData *channel);
|
||||||
|
|
||||||
|
[[nodiscard]] Data::GroupCall *groupCall() const {
|
||||||
|
return _call.get();
|
||||||
|
}
|
||||||
|
void setGroupCall(const MTPInputGroupCall &call);
|
||||||
|
void clearGroupCall();
|
||||||
|
|
||||||
// Still public data members.
|
// Still public data members.
|
||||||
const MTPint inputChat;
|
const MTPint inputChat;
|
||||||
|
|
||||||
|
@ -185,7 +193,10 @@ private:
|
||||||
AdminRightFlags _adminRights;
|
AdminRightFlags _adminRights;
|
||||||
int _version = 0;
|
int _version = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<Data::GroupCall> _call;
|
||||||
|
|
||||||
ChannelData *_migratedTo = nullptr;
|
ChannelData *_migratedTo = nullptr;
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
@ -27,12 +28,12 @@ constexpr auto kActiveAfterJoined = crl::time(1000);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
GroupCall::GroupCall(
|
GroupCall::GroupCall(
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
uint64 id,
|
uint64 id,
|
||||||
uint64 accessHash)
|
uint64 accessHash)
|
||||||
: _channel(channel)
|
: _id(id)
|
||||||
, _id(id)
|
|
||||||
, _accessHash(accessHash)
|
, _accessHash(accessHash)
|
||||||
|
, _peer(peer) // #TODO calls migration
|
||||||
, _speakingByActiveFinishTimer([=] { checkFinishSpeakingByActive(); }) {
|
, _speakingByActiveFinishTimer([=] { checkFinishSpeakingByActive(); }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,14 +47,21 @@ uint64 GroupCall::id() const {
|
||||||
return _id;
|
return _id;
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<ChannelData*> GroupCall::channel() const {
|
not_null<PeerData*> GroupCall::peer() const {
|
||||||
return _channel;
|
return _peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPInputGroupCall GroupCall::input() const {
|
MTPInputGroupCall GroupCall::input() const {
|
||||||
return MTP_inputGroupCall(MTP_long(_id), MTP_long(_accessHash));
|
return MTP_inputGroupCall(MTP_long(_id), MTP_long(_accessHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GroupCall::setPeer(not_null<PeerData*> peer) {
|
||||||
|
Expects(peer->migrateFrom() == _peer);
|
||||||
|
Expects(_peer->migrateTo() == peer);
|
||||||
|
|
||||||
|
_peer = peer;
|
||||||
|
}
|
||||||
|
|
||||||
auto GroupCall::participants() const
|
auto GroupCall::participants() const
|
||||||
-> const std::vector<Participant> & {
|
-> const std::vector<Participant> & {
|
||||||
return _participants;
|
return _participants;
|
||||||
|
@ -77,7 +85,7 @@ void GroupCall::requestParticipants() {
|
||||||
)).done([=](const MTPphone_GroupParticipants &result) {
|
)).done([=](const MTPphone_GroupParticipants &result) {
|
||||||
result.match([&](const MTPDphone_groupParticipants &data) {
|
result.match([&](const MTPDphone_groupParticipants &data) {
|
||||||
_nextOffset = qs(data.vnext_offset());
|
_nextOffset = qs(data.vnext_offset());
|
||||||
_channel->owner().processUsers(data.vusers());
|
_peer->owner().processUsers(data.vusers());
|
||||||
applyParticipantsSlice(
|
applyParticipantsSlice(
|
||||||
data.vparticipants().v,
|
data.vparticipants().v,
|
||||||
ApplySliceSource::SliceLoaded);
|
ApplySliceSource::SliceLoaded);
|
||||||
|
@ -92,30 +100,43 @@ void GroupCall::requestParticipants() {
|
||||||
});
|
});
|
||||||
_participantsSliceAdded.fire({});
|
_participantsSliceAdded.fire({});
|
||||||
_participantsRequestId = 0;
|
_participantsRequestId = 0;
|
||||||
changeChannelEmptyCallFlag();
|
changePeerEmptyCallFlag();
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
_fullCount = _participants.size();
|
_fullCount = _participants.size();
|
||||||
_allReceived = true;
|
_allReceived = true;
|
||||||
_participantsRequestId = 0;
|
_participantsRequestId = 0;
|
||||||
changeChannelEmptyCallFlag();
|
changePeerEmptyCallFlag();
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::changeChannelEmptyCallFlag() {
|
void GroupCall::changePeerEmptyCallFlag() {
|
||||||
constexpr auto flag = MTPDchannel::Flag::f_call_not_empty;
|
const auto chat = _peer->asChat();
|
||||||
if (_channel->call() != this) {
|
const auto channel = _peer->asChannel();
|
||||||
|
constexpr auto chatFlag = MTPDchat::Flag::f_call_not_empty;
|
||||||
|
constexpr auto channelFlag = MTPDchannel::Flag::f_call_not_empty;
|
||||||
|
if (_peer->groupCall() != this) {
|
||||||
return;
|
return;
|
||||||
} else if (fullCount() > 0) {
|
} else if (fullCount() > 0) {
|
||||||
if (!(_channel->flags() & flag)) {
|
if (chat && !(chat->flags() & chatFlag)) {
|
||||||
_channel->addFlags(flag);
|
chat->addFlags(chatFlag);
|
||||||
_channel->session().changes().peerUpdated(
|
chat->session().changes().peerUpdated(
|
||||||
_channel,
|
chat,
|
||||||
|
Data::PeerUpdate::Flag::GroupCall);
|
||||||
|
} else if (channel && !(channel->flags() & channelFlag)) {
|
||||||
|
channel->addFlags(channelFlag);
|
||||||
|
channel->session().changes().peerUpdated(
|
||||||
|
channel,
|
||||||
Data::PeerUpdate::Flag::GroupCall);
|
Data::PeerUpdate::Flag::GroupCall);
|
||||||
}
|
}
|
||||||
} else if (_channel->flags() & flag) {
|
} else if (chat && (chat->flags() & chatFlag)) {
|
||||||
_channel->removeFlags(flag);
|
chat->removeFlags(chatFlag);
|
||||||
_channel->session().changes().peerUpdated(
|
chat->session().changes().peerUpdated(
|
||||||
_channel,
|
chat,
|
||||||
|
Data::PeerUpdate::Flag::GroupCall);
|
||||||
|
} else if (channel && (channel->flags() & channelFlag)) {
|
||||||
|
channel->removeFlags(channelFlag);
|
||||||
|
channel->session().changes().peerUpdated(
|
||||||
|
channel,
|
||||||
Data::PeerUpdate::Flag::GroupCall);
|
Data::PeerUpdate::Flag::GroupCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,13 +187,17 @@ void GroupCall::applyCall(const MTPGroupCall &call, bool force) {
|
||||||
_canChangeJoinMuted = data.is_can_change_join_muted();
|
_canChangeJoinMuted = data.is_can_change_join_muted();
|
||||||
_version = data.vversion().v;
|
_version = data.vversion().v;
|
||||||
_fullCount = data.vparticipants_count().v;
|
_fullCount = data.vparticipants_count().v;
|
||||||
changeChannelEmptyCallFlag();
|
changePeerEmptyCallFlag();
|
||||||
}, [&](const MTPDgroupCallDiscarded &data) {
|
}, [&](const MTPDgroupCallDiscarded &data) {
|
||||||
const auto id = _id;
|
const auto id = _id;
|
||||||
const auto channel = _channel;
|
const auto peer = _peer;
|
||||||
crl::on_main(&channel->session(), [=] {
|
crl::on_main(&peer->session(), [=] {
|
||||||
if (channel->call() && channel->call()->id() == id) {
|
if (peer->groupCall() && peer->groupCall()->id() == id) {
|
||||||
channel->clearCall();
|
if (const auto chat = peer->asChat()) {
|
||||||
|
chat->clearGroupCall();
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
|
channel->clearGroupCall();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -189,7 +214,7 @@ void GroupCall::reload() {
|
||||||
MTPphone_GetGroupCall(input())
|
MTPphone_GetGroupCall(input())
|
||||||
).done([=](const MTPphone_GroupCall &result) {
|
).done([=](const MTPphone_GroupCall &result) {
|
||||||
result.match([&](const MTPDphone_groupCall &data) {
|
result.match([&](const MTPDphone_groupCall &data) {
|
||||||
_channel->owner().processUsers(data.vusers());
|
_peer->owner().processUsers(data.vusers());
|
||||||
_participants.clear();
|
_participants.clear();
|
||||||
_speakingByActiveFinishes.clear();
|
_speakingByActiveFinishes.clear();
|
||||||
_userBySsrc.clear();
|
_userBySsrc.clear();
|
||||||
|
@ -217,7 +242,7 @@ void GroupCall::applyParticipantsSlice(
|
||||||
for (const auto &participant : list) {
|
for (const auto &participant : list) {
|
||||||
participant.match([&](const MTPDgroupCallParticipant &data) {
|
participant.match([&](const MTPDgroupCallParticipant &data) {
|
||||||
const auto userId = data.vuser_id().v;
|
const auto userId = data.vuser_id().v;
|
||||||
const auto user = _channel->owner().user(userId);
|
const auto user = _peer->owner().user(userId);
|
||||||
const auto i = ranges::find(
|
const auto i = ranges::find(
|
||||||
_participants,
|
_participants,
|
||||||
user,
|
user,
|
||||||
|
@ -262,7 +287,7 @@ void GroupCall::applyParticipantsSlice(
|
||||||
if (i == end(_participants)) {
|
if (i == end(_participants)) {
|
||||||
_userBySsrc.emplace(value.ssrc, user);
|
_userBySsrc.emplace(value.ssrc, user);
|
||||||
_participants.push_back(value);
|
_participants.push_back(value);
|
||||||
_channel->owner().unregisterInvitedToCallUser(_id, user);
|
_peer->owner().unregisterInvitedToCallUser(_id, user);
|
||||||
++changedCount;
|
++changedCount;
|
||||||
} else {
|
} else {
|
||||||
if (i->ssrc != value.ssrc) {
|
if (i->ssrc != value.ssrc) {
|
||||||
|
@ -281,7 +306,7 @@ void GroupCall::applyParticipantsSlice(
|
||||||
}
|
}
|
||||||
if (sliceSource == ApplySliceSource::UpdateReceived) {
|
if (sliceSource == ApplySliceSource::UpdateReceived) {
|
||||||
_fullCount = changedCount;
|
_fullCount = changedCount;
|
||||||
changeChannelEmptyCallFlag();
|
changePeerEmptyCallFlag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +318,7 @@ void GroupCall::applyParticipantsMutes(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto userId = data.vuser_id().v;
|
const auto userId = data.vuser_id().v;
|
||||||
const auto user = _channel->owner().user(userId);
|
const auto user = _peer->owner().user(userId);
|
||||||
const auto i = ranges::find(
|
const auto i = ranges::find(
|
||||||
_participants,
|
_participants,
|
||||||
user,
|
user,
|
||||||
|
@ -466,7 +491,7 @@ void GroupCall::requestUnknownParticipants() {
|
||||||
MTP_int(kRequestPerPage)
|
MTP_int(kRequestPerPage)
|
||||||
)).done([=](const MTPphone_GroupParticipants &result) {
|
)).done([=](const MTPphone_GroupParticipants &result) {
|
||||||
result.match([&](const MTPDphone_groupParticipants &data) {
|
result.match([&](const MTPDphone_groupParticipants &data) {
|
||||||
_channel->owner().processUsers(data.vusers());
|
_peer->owner().processUsers(data.vusers());
|
||||||
applyParticipantsSlice(
|
applyParticipantsSlice(
|
||||||
data.vparticipants().v,
|
data.vparticipants().v,
|
||||||
ApplySliceSource::UnknownLoaded);
|
ApplySliceSource::UnknownLoaded);
|
||||||
|
@ -478,7 +503,7 @@ void GroupCall::requestUnknownParticipants() {
|
||||||
_unknownSpokenSsrcs.remove(ssrc);
|
_unknownSpokenSsrcs.remove(ssrc);
|
||||||
}
|
}
|
||||||
for (const auto [userId, when] : uids) {
|
for (const auto [userId, when] : uids) {
|
||||||
if (const auto user = _channel->owner().userLoaded(userId)) {
|
if (const auto user = _peer->owner().userLoaded(userId)) {
|
||||||
const auto isParticipant = ranges::contains(
|
const auto isParticipant = ranges::contains(
|
||||||
_participants,
|
_participants,
|
||||||
not_null{ user },
|
not_null{ user },
|
||||||
|
@ -564,7 +589,7 @@ bool GroupCall::canChangeJoinMuted() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiWrap &GroupCall::api() const {
|
ApiWrap &GroupCall::api() const {
|
||||||
return _channel->session().api();
|
return _peer->session().api();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
|
|
||||||
class UserData;
|
class UserData;
|
||||||
class ChannelData;
|
class PeerData;
|
||||||
|
|
||||||
class ApiWrap;
|
class ApiWrap;
|
||||||
|
|
||||||
|
@ -18,13 +18,15 @@ namespace Data {
|
||||||
|
|
||||||
class GroupCall final {
|
class GroupCall final {
|
||||||
public:
|
public:
|
||||||
GroupCall(not_null<ChannelData*> channel, uint64 id, uint64 accessHash);
|
GroupCall(not_null<PeerData*> peer, uint64 id, uint64 accessHash);
|
||||||
~GroupCall();
|
~GroupCall();
|
||||||
|
|
||||||
[[nodiscard]] uint64 id() const;
|
[[nodiscard]] uint64 id() const;
|
||||||
[[nodiscard]] not_null<ChannelData*> channel() const;
|
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||||
[[nodiscard]] MTPInputGroupCall input() const;
|
[[nodiscard]] MTPInputGroupCall input() const;
|
||||||
|
|
||||||
|
void setPeer(not_null<PeerData*> peer);
|
||||||
|
|
||||||
struct Participant {
|
struct Participant {
|
||||||
not_null<UserData*> user;
|
not_null<UserData*> user;
|
||||||
TimeId date = 0;
|
TimeId date = 0;
|
||||||
|
@ -86,13 +88,13 @@ private:
|
||||||
void applyParticipantsMutes(
|
void applyParticipantsMutes(
|
||||||
const MTPDupdateGroupCallParticipants &update);
|
const MTPDupdateGroupCallParticipants &update);
|
||||||
void requestUnknownParticipants();
|
void requestUnknownParticipants();
|
||||||
void changeChannelEmptyCallFlag();
|
void changePeerEmptyCallFlag();
|
||||||
void checkFinishSpeakingByActive();
|
void checkFinishSpeakingByActive();
|
||||||
|
|
||||||
const not_null<ChannelData*> _channel;
|
|
||||||
const uint64 _id = 0;
|
const uint64 _id = 0;
|
||||||
const uint64 _accessHash = 0;
|
const uint64 _accessHash = 0;
|
||||||
|
|
||||||
|
not_null<PeerData*> _peer;
|
||||||
int _version = 0;
|
int _version = 0;
|
||||||
mtpRequestId _participantsRequestId = 0;
|
mtpRequestId _participantsRequestId = 0;
|
||||||
mtpRequestId _reloadRequestId = 0;
|
mtpRequestId _reloadRequestId = 0;
|
||||||
|
|
|
@ -888,6 +888,26 @@ bool PeerData::canSendPolls() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PeerData::canManageGroupCall() const {
|
||||||
|
if (const auto chat = asChat()) {
|
||||||
|
return chat->amCreator()
|
||||||
|
|| (chat->adminRights() & ChatAdminRight::f_manage_call);
|
||||||
|
} else if (const auto group = asMegagroup()) {
|
||||||
|
return group->amCreator()
|
||||||
|
|| (group->adminRights() & ChatAdminRight::f_manage_call);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::GroupCall *PeerData::groupCall() const {
|
||||||
|
if (const auto chat = asChat()) {
|
||||||
|
return chat->groupCall();
|
||||||
|
} else if (const auto group = asMegagroup()) {
|
||||||
|
return group->groupCall();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void PeerData::setIsBlocked(bool is) {
|
void PeerData::setIsBlocked(bool is) {
|
||||||
const auto status = is
|
const auto status = is
|
||||||
? BlockStatus::Blocked
|
? BlockStatus::Blocked
|
||||||
|
|
|
@ -29,6 +29,7 @@ class Session;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
|
class GroupCall;
|
||||||
|
|
||||||
int PeerColorIndex(PeerId peerId);
|
int PeerColorIndex(PeerId peerId);
|
||||||
int PeerColorIndex(int32 bareId);
|
int PeerColorIndex(int32 bareId);
|
||||||
|
@ -202,6 +203,7 @@ public:
|
||||||
[[nodiscard]] rpl::producer<bool> slowmodeAppliedValue() const;
|
[[nodiscard]] rpl::producer<bool> slowmodeAppliedValue() const;
|
||||||
[[nodiscard]] int slowmodeSecondsLeft() const;
|
[[nodiscard]] int slowmodeSecondsLeft() const;
|
||||||
[[nodiscard]] bool canSendPolls() const;
|
[[nodiscard]] bool canSendPolls() const;
|
||||||
|
[[nodiscard]] bool canManageGroupCall() const;
|
||||||
|
|
||||||
[[nodiscard]] UserData *asUser();
|
[[nodiscard]] UserData *asUser();
|
||||||
[[nodiscard]] const UserData *asUser() const;
|
[[nodiscard]] const UserData *asUser() const;
|
||||||
|
@ -383,6 +385,8 @@ public:
|
||||||
}
|
}
|
||||||
void setLoadedStatus(LoadedStatus status);
|
void setLoadedStatus(LoadedStatus status);
|
||||||
|
|
||||||
|
[[nodiscard]] Data::GroupCall *groupCall() const;
|
||||||
|
|
||||||
const PeerId id;
|
const PeerId id;
|
||||||
QString name;
|
QString name;
|
||||||
MTPinputPeer input = MTP_inputPeerEmpty();
|
MTPinputPeer input = MTP_inputPeerEmpty();
|
||||||
|
|
|
@ -604,7 +604,12 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
chat->setFlags(data.vflags().v);
|
const auto callFlag = MTPDchat::Flag::f_call_not_empty;
|
||||||
|
const auto callNotEmpty = (data.vflags().v & callFlag)
|
||||||
|
|| (chat->groupCall()
|
||||||
|
&& chat->groupCall()->fullCount() > 0);
|
||||||
|
chat->setFlags(data.vflags().v
|
||||||
|
| (callNotEmpty ? callFlag : MTPDchat::Flag(0)));
|
||||||
chat->count = data.vparticipants_count().v;
|
chat->count = data.vparticipants_count().v;
|
||||||
|
|
||||||
if (canAddMembers != chat->canAddMembers()) {
|
if (canAddMembers != chat->canAddMembers()) {
|
||||||
|
@ -651,13 +656,21 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||||
channel->setDefaultRestrictions(
|
channel->setDefaultRestrictions(
|
||||||
MTP_chatBannedRights(MTP_flags(0), MTP_int(0)));
|
MTP_chatBannedRights(MTP_flags(0), MTP_int(0)));
|
||||||
}
|
}
|
||||||
|
const auto callFlag = MTPDchannel::Flag::f_call_not_empty;
|
||||||
|
const auto callNotEmpty = (data.vflags().v & callFlag)
|
||||||
|
|| (channel->groupCall()
|
||||||
|
&& channel->groupCall()->fullCount() > 0);
|
||||||
if (minimal) {
|
if (minimal) {
|
||||||
auto mask = 0
|
auto mask = 0
|
||||||
| MTPDchannel::Flag::f_broadcast
|
| MTPDchannel::Flag::f_broadcast
|
||||||
| MTPDchannel::Flag::f_verified
|
| MTPDchannel::Flag::f_verified
|
||||||
| MTPDchannel::Flag::f_megagroup
|
| MTPDchannel::Flag::f_megagroup
|
||||||
|
| MTPDchannel::Flag::f_call_active
|
||||||
|
| MTPDchannel::Flag::f_call_not_empty
|
||||||
| MTPDchannel_ClientFlag::f_forbidden;
|
| MTPDchannel_ClientFlag::f_forbidden;
|
||||||
channel->setFlags((channel->flags() & ~mask) | (data.vflags().v & mask));
|
channel->setFlags((channel->flags() & ~mask)
|
||||||
|
| (data.vflags().v & mask)
|
||||||
|
| (callNotEmpty ? callFlag : MTPDchannel::Flag(0)));
|
||||||
if (channel->input.type() == mtpc_inputPeerEmpty
|
if (channel->input.type() == mtpc_inputPeerEmpty
|
||||||
|| channel->inputChannel.type() == mtpc_inputChannelEmpty) {
|
|| channel->inputChannel.type() == mtpc_inputChannelEmpty) {
|
||||||
channel->setAccessHash(data.vaccess_hash().value_or_empty());
|
channel->setAccessHash(data.vaccess_hash().value_or_empty());
|
||||||
|
@ -686,9 +699,6 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||||
} else {
|
} else {
|
||||||
channel->setUnavailableReasons({});
|
channel->setUnavailableReasons({});
|
||||||
}
|
}
|
||||||
const auto callFlag = MTPDchannel::Flag::f_call_not_empty;
|
|
||||||
const auto callNotEmpty = (data.vflags().v & callFlag)
|
|
||||||
|| (channel->call() && channel->call()->fullCount() > 0);
|
|
||||||
channel->setFlags(data.vflags().v
|
channel->setFlags(data.vflags().v
|
||||||
| (callNotEmpty ? callFlag : MTPDchannel::Flag(0)));
|
| (callNotEmpty ? callFlag : MTPDchannel::Flag(0)));
|
||||||
//if (const auto feedId = data.vfeed_id()) { // #feed
|
//if (const auto feedId = data.vfeed_id()) { // #feed
|
||||||
|
@ -826,9 +836,9 @@ auto Session::invitedToCallUsers(uint64 callId) const
|
||||||
|
|
||||||
void Session::registerInvitedToCallUser(
|
void Session::registerInvitedToCallUser(
|
||||||
uint64 callId,
|
uint64 callId,
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
not_null<UserData*> user) {
|
not_null<UserData*> user) {
|
||||||
const auto call = channel->call();
|
const auto call = peer->groupCall();
|
||||||
if (call && call->id() == callId) {
|
if (call && call->id() == callId) {
|
||||||
const auto inCall = ranges::contains(
|
const auto inCall = ranges::contains(
|
||||||
call->participants(),
|
call->participants(),
|
||||||
|
@ -1164,6 +1174,7 @@ void Session::setupMigrationViewer() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chat->clearGroupCall();
|
||||||
if (const auto from = historyLoaded(chat)) {
|
if (const auto from = historyLoaded(chat)) {
|
||||||
if (const auto to = historyLoaded(channel)) {
|
if (const auto to = historyLoaded(channel)) {
|
||||||
if (to->inChatList() && from->inChatList()) {
|
if (to->inChatList() && from->inChatList()) {
|
||||||
|
|
|
@ -169,7 +169,7 @@ public:
|
||||||
-> const base::flat_set<not_null<UserData*>> &;
|
-> const base::flat_set<not_null<UserData*>> &;
|
||||||
void registerInvitedToCallUser(
|
void registerInvitedToCallUser(
|
||||||
uint64 callId,
|
uint64 callId,
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
not_null<UserData*> user);
|
not_null<UserData*> user);
|
||||||
void unregisterInvitedToCallUser(uint64 callId, not_null<UserData*> user);
|
void unregisterInvitedToCallUser(uint64 callId, not_null<UserData*> user);
|
||||||
|
|
||||||
|
|
|
@ -1053,9 +1053,11 @@ void History::applyServiceChanges(
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_messageActionGroupCall: {
|
case mtpc_messageActionGroupCall: {
|
||||||
|
const auto &d = action.c_messageActionGroupCall();
|
||||||
if (const auto channel = peer->asChannel()) {
|
if (const auto channel = peer->asChannel()) {
|
||||||
const auto &d = action.c_messageActionGroupCall();
|
channel->setGroupCall(d.vcall());
|
||||||
channel->setCall(d.vcall());
|
} else if (const auto chat = peer->asChat()) {
|
||||||
|
chat->setGroupCall(d.vcall());
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_game.h"
|
#include "data/data_game.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_group_call.h" // Data::GroupCall::id().
|
#include "data/data_group_call.h" // Data::GroupCall::id().
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
|
@ -38,18 +39,27 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kPinnedMessageTextLimit = 16;
|
constexpr auto kPinnedMessageTextLimit = 16;
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<bool> ChannelHasThisCallValue(
|
[[nodiscard]] bool PeerCallKnown(not_null<PeerData*> peer) {
|
||||||
not_null<ChannelData*> channel,
|
if (peer->groupCall() != nullptr) {
|
||||||
|
return true;
|
||||||
|
} else if (const auto chat = peer->asChat()) {
|
||||||
|
return !(chat->flags() & MTPDchat::Flag::f_call_active);
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
|
return !(channel->flags() & MTPDchannel::Flag::f_call_active);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<bool> PeerHasThisCallValue(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
uint64 id) {
|
uint64 id) {
|
||||||
return channel->session().changes().peerFlagsValue(
|
return peer->session().changes().peerFlagsValue(
|
||||||
channel,
|
peer,
|
||||||
Data::PeerUpdate::Flag::GroupCall
|
Data::PeerUpdate::Flag::GroupCall
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
return (channel->call() != nullptr)
|
return PeerCallKnown(peer);
|
||||||
|| !(channel->flags()
|
|
||||||
& MTPDchannel::Flag::f_call_active);
|
|
||||||
}) | rpl::map([=] {
|
}) | rpl::map([=] {
|
||||||
const auto call = channel->call();
|
const auto call = peer->groupCall();
|
||||||
return (call && call->id() == id);
|
return (call && call->id() == id);
|
||||||
}) | rpl::distinct_until_changed(
|
}) | rpl::distinct_until_changed(
|
||||||
) | rpl::take_while([=](bool hasThisCall) {
|
) | rpl::take_while([=](bool hasThisCall) {
|
||||||
|
@ -59,15 +69,15 @@ constexpr auto kPinnedMessageTextLimit = 16;
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::optional<bool> ChannelHasThisCall(
|
[[nodiscard]] std::optional<bool> PeerHasThisCall(
|
||||||
not_null<ChannelData*> channel,
|
not_null<PeerData*> peer,
|
||||||
uint64 id) {
|
uint64 id) {
|
||||||
const auto call = channel->call();
|
const auto call = peer->groupCall();
|
||||||
return call
|
return call
|
||||||
? std::make_optional(call->id() == id)
|
? std::make_optional(call->id() == id)
|
||||||
: (channel->flags() & MTPDchannel::Flag::f_call_active)
|
: PeerCallKnown(peer)
|
||||||
? std::nullopt
|
? std::make_optional(false)
|
||||||
: std::make_optional(false);
|
: std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] uint64 CallIdFromInput(const MTPInputGroupCall &data) {
|
[[nodiscard]] uint64 CallIdFromInput(const MTPInputGroupCall &data) {
|
||||||
|
@ -76,20 +86,20 @@ constexpr auto kPinnedMessageTextLimit = 16;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ClickHandlerPtr ChannelCallClickHandler(
|
[[nodiscard]] ClickHandlerPtr GroupCallClickHandler(
|
||||||
not_null<ChannelData*> megagroup,
|
not_null<PeerData*> peer,
|
||||||
uint64 callId) {
|
uint64 callId) {
|
||||||
return std::make_shared<LambdaClickHandler>([=] {
|
return std::make_shared<LambdaClickHandler>([=] {
|
||||||
const auto call = megagroup->call();
|
const auto call = peer->groupCall();
|
||||||
if (call && call->id() == callId) {
|
if (call && call->id() == callId) {
|
||||||
const auto &windows = megagroup->session().windows();
|
const auto &windows = peer->session().windows();
|
||||||
if (windows.empty()) {
|
if (windows.empty()) {
|
||||||
Core::App().domain().activate(&megagroup->session().account());
|
Core::App().domain().activate(&peer->session().account());
|
||||||
if (windows.empty()) {
|
if (windows.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
windows.front()->startOrJoinGroupCall(megagroup);
|
windows.front()->startOrJoinGroupCall(peer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -338,10 +348,8 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
return prepareDiscardedCallText(duration->v);
|
return prepareDiscardedCallText(duration->v);
|
||||||
}
|
}
|
||||||
const auto callId = CallIdFromInput(action.vcall());
|
const auto callId = CallIdFromInput(action.vcall());
|
||||||
const auto channel = history()->peer->asChannel();
|
const auto peer = history()->peer;
|
||||||
const auto linkCallId = !channel
|
const auto linkCallId = PeerHasThisCall(peer, callId).value_or(false)
|
||||||
? 0
|
|
||||||
: ChannelHasThisCall(channel, callId).value_or(false)
|
|
||||||
? callId
|
? callId
|
||||||
: 0;
|
: 0;
|
||||||
return prepareStartedCallText(linkCallId);
|
return prepareStartedCallText(linkCallId);
|
||||||
|
@ -350,16 +358,14 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
auto prepareInviteToGroupCall = [this](const MTPDmessageActionInviteToGroupCall &action) {
|
auto prepareInviteToGroupCall = [this](const MTPDmessageActionInviteToGroupCall &action) {
|
||||||
const auto callId = CallIdFromInput(action.vcall());
|
const auto callId = CallIdFromInput(action.vcall());
|
||||||
const auto owner = &history()->owner();
|
const auto owner = &history()->owner();
|
||||||
const auto channel = history()->peer->asChannel();
|
const auto peer = history()->peer;
|
||||||
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 (channel && callId) {
|
if (callId) {
|
||||||
owner->registerInvitedToCallUser(callId, channel, user);
|
owner->registerInvitedToCallUser(callId, peer, user);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto linkCallId = !channel
|
const auto linkCallId = PeerHasThisCall(peer, callId).value_or(false)
|
||||||
? 0
|
|
||||||
: ChannelHasThisCall(channel, callId).value_or(false)
|
|
||||||
? callId
|
? callId
|
||||||
: 0;
|
: 0;
|
||||||
return prepareInvitedToCallText(action.vusers().v, linkCallId);
|
return prepareInvitedToCallText(action.vusers().v, linkCallId);
|
||||||
|
@ -534,10 +540,10 @@ HistoryService::PreparedText HistoryService::prepareStartedCallText(
|
||||||
uint64 linkCallId) {
|
uint64 linkCallId) {
|
||||||
auto result = PreparedText{};
|
auto result = PreparedText{};
|
||||||
result.links.push_back(fromLink());
|
result.links.push_back(fromLink());
|
||||||
const auto channel = history()->peer->asChannel();
|
|
||||||
auto chatText = tr::lng_action_group_call_started_chat(tr::now);
|
auto chatText = tr::lng_action_group_call_started_chat(tr::now);
|
||||||
if (channel && linkCallId) {
|
if (linkCallId) {
|
||||||
result.links.push_back(ChannelCallClickHandler(channel, linkCallId));
|
const auto peer = history()->peer;
|
||||||
|
result.links.push_back(GroupCallClickHandler(peer, linkCallId));
|
||||||
chatText = textcmdLink(2, chatText);
|
chatText = textcmdLink(2, chatText);
|
||||||
}
|
}
|
||||||
result.text = tr::lng_action_group_call_started(
|
result.text = tr::lng_action_group_call_started(
|
||||||
|
@ -552,14 +558,14 @@ HistoryService::PreparedText HistoryService::prepareStartedCallText(
|
||||||
HistoryService::PreparedText HistoryService::prepareInvitedToCallText(
|
HistoryService::PreparedText HistoryService::prepareInvitedToCallText(
|
||||||
const QVector<MTPint> &users,
|
const QVector<MTPint> &users,
|
||||||
uint64 linkCallId) {
|
uint64 linkCallId) {
|
||||||
const auto channel = history()->peer->asChannel();
|
const auto owner = &history()->owner();
|
||||||
const auto owner = &channel->owner();
|
|
||||||
auto chatText = tr::lng_action_invite_user_chat(tr::now);
|
auto chatText = tr::lng_action_invite_user_chat(tr::now);
|
||||||
auto result = PreparedText{};
|
auto result = PreparedText{};
|
||||||
result.links.push_back(fromLink());
|
result.links.push_back(fromLink());
|
||||||
auto linkIndex = 1;
|
auto linkIndex = 1;
|
||||||
if (channel && linkCallId) {
|
if (linkCallId) {
|
||||||
result.links.push_back(ChannelCallClickHandler(channel, linkCallId));
|
const auto peer = history()->peer;
|
||||||
|
result.links.push_back(GroupCallClickHandler(peer, linkCallId));
|
||||||
chatText = textcmdLink(++linkIndex, chatText);
|
chatText = textcmdLink(++linkIndex, chatText);
|
||||||
}
|
}
|
||||||
if (users.size() == 1) {
|
if (users.size() == 1) {
|
||||||
|
@ -938,38 +944,35 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
||||||
updateText(prepareDiscardedCallText(discard.duration));
|
updateText(prepareDiscardedCallText(discard.duration));
|
||||||
}, call->lifetime);
|
}, call->lifetime);
|
||||||
|
|
||||||
if (const auto channel = history()->peer->asChannel()) {
|
const auto peer = history()->peer;
|
||||||
const auto has = ChannelHasThisCall(channel, id);
|
const auto has = PeerHasThisCall(peer, id);
|
||||||
if (!has.has_value()) {
|
if (!has.has_value()) {
|
||||||
ChannelHasThisCallValue(
|
PeerHasThisCallValue(
|
||||||
channel,
|
peer,
|
||||||
id
|
id
|
||||||
) | rpl::start_with_next([=](bool has) {
|
) | rpl::start_with_next([=](bool has) {
|
||||||
updateText(prepareStartedCallText(has ? id : 0));
|
updateText(prepareStartedCallText(has ? id : 0));
|
||||||
}, call->lifetime);
|
}, call->lifetime);
|
||||||
} else if (*has) {
|
} else if (*has) {
|
||||||
ChannelHasThisCallValue(
|
PeerHasThisCallValue(
|
||||||
channel,
|
peer,
|
||||||
id
|
id
|
||||||
) | rpl::skip(1) | rpl::start_with_next([=](bool has) {
|
) | rpl::skip(1) | rpl::start_with_next([=](bool has) {
|
||||||
Assert(!has);
|
Assert(!has);
|
||||||
updateText(prepareStartedCallText(0));
|
updateText(prepareStartedCallText(0));
|
||||||
}, call->lifetime);
|
}, call->lifetime);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.vaction().type() == mtpc_messageActionInviteToGroupCall) {
|
} else if (message.vaction().type() == mtpc_messageActionInviteToGroupCall) {
|
||||||
const auto &data = message.vaction().c_messageActionInviteToGroupCall();
|
const auto &data = message.vaction().c_messageActionInviteToGroupCall();
|
||||||
const auto id = CallIdFromInput(data.vcall());
|
const auto id = CallIdFromInput(data.vcall());
|
||||||
const auto channel = history()->peer->asChannel();
|
const auto peer = history()->peer;
|
||||||
const auto has = channel
|
const auto has = PeerHasThisCall(peer, id);
|
||||||
? ChannelHasThisCall(channel, id)
|
|
||||||
: std::make_optional(false);
|
|
||||||
auto hasLink = !has.has_value()
|
auto hasLink = !has.has_value()
|
||||||
? ChannelHasThisCallValue(channel, id)
|
? PeerHasThisCallValue(peer, id)
|
||||||
: (*has)
|
: (*has)
|
||||||
? ChannelHasThisCallValue(
|
? PeerHasThisCallValue(
|
||||||
channel,
|
peer,
|
||||||
id) | rpl::skip(1) | rpl::type_erased()
|
id) | rpl::skip(1) | rpl::type_erased()
|
||||||
: rpl::producer<bool>();
|
: rpl::producer<bool>();
|
||||||
if (!hasLink) {
|
if (!hasLink) {
|
||||||
|
|
|
@ -5419,16 +5419,15 @@ void HistoryWidget::setupGroupCallTracker() {
|
||||||
_groupCallBar->barClicks(),
|
_groupCallBar->barClicks(),
|
||||||
_groupCallBar->joinClicks()
|
_groupCallBar->joinClicks()
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
const auto channel = _history->peer->asChannel();
|
const auto peer = _history->peer;
|
||||||
if (!channel) {
|
const auto channel = peer->asChannel();
|
||||||
return;
|
if (channel && channel->amAnonymous()) {
|
||||||
} else if (channel->amAnonymous()) {
|
|
||||||
Ui::ShowMultilineToast({
|
Ui::ShowMultilineToast({
|
||||||
.text = tr::lng_group_call_no_anonymous(tr::now),
|
.text = tr::lng_group_call_no_anonymous(tr::now),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else if (channel->call()) {
|
} else if (peer->groupCall()) {
|
||||||
controller()->startOrJoinGroupCall(channel);
|
controller()->startOrJoinGroupCall(peer);
|
||||||
}
|
}
|
||||||
}, _groupCallBar->lifetime());
|
}, _groupCallBar->lifetime());
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,8 @@ void GenerateUserpicsInRow(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupCallTracker::GroupCallTracker(not_null<ChannelData*> channel)
|
GroupCallTracker::GroupCallTracker(not_null<PeerData*> peer)
|
||||||
: _channel(channel) {
|
: _peer(peer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
||||||
|
@ -300,7 +300,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
||||||
return RegenerateUserpics(state, call, st);
|
return RegenerateUserpics(state, call, st);
|
||||||
}) | rpl::start_with_next(pushNext, lifetime);
|
}) | rpl::start_with_next(pushNext, lifetime);
|
||||||
|
|
||||||
call->channel()->session().downloaderTaskFinished(
|
call->peer()->session().downloaderTaskFinished(
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
return state->someUserpicsNotLoaded;
|
return state->someUserpicsNotLoaded;
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
|
@ -327,15 +327,15 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::content() const {
|
rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::content() const {
|
||||||
const auto channel = _channel;
|
const auto peer = _peer;
|
||||||
return rpl::combine(
|
return rpl::combine(
|
||||||
channel->session().changes().peerFlagsValue(
|
peer->session().changes().peerFlagsValue(
|
||||||
channel,
|
peer,
|
||||||
Data::PeerUpdate::Flag::GroupCall),
|
Data::PeerUpdate::Flag::GroupCall),
|
||||||
Core::App().calls().currentGroupCallValue()
|
Core::App().calls().currentGroupCallValue()
|
||||||
) | rpl::map([=](const auto&, Calls::GroupCall *current) {
|
) | rpl::map([=](const auto&, Calls::GroupCall *current) {
|
||||||
const auto call = channel->call();
|
const auto call = peer->groupCall();
|
||||||
return (call && (!current || current->channel() != channel))
|
return (call && (!current || current->peer() != peer))
|
||||||
? call
|
? call
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}) | rpl::distinct_until_changed(
|
}) | rpl::distinct_until_changed(
|
||||||
|
|
|
@ -41,7 +41,7 @@ void GenerateUserpicsInRow(
|
||||||
|
|
||||||
class GroupCallTracker final {
|
class GroupCallTracker final {
|
||||||
public:
|
public:
|
||||||
GroupCallTracker(not_null<ChannelData*> channel);
|
explicit GroupCallTracker(not_null<PeerData*> peer);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<Ui::GroupCallBarContent> content() const;
|
[[nodiscard]] rpl::producer<Ui::GroupCallBarContent> content() const;
|
||||||
[[nodiscard]] rpl::producer<> joinClicks() const;
|
[[nodiscard]] rpl::producer<> joinClicks() const;
|
||||||
|
@ -51,7 +51,7 @@ public:
|
||||||
const UserpicsInRowStyle &st);
|
const UserpicsInRowStyle &st);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
not_null<ChannelData*> _channel;
|
const not_null<PeerData*> _peer;
|
||||||
|
|
||||||
rpl::event_stream<> _joinClicks;
|
rpl::event_stream<> _joinClicks;
|
||||||
|
|
||||||
|
|
|
@ -220,23 +220,7 @@ void TopBarWidget::call() {
|
||||||
|
|
||||||
void TopBarWidget::groupCall() {
|
void TopBarWidget::groupCall() {
|
||||||
if (const auto peer = _activeChat.key.peer()) {
|
if (const auto peer = _activeChat.key.peer()) {
|
||||||
if (const auto megagroup = peer->asMegagroup()) {
|
_controller->startOrJoinGroupCall(peer);
|
||||||
_controller->startOrJoinGroupCall(megagroup);
|
|
||||||
} else if (const auto chat = peer->asChat()) {
|
|
||||||
const auto callback = [=] {
|
|
||||||
Ui::hideLayer();
|
|
||||||
const auto start = [=](not_null<ChannelData*> megagroup) {
|
|
||||||
_controller->startOrJoinGroupCall(megagroup, true);
|
|
||||||
};
|
|
||||||
peer->session().api().migrateChat(
|
|
||||||
chat,
|
|
||||||
crl::guard(this, start));
|
|
||||||
};
|
|
||||||
Ui::show(Box<ConfirmBox>(
|
|
||||||
tr::lng_group_call_create_sure(tr::now),
|
|
||||||
tr::lng_continue(tr::now),
|
|
||||||
crl::guard(this, callback)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,6 +527,7 @@ void TopBarWidget::setActiveChat(
|
||||||
}
|
}
|
||||||
_activeChat = activeChat;
|
_activeChat = activeChat;
|
||||||
_sendAction = sendAction;
|
_sendAction = sendAction;
|
||||||
|
_titlePeerText.clear();
|
||||||
_back->clearState();
|
_back->clearState();
|
||||||
update();
|
update();
|
||||||
|
|
||||||
|
@ -736,11 +721,7 @@ void TopBarWidget::updateControlsVisibility() {
|
||||||
_call->setVisible(historyMode && callsEnabled);
|
_call->setVisible(historyMode && callsEnabled);
|
||||||
const auto groupCallsEnabled = [&] {
|
const auto groupCallsEnabled = [&] {
|
||||||
if (const auto peer = _activeChat.key.peer()) {
|
if (const auto peer = _activeChat.key.peer()) {
|
||||||
if (const auto megagroup = peer->asMegagroup()) {
|
return peer->canManageGroupCall();
|
||||||
return megagroup->canManageCall();
|
|
||||||
} else if (const auto chat = peer->asChat()) {
|
|
||||||
return chat->amCreator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -933,9 +933,10 @@ void SessionController::closeThirdSection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionController::startOrJoinGroupCall(
|
void SessionController::startOrJoinGroupCall(
|
||||||
not_null<ChannelData*> megagroup,
|
not_null<PeerData*> peer,
|
||||||
bool confirmedLeaveOther) {
|
bool confirmedLeaveOther) {
|
||||||
if (megagroup->amAnonymous()) {
|
const auto channel = peer->asChannel();
|
||||||
|
if (channel && channel->amAnonymous()) {
|
||||||
Ui::ShowMultilineToast({
|
Ui::ShowMultilineToast({
|
||||||
.text = tr::lng_group_call_no_anonymous(tr::now),
|
.text = tr::lng_group_call_no_anonymous(tr::now),
|
||||||
});
|
});
|
||||||
|
@ -945,7 +946,7 @@ void SessionController::startOrJoinGroupCall(
|
||||||
const auto confirm = [&](QString text, QString button) {
|
const auto confirm = [&](QString text, QString button) {
|
||||||
Ui::show(Box<ConfirmBox>(text, button, crl::guard(this, [=] {
|
Ui::show(Box<ConfirmBox>(text, button, crl::guard(this, [=] {
|
||||||
Ui::hideLayer();
|
Ui::hideLayer();
|
||||||
startOrJoinGroupCall(megagroup, true);
|
startOrJoinGroupCall(peer, true);
|
||||||
})));
|
})));
|
||||||
};
|
};
|
||||||
if (!confirmedLeaveOther && calls.inCall()) {
|
if (!confirmedLeaveOther && calls.inCall()) {
|
||||||
|
@ -954,19 +955,19 @@ void SessionController::startOrJoinGroupCall(
|
||||||
tr::lng_call_leave_to_other_sure(tr::now),
|
tr::lng_call_leave_to_other_sure(tr::now),
|
||||||
tr::lng_call_bar_hangup(tr::now));
|
tr::lng_call_bar_hangup(tr::now));
|
||||||
} else if (!confirmedLeaveOther && calls.inGroupCall()) {
|
} else if (!confirmedLeaveOther && calls.inGroupCall()) {
|
||||||
if (calls.currentGroupCall()->channel() == megagroup) {
|
if (calls.currentGroupCall()->peer() == peer) {
|
||||||
calls.activateCurrentCall();
|
calls.activateCurrentCall();
|
||||||
} else {
|
} else {
|
||||||
confirm(
|
confirm(
|
||||||
tr::lng_group_call_leave_to_other_sure(tr::now),
|
tr::lng_group_call_leave_to_other_sure(tr::now),
|
||||||
tr::lng_group_call_leave(tr::now));
|
tr::lng_group_call_leave(tr::now));
|
||||||
}
|
}
|
||||||
} else if (!confirmedLeaveOther && !megagroup->call()) {
|
} else if (!confirmedLeaveOther && !peer->groupCall()) {
|
||||||
confirm(
|
confirm(
|
||||||
tr::lng_group_call_create_sure(tr::now),
|
tr::lng_group_call_create_sure(tr::now),
|
||||||
tr::lng_continue(tr::now));
|
tr::lng_continue(tr::now));
|
||||||
} else {
|
} else {
|
||||||
calls.startOrJoinGroupCall(megagroup);
|
calls.startOrJoinGroupCall(peer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,7 @@ public:
|
||||||
void closeThirdSection();
|
void closeThirdSection();
|
||||||
|
|
||||||
void startOrJoinGroupCall(
|
void startOrJoinGroupCall(
|
||||||
not_null<ChannelData*> megagroup,
|
not_null<PeerData*> peer,
|
||||||
bool confirmedLeaveOther = false);
|
bool confirmedLeaveOther = false);
|
||||||
|
|
||||||
void showSection(
|
void showSection(
|
||||||
|
|
Loading…
Add table
Reference in a new issue