mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Allow to accept / reject requests by link.
This commit is contained in:
parent
9e05e44a14
commit
b4895ef730
5 changed files with 349 additions and 19 deletions
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "base/unixtime.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
|
@ -435,6 +436,77 @@ void InviteLinks::requestMyLinks(not_null<PeerData*> peer) {
|
||||||
_firstSliceRequests.emplace(peer, requestId);
|
_firstSliceRequests.emplace(peer, requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InviteLinks::processRequest(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const QString &link,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
bool approved,
|
||||||
|
Fn<void()> done,
|
||||||
|
Fn<void()> fail) {
|
||||||
|
if (_processRequests.contains({ peer, user })) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_processRequests.emplace(
|
||||||
|
std::pair{ peer, user },
|
||||||
|
ProcessRequest{ std::move(done), std::move(fail) });
|
||||||
|
using Flag = MTPmessages_HideChatJoinRequest::Flag;
|
||||||
|
_api->request(MTPmessages_HideChatJoinRequest(
|
||||||
|
MTP_flags(approved ? Flag::f_approved : Flag(0)),
|
||||||
|
peer->input,
|
||||||
|
user->inputUser
|
||||||
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
if (const auto chat = peer->asChat()) {
|
||||||
|
if (chat->count > 0) {
|
||||||
|
if (chat->participants.size() >= chat->count) {
|
||||||
|
chat->participants.emplace(user);
|
||||||
|
}
|
||||||
|
++chat->count;
|
||||||
|
}
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
|
_api->requestParticipantsCountDelayed(channel);
|
||||||
|
}
|
||||||
|
_api->applyUpdates(result);
|
||||||
|
if (approved) {
|
||||||
|
const auto i = _firstJoined.find({ peer, link });
|
||||||
|
if (i != end(_firstJoined)) {
|
||||||
|
++i->second.count;
|
||||||
|
i->second.users.insert(
|
||||||
|
begin(i->second.users),
|
||||||
|
JoinedByLinkUser{ user, base::unixtime::now() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (const auto callbacks = _processRequests.take({ peer, user })) {
|
||||||
|
if (const auto &done = callbacks->done) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
if (const auto callbacks = _processRequests.take({ peer, user })) {
|
||||||
|
if (const auto &fail = callbacks->fail) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InviteLinks::applyExternalUpdate(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
InviteLink updated) {
|
||||||
|
if (const auto i = _firstSlices.find(peer); i != end(_firstSlices)) {
|
||||||
|
for (auto &link : i->second.links) {
|
||||||
|
if (link.link == updated.link) {
|
||||||
|
link = updated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_updates.fire({
|
||||||
|
.peer = peer,
|
||||||
|
.admin = updated.admin,
|
||||||
|
.was = updated.link,
|
||||||
|
.now = updated,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<JoinedByLinkSlice> InviteLinks::lookupJoinedFirstSlice(
|
std::optional<JoinedByLinkSlice> InviteLinks::lookupJoinedFirstSlice(
|
||||||
LinkKey key) const {
|
LinkKey key) const {
|
||||||
const auto i = _firstJoined.find(key);
|
const auto i = _firstJoined.find(key);
|
||||||
|
@ -498,7 +570,7 @@ void InviteLinks::requestJoinedFirstSlice(LinkKey key) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto requestId = _api->request(MTPmessages_GetChatInviteImporters(
|
const auto requestId = _api->request(MTPmessages_GetChatInviteImporters(
|
||||||
MTP_flags(0),
|
MTP_flags(MTPmessages_GetChatInviteImporters::Flag::f_link),
|
||||||
key.peer->input,
|
key.peer->input,
|
||||||
MTP_string(key.link),
|
MTP_string(key.link),
|
||||||
MTPstring(), // q
|
MTPstring(), // q
|
||||||
|
@ -645,6 +717,7 @@ auto InviteLinks::parse(
|
||||||
.expireDate = data.vexpire_date().value_or_empty(),
|
.expireDate = data.vexpire_date().value_or_empty(),
|
||||||
.usageLimit = data.vusage_limit().value_or_empty(),
|
.usageLimit = data.vusage_limit().value_or_empty(),
|
||||||
.usage = data.vusage().value_or_empty(),
|
.usage = data.vusage().value_or_empty(),
|
||||||
|
.requested = data.vrequested().value_or_empty(),
|
||||||
.requestApproval = data.is_request_needed(),
|
.requestApproval = data.is_request_needed(),
|
||||||
.permanent = data.is_permanent(),
|
.permanent = data.is_permanent(),
|
||||||
.revoked = data.is_revoked(),
|
.revoked = data.is_revoked(),
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct InviteLink {
|
||||||
TimeId expireDate = 0;
|
TimeId expireDate = 0;
|
||||||
int usageLimit = 0;
|
int usageLimit = 0;
|
||||||
int usage = 0;
|
int usage = 0;
|
||||||
|
int requested = 0;
|
||||||
bool requestApproval = false;
|
bool requestApproval = false;
|
||||||
bool permanent = false;
|
bool permanent = false;
|
||||||
bool revoked = false;
|
bool revoked = false;
|
||||||
|
@ -100,6 +101,15 @@ public:
|
||||||
void requestMyLinks(not_null<PeerData*> peer);
|
void requestMyLinks(not_null<PeerData*> peer);
|
||||||
[[nodiscard]] const Links &myLinks(not_null<PeerData*> peer) const;
|
[[nodiscard]] const Links &myLinks(not_null<PeerData*> peer) const;
|
||||||
|
|
||||||
|
void processRequest(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const QString &link,
|
||||||
|
not_null<UserData*> user,
|
||||||
|
bool approved,
|
||||||
|
Fn<void()> done,
|
||||||
|
Fn<void()> fail);
|
||||||
|
void applyExternalUpdate(not_null<PeerData*> peer, InviteLink updated);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<JoinedByLinkSlice> joinedFirstSliceValue(
|
[[nodiscard]] rpl::producer<JoinedByLinkSlice> joinedFirstSliceValue(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const QString &link,
|
const QString &link,
|
||||||
|
@ -136,6 +146,10 @@ private:
|
||||||
return (a.peer == b.peer) && (a.link == b.link);
|
return (a.peer == b.peer) && (a.link == b.link);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
struct ProcessRequest {
|
||||||
|
Fn<void()> done;
|
||||||
|
Fn<void()> fail;
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]] Links parseSlice(
|
[[nodiscard]] Links parseSlice(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
|
@ -199,6 +213,10 @@ private:
|
||||||
not_null<PeerData*>,
|
not_null<PeerData*>,
|
||||||
std::vector<Fn<void()>>> _deleteRevokedCallbacks;
|
std::vector<Fn<void()>>> _deleteRevokedCallbacks;
|
||||||
|
|
||||||
|
base::flat_map<
|
||||||
|
std::pair<not_null<PeerData*>, not_null<UserData*>>,
|
||||||
|
ProcessRequest> _processRequests;
|
||||||
|
|
||||||
rpl::event_stream<Update> _updates;
|
rpl::event_stream<Update> _updates;
|
||||||
|
|
||||||
struct AllRevokedDestroyed {
|
struct AllRevokedDestroyed {
|
||||||
|
|
|
@ -57,30 +57,109 @@ constexpr auto kShareQrPadding = 16;
|
||||||
|
|
||||||
using LinkData = Api::InviteLink;
|
using LinkData = Api::InviteLink;
|
||||||
|
|
||||||
class Controller final : public PeerListController {
|
class RequestedRow final : public PeerListRow {
|
||||||
public:
|
public:
|
||||||
|
explicit RequestedRow(not_null<PeerData*> peer);
|
||||||
|
|
||||||
|
QSize actionSize() const override;
|
||||||
|
QMargins actionMargins() const override;
|
||||||
|
void paintAction(
|
||||||
|
Painter &p,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int outerWidth,
|
||||||
|
bool selected,
|
||||||
|
bool actionSelected) override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
RequestedRow::RequestedRow(not_null<PeerData*> peer)
|
||||||
|
: PeerListRow(peer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize RequestedRow::actionSize() const {
|
||||||
|
return QSize(
|
||||||
|
st::inviteLinkThreeDotsIcon.width(),
|
||||||
|
st::inviteLinkThreeDotsIcon.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
QMargins RequestedRow::actionMargins() const {
|
||||||
|
return QMargins(
|
||||||
|
0,
|
||||||
|
(st::inviteLinkList.item.height - actionSize().height()) / 2,
|
||||||
|
st::inviteLinkThreeDotsSkip,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestedRow::paintAction(
|
||||||
|
Painter &p,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int outerWidth,
|
||||||
|
bool selected,
|
||||||
|
bool actionSelected) {
|
||||||
|
(actionSelected
|
||||||
|
? st::inviteLinkThreeDotsIconOver
|
||||||
|
: st::inviteLinkThreeDotsIcon).paint(p, x, y, outerWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Controller final
|
||||||
|
: public PeerListController
|
||||||
|
, public base::has_weak_ptr {
|
||||||
|
public:
|
||||||
|
enum class Role {
|
||||||
|
Requested,
|
||||||
|
Joined,
|
||||||
|
};
|
||||||
Controller(
|
Controller(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
not_null<UserData*> admin,
|
not_null<UserData*> admin,
|
||||||
rpl::producer<LinkData> data);
|
rpl::producer<LinkData> data,
|
||||||
|
Role role);
|
||||||
|
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
void loadMoreRows() override;
|
void loadMoreRows() override;
|
||||||
void rowClicked(not_null<PeerListRow*> row) override;
|
void rowClicked(not_null<PeerListRow*> row) override;
|
||||||
|
void rowActionClicked(not_null<PeerListRow*> row) override;
|
||||||
Main::Session &session() const override;
|
Main::Session &session() const override;
|
||||||
|
|
||||||
rpl::producer<int> boxHeightValue() const override;
|
rpl::producer<int> boxHeightValue() const override;
|
||||||
int descriptionTopSkipMin() const override;
|
int descriptionTopSkipMin() const override;
|
||||||
|
|
||||||
|
struct Processed {
|
||||||
|
not_null<UserData*> user;
|
||||||
|
bool approved = false;
|
||||||
|
};
|
||||||
|
[[nodiscard]] rpl::producer<Processed> processed() const {
|
||||||
|
return _processed.events();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<PeerListRow*> row) override;
|
||||||
|
|
||||||
|
void setupAboveJoinedWidget();
|
||||||
void appendSlice(const Api::JoinedByLinkSlice &slice);
|
void appendSlice(const Api::JoinedByLinkSlice &slice);
|
||||||
void addHeaderBlock(not_null<Ui::VerticalLayout*> container);
|
void addHeaderBlock(not_null<Ui::VerticalLayout*> container);
|
||||||
|
not_null<Ui::SlideWrap<>*> addRequestedListBlock(
|
||||||
|
not_null<Ui::VerticalLayout*> container);
|
||||||
|
void updateWithProcessed(Processed processed);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<LinkData> dataValue() const;
|
[[nodiscard]] rpl::producer<LinkData> dataValue() const;
|
||||||
|
|
||||||
|
[[nodiscard]] base::unique_qptr<Ui::PopupMenu> createRowContextMenu(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<PeerListRow*> row);
|
||||||
|
void processRequest(not_null<UserData*> user, bool approved);
|
||||||
|
|
||||||
const not_null<PeerData*> _peer;
|
const not_null<PeerData*> _peer;
|
||||||
|
const Role _role = Role::Joined;
|
||||||
rpl::variable<LinkData> _data;
|
rpl::variable<LinkData> _data;
|
||||||
|
|
||||||
|
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||||
|
rpl::event_stream<Processed> _processed;
|
||||||
|
|
||||||
QString _link;
|
QString _link;
|
||||||
bool _revoked = false;
|
bool _revoked = false;
|
||||||
|
|
||||||
|
@ -220,10 +299,12 @@ void QrBox(
|
||||||
Controller::Controller(
|
Controller::Controller(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
not_null<UserData*> admin,
|
not_null<UserData*> admin,
|
||||||
rpl::producer<LinkData> data)
|
rpl::producer<LinkData> data,
|
||||||
|
Role role)
|
||||||
: _peer(peer)
|
: _peer(peer)
|
||||||
|
, _role(role)
|
||||||
, _data(LinkData{ .admin = admin })
|
, _data(LinkData{ .admin = admin })
|
||||||
, _api(&_peer->session().api().instance()) {
|
, _api(&session().api().instance()) {
|
||||||
_data = std::move(data);
|
_data = std::move(data);
|
||||||
const auto current = _data.current();
|
const auto current = _data.current();
|
||||||
_link = current.link;
|
_link = current.link;
|
||||||
|
@ -386,7 +467,87 @@ void Controller::addHeaderBlock(not_null<Ui::VerticalLayout*> container) {
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<Ui::SlideWrap<>*> Controller::addRequestedListBlock(
|
||||||
|
not_null<Ui::VerticalLayout*> container) {
|
||||||
|
using namespace Settings;
|
||||||
|
|
||||||
|
auto result = container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Ui::VerticalLayout>(
|
||||||
|
container)));
|
||||||
|
const auto wrap = result->entity();
|
||||||
|
// Make this container occupy full width.
|
||||||
|
wrap->add(object_ptr<Ui::RpWidget>(wrap));
|
||||||
|
AddDivider(wrap);
|
||||||
|
AddSkip(wrap);
|
||||||
|
auto requestedCount = dataValue(
|
||||||
|
) | rpl::filter([](const LinkData &data) {
|
||||||
|
return data.requested > 0;
|
||||||
|
}) | rpl::map([=](const LinkData &data) {
|
||||||
|
return float64(data.requested);
|
||||||
|
});
|
||||||
|
AddSubsectionTitle(
|
||||||
|
wrap,
|
||||||
|
tr::lng_group_invite_requested_full(
|
||||||
|
lt_count_decimal,
|
||||||
|
std::move(requestedCount)));
|
||||||
|
|
||||||
|
const auto delegate = container->lifetime().make_state<
|
||||||
|
PeerListContentDelegateSimple
|
||||||
|
>();
|
||||||
|
const auto controller = container->lifetime().make_state<
|
||||||
|
Controller
|
||||||
|
>(_peer, _data.current().admin, _data.value(), Role::Requested);
|
||||||
|
const auto content = container->add(object_ptr<PeerListContent>(
|
||||||
|
container,
|
||||||
|
controller));
|
||||||
|
delegate->setContent(content);
|
||||||
|
controller->setDelegate(delegate);
|
||||||
|
|
||||||
|
controller->processed(
|
||||||
|
) | rpl::start_with_next([=](Processed processed) {
|
||||||
|
updateWithProcessed(processed);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Controller::prepare() {
|
void Controller::prepare() {
|
||||||
|
if (_role == Role::Joined) {
|
||||||
|
setupAboveJoinedWidget();
|
||||||
|
|
||||||
|
_allLoaded = (_data.current().usage == 0);
|
||||||
|
|
||||||
|
const auto &inviteLinks = session().api().inviteLinks();
|
||||||
|
const auto slice = inviteLinks.joinedFirstSliceLoaded(_peer, _link);
|
||||||
|
if (slice) {
|
||||||
|
appendSlice(*slice);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_allLoaded = (_data.current().requested == 0);
|
||||||
|
}
|
||||||
|
loadMoreRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::updateWithProcessed(Processed processed) {
|
||||||
|
const auto user = processed.user;
|
||||||
|
auto updated = _data.current();
|
||||||
|
if (processed.approved) {
|
||||||
|
++updated.usage;
|
||||||
|
if (!delegate()->peerListFindRow(user->id.value)) {
|
||||||
|
delegate()->peerListPrependRow(
|
||||||
|
std::make_unique<PeerListRow>(user));
|
||||||
|
delegate()->peerListRefreshRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (updated.requested > 0) {
|
||||||
|
--updated.requested;
|
||||||
|
}
|
||||||
|
session().api().inviteLinks().applyExternalUpdate(_peer, updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::setupAboveJoinedWidget() {
|
||||||
using namespace Settings;
|
using namespace Settings;
|
||||||
|
|
||||||
auto header = object_ptr<Ui::VerticalLayout>((QWidget*)nullptr);
|
auto header = object_ptr<Ui::VerticalLayout>((QWidget*)nullptr);
|
||||||
|
@ -406,6 +567,8 @@ void Controller::prepare() {
|
||||||
rpl::single(langDateTime(base::unixtime::parse(current.date))));
|
rpl::single(langDateTime(base::unixtime::parse(current.date))));
|
||||||
AddSkip(container, st::membersMarginBottom);
|
AddSkip(container, st::membersMarginBottom);
|
||||||
|
|
||||||
|
auto requestedWrap = addRequestedListBlock(container);
|
||||||
|
|
||||||
const auto listHeaderWrap = container->add(
|
const auto listHeaderWrap = container->add(
|
||||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
container,
|
container,
|
||||||
|
@ -484,6 +647,8 @@ void Controller::prepare() {
|
||||||
} else {
|
} else {
|
||||||
remaining->show();
|
remaining->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestedWrap->toggle(data.requested > 0, anim::type::instant);
|
||||||
}, remaining->lifetime());
|
}, remaining->lifetime());
|
||||||
|
|
||||||
rpl::combine(
|
rpl::combine(
|
||||||
|
@ -500,22 +665,16 @@ void Controller::prepare() {
|
||||||
_headerWidget = header.data();
|
_headerWidget = header.data();
|
||||||
|
|
||||||
delegate()->peerListSetAboveWidget(std::move(header));
|
delegate()->peerListSetAboveWidget(std::move(header));
|
||||||
_allLoaded = (current.usage == 0);
|
|
||||||
|
|
||||||
const auto &inviteLinks = _peer->session().api().inviteLinks();
|
|
||||||
const auto slice = inviteLinks.joinedFirstSliceLoaded(_peer, _link);
|
|
||||||
if (slice) {
|
|
||||||
appendSlice(*slice);
|
|
||||||
}
|
|
||||||
loadMoreRows();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::loadMoreRows() {
|
void Controller::loadMoreRows() {
|
||||||
if (_requestId || _allLoaded) {
|
if (_requestId || _allLoaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
using Flag = MTPmessages_GetChatInviteImporters::Flag;
|
||||||
_requestId = _api.request(MTPmessages_GetChatInviteImporters(
|
_requestId = _api.request(MTPmessages_GetChatInviteImporters(
|
||||||
MTP_flags(0),
|
MTP_flags(Flag::f_link
|
||||||
|
| (_role == Role::Requested ? Flag::f_requested : Flag(0))),
|
||||||
_peer->input,
|
_peer->input,
|
||||||
MTP_string(_link),
|
MTP_string(_link),
|
||||||
MTPstring(), // q
|
MTPstring(), // q
|
||||||
|
@ -536,8 +695,9 @@ void Controller::loadMoreRows() {
|
||||||
void Controller::appendSlice(const Api::JoinedByLinkSlice &slice) {
|
void Controller::appendSlice(const Api::JoinedByLinkSlice &slice) {
|
||||||
for (const auto &user : slice.users) {
|
for (const auto &user : slice.users) {
|
||||||
_lastUser = user;
|
_lastUser = user;
|
||||||
delegate()->peerListAppendRow(
|
delegate()->peerListAppendRow((_role == Role::Requested)
|
||||||
std::make_unique<PeerListRow>(user.user));
|
? std::make_unique<RequestedRow>(user.user)
|
||||||
|
: std::make_unique<PeerListRow>(user.user));
|
||||||
}
|
}
|
||||||
delegate()->peerListRefreshRows();
|
delegate()->peerListRefreshRows();
|
||||||
if (delegate()->peerListFullRowsCount() > 0) {
|
if (delegate()->peerListFullRowsCount() > 0) {
|
||||||
|
@ -552,6 +712,71 @@ void Controller::rowClicked(not_null<PeerListRow*> row) {
|
||||||
Ui::showPeerProfile(row->peer());
|
Ui::showPeerProfile(row->peer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::rowActionClicked(not_null<PeerListRow*> row) {
|
||||||
|
if (_role != Role::Requested) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delegate()->peerListShowRowMenu(row, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
base::unique_qptr<Ui::PopupMenu> Controller::rowContextMenu(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<PeerListRow*> row) {
|
||||||
|
auto result = createRowContextMenu(parent, row);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
// First clear _menu value, so that we don't check row positions yet.
|
||||||
|
base::take(_menu);
|
||||||
|
|
||||||
|
// Here unique_qptr is used like a shared pointer, where
|
||||||
|
// not the last destroyed pointer destroys the object, but the first.
|
||||||
|
_menu = base::unique_qptr<Ui::PopupMenu>(result.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
base::unique_qptr<Ui::PopupMenu> Controller::createRowContextMenu(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<PeerListRow*> row) {
|
||||||
|
const auto user = row->peer()->asUser();
|
||||||
|
Assert(user != nullptr);
|
||||||
|
|
||||||
|
auto result = base::make_unique_q<Ui::PopupMenu>(parent);
|
||||||
|
const auto add = _peer->isBroadcast()
|
||||||
|
? tr::lng_group_requests_add_channel(tr::now)
|
||||||
|
: tr::lng_group_requests_add(tr::now);
|
||||||
|
result->addAction(add, [=] {
|
||||||
|
processRequest(user, true);
|
||||||
|
});
|
||||||
|
result->addAction(tr::lng_group_requests_dismiss(tr::now), [=] {
|
||||||
|
processRequest(user, false);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::processRequest(
|
||||||
|
not_null<UserData*> user,
|
||||||
|
bool approved) {
|
||||||
|
const auto done = crl::guard(this, [=] {
|
||||||
|
_processed.fire({ user, approved });
|
||||||
|
if (const auto row = delegate()->peerListFindRow(user->id.value)) {
|
||||||
|
delegate()->peerListRemoveRow(row);
|
||||||
|
delegate()->peerListRefreshRows();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const auto fail = crl::guard(this, [=] {
|
||||||
|
_processed.fire({ user, false });
|
||||||
|
});
|
||||||
|
session().api().inviteLinks().processRequest(
|
||||||
|
_peer,
|
||||||
|
_data.current().link,
|
||||||
|
user,
|
||||||
|
approved,
|
||||||
|
done,
|
||||||
|
fail);
|
||||||
|
}
|
||||||
|
|
||||||
Main::Session &Controller::session() const {
|
Main::Session &Controller::session() const {
|
||||||
return _peer->session();
|
return _peer->session();
|
||||||
}
|
}
|
||||||
|
@ -1055,7 +1280,11 @@ void ShowInviteLinkBox(
|
||||||
};
|
};
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box<PeerListBox>(
|
Box<PeerListBox>(
|
||||||
std::make_unique<Controller>(peer, link.admin, std::move(data)),
|
std::make_unique<Controller>(
|
||||||
|
peer,
|
||||||
|
link.admin,
|
||||||
|
std::move(data),
|
||||||
|
Controller::Role::Joined),
|
||||||
std::move(initBox)),
|
std::move(initBox)),
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,16 @@ private:
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_count_decimal,
|
lt_count_decimal,
|
||||||
link.usageLimit - link.usage);
|
link.usageLimit - link.usage);
|
||||||
|
} else if (link.usage > 0 && link.requested > 0) {
|
||||||
|
result += ", " + tr::lng_group_invite_requested(
|
||||||
|
tr::now,
|
||||||
|
lt_count_decimal,
|
||||||
|
link.requested);
|
||||||
|
} else if (link.requested > 0) {
|
||||||
|
result = tr::lng_group_invite_requested_full(
|
||||||
|
tr::now,
|
||||||
|
lt_count_decimal,
|
||||||
|
link.requested);
|
||||||
}
|
}
|
||||||
if (link.expireDate > now) {
|
if (link.expireDate > now) {
|
||||||
const auto left = (link.expireDate - now);
|
const auto left = (link.expireDate - now);
|
||||||
|
|
|
@ -309,8 +309,8 @@ void CreateInviteLinkBox(
|
||||||
bool isGroup,
|
bool isGroup,
|
||||||
Fn<void(InviteLinkFields)> done) {
|
Fn<void(InviteLinkFields)> done) {
|
||||||
EditInviteLinkBox(
|
EditInviteLinkBox(
|
||||||
box,
|
box,
|
||||||
InviteLinkFields{ .isGroup = isGroup },
|
InviteLinkFields{ .isGroup = isGroup },
|
||||||
std::move(done));
|
std::move(done));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue