Improve group call members list updating.

This commit is contained in:
John Preston 2020-11-27 17:50:41 +03:00
parent 8618fe41ee
commit a6b4cdd62d
11 changed files with 332 additions and 164 deletions

View file

@ -426,9 +426,9 @@ bool PeerListRow::checked() const {
return _checkbox && _checkbox->checked();
}
void PeerListRow::setCustomStatus(const QString &status) {
void PeerListRow::setCustomStatus(const QString &status, bool active) {
setStatusText(status);
_statusType = StatusType::Custom;
_statusType = active ? StatusType::CustomActive : StatusType::Custom;
_statusValidTill = 0;
}
@ -438,7 +438,10 @@ void PeerListRow::clearCustomStatus() {
}
void PeerListRow::refreshStatus() {
if (!_initialized || special() || _statusType == StatusType::Custom) {
if (!_initialized
|| special()
|| _statusType == StatusType::Custom
|| _statusType == StatusType::CustomActive) {
return;
}
_statusType = StatusType::LastSeen;
@ -550,7 +553,8 @@ void PeerListRow::paintStatusText(
int availableWidth,
int outerWidth,
bool selected) {
auto statusHasOnlineColor = (_statusType == PeerListRow::StatusType::Online);
auto statusHasOnlineColor = (_statusType == PeerListRow::StatusType::Online)
|| (_statusType == PeerListRow::StatusType::CustomActive);
p.setFont(st::contactsStatusFont);
p.setPen(statusHasOnlineColor ? st.statusFgActive : (selected ? st.statusFgOver : st.statusFg));
_status.drawLeftElided(p, x, y, availableWidth, outerWidth);

View file

@ -88,7 +88,7 @@ public:
[[nodiscard]] virtual auto generatePaintUserpicCallback()
-> PaintRoundImageCallback;
void setCustomStatus(const QString &status);
void setCustomStatus(const QString &status, bool active = false);
void clearCustomStatus();
// Box interface.
@ -127,6 +127,7 @@ public:
Online,
LastSeen,
Custom,
CustomActive,
};
virtual void refreshStatus();
crl::time refreshStatusTime() const;

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "base/unixtime.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "data/data_changes.h"
@ -93,19 +94,21 @@ void GroupCall::start() {
void GroupCall::join(const MTPInputGroupCall &inputCall) {
setState(State::Joining);
_channel->setCall(inputCall);
inputCall.match([&](const MTPDinputGroupCall &data) {
_id = data.vid().v;
_accessHash = data.vaccess_hash().v;
createAndStartController();
rejoin();
});
_channel->setCall(inputCall);
_channel->session().changes().peerFlagsValue(
_channel,
Data::PeerUpdate::Flag::GroupCall
) | rpl::start_with_next([=] {
checkParticipants();
using Update = Data::GroupCall::ParticipantUpdate;
_channel->call()->participantUpdated(
) | rpl::filter([=](const Update &update) {
return (_instance != nullptr) && update.removed;
}) | rpl::start_with_next([=](const Update &update) {
_instance->removeSsrcs({ update.participant.source });
}, _lifetime);
}
@ -113,6 +116,9 @@ void GroupCall::rejoin() {
Expects(_state.current() == State::Joining);
_mySsrc = 0;
applySelfInCallLocally();
LOG(("Call Info: Requesting join payload."));
const auto weak = base::make_weak(this);
_instance->emitJoinPayload([=](tgcalls::GroupJoinPayload payload) {
crl::on_main(weak, [=, payload = std::move(payload)]{
@ -134,6 +140,9 @@ void GroupCall::rejoin() {
root.insert("fingerprints", fingerprints);
root.insert("ssrc", double(payload.ssrc));
LOG(("Call Info: Join payload received, joining with source: %1."
).arg(ssrc));
const auto json = QJsonDocument(root).toJson(
QJsonDocument::Compact);
const auto muted = _muted.current();
@ -146,6 +155,7 @@ void GroupCall::rejoin() {
)).done([=](const MTPUpdates &updates) {
_mySsrc = ssrc;
setState(State::Joined);
applySelfInCallLocally();
if (_muted.current() != muted) {
sendMutedUpdate();
@ -159,28 +169,28 @@ void GroupCall::rejoin() {
});
}
void GroupCall::checkParticipants() {
if (!joined()) {
return;
}
void GroupCall::applySelfInCallLocally() {
const auto call = _channel->call();
if (!call || call->id() != _id) {
finish(FinishType::Ended);
return;
}
const auto &sources = call->sources();
if (sources.size() != call->fullCount() || sources.empty()) {
call->reload();
return;
}
auto ssrcs = std::vector<uint32_t>();
ssrcs.reserve(sources.size());
for (const auto source : sources) {
if (source != _mySsrc) {
ssrcs.push_back(source);
}
}
// _instance->setSsrcs(std::move(ssrcs));
const auto my = [&] {
const auto self = _channel->session().userId();
const auto now = base::unixtime::now();
using Flag = MTPDgroupCallParticipant::Flag;
return MTP_groupCallParticipant(
MTP_flags((_mySsrc ? Flag(0) : Flag::f_left)
| (_muted.current() ? Flag::f_muted : Flag(0))),
MTP_int(self),
MTP_int(now),
MTP_int(0),
MTP_int(_mySsrc));
};
call->applyUpdateChecked(
MTP_updateGroupCallParticipants(
inputCall(),
MTP_vector<MTPGroupCallParticipant>(1, my()),
MTP_int(0)).c_updateGroupCallParticipants());
}
void GroupCall::hangup() {
@ -292,7 +302,6 @@ void GroupCall::handleUpdate(const MTPGroupCall &call) {
});
}
_instance->setJoinResponsePayload(payload);
checkParticipants();
});
}
}, [&](const MTPDgroupCallDiscarded &data) {

View file

@ -36,6 +36,9 @@ public:
const MTPInputGroupCall &inputCall);
~GroupCall();
[[nodiscard]] uint64 id() const {
return _id;
}
[[nodiscard]] not_null<ChannelData*> channel() const {
return _channel;
}
@ -92,11 +95,11 @@ private:
void handleControllerError(const QString &error);
void createAndStartController();
void destroyController();
void checkParticipants();
void setState(State state);
void finish(FinishType type);
void sendMutedUpdate();
void applySelfInCallLocally();
void rejoin();
[[nodiscard]] MTPInputGroupCall inputCall() const;

View file

@ -24,40 +24,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Calls {
namespace {
class MembersController final
: public PeerListController
, public base::has_weak_ptr {
public:
explicit MembersController(not_null<GroupCall*> call);
Main::Session &session() const override;
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void rowActionClicked(not_null<PeerListRow*> row) override;
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
QWidget *parent,
not_null<PeerListRow*> row) override;
void loadMoreRows() override;
private:
[[nodiscard]] std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user) const;
void prepareRows();
void setupListChangeViewers();
bool appendRow(not_null<UserData*> user);
bool prependRow(not_null<UserData*> user);
bool removeRow(not_null<UserData*> user);
const base::weak_ptr<GroupCall> _call;
const not_null<ChannelData*> _channel;
Ui::BoxPointer _addBox;
rpl::lifetime _lifetime;
};
class Row final : public PeerListRow {
public:
Row(not_null<ChannelData*> channel, not_null<UserData*> user);
@ -68,6 +34,8 @@ public:
Muted,
};
void updateState(const Data::GroupCall::Participant *participant);
void addActionRipple(QPoint point, Fn<void()> updateCallback) override;
void stopLastActionRipple() override;
@ -108,6 +76,50 @@ private:
};
class MembersController final
: public PeerListController
, public base::has_weak_ptr {
public:
explicit MembersController(not_null<GroupCall*> call);
Main::Session &session() const override;
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void rowActionClicked(not_null<PeerListRow*> row) override;
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
QWidget *parent,
not_null<PeerListRow*> row) override;
void loadMoreRows() override;
[[nodiscard]] rpl::producer<int> fullCountValue() const {
return _fullCount.value();
}
private:
[[nodiscard]] std::unique_ptr<PeerListRow> createSelfRow() const;
[[nodiscard]] std::unique_ptr<PeerListRow> createRow(
const Data::GroupCall::Participant &participant) const;
void prepareRows(not_null<Data::GroupCall*> real);
void setupListChangeViewers(not_null<GroupCall*> call);
void subscribeToChanges(not_null<Data::GroupCall*> real);
void updateRow(
const Data::GroupCall::Participant &participant);
void updateRow(
not_null<Row*> row,
const Data::GroupCall::Participant *participant) const;
const base::weak_ptr<GroupCall> _call;
const not_null<ChannelData*> _channel;
rpl::variable<int> _fullCount = 1;
Ui::BoxPointer _addBox;
rpl::lifetime _lifetime;
};
Row::Row(not_null<ChannelData*> channel, not_null<UserData*> user)
: PeerListRow(user)
, _state(ComputeState(channel, user))
@ -115,6 +127,24 @@ Row::Row(not_null<ChannelData*> channel, not_null<UserData*> user)
refreshStatus();
}
void Row::updateState(const Data::GroupCall::Participant *participant) {
if (!participant) {
if (peer()->isSelf()) {
setCustomStatus(tr::lng_group_call_connecting(tr::now));
} else {
setCustomStatus(QString());
}
_state = State::Inactive;
} else if (!participant->muted) {
_state = State::Active;
} else if (participant->canSelfUnmute) {
_state = State::Inactive;
} else {
_state = State::Muted;
}
_st = ComputeIconStyle(_state);
}
void Row::paintAction(
Painter &p,
int x,
@ -146,7 +176,7 @@ void Row::refreshStatus() {
case State::Active: return tr::lng_group_call_active(tr::now);
}
Unexpected("State in Row::refreshStatus.");
}());
}(), (_state == State::Active));
}
Row::State Row::ComputeState(
@ -202,18 +232,81 @@ void Row::stopLastActionRipple() {
MembersController::MembersController(not_null<GroupCall*> call)
: _call(call)
, _channel(call->channel()) {
setupListChangeViewers();
setupListChangeViewers(call);
}
void MembersController::setupListChangeViewers() {
const auto call = _call.get();
void MembersController::setupListChangeViewers(not_null<GroupCall*> call) {
const auto channel = call->channel();
channel->session().changes().peerUpdates(
channel->session().changes().peerFlagsValue(
channel,
Data::PeerUpdate::Flag::GroupCall
) | rpl::start_with_next([=] {
prepareRows();
) | rpl::map([=] {
return channel->call();
}) | rpl::filter([=](Data::GroupCall *real) {
const auto call = _call.get();
return call && real && (real->id() == call->id());
}) | rpl::take(
1
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
subscribeToChanges(real);
}, _lifetime);
call->stateValue(
) | rpl::start_with_next([=] {
const auto call = _call.get();
const auto real = channel->call();
if (call && real && (real->id() == call->id())) {
//updateRow(channel->session().user());
}
}, _lifetime);
}
void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
_fullCount = real->fullCountValue(
) | rpl::map([](int value) {
return std::max(value, 1);
});
real->participantsSliceAdded(
) | rpl::start_with_next([=] {
prepareRows(real);
}, _lifetime);
using Update = Data::GroupCall::ParticipantUpdate;
real->participantUpdated(
) | rpl::start_with_next([=](const Update &update) {
const auto user = update.participant.user;
if (update.removed) {
if (auto row = delegate()->peerListFindRow(user->id)) {
if (user->isSelf()) {
static_cast<Row*>(row)->updateState(nullptr);
delegate()->peerListUpdateRow(row);
} else {
delegate()->peerListRemoveRow(row);
delegate()->peerListRefreshRows();
}
}
} else {
updateRow(update.participant);
}
}, _lifetime);
}
void MembersController::updateRow(
const Data::GroupCall::Participant &participant) {
if (auto row = delegate()->peerListFindRow(participant.user->id)) {
updateRow(static_cast<Row*>(row), &participant);
} else if (auto row = createRow(participant)) {
delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows();
}
}
void MembersController::updateRow(
not_null<Row*> row,
const Data::GroupCall::Participant *participant) const {
row->updateState(participant);
delegate()->peerListUpdateRow(row);
}
Main::Session &MembersController::session() const {
@ -226,17 +319,18 @@ void MembersController::prepare() {
setDescriptionText(tr::lng_contacts_loading(tr::now));
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
prepareRows();
delegate()->peerListRefreshRows();
const auto call = _call.get();
if (const auto real = _channel->call();
real && call && real->id() == call->id()) {
prepareRows(real);
} else if (auto row = createSelfRow()) {
delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows();
}
loadMoreRows();
}
void MembersController::prepareRows() {
const auto real = _channel->call();
if (!real) {
return;
}
void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
auto foundSelf = false;
auto changed = false;
const auto &participants = real->participants();
@ -262,13 +356,19 @@ void MembersController::prepareRows() {
}
}
if (!foundSelf) {
if (auto row = createRow(_channel->session().user())) {
const auto self = _channel->session().user();
const auto i = ranges::find(
participants,
_channel->session().user(),
&Data::GroupCall::Participant::user);
auto row = (i != end(participants)) ? createRow(*i) : createSelfRow();
if (row) {
changed = true;
delegate()->peerListAppendRow(std::move(row));
}
}
for (const auto &participant : participants) {
if (auto row = createRow(participant.user)) {
if (auto row = createRow(participant)) {
changed = true;
delegate()->peerListAppendRow(std::move(row));
}
@ -279,10 +379,8 @@ void MembersController::prepareRows() {
}
void MembersController::loadMoreRows() {
if (const auto call = _call.get()) {
if (const auto real = call->channel()->call()) {
real->requestParticipants();
}
if (const auto real = _channel->call()) {
real->requestParticipants();
}
}
@ -308,33 +406,18 @@ base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
return nullptr;
}
bool MembersController::appendRow(not_null<UserData*> user) {
if (delegate()->peerListFindRow(user->id)) {
return false;
}
delegate()->peerListAppendRow(createRow(user));
return true;
}
bool MembersController::prependRow(not_null<UserData*> user) {
if (auto row = delegate()->peerListFindRow(user->id)) {
return false;
}
delegate()->peerListPrependRow(createRow(user));
return true;
}
bool MembersController::removeRow(not_null<UserData*> user) {
if (auto row = delegate()->peerListFindRow(user->id)) {
delegate()->peerListRemoveRow(row);
return true;
}
return false;
std::unique_ptr<PeerListRow> MembersController::createSelfRow() const {
const auto self = _channel->session().user();
auto result = std::make_unique<Row>(_channel, self);
updateRow(result.get(), nullptr);
return result;
}
std::unique_ptr<PeerListRow> MembersController::createRow(
not_null<UserData*> user) const {
return std::make_unique<Row>(_channel, user);
const Data::GroupCall::Participant &participant) const {
auto result = std::make_unique<Row>(_channel, participant.user);
updateRow(result.get(), &participant);
return result;
}
} // namespace
@ -393,19 +476,13 @@ void GroupMembers::setupHeader(not_null<GroupCall*> call) {
object_ptr<Ui::FlatLabel> GroupMembers::setupTitle(
not_null<GroupCall*> call) {
const auto channel = call->channel();
auto count = channel->session().changes().peerFlagsValue(
channel,
Data::PeerUpdate::Flag::GroupCall
) | rpl::map([=] {
const auto call = channel->call();
return std::max(call ? call->fullCount() : 0, 1);
});
const auto controller = static_cast<MembersController*>(
_listController.get());
auto result = object_ptr<Ui::FlatLabel>(
_titleWrap,
tr::lng_chat_status_members(
lt_count_decimal,
std::move(count) | tr::to_count(),
controller->fullCountValue() | tr::to_count(),
Ui::Text::Upper
),
st::groupCallHeaderLabel);

View file

@ -13,6 +13,10 @@ namespace Ui {
class ScrollArea;
} // namespace Ui
namespace Data {
class GroupCall;
} // namespace Data
namespace Calls {
class GroupCall;
@ -58,7 +62,6 @@ private:
void setupButtons();
void addMember();
void showMembersWithSearch(bool withSearch);
void updateHeaderControlsGeometry(int newWidth);
base::weak_ptr<GroupCall> _call;

View file

@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/window.h"
#include "ui/effects/ripple_animation.h"
#include "ui/layers/layer_manager.h"
#include "boxes/confirm_box.h"
#include "core/application.h"
#include "lang/lang_keys.h"
#include "base/event_filter.h"
@ -216,6 +218,7 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call)
: _call(call)
, _channel(call->channel())
, _window(std::make_unique<Ui::Window>(Core::App().getModalParent()))
, _layerBg(std::make_unique<Ui::LayerManager>(_window->body()))
#ifdef Q_OS_WIN
, _controls(std::make_unique<Ui::Platform::TitleControls>(
_window.get(),
@ -300,9 +303,10 @@ void GroupPanel::initControls() {
}
});
_hangup->setClickedCallback([=] {
if (_call) {
_call->hangup();
}
_layerBg->showBox(Box<ConfirmBox>(
tr::lng_group_call_leave_sure(tr::now),
tr::lng_group_call_leave(tr::now),
[=] { if (_call) _call->hangup(); }));
});
_settings->setClickedCallback([=] {
});
@ -409,7 +413,7 @@ void GroupPanel::updateControlsGeometry() {
- membersTop
- st::groupCallMembersMargin.bottom();
_members->setGeometry(
st::groupCallMembersMargin.left(),
(widget()->width() - membersWidth) / 2,
membersTop,
membersWidth,
std::min(desiredHeight, availableHeight));
@ -426,6 +430,7 @@ void GroupPanel::refreshTitle() {
widget(),
tr::lng_group_call_title(),
st::groupCallHeaderLabel);
_title->setAttribute(Qt::WA_TransparentForMouseEvents);
_window->setTitle(u" "_q);
}
const auto best = _title->naturalWidth();

View file

@ -30,6 +30,7 @@ template <typename Widget>
class PaddingWrap;
class Window;
class ScrollArea;
class LayerManager;
namespace Platform {
class TitleControls;
} // namespace Platform
@ -84,6 +85,7 @@ private:
not_null<ChannelData*> _channel;
const std::unique_ptr<Ui::Window> _window;
const std::unique_ptr<Ui::LayerManager> _layerBg;
#ifdef Q_OS_WIN
std::unique_ptr<Ui::Platform::TitleControls> _controls;

View file

@ -51,14 +51,10 @@ auto GroupCall::participants() const
return _participants;
}
const base::flat_set<uint32> &GroupCall::sources() const {
return _sources;
}
void GroupCall::requestParticipants() {
if (_participantsRequestId || _reloadRequestId) {
return;
} else if (_participants.size() >= _fullCount && _allReceived) {
} else if (_participants.size() >= _fullCount.current() && _allReceived) {
return;
} else if (_allReceived) {
reload();
@ -83,9 +79,7 @@ void GroupCall::requestParticipants() {
_fullCount = _participants.size();
}
});
_channel->session().changes().peerUpdated(
_channel,
PeerUpdate::Flag::GroupCall);
_participantsSliceAdded.fire({});
_participantsRequestId = 0;
}).fail([=](const RPCError &error) {
_fullCount = _participants.size();
@ -98,13 +92,26 @@ void GroupCall::requestParticipants() {
}
int GroupCall::fullCount() const {
return _fullCount;
return _fullCount.current();
}
rpl::producer<int> GroupCall::fullCountValue() const {
return _fullCount.value();
}
bool GroupCall::participantsLoaded() const {
return _allReceived;
}
rpl::producer<> GroupCall::participantsSliceAdded() {
return _participantsSliceAdded.events();
}
auto GroupCall::participantUpdated() const
-> rpl::producer<ParticipantUpdate> {
return _participantUpdates.events();
}
void GroupCall::applyUpdate(const MTPGroupCall &update) {
applyCall(update, false);
}
@ -112,7 +119,7 @@ void GroupCall::applyUpdate(const MTPGroupCall &update) {
void GroupCall::applyCall(const MTPGroupCall &call, bool force) {
call.match([&](const MTPDgroupCall &data) {
const auto changed = (_version != data.vversion().v)
|| (_fullCount != data.vparticipants_count().v);
|| (_fullCount.current() != data.vparticipants_count().v);
if (!force && !changed) {
return;
} else if (!force && _version > data.vversion().v) {
@ -130,9 +137,6 @@ void GroupCall::applyCall(const MTPGroupCall &call, bool force) {
_finished = true;
_duration = data.vduration().v;
});
_channel->session().changes().peerUpdated(
_channel,
PeerUpdate::Flag::GroupCall);
}
void GroupCall::reload() {
@ -148,17 +152,10 @@ void GroupCall::reload() {
result.match([&](const MTPDphone_groupCall &data) {
_channel->owner().processUsers(data.vusers());
_participants.clear();
_sources.clear();
applyParticipantsSlice(data.vparticipants().v);
for (const auto &source : data.vsources().v) {
_sources.emplace(source.v);
}
_fullCount = _sources.size();
if (_participants.size() > _fullCount) {
_fullCount = _participants.size();
}
_allReceived = (_fullCount == _participants.size());
applyCall(data.vcall(), true);
_allReceived = (_fullCount.current() == _participants.size());
_participantsSliceAdded.fire({});
});
_reloadRequestId = 0;
}).fail([=](const RPCError &error) {
@ -167,7 +164,9 @@ void GroupCall::reload() {
}
void GroupCall::applyParticipantsSlice(
const QVector<MTPGroupCallParticipant> &list) {
const QVector<MTPGroupCallParticipant> &list,
bool sendIndividualUpdates) {
auto fullCount = _fullCount.current();
for (const auto &participant : list) {
participant.match([&](const MTPDgroupCallParticipant &data) {
const auto userId = data.vuser_id().v;
@ -178,11 +177,17 @@ void GroupCall::applyParticipantsSlice(
&Participant::user);
if (data.is_left()) {
if (i != end(_participants)) {
_sources.remove(i->source);
auto update = ParticipantUpdate{
.participant = *i,
.removed = true,
};
_participants.erase(i);
if (sendIndividualUpdates) {
_participantUpdates.fire(std::move(update));
}
}
if (_fullCount > _participants.size()) {
--_fullCount;
if (fullCount > _participants.size()) {
--fullCount;
}
return;
}
@ -195,28 +200,69 @@ void GroupCall::applyParticipantsSlice(
};
if (i == end(_participants)) {
_participants.push_back(value);
++_fullCount;
++fullCount;
} else {
*i = value;
}
_sources.emplace(uint32(data.vsource().v));
_participantUpdates.fire({
.participant = value,
});
});
}
ranges::sort(_participants, std::greater<>(), &Participant::date);
ranges::sort(_participants, std::greater<>(), [](const Participant &p) {
return p.lastActivePrecise
? p.lastActivePrecise
: p.lastActive
? p.lastActive
: p.date;
});
_fullCount = fullCount;
}
void GroupCall::applyParticipantsMutes(
const MTPDupdateGroupCallParticipants &update) {
for (const auto &participant : update.vparticipants().v) {
participant.match([&](const MTPDgroupCallParticipant &data) {
if (data.is_left()) {
return;
}
const auto userId = data.vuser_id().v;
const auto user = _channel->owner().user(userId);
const auto i = ranges::find(
_participants,
user,
&Participant::user);
if (i != end(_participants)) {
i->muted = data.is_muted();
i->canSelfUnmute = data.is_can_self_unmute();
_participantUpdates.fire({
.participant = *i,
});
}
});
}
}
void GroupCall::applyUpdate(const MTPDupdateGroupCallParticipants &update) {
if (update.vversion().v <= _version) {
const auto version = update.vversion().v;
if (version < _version) {
return;
} else if (update.vversion().v != _version + 1) {
} else if (version == _version) {
applyParticipantsMutes(update);
return;
} else if (version != _version + 1) {
applyParticipantsMutes(update);
reload();
return;
}
_version = update.vversion().v;
applyParticipantsSlice(update.vparticipants().v);
_channel->session().changes().peerUpdated(
_channel,
PeerUpdate::Flag::GroupCall);
applyUpdateChecked(update);
}
void GroupCall::applyUpdateChecked(
const MTPDupdateGroupCallParticipants &update) {
applyParticipantsSlice(update.vparticipants().v, true);
}
} // namespace Data

View file

@ -24,21 +24,32 @@ public:
struct Participant {
not_null<UserData*> user;
TimeId date = 0;
TimeId lastActive = 0;
TimeId lastActivePrecise = 0;
uint32 source = 0;
bool muted = false;
bool canSelfUnmute = false;
};
struct ParticipantUpdate {
Participant participant;
bool removed = false;
};
[[nodiscard]] auto participants() const
-> const std::vector<Participant> &;
[[nodiscard]] const base::flat_set<uint32> &sources() const;
void requestParticipants();
[[nodiscard]] bool participantsLoaded() const;
[[nodiscard]] rpl::producer<> participantsSliceAdded();
[[nodiscard]] rpl::producer<ParticipantUpdate> participantUpdated() const;
void applyUpdate(const MTPGroupCall &update);
void applyUpdate(const MTPDupdateGroupCallParticipants &update);
void applyUpdateChecked(
const MTPDupdateGroupCallParticipants &update);
[[nodiscard]] int fullCount() const;
[[nodiscard]] rpl::producer<int> fullCountValue() const;
void reload();
[[nodiscard]] bool finished() const;
@ -46,7 +57,11 @@ public:
private:
void applyCall(const MTPGroupCall &call, bool force);
void applyParticipantsSlice(const QVector<MTPGroupCallParticipant> &list);
void applyParticipantsSlice(
const QVector<MTPGroupCallParticipant> &list,
bool sendIndividualUpdates = false);
void applyParticipantsMutes(
const MTPDupdateGroupCallParticipants &update);
const not_null<ChannelData*> _channel;
const uint64 _id = 0;
@ -57,9 +72,12 @@ private:
mtpRequestId _reloadRequestId = 0;
std::vector<Participant> _participants;
base::flat_set<uint32> _sources;
QString _nextOffset;
int _fullCount = 0;
rpl::variable<int> _fullCount = 0;
rpl::event_stream<ParticipantUpdate> _participantUpdates;
rpl::event_stream<> _participantsSliceAdded;
int _duration = 0;
bool _finished = false;
bool _allReceived = false;

@ -1 +1 @@
Subproject commit d2c6ad40d717e604859589d854b81229abd11763
Subproject commit ac86c0ee86293d6fced7dcb48a8c93657f18a7f3