Fix other admins links management.

This commit is contained in:
John Preston 2021-02-05 21:35:29 +04:00
parent ac33a8bd96
commit d188ab6719
9 changed files with 160 additions and 62 deletions

View file

@ -115,19 +115,19 @@ void InviteLinks::performCreate(
}).send(); }).send();
} }
auto InviteLinks::lookupPermanent(not_null<PeerData*> peer) -> Link* { auto InviteLinks::lookupMyPermanent(not_null<PeerData*> peer) -> Link* {
auto i = _firstSlices.find(peer); auto i = _firstSlices.find(peer);
return (i != end(_firstSlices)) ? lookupPermanent(i->second) : nullptr; return (i != end(_firstSlices)) ? lookupMyPermanent(i->second) : nullptr;
} }
auto InviteLinks::lookupPermanent(Links &links) -> Link* { auto InviteLinks::lookupMyPermanent(Links &links) -> Link* {
const auto first = links.links.begin(); const auto first = links.links.begin();
return (first != end(links.links) && first->permanent && !first->revoked) return (first != end(links.links) && first->permanent && !first->revoked)
? &*first ? &*first
: nullptr; : nullptr;
} }
auto InviteLinks::lookupPermanent(const Links &links) const -> const Link* { auto InviteLinks::lookupMyPermanent(const Links &links) const -> const Link* {
const auto first = links.links.begin(); const auto first = links.links.begin();
return (first != end(links.links) && first->permanent && !first->revoked) return (first != end(links.links) && first->permanent && !first->revoked)
? &*first ? &*first
@ -139,12 +139,29 @@ auto InviteLinks::prepend(
not_null<UserData*> admin, not_null<UserData*> admin,
const MTPExportedChatInvite &invite) -> Link { const MTPExportedChatInvite &invite) -> Link {
const auto link = parse(peer, invite); const auto link = parse(peer, invite);
if (admin->isSelf()) {
prependMyToFirstSlice(peer, admin, link);
}
_updates.fire(Update{
.peer = peer,
.admin = admin,
.now = link
});
return link;
}
void InviteLinks::prependMyToFirstSlice(
not_null<PeerData*> peer,
not_null<UserData*> admin,
const Link &link) {
Expects(admin->isSelf());
auto i = _firstSlices.find(peer); auto i = _firstSlices.find(peer);
if (i == end(_firstSlices)) { if (i == end(_firstSlices)) {
i = _firstSlices.emplace(peer).first; i = _firstSlices.emplace(peer).first;
} }
auto &links = i->second; auto &links = i->second;
const auto permanent = lookupPermanent(links); const auto permanent = lookupMyPermanent(links);
const auto hadPermanent = (permanent != nullptr); const auto hadPermanent = (permanent != nullptr);
auto updateOldPermanent = Update{ auto updateOldPermanent = Update{
.peer = peer, .peer = peer,
@ -176,12 +193,6 @@ auto InviteLinks::prepend(
if (updateOldPermanent.now) { if (updateOldPermanent.now) {
_updates.fire(std::move(updateOldPermanent)); _updates.fire(std::move(updateOldPermanent));
} }
_updates.fire(Update{
.peer = peer,
.admin = admin,
.now = link
});
return link;
} }
void InviteLinks::edit( void InviteLinks::edit(
@ -383,14 +394,14 @@ void InviteLinks::requestMyLinks(not_null<PeerData*> peer) {
auto slice = parseSlice(peer, result); auto slice = parseSlice(peer, result);
auto i = _firstSlices.find(peer); auto i = _firstSlices.find(peer);
const auto permanent = (i != end(_firstSlices)) const auto permanent = (i != end(_firstSlices))
? lookupPermanent(i->second) ? lookupMyPermanent(i->second)
: nullptr; : nullptr;
if (!permanent) { if (!permanent) {
BringPermanentToFront(slice); BringPermanentToFront(slice);
const auto j = _firstSlices.emplace_or_assign( const auto j = _firstSlices.emplace_or_assign(
peer, peer,
std::move(slice)).first; std::move(slice)).first;
if (const auto permanent = lookupPermanent(j->second)) { if (const auto permanent = lookupMyPermanent(j->second)) {
editPermanentLink(peer, permanent->link); editPermanentLink(peer, permanent->link);
} }
} else { } else {
@ -506,7 +517,7 @@ void InviteLinks::setMyPermanent(
.peer = peer, .peer = peer,
.admin = peer->session().user(), .admin = peer->session().user(),
}; };
if (const auto permanent = lookupPermanent(links)) { if (const auto permanent = lookupMyPermanent(links)) {
if (permanent->link == link.link) { if (permanent->link == link.link) {
if (permanent->usage != link.usage) { if (permanent->usage != link.usage) {
permanent->usage = link.usage; permanent->usage = link.usage;
@ -548,7 +559,7 @@ void InviteLinks::clearMyPermanent(not_null<PeerData*> peer) {
return; return;
} }
auto &links = i->second; auto &links = i->second;
const auto permanent = lookupPermanent(links); const auto permanent = lookupMyPermanent(links);
if (!permanent) { if (!permanent) {
return; return;
} }
@ -590,7 +601,7 @@ auto InviteLinks::parseSlice(
const MTPmessages_ExportedChatInvites &slice) const -> Links { const MTPmessages_ExportedChatInvites &slice) const -> Links {
auto i = _firstSlices.find(peer); auto i = _firstSlices.find(peer);
const auto permanent = (i != end(_firstSlices)) const auto permanent = (i != end(_firstSlices))
? lookupPermanent(i->second) ? lookupMyPermanent(i->second)
: nullptr; : nullptr;
auto result = Links(); auto result = Links();
slice.match([&](const MTPDmessages_exportedChatInvites &data) { slice.match([&](const MTPDmessages_exportedChatInvites &data) {

View file

@ -140,13 +140,17 @@ private:
[[nodiscard]] Link parse( [[nodiscard]] Link parse(
not_null<PeerData*> peer, not_null<PeerData*> peer,
const MTPExportedChatInvite &invite) const; const MTPExportedChatInvite &invite) const;
[[nodiscard]] Link *lookupPermanent(not_null<PeerData*> peer); [[nodiscard]] Link *lookupMyPermanent(not_null<PeerData*> peer);
[[nodiscard]] Link *lookupPermanent(Links &links); [[nodiscard]] Link *lookupMyPermanent(Links &links);
[[nodiscard]] const Link *lookupPermanent(const Links &links) const; [[nodiscard]] const Link *lookupMyPermanent(const Links &links) const;
Link prepend( Link prepend(
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> admin, not_null<UserData*> admin,
const MTPExportedChatInvite &invite); const MTPExportedChatInvite &invite);
void prependMyToFirstSlice(
not_null<PeerData*> peer,
not_null<UserData*> admin,
const Link &link);
void notify(not_null<PeerData*> peer); void notify(not_null<PeerData*> peer);
void editPermanentLink( void editPermanentLink(

View file

@ -928,6 +928,9 @@ peerListWithInviteViaLink: PeerList(peerListBox) {
0px, 0px,
membersMarginBottom); membersMarginBottom);
} }
peerListSingleRow: PeerList(peerListBox) {
padding: margins(0px, 0px, 0px, 0px);
}
scheduleHeight: 95px; scheduleHeight: 95px;
scheduleDateTop: 38px; scheduleDateTop: 38px;

View file

@ -1073,24 +1073,26 @@ void Controller::fillManageSection() {
st::infoIconPermissions); st::infoIconPermissions);
} }
if (canEditInviteLinks) { if (canEditInviteLinks) {
auto count = Info::Profile::MigratedOrMeValue(
_peer
) | rpl::map([=](not_null<PeerData*> peer) {
peer->session().api().inviteLinks().requestMyLinks(peer);
return peer->session().changes().peerUpdates(
peer,
Data::PeerUpdate::Flag::InviteLinks
) | rpl::map([=] {
return peer->session().api().inviteLinks().myLinks(
peer).count;
});
}) | rpl::flatten_latest(
) | rpl::start_spawning(_controls.buttonsLayout->lifetime());
AddButtonWithCount( AddButtonWithCount(
_controls.buttonsLayout, _controls.buttonsLayout,
tr::lng_manage_peer_invite_links(), tr::lng_manage_peer_invite_links(),
Info::Profile::MigratedOrMeValue( rpl::duplicate(count) | ToPositiveNumberString(),
_peer
) | rpl::map([=](not_null<PeerData*> peer) {
peer->session().api().inviteLinks().requestMyLinks(peer);
return peer->session().changes().peerUpdates(
peer,
Data::PeerUpdate::Flag::InviteLinks
) | rpl::map([=] {
return peer->session().api().inviteLinks().myLinks(
peer).count;
});
}) | rpl::flatten_latest(
) | ToPositiveNumberString(),
[=] { Ui::show( [=] { Ui::show(
Box(ManageInviteLinksBox, _peer, _peer->session().user()), Box(ManageInviteLinksBox, _peer, _peer->session().user(), 0, 0),
Ui::LayerOption::KeepOther); Ui::LayerOption::KeepOther);
}, },
st::infoIconInviteLinks); st::infoIconInviteLinks);

View file

@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "settings/settings_common.h" #include "settings/settings_common.h"
#include "mtproto/sender.h" #include "mtproto/sender.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h" #include "styles/style_info.h"
#include <QtGui/QGuiApplication> #include <QtGui/QGuiApplication>
@ -75,7 +76,9 @@ private:
class SingleRowController final : public PeerListController { class SingleRowController final : public PeerListController {
public: public:
SingleRowController(not_null<PeerData*> peer, TimeId date); SingleRowController(
not_null<PeerData*> peer,
rpl::producer<QString> status);
void prepare() override; void prepare() override;
void loadMoreRows() override; void loadMoreRows() override;
@ -84,7 +87,8 @@ public:
private: private:
const not_null<PeerData*> _peer; const not_null<PeerData*> _peer;
TimeId _date = 0; rpl::producer<QString> _status;
rpl::lifetime _lifetime;
}; };
@ -164,23 +168,15 @@ void AddHeader(
} else { } else {
AddDivider(container); AddDivider(container);
} }
AddSkip(container);
} }
AddSkip(container);
AddSubsectionTitle( AddSubsectionTitle(
container, container,
tr::lng_group_invite_created_by()); tr::lng_group_invite_created_by());
AddSinglePeerRow(
const auto delegate = container->lifetime().make_state<
PeerListContentDelegateSimple
>();
const auto controller = container->lifetime().make_state<
SingleRowController
>(data.admin, data.date);
const auto content = container->add(object_ptr<PeerListContent>(
container, container,
controller)); data.admin,
delegate->setContent(content); rpl::single(langDateTime(base::unixtime::parse(data.date))));
controller->setDelegate(delegate);
} }
Controller::Controller(not_null<PeerData*> peer, const LinkData &data) Controller::Controller(not_null<PeerData*> peer, const LinkData &data)
@ -258,14 +254,19 @@ Main::Session &Controller::session() const {
SingleRowController::SingleRowController( SingleRowController::SingleRowController(
not_null<PeerData*> peer, not_null<PeerData*> peer,
TimeId date) rpl::producer<QString> status)
: _peer(peer) : _peer(peer)
, _date(date) { , _status(std::move(status)) {
} }
void SingleRowController::prepare() { void SingleRowController::prepare() {
auto row = std::make_unique<PeerListRow>(_peer); auto row = std::make_unique<PeerListRow>(_peer);
row->setCustomStatus(langDateTime(base::unixtime::parse(_date))); const auto raw = row.get();
std::move(
_status
) | rpl::start_with_next([=](const QString &status) {
raw->setCustomStatus(status);
}, _lifetime);
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
@ -283,6 +284,24 @@ Main::Session &SingleRowController::session() const {
} // namespace } // namespace
void AddSinglePeerRow(
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer,
rpl::producer<QString> status) {
const auto delegate = container->lifetime().make_state<
PeerListContentDelegateSimple
>();
const auto controller = container->lifetime().make_state<
SingleRowController
>(peer, std::move(status));
controller->setStyleOverrides(&st::peerListSingleRow);
const auto content = container->add(object_ptr<PeerListContent>(
container,
controller));
delegate->setContent(content);
controller->setDelegate(delegate);
}
void AddPermanentLinkBlock( void AddPermanentLinkBlock(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer, not_null<PeerData*> peer,

View file

@ -19,6 +19,11 @@ namespace Ui {
class VerticalLayout; class VerticalLayout;
} // namespace Ui } // namespace Ui
void AddSinglePeerRow(
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer,
rpl::producer<QString> status);
void AddPermanentLinkBlock( void AddPermanentLinkBlock(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer, not_null<PeerData*> peer,

View file

@ -341,7 +341,16 @@ crl::time Row::updateExpireIn() const {
QString Row::generateName() { QString Row::generateName() {
auto result = _data.link; auto result = _data.link;
return result.replace(qstr("https://"), QString()); return result.replace(
qstr("https://"),
QString()
).replace(
qstr("t.me/+"),
QString()
).replace(
qstr("t.me/joinchat/"),
QString()
);
} }
QString Row::generateShortName() { QString Row::generateShortName() {
@ -393,8 +402,13 @@ public:
LinksController( LinksController(
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> admin, not_null<UserData*> admin,
int count,
bool revoked); bool revoked);
[[nodiscard]] rpl::producer<int> fullCountValue() const {
return _count.value();
}
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;
@ -434,6 +448,7 @@ private:
const not_null<PeerData*> _peer; const not_null<PeerData*> _peer;
const not_null<UserData*> _admin; const not_null<UserData*> _admin;
const bool _revoked = false; const bool _revoked = false;
rpl::variable<int> _count;
base::unique_qptr<Ui::PopupMenu> _menu; base::unique_qptr<Ui::PopupMenu> _menu;
QString _offsetLink; QString _offsetLink;
@ -453,10 +468,12 @@ private:
LinksController::LinksController( LinksController::LinksController(
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> admin, not_null<UserData*> admin,
int count,
bool revoked) bool revoked)
: _peer(peer) : _peer(peer)
, _admin(admin) , _admin(admin)
, _revoked(revoked) , _revoked(revoked)
, _count(count)
, _updateExpiringTimer([=] { expiringProgressTimer(); }) { , _updateExpiringTimer([=] { expiringProgressTimer(); }) {
style::PaletteChanged( style::PaletteChanged(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
@ -475,7 +492,9 @@ LinksController::LinksController(
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
} else if (update.was.isEmpty()) { } else if (update.was.isEmpty()) {
if (!update.now->permanent || update.now->revoked) { if (update.now->permanent && !update.now->revoked) {
_permanentFound.fire_copy(*update.now);
} else {
prependRow(*update.now, now); prependRow(*update.now, now);
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
@ -547,6 +566,9 @@ void LinksController::appendSlice(const InviteLinksSlice &slice) {
if (slice.links.size() >= slice.count) { if (slice.links.size() >= slice.count) {
_allLoaded = true; _allLoaded = true;
} }
const auto rowsCount = delegate()->peerListFullRowsCount();
const auto minimalCount = _revoked ? rowsCount : (rowsCount + 1);
_count = _allLoaded ? minimalCount : std::max(slice.count, minimalCount);
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
@ -797,7 +819,7 @@ void AdminsController::loadMoreRows() {
void AdminsController::rowClicked(not_null<PeerListRow*> row) { void AdminsController::rowClicked(not_null<PeerListRow*> row) {
Ui::show( Ui::show(
Box(ManageInviteLinksBox, _peer, row->peer()->asUser()), Box(ManageInviteLinksBox, _peer, row->peer()->asUser(), 0, 0),
Ui::LayerOption::KeepOther); Ui::LayerOption::KeepOther);
} }
@ -816,13 +838,14 @@ void AdminsController::appendRow(not_null<UserData*> user, int count) {
struct LinksList { struct LinksList {
not_null<Ui::RpWidget*> widget; not_null<Ui::RpWidget*> widget;
rpl::producer<InviteLinkData> permanentFound; not_null<LinksController*> controller;
}; };
LinksList AddLinksList( LinksList AddLinksList(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> admin, not_null<UserData*> admin,
int count,
bool revoked) { bool revoked) {
auto &lifetime = container->lifetime(); auto &lifetime = container->lifetime();
const auto delegate = lifetime.make_state< const auto delegate = lifetime.make_state<
@ -831,6 +854,7 @@ LinksList AddLinksList(
const auto controller = lifetime.make_state<LinksController>( const auto controller = lifetime.make_state<LinksController>(
peer, peer,
admin, admin,
count,
revoked); revoked);
controller->setStyleOverrides(&st::inviteLinkList); controller->setStyleOverrides(&st::inviteLinkList);
const auto content = container->add(object_ptr<PeerListContent>( const auto content = container->add(object_ptr<PeerListContent>(
@ -839,7 +863,7 @@ LinksList AddLinksList(
delegate->setContent(content); delegate->setContent(content);
controller->setDelegate(delegate); controller->setDelegate(delegate);
return { content, controller->permanentFound() }; return { content, controller };
} }
not_null<Ui::RpWidget*> AddAdminsList( not_null<Ui::RpWidget*> AddAdminsList(
@ -866,7 +890,9 @@ not_null<Ui::RpWidget*> AddAdminsList(
void ManageInviteLinksBox( void ManageInviteLinksBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> admin) { not_null<UserData*> admin,
int count,
int revokedCount) {
using namespace Settings; using namespace Settings;
box->setTitle(tr::lng_group_invite_title()); box->setTitle(tr::lng_group_invite_title());
@ -875,6 +901,22 @@ void ManageInviteLinksBox(
const auto permanentFromList = box->lifetime().make_state< const auto permanentFromList = box->lifetime().make_state<
rpl::event_stream<InviteLinkData> rpl::event_stream<InviteLinkData>
>(); >();
const auto countValue = box->lifetime().make_state<rpl::variable<int>>(
count);
if (!admin->isSelf()) {
auto status = countValue->value() | rpl::map([](int count) {
// #TODO links
return (count == 1)
? "1 link"
: QString::number(count) + " links";
});
AddSinglePeerRow(
container,
admin,
std::move(status));
}
AddSubsectionTitle(container, tr::lng_create_permanent_link_title()); AddSubsectionTitle(container, tr::lng_create_permanent_link_title());
AddPermanentLinkBlock( AddPermanentLinkBlock(
container, container,
@ -899,10 +941,15 @@ void ManageInviteLinksBox(
st::inviteLinkRevokedTitlePadding)); st::inviteLinkRevokedTitlePadding));
} }
auto [list, newPermanent] = AddLinksList(container, peer, admin, false); auto [list, controller] = AddLinksList(
container,
peer,
admin,
count,
false);
*countValue = controller->fullCountValue();
std::move( controller->permanentFound(
newPermanent
) | rpl::start_with_next([=](InviteLinkData &&data) { ) | rpl::start_with_next([=](InviteLinkData &&data) {
permanentFromList->fire(std::move(data)); permanentFromList->fire(std::move(data));
}, container->lifetime()); }, container->lifetime());
@ -940,7 +987,12 @@ void ManageInviteLinksBox(
tr::lng_group_invite_revoked_title(), tr::lng_group_invite_revoked_title(),
st::settingsSubsectionTitle), st::settingsSubsectionTitle),
st::inviteLinkRevokedTitlePadding)); st::inviteLinkRevokedTitlePadding));
const auto revoked = AddLinksList(container, peer, admin, true).widget; const auto revoked = AddLinksList(
container,
peer,
admin,
revokedCount,
true).widget;
const auto deleteAll = Ui::CreateChild<Ui::LinkButton>( const auto deleteAll = Ui::CreateChild<Ui::LinkButton>(
container.get(), container.get(),

View file

@ -14,4 +14,6 @@ class PeerData;
void ManageInviteLinksBox( void ManageInviteLinksBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> admin); not_null<UserData*> admin,
int count,
int revokedCount);

View file

@ -193,7 +193,7 @@ void Controller::createContent() {
tr::lng_group_invite_manage(), tr::lng_group_invite_manage(),
rpl::single(QString()), rpl::single(QString()),
[=] { Ui::show( [=] { Ui::show(
Box(ManageInviteLinksBox, _peer, _peer->session().user()), Box(ManageInviteLinksBox, _peer, _peer->session().user(), 0, 0),
Ui::LayerOption::KeepOther); Ui::LayerOption::KeepOther);
}, },
st::manageGroupButton, st::manageGroupButton,