mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Allow to rejoin with changing of 'join_as'.
This commit is contained in:
parent
4d093f78e2
commit
b670ca2a51
13 changed files with 235 additions and 123 deletions
|
@ -287,7 +287,7 @@ updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
|
|||
updateMessageID#4e90bfd6 id:int random_id:long = Update;
|
||||
updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update;
|
||||
updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update;
|
||||
updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update;
|
||||
updateChatUserTyping#86cadb6c chat_id:int from_id:Peer action:SendMessageAction = Update;
|
||||
updateChatParticipants#7761198 participants:ChatParticipants = Update;
|
||||
updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
|
||||
updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update;
|
||||
|
@ -364,7 +364,7 @@ updateChannelMessageForwards#6e8a84df channel_id:int id:int forwards:int = Updat
|
|||
updateReadChannelDiscussionInbox#1cc7de54 flags:# channel_id:int top_msg_id:int read_max_id:int broadcast_id:flags.0?int broadcast_post:flags.0?int = Update;
|
||||
updateReadChannelDiscussionOutbox#4638a26c channel_id:int top_msg_id:int read_max_id:int = Update;
|
||||
updatePeerBlocked#246a4b22 peer_id:Peer blocked:Bool = Update;
|
||||
updateChannelUserTyping#ff2abe9f flags:# channel_id:int top_msg_id:flags.0?int user_id:int action:SendMessageAction = Update;
|
||||
updateChannelUserTyping#6b171718 flags:# channel_id:int top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update;
|
||||
updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector<int> pts:int pts_count:int = Update;
|
||||
updatePinnedChannelMessages#8588878b flags:# pinned:flags.0?true channel_id:int messages:Vector<int> pts:int pts_count:int = Update;
|
||||
updateChat#1330a196 chat_id:int = Update;
|
||||
|
@ -1207,7 +1207,7 @@ groupCall#c0c2052e flags:# join_muted:flags.1?true can_change_join_muted:flags.2
|
|||
|
||||
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
|
||||
|
||||
groupCallParticipant#7c48057b flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:flags.12?int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long = GroupCallParticipant;
|
||||
groupCallParticipant#19adba89 flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long = GroupCallParticipant;
|
||||
|
||||
phone.groupCall#9e727aad call:GroupCall participants:Vector<GroupCallParticipant> participants_next_offset:string chats:Vector<Chat> users:Vector<User> = phone.GroupCall;
|
||||
|
||||
|
@ -1611,14 +1611,14 @@ phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall durati
|
|||
phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
|
||||
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
|
||||
phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool;
|
||||
phone.createGroupCall#7c068f5 peer:InputPeer join_as:InputPeer random_id:int = Updates;
|
||||
phone.createGroupCall#bd3dabe0 peer:InputPeer random_id:int = Updates;
|
||||
phone.joinGroupCall#3633a5b0 flags:# muted:flags.0?true call:InputGroupCall join_as:InputPeer params:DataJSON = Updates;
|
||||
phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates;
|
||||
phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector<InputUser> = Updates;
|
||||
phone.discardGroupCall#7a777135 call:InputGroupCall = Updates;
|
||||
phone.toggleGroupCallSettings#74bbb43d flags:# call:InputGroupCall join_muted:flags.0?Bool = Updates;
|
||||
phone.getGroupCall#c7cb017 call:InputGroupCall = phone.GroupCall;
|
||||
phone.getGroupParticipants#c9f1d285 call:InputGroupCall ids:Vector<int> sources:Vector<int> offset:string limit:int = phone.GroupParticipants;
|
||||
phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector<InputPeer> sources:Vector<int> offset:string limit:int = phone.GroupParticipants;
|
||||
phone.checkGroupCall#b74a7bea call:InputGroupCall source:int = Bool;
|
||||
phone.toggleGroupCallRecord#c02a66d7 flags:# start:flags.0?true call:InputGroupCall title:flags.1?string = Updates;
|
||||
phone.editGroupCallParticipant#d975eb80 flags:# muted:flags.0?true call:InputGroupCall participant:InputPeer volume:flags.1?int raise_hand:flags.2?Bool = Updates;
|
||||
|
|
|
@ -240,16 +240,16 @@ Updates::Updates(not_null<Main::Session*> session)
|
|||
) | rpl::filter([](not_null<PeerData*> peer) {
|
||||
return peer->isChat() || peer->isMegagroup();
|
||||
}) | rpl::start_with_next([=](not_null<PeerData*> peer) {
|
||||
if (const auto users = _pendingSpeakingCallMembers.take(peer)) {
|
||||
if (const auto list = _pendingSpeakingCallParticipants.take(peer)) {
|
||||
if (const auto call = peer->groupCall()) {
|
||||
for (const auto [userId, when] : *users) {
|
||||
for (const auto [participantPeerId, when] : *list) {
|
||||
call->applyActiveUpdate(
|
||||
userId,
|
||||
participantPeerId,
|
||||
Data::LastSpokeTimes{
|
||||
.anything = when,
|
||||
.voice = when
|
||||
},
|
||||
peer->owner().userLoaded(userId));
|
||||
peer->owner().peerLoaded(participantPeerId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -915,16 +915,16 @@ bool Updates::isQuitPrevent() {
|
|||
void Updates::handleSendActionUpdate(
|
||||
PeerId peerId,
|
||||
MsgId rootId,
|
||||
UserId userId,
|
||||
PeerId fromId,
|
||||
const MTPSendMessageAction &action) {
|
||||
const auto history = session().data().historyLoaded(peerId);
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
const auto peer = history->peer;
|
||||
const auto user = (userId == session().userId())
|
||||
const auto from = (fromId == session().userPeerId())
|
||||
? session().user().get()
|
||||
: session().data().userLoaded(userId);
|
||||
: session().data().peerLoaded(fromId);
|
||||
const auto isSpeakingInCall = (action.type()
|
||||
== mtpc_speakingInGroupCallAction);
|
||||
if (isSpeakingInCall) {
|
||||
|
@ -935,9 +935,9 @@ void Updates::handleSendActionUpdate(
|
|||
const auto now = crl::now();
|
||||
if (call) {
|
||||
call->applyActiveUpdate(
|
||||
userId,
|
||||
fromId,
|
||||
Data::LastSpokeTimes{ .anything = now, .voice = now },
|
||||
user);
|
||||
from);
|
||||
} else {
|
||||
const auto chat = peer->asChat();
|
||||
const auto channel = peer->asChannel();
|
||||
|
@ -945,13 +945,15 @@ void Updates::handleSendActionUpdate(
|
|||
? (chat->flags() & MTPDchat::Flag::f_call_active)
|
||||
: (channel->flags() & MTPDchannel::Flag::f_call_active);
|
||||
if (active) {
|
||||
_pendingSpeakingCallMembers.emplace(
|
||||
peer).first->second[userId] = now;
|
||||
session().api().requestFullPeer(peer);
|
||||
_pendingSpeakingCallParticipants.emplace(
|
||||
peer).first->second[fromId] = now;
|
||||
if (peerIsUser(fromId)) {
|
||||
session().api().requestFullPeer(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!user || user->isSelf()) {
|
||||
if (!from || !from->isUser() || from->isSelf()) {
|
||||
return;
|
||||
}
|
||||
const auto when = requestingDifference()
|
||||
|
@ -960,7 +962,7 @@ void Updates::handleSendActionUpdate(
|
|||
session().data().registerSendAction(
|
||||
history,
|
||||
rootId,
|
||||
user,
|
||||
from->asUser(),
|
||||
action,
|
||||
when);
|
||||
}
|
||||
|
@ -1642,19 +1644,21 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
|
||||
case mtpc_updateChatUserTyping: {
|
||||
auto &d = update.c_updateChatUserTyping();
|
||||
const auto fromId = peerFromMTP(d.vfrom_id());
|
||||
handleSendActionUpdate(
|
||||
peerFromChat(d.vchat_id()),
|
||||
0,
|
||||
d.vuser_id().v,
|
||||
fromId,
|
||||
d.vaction());
|
||||
} break;
|
||||
|
||||
case mtpc_updateChannelUserTyping: {
|
||||
const auto &d = update.c_updateChannelUserTyping();
|
||||
const auto fromId = peerFromMTP(d.vfrom_id());
|
||||
handleSendActionUpdate(
|
||||
peerFromChannel(d.vchannel_id()),
|
||||
d.vtop_msg_id().value_or_empty(),
|
||||
d.vuser_id().v,
|
||||
fromId,
|
||||
d.vaction());
|
||||
} break;
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ private:
|
|||
void handleSendActionUpdate(
|
||||
PeerId peerId,
|
||||
MsgId rootId,
|
||||
UserId userId,
|
||||
PeerId fromId,
|
||||
const MTPSendMessageAction &action);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
@ -168,7 +168,7 @@ private:
|
|||
base::flat_map<int, ActiveChatTracker> _activeChats;
|
||||
base::flat_map<
|
||||
not_null<PeerData*>,
|
||||
base::flat_map<UserId, crl::time>> _pendingSpeakingCallMembers;
|
||||
base::flat_map<PeerId, crl::time>> _pendingSpeakingCallParticipants;
|
||||
|
||||
mtpRequestId _onlineRequest = 0;
|
||||
base::Timer _idleFinishTimer;
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "calls/calls_choose_join_as.h"
|
||||
|
||||
#include "calls/calls_group_common.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_channel.h"
|
||||
|
@ -18,8 +19,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/layers/generic_box.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_calls.h"
|
||||
|
||||
namespace Calls {
|
||||
namespace Calls::Group {
|
||||
namespace {
|
||||
|
||||
using Context = ChooseJoinAsProcess::Context;
|
||||
|
@ -107,9 +109,8 @@ not_null<PeerData*> ListController::selected() const {
|
|||
void ChooseJoinAsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
Context context,
|
||||
std::vector<not_null<PeerData*>> list,
|
||||
not_null<PeerData*> selected,
|
||||
Fn<void(not_null<PeerData*>)> done) {
|
||||
JoinInfo info,
|
||||
Fn<void(JoinInfo)> done) {
|
||||
box->setTitle([&] {
|
||||
switch (context) {
|
||||
case Context::Create: return tr::lng_group_call_start_as_header();
|
||||
|
@ -121,23 +122,31 @@ void ChooseJoinAsBox(
|
|||
box->addRow(object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_group_call_join_as_about(),
|
||||
st::confirmPhoneAboutLabel));
|
||||
(context == Context::Switch
|
||||
? st::groupCallBoxLabel
|
||||
: st::confirmPhoneAboutLabel)));
|
||||
|
||||
auto &lifetime = box->lifetime();
|
||||
const auto delegate = lifetime.make_state<
|
||||
PeerListContentDelegateSimple
|
||||
>();
|
||||
const auto controller = lifetime.make_state<ListController>(
|
||||
std::move(list),
|
||||
selected);
|
||||
//controller->setStyleOverrides();
|
||||
info.possibleJoinAs,
|
||||
info.joinAs);
|
||||
if (context == Context::Switch) {
|
||||
controller->setStyleOverrides(
|
||||
&st::groupCallInviteMembersList,
|
||||
&st::groupCallMultiSelect);
|
||||
}
|
||||
const auto content = box->addRow(
|
||||
object_ptr<PeerListContent>(box, controller),
|
||||
style::margins());
|
||||
delegate->setContent(content);
|
||||
controller->setDelegate(delegate);
|
||||
box->addButton(tr::lng_continue(), [=] {
|
||||
done(controller->selected());
|
||||
auto copy = info;
|
||||
copy.joinAs = controller->selected();
|
||||
done(std::move(copy));
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
@ -153,13 +162,16 @@ ChooseJoinAsProcess::~ChooseJoinAsProcess() {
|
|||
void ChooseJoinAsProcess::start(
|
||||
not_null<PeerData*> peer,
|
||||
Context context,
|
||||
Fn<void(not_null<PeerData*>, not_null<PeerData*>)> done) {
|
||||
Fn<void(object_ptr<Ui::BoxContent>)> showBox,
|
||||
Fn<void(JoinInfo)> done,
|
||||
PeerData *currentJoinAs) {
|
||||
Expects(done != nullptr);
|
||||
|
||||
const auto session = &peer->session();
|
||||
if (_request) {
|
||||
const auto already = _request->peer;
|
||||
_request->context = context;
|
||||
_request->showBox = std::move(showBox);
|
||||
_request->done = std::move(done);
|
||||
if (already == peer) {
|
||||
return;
|
||||
|
@ -173,6 +185,7 @@ void ChooseJoinAsProcess::start(
|
|||
_request = std::make_unique<ChannelsListRequest>(
|
||||
ChannelsListRequest{
|
||||
.peer = peer,
|
||||
.showBox = std::move(showBox),
|
||||
.done = std::move(done),
|
||||
.context = context });
|
||||
session->account().sessionChanges(
|
||||
|
@ -180,12 +193,12 @@ void ChooseJoinAsProcess::start(
|
|||
_request = nullptr;
|
||||
}, _request->lifetime);
|
||||
|
||||
const auto finish = [=](not_null<PeerData*> joinAs) {
|
||||
const auto finish = [=](JoinInfo info) {
|
||||
const auto peer = _request->peer;
|
||||
const auto done = std::move(_request->done);
|
||||
const auto box = _request->box;
|
||||
_request = nullptr;
|
||||
done(peer, joinAs);
|
||||
done(std::move(info));
|
||||
if (const auto strong = box.data()) {
|
||||
strong->closeBox();
|
||||
}
|
||||
|
@ -200,8 +213,9 @@ void ChooseJoinAsProcess::start(
|
|||
});
|
||||
const auto peer = _request->peer;
|
||||
const auto self = peer->session().user();
|
||||
auto info = JoinInfo{ .peer = peer, .joinAs = self };
|
||||
if (chats.size() == 1) {
|
||||
finish(self);
|
||||
finish(info);
|
||||
return;
|
||||
}
|
||||
auto list = std::vector<not_null<PeerData*>>();
|
||||
|
@ -210,8 +224,8 @@ void ChooseJoinAsProcess::start(
|
|||
for (const auto &chat : chats) {
|
||||
list.push_back(session->data().processChat(chat));
|
||||
}
|
||||
const auto selectedId = peer->groupCallDefaultJoinAs();
|
||||
const auto selected = [&]() -> not_null<PeerData*> {
|
||||
const auto selected = [&]() -> PeerData* {
|
||||
const auto selectedId = peer->groupCallDefaultJoinAs();
|
||||
if (!selectedId) {
|
||||
return self;
|
||||
}
|
||||
|
@ -220,22 +234,27 @@ void ChooseJoinAsProcess::start(
|
|||
? not_null(loaded)
|
||||
: self;
|
||||
}();
|
||||
_request->box = Ui::show(
|
||||
Box(
|
||||
ChooseJoinAsBox,
|
||||
_request->context,
|
||||
std::move(list),
|
||||
selected,
|
||||
crl::guard(&_request->guard, finish)),
|
||||
Ui::LayerOption::KeepOther);
|
||||
|
||||
_request->box->boxClosing(
|
||||
info.joinAs = currentJoinAs ? currentJoinAs : selected;
|
||||
info.possibleJoinAs = std::move(list);
|
||||
auto box = Box(
|
||||
ChooseJoinAsBox,
|
||||
context,
|
||||
std::move(info),
|
||||
crl::guard(&_request->guard, finish));
|
||||
box->boxClosing(
|
||||
) | rpl::start_with_next([=] {
|
||||
_request = nullptr;
|
||||
}, _request->lifetime);
|
||||
|
||||
_request->box = box.data();
|
||||
_request->showBox(std::move(box));
|
||||
}).fail([=](const RPCError &error) {
|
||||
finish(session->user());
|
||||
finish({
|
||||
.peer = _request->peer,
|
||||
.joinAs = _request->peer->session().user(),
|
||||
});
|
||||
}).send();
|
||||
}
|
||||
|
||||
} // namespace Calls
|
||||
} // namespace Calls::Group
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "base/weak_ptr.h"
|
||||
#include "base/object_ptr.h"
|
||||
|
||||
class PeerData;
|
||||
|
||||
|
@ -15,7 +16,9 @@ namespace Ui {
|
|||
class BoxContent;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Calls {
|
||||
namespace Calls::Group {
|
||||
|
||||
struct JoinInfo;
|
||||
|
||||
class ChooseJoinAsProcess final {
|
||||
public:
|
||||
|
@ -31,12 +34,15 @@ public:
|
|||
void start(
|
||||
not_null<PeerData*> peer,
|
||||
Context context,
|
||||
Fn<void(not_null<PeerData*> peer, not_null<PeerData*> joinAs)> done);
|
||||
Fn<void(object_ptr<Ui::BoxContent>)> showBox,
|
||||
Fn<void(JoinInfo)> done,
|
||||
PeerData *currentJoinAs = nullptr);
|
||||
|
||||
private:
|
||||
struct ChannelsListRequest {
|
||||
not_null<PeerData*> peer;
|
||||
Fn<void(not_null<PeerData*>, not_null<PeerData*>)> done;
|
||||
Fn<void(object_ptr<Ui::BoxContent>)> showBox;
|
||||
Fn<void(JoinInfo)> done;
|
||||
base::has_weak_ptr guard;
|
||||
QPointer<Ui::BoxContent> box;
|
||||
rpl::lifetime lifetime;
|
||||
|
@ -47,4 +53,4 @@ private:
|
|||
|
||||
};
|
||||
|
||||
} // namespace Calls
|
||||
} // namespace Calls::Group
|
||||
|
|
|
@ -102,14 +102,14 @@ constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
|
|||
|
||||
GroupCall::GroupCall(
|
||||
not_null<Delegate*> delegate,
|
||||
not_null<PeerData*> peer,
|
||||
const MTPInputGroupCall &inputCall,
|
||||
not_null<PeerData*> joinAs)
|
||||
Group::JoinInfo info,
|
||||
const MTPInputGroupCall &inputCall)
|
||||
: _delegate(delegate)
|
||||
, _peer(peer)
|
||||
, _history(peer->owner().history(peer))
|
||||
, _joinAs(joinAs)
|
||||
, _api(&peer->session().mtp())
|
||||
, _peer(info.peer)
|
||||
, _history(_peer->owner().history(_peer))
|
||||
, _api(&_peer->session().mtp())
|
||||
, _joinAs(info.joinAs)
|
||||
, _possibleJoinAs(std::move(info.possibleJoinAs))
|
||||
, _lastSpokeCheckTimer([=] { checkLastSpoke(); })
|
||||
, _checkJoinedTimer([=] { checkJoined(); })
|
||||
, _pushToTalkCancelTimer([=] { pushToTalkCancel(); })
|
||||
|
@ -247,7 +247,6 @@ void GroupCall::playConnectingSoundOnce() {
|
|||
void GroupCall::start() {
|
||||
_createRequestId = _api.request(MTPphone_CreateGroupCall(
|
||||
_peer->input,
|
||||
_joinAs->input,
|
||||
MTP_int(openssl::RandomValue<int32>())
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_acceptFields = true;
|
||||
|
@ -499,6 +498,21 @@ void GroupCall::discard() {
|
|||
}).send();
|
||||
}
|
||||
|
||||
void GroupCall::rejoinAs(Group::JoinInfo info) {
|
||||
_possibleJoinAs = std::move(info.possibleJoinAs);
|
||||
if (info.joinAs == _joinAs) {
|
||||
return;
|
||||
}
|
||||
const auto event = Group::RejoinEvent{
|
||||
.wasJoinAs = _joinAs,
|
||||
.nowJoinAs = info.joinAs,
|
||||
};
|
||||
_joinAs = info.joinAs;
|
||||
setState(State::Joining);
|
||||
rejoin();
|
||||
_rejoinEvents.fire_copy(event);
|
||||
}
|
||||
|
||||
void GroupCall::finish(FinishType type) {
|
||||
Expects(type != FinishType::None);
|
||||
|
||||
|
@ -667,15 +681,15 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) {
|
|||
handleOtherParticipants(data);
|
||||
return;
|
||||
}
|
||||
if (data.is_left() && data.vsource().value_or_empty() == _mySsrc) {
|
||||
if (data.is_left() && data.vsource().v == _mySsrc) {
|
||||
// I was removed from the call, rejoin.
|
||||
LOG(("Call Info: Rejoin after got 'left' with my ssrc."));
|
||||
setState(State::Joining);
|
||||
rejoin();
|
||||
} else if (!data.is_left() && data.vsource().value_or_empty() != _mySsrc) {
|
||||
} else if (!data.is_left() && data.vsource().v != _mySsrc) {
|
||||
// I joined from another device, hangup.
|
||||
LOG(("Call Info: Hangup after '!left' with ssrc %1, my %2."
|
||||
).arg(data.vsource().value_or_empty()
|
||||
).arg(data.vsource().v
|
||||
).arg(_mySsrc));
|
||||
_mySsrc = 0;
|
||||
hangup();
|
||||
|
|
|
@ -39,6 +39,8 @@ namespace Group {
|
|||
struct MuteRequest;
|
||||
struct VolumeRequest;
|
||||
struct ParticipantState;
|
||||
struct JoinInfo;
|
||||
struct RejoinEvent;
|
||||
} // namespace Group
|
||||
|
||||
enum class MuteState {
|
||||
|
@ -88,9 +90,8 @@ public:
|
|||
|
||||
GroupCall(
|
||||
not_null<Delegate*> delegate,
|
||||
not_null<PeerData*> peer,
|
||||
const MTPInputGroupCall &inputCall,
|
||||
not_null<PeerData*> joinAs);
|
||||
Group::JoinInfo info,
|
||||
const MTPInputGroupCall &inputCall);
|
||||
~GroupCall();
|
||||
|
||||
[[nodiscard]] uint64 id() const {
|
||||
|
@ -102,10 +103,15 @@ public:
|
|||
[[nodiscard]] not_null<PeerData*> joinAs() const {
|
||||
return _joinAs;
|
||||
}
|
||||
[[nodiscard]] auto possibleJoinAs() const
|
||||
-> const std::vector<not_null<PeerData*>>& {
|
||||
return _possibleJoinAs;
|
||||
}
|
||||
|
||||
void start();
|
||||
void hangup();
|
||||
void discard();
|
||||
void rejoinAs(Group::JoinInfo info);
|
||||
void join(const MTPInputGroupCall &inputCall);
|
||||
void handleUpdate(const MTPGroupCall &call);
|
||||
void handleUpdate(const MTPDupdateGroupCallParticipants &data);
|
||||
|
@ -142,6 +148,9 @@ public:
|
|||
[[nodiscard]] rpl::producer<LevelUpdate> levelUpdates() const {
|
||||
return _levelUpdates.events();
|
||||
}
|
||||
[[nodiscard]] rpl::producer<Group::RejoinEvent> rejoinEvents() const {
|
||||
return _rejoinEvents.events();
|
||||
}
|
||||
static constexpr auto kSpeakLevelThreshold = 0.2;
|
||||
|
||||
void setCurrentAudioDevice(bool input, const QString &deviceId);
|
||||
|
@ -211,11 +220,13 @@ private:
|
|||
const not_null<Delegate*> _delegate;
|
||||
not_null<PeerData*> _peer; // Can change in legacy group migration.
|
||||
not_null<History*> _history; // Can change in legacy group migration.
|
||||
not_null<PeerData*> _joinAs;
|
||||
MTP::Sender _api;
|
||||
rpl::variable<State> _state = State::Creating;
|
||||
bool _instanceConnected = false;
|
||||
|
||||
not_null<PeerData*> _joinAs;
|
||||
std::vector<not_null<PeerData*>> _possibleJoinAs;
|
||||
|
||||
rpl::variable<MuteState> _muted = MuteState::Muted;
|
||||
bool _acceptFields = false;
|
||||
|
||||
|
@ -230,6 +241,7 @@ private:
|
|||
std::unique_ptr<tgcalls::GroupInstanceImpl> _instance;
|
||||
rpl::event_stream<LevelUpdate> _levelUpdates;
|
||||
base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke;
|
||||
rpl::event_stream<Group::RejoinEvent> _rejoinEvents;
|
||||
base::Timer _lastSpokeCheckTimer;
|
||||
base::Timer _checkJoinedTimer;
|
||||
|
||||
|
|
|
@ -34,4 +34,15 @@ struct ParticipantState {
|
|||
bool locallyOnly = false;
|
||||
};
|
||||
|
||||
struct RejoinEvent {
|
||||
not_null<PeerData*> wasJoinAs;
|
||||
not_null<PeerData*> nowJoinAs;
|
||||
};
|
||||
|
||||
struct JoinInfo {
|
||||
not_null<PeerData*> peer;
|
||||
not_null<PeerData*> joinAs;
|
||||
std::vector<not_null<PeerData*>> possibleJoinAs;
|
||||
};
|
||||
|
||||
} // namespace Calls::Group
|
||||
|
|
|
@ -855,6 +855,29 @@ void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
|
|||
updateRowLevel(i->second, update.value);
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
call->rejoinEvents(
|
||||
) | rpl::start_with_next([=](const Group::RejoinEvent &event) {
|
||||
const auto guard = gsl::finally([&] {
|
||||
delegate()->peerListRefreshRows();
|
||||
});
|
||||
if (const auto row = findRow(event.wasJoinAs)) {
|
||||
if (row->state() != Row::State::Invited) {
|
||||
if (const auto min = _fullCountMin.current()) {
|
||||
_fullCountMin = min - 1;
|
||||
}
|
||||
}
|
||||
removeRow(row);
|
||||
}
|
||||
if (findRow(event.nowJoinAs)) {
|
||||
return;
|
||||
} else if (auto row = createRowForMe()) {
|
||||
if (row->state() != Row::State::Invited) {
|
||||
_fullCountMin = _fullCountMin.current() + 1;
|
||||
}
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||
|
|
|
@ -9,7 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "calls/calls_group_call.h"
|
||||
#include "calls/calls_group_panel.h" // LeaveGroupCallBox.
|
||||
#include "calls/calls_group_common.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "calls/calls_choose_join_as.h"
|
||||
#include "ui/widgets/level_meter.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
|
@ -100,6 +102,7 @@ void GroupCallSettingsBox(
|
|||
float micLevel = 0.;
|
||||
Ui::Animations::Simple micLevelAnimation;
|
||||
base::Timer levelUpdateTimer;
|
||||
Group::ChooseJoinAsProcess joinAsProcess;
|
||||
bool generatingLink = false;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
|
@ -115,16 +118,40 @@ void GroupCallSettingsBox(
|
|||
const auto joinMuted = goodReal ? real->joinMuted() : false;
|
||||
const auto canChangeJoinMuted = (goodReal && real->canChangeJoinMuted());
|
||||
const auto addCheck = (peer->canManageGroupCall() && canChangeJoinMuted);
|
||||
if (addCheck) {
|
||||
const auto addEditJoinAs = (call->possibleJoinAs().size() > 1);
|
||||
if (addCheck || addEditJoinAs) {
|
||||
AddSkip(layout);
|
||||
}
|
||||
const auto editJoinAs = addEditJoinAs
|
||||
? AddButton(
|
||||
layout,
|
||||
tr::lng_group_call_display_as_header(),
|
||||
st::groupCallSettingsButton).get()
|
||||
: nullptr;
|
||||
if (editJoinAs) {
|
||||
editJoinAs->setClickedCallback([=] {
|
||||
const auto context = Group::ChooseJoinAsProcess::Context::Switch;
|
||||
const auto callback = [=](Group::JoinInfo info) {
|
||||
call->rejoinAs(info);
|
||||
};
|
||||
auto showBox = [=](object_ptr<Ui::BoxContent> next) {
|
||||
box->getDelegate()->show(std::move(next));
|
||||
};
|
||||
state->joinAsProcess.start(
|
||||
peer,
|
||||
context,
|
||||
showBox,
|
||||
callback,
|
||||
call->joinAs());
|
||||
});
|
||||
}
|
||||
const auto muteJoined = addCheck
|
||||
? AddButton(
|
||||
layout,
|
||||
tr::lng_group_call_new_muted(),
|
||||
st::groupCallSettingsButton)->toggleOn(rpl::single(joinMuted))
|
||||
: nullptr;
|
||||
if (addCheck) {
|
||||
if (addCheck || addEditJoinAs) {
|
||||
AddSkip(layout);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "calls/calls_instance.h"
|
||||
|
||||
#include "calls/calls_group_common.h"
|
||||
#include "mtproto/mtproto_dh_utils.h"
|
||||
#include "core/application.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -61,27 +62,18 @@ void Instance::startOutgoingCall(not_null<UserData*> user, bool video) {
|
|||
|
||||
void Instance::startOrJoinGroupCall(not_null<PeerData*> peer) {
|
||||
const auto context = peer->groupCall()
|
||||
? ChooseJoinAsProcess::Context::Join
|
||||
: ChooseJoinAsProcess::Context::Create;
|
||||
_chooseJoinAs.start(peer, context, [=](
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PeerData*> joinAs) {
|
||||
startOrJoinGroupCall(peer, joinAs);
|
||||
? Group::ChooseJoinAsProcess::Context::Join
|
||||
: Group::ChooseJoinAsProcess::Context::Create;
|
||||
_chooseJoinAs.start(peer, context, [=](object_ptr<Ui::BoxContent> box) {
|
||||
Ui::show(std::move(box), Ui::LayerOption::KeepOther);
|
||||
}, [=](Group::JoinInfo info) {
|
||||
const auto call = info.peer->groupCall();
|
||||
createGroupCall(
|
||||
std::move(info),
|
||||
call ? call->input() : MTP_inputGroupCall(MTPlong(), MTPlong()));
|
||||
});
|
||||
}
|
||||
|
||||
void Instance::startOrJoinGroupCall(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PeerData*> joinAs) {
|
||||
destroyCurrentCall();
|
||||
|
||||
const auto call = peer->groupCall();
|
||||
createGroupCall(
|
||||
peer,
|
||||
call ? call->input() : MTP_inputGroupCall(MTPlong(), MTPlong()),
|
||||
joinAs);
|
||||
}
|
||||
|
||||
void Instance::callFinished(not_null<Call*> call) {
|
||||
crl::on_main(call, [=] {
|
||||
destroyCall(call);
|
||||
|
@ -208,19 +200,17 @@ void Instance::destroyGroupCall(not_null<GroupCall*> call) {
|
|||
}
|
||||
|
||||
void Instance::createGroupCall(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPInputGroupCall &inputCall,
|
||||
not_null<PeerData*> joinAs) {
|
||||
Group::JoinInfo info,
|
||||
const MTPInputGroupCall &inputCall) {
|
||||
destroyCurrentCall();
|
||||
|
||||
auto call = std::make_unique<GroupCall>(
|
||||
getGroupCallDelegate(),
|
||||
peer,
|
||||
inputCall,
|
||||
joinAs);
|
||||
std::move(info),
|
||||
inputCall);
|
||||
const auto raw = call.get();
|
||||
|
||||
peer->session().account().sessionChanges(
|
||||
info.peer->session().account().sessionChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
destroyGroupCall(raw);
|
||||
}, raw->lifetime());
|
||||
|
|
|
@ -16,16 +16,18 @@ namespace Platform {
|
|||
enum class PermissionType;
|
||||
} // namespace Platform
|
||||
|
||||
namespace Media {
|
||||
namespace Audio {
|
||||
namespace Media::Audio {
|
||||
class Track;
|
||||
} // namespace Audio
|
||||
} // namespace Media
|
||||
} // namespace Media::Audio
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Calls::Group {
|
||||
struct JoinInfo;
|
||||
} // namespace Calls::Group
|
||||
|
||||
namespace Calls {
|
||||
|
||||
class Panel;
|
||||
|
@ -42,9 +44,6 @@ public:
|
|||
|
||||
void startOutgoingCall(not_null<UserData*> user, bool video);
|
||||
void startOrJoinGroupCall(not_null<PeerData*> peer);
|
||||
void startOrJoinGroupCall(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PeerData*> joinAs);
|
||||
void handleUpdate(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPUpdate &update);
|
||||
|
@ -107,9 +106,8 @@ private:
|
|||
void destroyCall(not_null<Call*> call);
|
||||
|
||||
void createGroupCall(
|
||||
not_null<PeerData*> peer,
|
||||
const MTPInputGroupCall &inputCall,
|
||||
not_null<PeerData*> joinAs);
|
||||
Group::JoinInfo info,
|
||||
const MTPInputGroupCall &inputCall);
|
||||
void destroyGroupCall(not_null<GroupCall*> call);
|
||||
|
||||
void requestPermissionOrFail(
|
||||
|
@ -150,7 +148,7 @@ private:
|
|||
|
||||
base::flat_map<QString, std::unique_ptr<Media::Audio::Track>> _tracks;
|
||||
|
||||
ChooseJoinAsProcess _chooseJoinAs;
|
||||
Group::ChooseJoinAsProcess _chooseJoinAs;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ void GroupCall::requestParticipants() {
|
|||
}
|
||||
_participantsRequestId = api().request(MTPphone_GetGroupParticipants(
|
||||
input(),
|
||||
MTP_vector<MTPint>(), // ids
|
||||
MTP_vector<MTPInputPeer>(), // ids
|
||||
MTP_vector<MTPint>(), // ssrcs
|
||||
MTP_string(_nextOffset),
|
||||
MTP_int(kRequestPerPage)
|
||||
|
@ -296,7 +296,7 @@ void GroupCall::applyParticipantsSlice(
|
|||
.peer = participantPeer,
|
||||
.date = data.vdate().v,
|
||||
.lastActive = lastActive,
|
||||
.ssrc = uint32(data.vsource().value_or_empty()),
|
||||
.ssrc = uint32(data.vsource().v),
|
||||
.volume = volume,
|
||||
.applyVolumeFromMin = applyVolumeFromMin,
|
||||
.speaking = canSelfUnmute && (was ? was->speaking : false),
|
||||
|
@ -469,7 +469,7 @@ void GroupCall::requestUnknownParticipants() {
|
|||
}
|
||||
return result;
|
||||
}();
|
||||
const auto peerIds = [&] {
|
||||
const auto participantPeerIds = [&] {
|
||||
if (_unknownSpokenPeerIds.size() + ssrcs.size() < kRequestPerPage) {
|
||||
return base::take(_unknownSpokenPeerIds);
|
||||
}
|
||||
|
@ -478,8 +478,9 @@ void GroupCall::requestUnknownParticipants() {
|
|||
if (available > 0) {
|
||||
result.reserve(available);
|
||||
while (result.size() < available) {
|
||||
const auto [userId, when] = _unknownSpokenPeerIds.back();
|
||||
result.emplace(userId, when);
|
||||
const auto &back = _unknownSpokenPeerIds.back();
|
||||
const auto [participantPeerId, when] = back;
|
||||
result.emplace(participantPeerId, when);
|
||||
_unknownSpokenPeerIds.erase(_unknownSpokenPeerIds.end() - 1);
|
||||
}
|
||||
}
|
||||
|
@ -490,16 +491,23 @@ void GroupCall::requestUnknownParticipants() {
|
|||
for (const auto [ssrc, when] : ssrcs) {
|
||||
ssrcInputs.push_back(MTP_int(ssrc));
|
||||
}
|
||||
auto uidInputs = QVector<MTPint>();
|
||||
uidInputs.reserve(peerIds.size());
|
||||
for (const auto [peerId, when] : peerIds) {
|
||||
Assert(peerIsUser(peerId)); // #TODO calls
|
||||
uidInputs.push_back(MTP_int(peerToUser(peerId)));
|
||||
auto peerInputs = QVector<MTPInputPeer>();
|
||||
peerInputs.reserve(participantPeerIds.size());
|
||||
for (const auto [participantPeerId, when] : participantPeerIds) {
|
||||
if (const auto userId = peerToUser(participantPeerId)) {
|
||||
peerInputs.push_back(
|
||||
MTP_inputPeerUser(MTP_int(userId), MTP_long(0)));
|
||||
} else if (const auto chatId = peerToChat(participantPeerId)) {
|
||||
peerInputs.push_back(MTP_inputPeerChat(MTP_int(chatId)));
|
||||
} else if (const auto channelId = peerToChannel(participantPeerId)) {
|
||||
peerInputs.push_back(
|
||||
MTP_inputPeerChannel(MTP_int(channelId), MTP_long(0)));
|
||||
}
|
||||
}
|
||||
_unknownParticipantPeersRequestId = api().request(
|
||||
MTPphone_GetGroupParticipants(
|
||||
input(),
|
||||
MTP_vector<MTPint>(uidInputs),
|
||||
MTP_vector<MTPInputPeer>(peerInputs),
|
||||
MTP_vector<MTPint>(ssrcInputs),
|
||||
MTP_string(QString()),
|
||||
MTP_int(kRequestPerPage)
|
||||
|
@ -517,17 +525,17 @@ void GroupCall::requestUnknownParticipants() {
|
|||
applyLastSpoke(ssrc, when, now);
|
||||
_unknownSpokenSsrcs.remove(ssrc);
|
||||
}
|
||||
for (const auto [peerId, when] : peerIds) {
|
||||
if (const auto participantPeer = _peer->owner().peerLoaded(peerId)) {
|
||||
for (const auto [id, when] : participantPeerIds) {
|
||||
if (const auto participantPeer = _peer->owner().peerLoaded(id)) {
|
||||
const auto isParticipant = ranges::contains(
|
||||
_participants,
|
||||
not_null{ participantPeer },
|
||||
&Participant::peer);
|
||||
if (isParticipant) {
|
||||
applyActiveUpdate(peerId, when, participantPeer);
|
||||
applyActiveUpdate(id, when, participantPeer);
|
||||
}
|
||||
}
|
||||
_unknownSpokenPeerIds.remove(peerId);
|
||||
_unknownSpokenPeerIds.remove(id);
|
||||
}
|
||||
requestUnknownParticipants();
|
||||
}).fail([=](const RPCError &error) {
|
||||
|
@ -535,8 +543,8 @@ void GroupCall::requestUnknownParticipants() {
|
|||
for (const auto [ssrc, when] : ssrcs) {
|
||||
_unknownSpokenSsrcs.remove(ssrc);
|
||||
}
|
||||
for (const auto [peerId, when] : peerIds) {
|
||||
_unknownSpokenPeerIds.remove(peerId);
|
||||
for (const auto [participantPeerId, when] : participantPeerIds) {
|
||||
_unknownSpokenPeerIds.remove(participantPeerId);
|
||||
}
|
||||
requestUnknownParticipants();
|
||||
}).send();
|
||||
|
|
Loading…
Add table
Reference in a new issue