mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Improve group call members list updating.
This commit is contained in:
parent
8618fe41ee
commit
a6b4cdd62d
11 changed files with 332 additions and 164 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
2
Telegram/ThirdParty/tgcalls
vendored
2
Telegram/ThirdParty/tgcalls
vendored
|
@ -1 +1 @@
|
|||
Subproject commit d2c6ad40d717e604859589d854b81229abd11763
|
||||
Subproject commit ac86c0ee86293d6fced7dcb48a8c93657f18a7f3
|
Loading…
Add table
Reference in a new issue