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