mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 15:17:07 +02:00
Allow deleting revoked invite links.
This commit is contained in:
parent
144bad6c74
commit
819cd4a099
5 changed files with 281 additions and 33 deletions
Telegram
Resources/langs
SourceFiles
|
@ -1192,6 +1192,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_group_invite_context_revoke" = "Revoke";
|
||||
"lng_group_invite_context_delete" = "Delete";
|
||||
"lng_group_invite_context_delete_all" = "Delete all";
|
||||
"lng_group_invite_delete_sure" = "Are you sure you want to delete that revoked link?";
|
||||
"lng_group_invite_delete_all_sure" = "Are you sure you want to delete all revoked links? This action cannot be undone.";
|
||||
"lng_group_invite_revoked_title" = "Revoked links";
|
||||
"lng_group_invite_revoke_about" = "Are you sure you want to revoke that invite link?";
|
||||
"lng_group_invite_link_expired" = "Expired";
|
||||
|
|
|
@ -122,25 +122,34 @@ auto InviteLinks::prepend(
|
|||
}
|
||||
auto &links = i->second;
|
||||
const auto permanent = lookupPermanent(links);
|
||||
if (link.permanent) {
|
||||
auto update = Update{ .peer = peer };
|
||||
if (permanent) {
|
||||
update.was = permanent->link;
|
||||
permanent->revoked = true;
|
||||
}
|
||||
editPermanentLink(peer, link.link);
|
||||
if (permanent) {
|
||||
update.now = *permanent;
|
||||
_updates.fire(std::move(update));
|
||||
const auto hadPermanent = (permanent != nullptr);
|
||||
auto updateOldPermanent = Update{ .peer = peer };
|
||||
if (link.permanent && hadPermanent) {
|
||||
updateOldPermanent.was = permanent->link;
|
||||
updateOldPermanent.now = *permanent;
|
||||
updateOldPermanent.now->revoked = true;
|
||||
links.links.erase(begin(links.links));
|
||||
if (links.count > 0) {
|
||||
--links.count;
|
||||
}
|
||||
}
|
||||
// Must not dereference 'permanent' pointer after that.
|
||||
|
||||
++links.count;
|
||||
if (permanent && !link.permanent) {
|
||||
if (hadPermanent && !link.permanent) {
|
||||
links.links.insert(begin(links.links) + 1, link);
|
||||
} else {
|
||||
links.links.insert(begin(links.links), link);
|
||||
}
|
||||
|
||||
if (link.permanent) {
|
||||
editPermanentLink(peer, link.link);
|
||||
}
|
||||
notify(peer);
|
||||
|
||||
if (updateOldPermanent.now) {
|
||||
_updates.fire(std::move(updateOldPermanent));
|
||||
}
|
||||
_updates.fire(Update{ .peer = peer, .now = link });
|
||||
return link;
|
||||
}
|
||||
|
@ -162,7 +171,10 @@ void InviteLinks::performEdit(
|
|||
TimeId expireDate,
|
||||
int usageLimit) {
|
||||
const auto key = LinkKey{ peer, link };
|
||||
if (const auto i = _editCallbacks.find(key); i != end(_editCallbacks)) {
|
||||
if (_deleteCallbacks.contains(key)) {
|
||||
return;
|
||||
} else if (const auto i = _editCallbacks.find(key)
|
||||
; i != end(_editCallbacks)) {
|
||||
if (done) {
|
||||
i->second.push_back(std::move(done));
|
||||
}
|
||||
|
@ -184,7 +196,7 @@ void InviteLinks::performEdit(
|
|||
}
|
||||
|
||||
using Flag = MTPmessages_EditExportedChatInvite::Flag;
|
||||
const auto requestId = _api->request(MTPmessages_EditExportedChatInvite(
|
||||
_api->request(MTPmessages_EditExportedChatInvite(
|
||||
MTP_flags((revoke ? Flag::f_revoked : Flag(0))
|
||||
| ((!revoke && expireDate) ? Flag::f_expire_date : Flag(0))
|
||||
| ((!revoke && usageLimit) ? Flag::f_usage_limit : Flag(0))),
|
||||
|
@ -205,8 +217,14 @@ void InviteLinks::performEdit(
|
|||
key.link,
|
||||
&Link::link);
|
||||
if (j != end(i->second.links)) {
|
||||
*j = link;
|
||||
notify(peer);
|
||||
if (link.revoked && !j->revoked) {
|
||||
i->second.links.erase(j);
|
||||
if (i->second.count > 0) {
|
||||
--i->second.count;
|
||||
}
|
||||
} else {
|
||||
*j = link;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &callback : *callbacks) {
|
||||
|
@ -215,7 +233,7 @@ void InviteLinks::performEdit(
|
|||
_updates.fire(Update{
|
||||
.peer = peer,
|
||||
.was = key.link,
|
||||
.now = link
|
||||
.now = link,
|
||||
});
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
|
@ -236,6 +254,72 @@ void InviteLinks::revokePermanent(
|
|||
performCreate(peer, std::move(done), true);
|
||||
}
|
||||
|
||||
void InviteLinks::destroy(
|
||||
not_null<PeerData*> peer,
|
||||
const QString &link,
|
||||
Fn<void()> done) {
|
||||
const auto key = LinkKey{ peer, link };
|
||||
|
||||
if (const auto i = _deleteCallbacks.find(key)
|
||||
; i != end(_deleteCallbacks)) {
|
||||
if (done) {
|
||||
i->second.push_back(std::move(done));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto &callbacks = _deleteCallbacks[key];
|
||||
if (done) {
|
||||
callbacks.push_back(std::move(done));
|
||||
}
|
||||
|
||||
_api->request(MTPmessages_DeleteExportedChatInvite(
|
||||
peer->input,
|
||||
MTP_string(link)
|
||||
)).done([=](const MTPBool &result) {
|
||||
const auto callbacks = _deleteCallbacks.take(key);
|
||||
if (callbacks) {
|
||||
for (const auto &callback : *callbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
_updates.fire(Update{
|
||||
.peer = peer,
|
||||
.was = key.link,
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
_deleteCallbacks.erase(key);
|
||||
}).send();
|
||||
}
|
||||
|
||||
void InviteLinks::destroyAllRevoked(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> done) {
|
||||
if (const auto i = _deleteRevokedCallbacks.find(peer)
|
||||
; i != end(_deleteRevokedCallbacks)) {
|
||||
if (done) {
|
||||
i->second.push_back(std::move(done));
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto &callbacks = _deleteRevokedCallbacks[peer];
|
||||
if (done) {
|
||||
callbacks.push_back(std::move(done));
|
||||
}
|
||||
|
||||
_api->request(MTPmessages_DeleteRevokedExportedChatInvites(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
if (const auto callbacks = _deleteRevokedCallbacks.take(peer)) {
|
||||
for (const auto &callback : *callbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
_allRevokedDestroyed.fire_copy(peer);
|
||||
}).fail([=](const RPCError &error) {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void InviteLinks::requestLinks(not_null<PeerData*> peer) {
|
||||
if (_firstSliceRequests.contains(peer)) {
|
||||
return;
|
||||
|
@ -317,6 +401,15 @@ auto InviteLinks::updates(
|
|||
});
|
||||
}
|
||||
|
||||
rpl::producer<> InviteLinks::allRevokedDestroyed(
|
||||
not_null<PeerData*> peer) const {
|
||||
using namespace rpl::mappers;
|
||||
return _allRevokedDestroyed.events(
|
||||
) | rpl::filter(
|
||||
_1 == peer
|
||||
) | rpl::to_empty;
|
||||
}
|
||||
|
||||
void InviteLinks::requestJoinedFirstSlice(LinkKey key) {
|
||||
if (_firstJoinedRequests.contains(key)) {
|
||||
return;
|
||||
|
@ -351,26 +444,63 @@ void InviteLinks::setPermanent(
|
|||
i = _firstSlices.emplace(peer).first;
|
||||
}
|
||||
auto &links = i->second;
|
||||
auto updateOldPermanent = Update{ .peer = peer };
|
||||
if (const auto permanent = lookupPermanent(links)) {
|
||||
if (permanent->link == link.link) {
|
||||
if (permanent->usage != link.usage) {
|
||||
permanent->usage = link.usage;
|
||||
notify(peer);
|
||||
_updates.fire(Update{
|
||||
.peer = peer,
|
||||
.was = link.link,
|
||||
.now = *permanent
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
permanent->revoked = true;
|
||||
updateOldPermanent.was = permanent->link;
|
||||
updateOldPermanent.now = *permanent;
|
||||
updateOldPermanent.now->revoked = true;
|
||||
links.links.erase(begin(links.links));
|
||||
if (links.count > 0) {
|
||||
--links.count;
|
||||
}
|
||||
}
|
||||
links.links.insert(begin(links.links), link);
|
||||
|
||||
editPermanentLink(peer, link.link);
|
||||
notify(peer);
|
||||
|
||||
if (updateOldPermanent.now) {
|
||||
_updates.fire(std::move(updateOldPermanent));
|
||||
}
|
||||
_updates.fire(Update{ .peer = peer, .now = link });
|
||||
}
|
||||
|
||||
void InviteLinks::clearPermanent(not_null<PeerData*> peer) {
|
||||
if (const auto permanent = lookupPermanent(peer)) {
|
||||
permanent->revoked = true;
|
||||
editPermanentLink(peer, QString());
|
||||
notify(peer);
|
||||
auto i = _firstSlices.find(peer);
|
||||
if (i == end(_firstSlices)) {
|
||||
return;
|
||||
}
|
||||
auto &links = i->second;
|
||||
const auto permanent = lookupPermanent(links);
|
||||
if (!permanent) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto updateOldPermanent = Update{ .peer = peer };
|
||||
updateOldPermanent.was = permanent->link;
|
||||
updateOldPermanent.now = *permanent;
|
||||
updateOldPermanent.now->revoked = true;
|
||||
links.links.erase(begin(links.links));
|
||||
if (links.count > 0) {
|
||||
--links.count;
|
||||
}
|
||||
|
||||
editPermanentLink(peer, QString());
|
||||
notify(peer);
|
||||
|
||||
if (updateOldPermanent.now) {
|
||||
_updates.fire(std::move(updateOldPermanent));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,13 @@ public:
|
|||
void revokePermanent(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void(Link)> done = nullptr);
|
||||
void destroy(
|
||||
not_null<PeerData*> peer,
|
||||
const QString &link,
|
||||
Fn<void()> done = nullptr);
|
||||
void destroyAllRevoked(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<void()> done = nullptr);
|
||||
|
||||
void setPermanent(
|
||||
not_null<PeerData*> peer,
|
||||
|
@ -85,6 +92,8 @@ public:
|
|||
int fullCount);
|
||||
[[nodiscard]] rpl::producer<Update> updates(
|
||||
not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] rpl::producer<> allRevokedDestroyed(
|
||||
not_null<PeerData*> peer) const;
|
||||
|
||||
void requestMoreLinks(
|
||||
not_null<PeerData*> peer,
|
||||
|
@ -159,8 +168,13 @@ private:
|
|||
not_null<PeerData*>,
|
||||
std::vector<Fn<void(Link)>>> _createCallbacks;
|
||||
base::flat_map<LinkKey, std::vector<Fn<void(Link)>>> _editCallbacks;
|
||||
base::flat_map<LinkKey, std::vector<Fn<void()>>> _deleteCallbacks;
|
||||
base::flat_map<
|
||||
not_null<PeerData*>,
|
||||
std::vector<Fn<void()>>> _deleteRevokedCallbacks;
|
||||
|
||||
rpl::event_stream<Update> _updates;
|
||||
rpl::event_stream<not_null<PeerData*>> _allRevokedDestroyed;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -311,6 +311,36 @@ void EditLink(not_null<PeerData*> peer, const InviteLinkData &data) {
|
|||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void DeleteLink(not_null<PeerData*> peer, const QString &link) {
|
||||
const auto box = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto sure = [=] {
|
||||
const auto finish = [=] {
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
};
|
||||
peer->session().api().inviteLinks().destroy(peer, link, finish);
|
||||
};
|
||||
*box = Ui::show(
|
||||
Box<ConfirmBox>(tr::lng_group_invite_delete_sure(tr::now), sure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void DeleteAllRevoked(not_null<PeerData*> peer) {
|
||||
const auto box = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto sure = [=] {
|
||||
const auto finish = [=] {
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
};
|
||||
peer->session().api().inviteLinks().destroyAllRevoked(peer, finish);
|
||||
};
|
||||
*box = Ui::show(
|
||||
Box<ConfirmBox>(tr::lng_group_invite_delete_all_sure(tr::now), sure),
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
not_null<Ui::SettingsButton*> AddCreateLinkButton(
|
||||
not_null<Ui::VerticalLayout*> container) {
|
||||
const auto result = container->add(
|
||||
|
@ -445,6 +475,7 @@ public:
|
|||
Controller(not_null<PeerData*> peer, bool revoked);
|
||||
|
||||
void prepare() override;
|
||||
void loadMoreRows() override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
void rowActionClicked(not_null<PeerListRow*> row) override;
|
||||
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
|
||||
|
@ -467,6 +498,7 @@ private:
|
|||
void updateRow(const InviteLinkData &data, TimeId now);
|
||||
bool removeRow(const QString &link);
|
||||
|
||||
void appendSlice(const InviteLinksSlice &slice);
|
||||
void checkExpiringTimer(not_null<Row*> row);
|
||||
void expiringProgressTimer();
|
||||
|
||||
|
@ -474,10 +506,14 @@ private:
|
|||
QWidget *parent,
|
||||
not_null<PeerListRow*> row);
|
||||
|
||||
not_null<PeerData*> _peer;
|
||||
bool _revoked = false;
|
||||
const not_null<PeerData*> _peer;
|
||||
const bool _revoked = false;
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
|
||||
QString _offsetLink;
|
||||
bool _requesting = false;
|
||||
bool _allLoaded = false;
|
||||
|
||||
base::flat_set<not_null<Row*>> _expiringRows;
|
||||
base::Timer _updateExpiringTimer;
|
||||
|
||||
|
@ -501,8 +537,7 @@ Controller::Controller(not_null<PeerData*> peer, bool revoked)
|
|||
peer
|
||||
) | rpl::start_with_next([=](const Api::InviteLinkUpdate &update) {
|
||||
const auto now = base::unixtime::now();
|
||||
if (!update.now
|
||||
|| (!update.was.isEmpty() && update.now->revoked != _revoked)) {
|
||||
if (!update.now || update.now->revoked != _revoked) {
|
||||
if (removeRow(update.was)) {
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
|
@ -513,15 +548,63 @@ Controller::Controller(not_null<PeerData*> peer, bool revoked)
|
|||
updateRow(*update.now, now);
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
if (_revoked) {
|
||||
peer->session().api().inviteLinks().allRevokedDestroyed(
|
||||
peer
|
||||
) | rpl::start_with_next([=] {
|
||||
_requesting = false;
|
||||
_allLoaded = true;
|
||||
while (delegate()->peerListFullRowsCount()) {
|
||||
delegate()->peerListRemoveRow(delegate()->peerListRowAt(0));
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
}, _lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::prepare() {
|
||||
if (!_revoked) {
|
||||
appendSlice(_peer->session().api().inviteLinks().links(_peer));
|
||||
}
|
||||
if (!delegate()->peerListFullRowsCount()) {
|
||||
loadMoreRows();
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::loadMoreRows() {
|
||||
if (_requesting || _allLoaded) {
|
||||
return;
|
||||
}
|
||||
_requesting = true;
|
||||
const auto done = [=](const InviteLinksSlice &slice) {
|
||||
if (!_requesting) {
|
||||
return;
|
||||
}
|
||||
_requesting = false;
|
||||
if (slice.links.empty()) {
|
||||
_allLoaded = true;
|
||||
return;
|
||||
}
|
||||
appendSlice(slice);
|
||||
};
|
||||
_peer->session().api().inviteLinks().requestMoreLinks(
|
||||
_peer,
|
||||
_offsetLink,
|
||||
_revoked,
|
||||
crl::guard(this, done));
|
||||
}
|
||||
|
||||
void Controller::appendSlice(const InviteLinksSlice &slice) {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto &links = _peer->session().api().inviteLinks().links(_peer);
|
||||
for (const auto &link : links.links) {
|
||||
for (const auto &link : slice.links) {
|
||||
if (!link.permanent || link.revoked) {
|
||||
appendRow(link, now);
|
||||
}
|
||||
_offsetLink = link.link;
|
||||
}
|
||||
if (slice.links.size() >= slice.count) {
|
||||
_allLoaded = true;
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
|
@ -559,9 +642,9 @@ base::unique_qptr<Ui::PopupMenu> Controller::createRowContextMenu(
|
|||
const auto link = data.link;
|
||||
auto result = base::make_unique_q<Ui::PopupMenu>(parent);
|
||||
if (data.revoked) {
|
||||
//result->addAction(tr::lng_group_invite_context_delete(tr::now), [=] {
|
||||
// // #TODO links delete
|
||||
//});
|
||||
result->addAction(tr::lng_group_invite_context_delete(tr::now), [=] {
|
||||
DeleteLink(_peer, link);
|
||||
});
|
||||
} else {
|
||||
result->addAction(tr::lng_group_invite_context_copy(tr::now), [=] {
|
||||
CopyLink(link);
|
||||
|
@ -576,7 +659,6 @@ base::unique_qptr<Ui::PopupMenu> Controller::createRowContextMenu(
|
|||
const auto box = std::make_shared<QPointer<ConfirmBox>>();
|
||||
const auto revoke = crl::guard(this, [=] {
|
||||
const auto done = crl::guard(this, [=](InviteLinkData data) {
|
||||
// #TODO links add to revoked, remove from list
|
||||
if (*box) {
|
||||
(*box)->closeBox();
|
||||
}
|
||||
|
@ -946,6 +1028,23 @@ void ManageInviteLinksBox(
|
|||
st::inviteLinkRevokedTitlePadding));
|
||||
const auto revoked = AddLinksList(container, peer, true);
|
||||
|
||||
const auto deleteAll = Ui::CreateChild<Ui::LinkButton>(
|
||||
container.get(),
|
||||
tr::lng_group_invite_context_delete_all(tr::now),
|
||||
st::boxLinkButton);
|
||||
rpl::combine(
|
||||
header->topValue(),
|
||||
container->widthValue()
|
||||
) | rpl::start_with_next([=](int top, int outerWidth) {
|
||||
deleteAll->moveToRight(
|
||||
st::inviteLinkRevokedTitlePadding.left(),
|
||||
top + st::inviteLinkRevokedTitlePadding.top(),
|
||||
outerWidth);
|
||||
}, deleteAll->lifetime());
|
||||
deleteAll->setClickedCallback([=] {
|
||||
DeleteAllRevoked(peer);
|
||||
});
|
||||
|
||||
rpl::combine(
|
||||
list->heightValue(),
|
||||
revoked->heightValue()
|
||||
|
@ -953,5 +1052,8 @@ void ManageInviteLinksBox(
|
|||
dividerAbout->toggle(!list, anim::type::instant);
|
||||
divider->toggle(list > 0 && revoked > 0, anim::type::instant);
|
||||
header->toggle(revoked > 0, anim::type::instant);
|
||||
deleteAll->setVisible(revoked > 0);
|
||||
}, header->lifetime());
|
||||
|
||||
box->addButton(tr::lng_about_done(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
|
|
@ -916,6 +916,6 @@ inviteLinkList: PeerList(defaultPeerList) {
|
|||
inviteLinkIconSkip: 7px;
|
||||
inviteLinkIconStroke: 2px;
|
||||
inviteLinkIcon: icon {{ "info/edit/links_link", mediaviewFileExtFg }};
|
||||
inviteLinkThreeDotsSkip: 8px;
|
||||
inviteLinkThreeDotsSkip: 12px;
|
||||
inviteLinkRevokedTitlePadding: margins(22px, 16px, 10px, 9px);
|
||||
inviteLinkLimitMargin: margins(22px, 8px, 22px, 8px);
|
||||
|
|
Loading…
Add table
Reference in a new issue