mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Show full requests list in a box.
This commit is contained in:
parent
b4895ef730
commit
7f428f2eeb
6 changed files with 471 additions and 15 deletions
|
@ -174,12 +174,14 @@ PRIVATE
|
|||
boxes/peers/edit_peer_invite_link.h
|
||||
boxes/peers/edit_peer_invite_links.cpp
|
||||
boxes/peers/edit_peer_invite_links.h
|
||||
boxes/peers/edit_peer_type_box.cpp
|
||||
boxes/peers/edit_peer_type_box.h
|
||||
boxes/peers/edit_peer_history_visibility_box.cpp
|
||||
boxes/peers/edit_peer_history_visibility_box.h
|
||||
boxes/peers/edit_peer_permissions_box.cpp
|
||||
boxes/peers/edit_peer_permissions_box.h
|
||||
boxes/peers/edit_peer_requests_box.cpp
|
||||
boxes/peers/edit_peer_requests_box.h
|
||||
boxes/peers/edit_peer_type_box.cpp
|
||||
boxes/peers/edit_peer_type_box.h
|
||||
boxes/about_box.cpp
|
||||
boxes/about_box.h
|
||||
boxes/about_sponsored_box.cpp
|
||||
|
|
|
@ -270,6 +270,7 @@ bool PeerListController::hasComplexSearch() const {
|
|||
|
||||
void PeerListController::search(const QString &query) {
|
||||
Expects(hasComplexSearch());
|
||||
|
||||
_searchController->searchQuery(query);
|
||||
}
|
||||
|
||||
|
|
|
@ -925,9 +925,8 @@ void ParticipantsBoxController::Start(
|
|||
});
|
||||
}
|
||||
};
|
||||
Ui::show(
|
||||
Box<PeerListBox>(std::move(controller), initBox),
|
||||
Ui::LayerOption::KeepOther);
|
||||
navigation->parentController()->show(
|
||||
Box<PeerListBox>(std::move(controller), initBox));
|
||||
}
|
||||
|
||||
void ParticipantsBoxController::addNewItem() {
|
||||
|
|
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peers/edit_peer_permissions_box.h"
|
||||
#include "boxes/peers/edit_peer_invite_links.h"
|
||||
#include "boxes/peers/edit_linked_chat_box.h"
|
||||
#include "boxes/peers/edit_peer_requests_box.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "ui/boxes/single_choice_box.h"
|
||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||
|
@ -1107,22 +1108,23 @@ void Controller::fillPendingRequestsButton() {
|
|||
_controls.buttonsLayout,
|
||||
object_ptr<Ui::VerticalLayout>(
|
||||
_controls.buttonsLayout)));
|
||||
const auto showPendingRequestsBox = [=] {
|
||||
auto controller = std::make_unique<RequestsBoxController>(
|
||||
_navigation,
|
||||
_peer->migrateToOrMe());
|
||||
const auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
|
||||
};
|
||||
_navigation->parentController()->show(
|
||||
Box<PeerListBox>(std::move(controller), initBox));
|
||||
};
|
||||
AddButtonWithCount(
|
||||
wrap->entity(),
|
||||
(_isGroup
|
||||
? tr::lng_manage_peer_requests()
|
||||
: tr::lng_manage_peer_requests_channel()),
|
||||
rpl::duplicate(pendingRequestsCount) | ToPositiveNumberString(),
|
||||
[=] {
|
||||
_navigation->parentController()->show(
|
||||
Box( // #TODO requests
|
||||
ManageInviteLinksBox,
|
||||
_peer,
|
||||
_peer->session().user(),
|
||||
0,
|
||||
0),
|
||||
Ui::LayerOption::KeepOther);
|
||||
},
|
||||
showPendingRequestsBox,
|
||||
st::infoIconRequests);
|
||||
std::move(
|
||||
pendingRequestsCount
|
||||
|
|
344
Telegram/SourceFiles/boxes/peers/edit_peer_requests_box.cpp
Normal file
344
Telegram/SourceFiles/boxes/peers/edit_peer_requests_box.cpp
Normal file
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/peers/edit_peer_requests_box.h"
|
||||
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/peers/edit_participants_box.h" // SubscribeToMigration
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kFirstPageCount = 16;
|
||||
constexpr auto kPerPage = 200;
|
||||
constexpr auto kServerSearchDelay = crl::time(1000);
|
||||
|
||||
class Row final : public PeerListRow {
|
||||
public:
|
||||
Row(not_null<UserData*> user, TimeId date);
|
||||
|
||||
//QSize actionSize() const override;
|
||||
//void paintAction(
|
||||
// Painter &p,
|
||||
// int x,
|
||||
// int y,
|
||||
// int outerWidth,
|
||||
// bool selected,
|
||||
// bool actionSelected) override;
|
||||
|
||||
//not_null<UserData*> user() const;
|
||||
|
||||
private:
|
||||
TimeId _date = 0;
|
||||
|
||||
};
|
||||
|
||||
Row::Row(not_null<UserData*> user, TimeId date)
|
||||
: PeerListRow(user)
|
||||
, _date(date) {
|
||||
setCustomStatus(QString::number(_date));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RequestsBoxController::RequestsBoxController(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer)
|
||||
: PeerListController(CreateSearchController(peer))
|
||||
, _navigation(navigation)
|
||||
, _peer(peer)
|
||||
, _api(&_peer->session().mtp()) {
|
||||
subscribeToMigration();
|
||||
}
|
||||
|
||||
Main::Session &RequestsBoxController::session() const {
|
||||
return _peer->session();
|
||||
}
|
||||
|
||||
auto RequestsBoxController::CreateSearchController(not_null<PeerData*> peer)
|
||||
-> std::unique_ptr<PeerListSearchController> {
|
||||
return std::make_unique<RequestsBoxSearchController>(peer);
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListRow> RequestsBoxController::createSearchRow(
|
||||
not_null<PeerData*> peer) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
return createRow(user);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RequestsBoxController::prepare() {
|
||||
delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled);
|
||||
delegate()->peerListSetTitle(_peer->isBroadcast()
|
||||
? tr::lng_manage_peer_requests_channel()
|
||||
: tr::lng_manage_peer_requests());
|
||||
setDescriptionText(tr::lng_contacts_loading(tr::now));
|
||||
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
|
||||
loadMoreRows();
|
||||
}
|
||||
|
||||
void RequestsBoxController::loadMoreRows() {
|
||||
if (searchController() && searchController()->loadMoreRows()) {
|
||||
return;
|
||||
} else if (_loadRequestId || _allLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First query is small and fast, next loads a lot of rows.
|
||||
const auto limit = _offsetDate ? kPerPage : kFirstPageCount;
|
||||
using Flag = MTPmessages_GetChatInviteImporters::Flag;
|
||||
_loadRequestId = _api.request(MTPmessages_GetChatInviteImporters(
|
||||
MTP_flags(Flag::f_requested),
|
||||
_peer->input,
|
||||
MTPstring(), // link
|
||||
MTPstring(), // q
|
||||
MTP_int(_offsetDate),
|
||||
_offsetUser ? _offsetUser->inputUser : MTP_inputUserEmpty(),
|
||||
MTP_int(limit)
|
||||
)).done([=](const MTPmessages_ChatInviteImporters &result) {
|
||||
const auto firstLoad = !_offsetDate;
|
||||
_loadRequestId = 0;
|
||||
|
||||
result.match([&](const MTPDmessages_chatInviteImporters &data) {
|
||||
const auto count = data.vcount().v;
|
||||
const auto &importers = data.vimporters().v;
|
||||
auto &owner = _peer->owner();
|
||||
for (const auto &importer : importers) {
|
||||
importer.match([&](const MTPDchatInviteImporter &data) {
|
||||
_offsetDate = data.vdate().v;
|
||||
_offsetUser = owner.user(data.vuser_id());
|
||||
appendRow(_offsetUser, _offsetDate);
|
||||
});
|
||||
}
|
||||
// To be sure - wait for a whole empty result list.
|
||||
_allLoaded = importers.isEmpty();
|
||||
});
|
||||
|
||||
if (_allLoaded
|
||||
|| (firstLoad && delegate()->peerListFullRowsCount() > 0)) {
|
||||
refreshDescription();
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_loadRequestId = 0;
|
||||
_allLoaded = true;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void RequestsBoxController::refreshDescription() {
|
||||
setDescriptionText((delegate()->peerListFullRowsCount() > 0)
|
||||
? QString()
|
||||
: _peer->isBroadcast()
|
||||
? tr::lng_group_removed_list_about(tr::now)
|
||||
: tr::lng_channel_removed_list_about(tr::now));
|
||||
}
|
||||
|
||||
void RequestsBoxController::rowClicked(not_null<PeerListRow*> row) {
|
||||
_navigation->showPeerInfo(row->peer());
|
||||
}
|
||||
|
||||
void RequestsBoxController::appendRow(
|
||||
not_null<UserData*> user,
|
||||
TimeId date) {
|
||||
if (!delegate()->peerListFindRow(user->id.value)) {
|
||||
if (auto row = createRow(user, date)) {
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
setDescriptionText(QString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListRow> RequestsBoxController::createRow(
|
||||
not_null<UserData*> user,
|
||||
TimeId date) {
|
||||
if (!date) {
|
||||
const auto search = static_cast<RequestsBoxSearchController*>(
|
||||
searchController());
|
||||
date = search->dateForUser(user);
|
||||
}
|
||||
return std::make_unique<Row>(user, date);
|
||||
}
|
||||
|
||||
void RequestsBoxController::subscribeToMigration() {
|
||||
const auto chat = _peer->asChat();
|
||||
if (!chat) {
|
||||
return;
|
||||
}
|
||||
SubscribeToMigration(
|
||||
chat,
|
||||
lifetime(),
|
||||
[=](not_null<ChannelData*> channel) { migrate(chat, channel); });
|
||||
}
|
||||
|
||||
void RequestsBoxController::migrate(
|
||||
not_null<ChatData*> chat,
|
||||
not_null<ChannelData*> channel) {
|
||||
_peer = channel;
|
||||
}
|
||||
|
||||
RequestsBoxSearchController::RequestsBoxSearchController(
|
||||
not_null<PeerData*> peer)
|
||||
: _peer(peer)
|
||||
, _api(&_peer->session().mtp()) {
|
||||
_timer.setCallback([=] { searchOnServer(); });
|
||||
}
|
||||
|
||||
void RequestsBoxSearchController::searchQuery(const QString &query) {
|
||||
if (_query != query) {
|
||||
_query = query;
|
||||
_offsetDate = 0;
|
||||
_offsetUser = nullptr;
|
||||
_requestId = 0;
|
||||
_allLoaded = false;
|
||||
if (!_query.isEmpty() && !searchInCache()) {
|
||||
_timer.callOnce(kServerSearchDelay);
|
||||
} else {
|
||||
_timer.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RequestsBoxSearchController::searchOnServer() {
|
||||
Expects(!_query.isEmpty());
|
||||
|
||||
loadMoreRows();
|
||||
}
|
||||
|
||||
bool RequestsBoxSearchController::isLoading() {
|
||||
return _timer.isActive() || _requestId;
|
||||
}
|
||||
|
||||
void RequestsBoxSearchController::removeFromCache(not_null<UserData*> user) {
|
||||
for (auto &entry : _cache) {
|
||||
auto &items = entry.second.items;
|
||||
const auto j = ranges::remove(items, user, &Item::user);
|
||||
if (j != end(items)) {
|
||||
entry.second.requestedCount -= (end(items) - j);
|
||||
items.erase(j, end(items));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TimeId RequestsBoxSearchController::dateForUser(not_null<UserData*> user) {
|
||||
if (const auto i = _dates.find(user); i != end(_dates)) {
|
||||
return i->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool RequestsBoxSearchController::searchInCache() {
|
||||
const auto i = _cache.find(_query);
|
||||
if (i != _cache.cend()) {
|
||||
_requestId = 0;
|
||||
searchDone(
|
||||
_requestId,
|
||||
i->second.items,
|
||||
i->second.requestedCount);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RequestsBoxSearchController::loadMoreRows() {
|
||||
if (_query.isEmpty()) {
|
||||
return false;
|
||||
} else if (_allLoaded || isLoading()) {
|
||||
return true;
|
||||
}
|
||||
// For search we request a lot of rows from the first query.
|
||||
// (because we've waited for search request by timer already,
|
||||
// so we don't expect it to be fast, but we want to fill cache).
|
||||
const auto limit = kPerPage;
|
||||
using Flag = MTPmessages_GetChatInviteImporters::Flag;
|
||||
_requestId = _api.request(MTPmessages_GetChatInviteImporters(
|
||||
MTP_flags(Flag::f_requested | Flag::f_q),
|
||||
_peer->input,
|
||||
MTPstring(), // link
|
||||
MTP_string(_query),
|
||||
MTP_int(_offsetDate),
|
||||
_offsetUser ? _offsetUser->inputUser : MTP_inputUserEmpty(),
|
||||
MTP_int(limit)
|
||||
)).done([=](
|
||||
const MTPmessages_ChatInviteImporters &result,
|
||||
mtpRequestId requestId) {
|
||||
auto items = std::vector<Item>();
|
||||
result.match([&](const MTPDmessages_chatInviteImporters &data) {
|
||||
const auto count = data.vcount().v;
|
||||
const auto &importers = data.vimporters().v;
|
||||
auto &owner = _peer->owner();
|
||||
items.reserve(importers.size());
|
||||
for (const auto &importer : importers) {
|
||||
importer.match([&](const MTPDchatInviteImporter &data) {
|
||||
items.push_back({
|
||||
owner.user(data.vuser_id()),
|
||||
data.vdate().v,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
searchDone(requestId, items, limit);
|
||||
|
||||
auto it = _queries.find(requestId);
|
||||
if (it != _queries.cend()) {
|
||||
const auto &query = it->second.text;
|
||||
if (it->second.offsetDate == 0) {
|
||||
auto &entry = _cache[query];
|
||||
entry.items = std::move(items);
|
||||
entry.requestedCount = limit;
|
||||
}
|
||||
_queries.erase(it);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
|
||||
if (_requestId == requestId) {
|
||||
_requestId = 0;
|
||||
_allLoaded = true;
|
||||
delegate()->peerListSearchRefreshRows();
|
||||
}
|
||||
}).send();
|
||||
|
||||
auto entry = Query();
|
||||
entry.text = _query;
|
||||
entry.offsetDate = _offsetDate;
|
||||
_queries.emplace(_requestId, entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RequestsBoxSearchController::searchDone(
|
||||
mtpRequestId requestId,
|
||||
const std::vector<Item> &items,
|
||||
int requestedCount) {
|
||||
if (_requestId != requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
_requestId = 0;
|
||||
if (!_offsetDate) {
|
||||
_dates.clear();
|
||||
}
|
||||
for (const auto &[user, date] : items) {
|
||||
_offsetDate = date;
|
||||
_offsetUser = user;
|
||||
_dates.emplace(user, date);
|
||||
delegate()->peerListSearchAddRow(user);
|
||||
}
|
||||
if (items.size() < requestedCount) {
|
||||
// We want cache to have full information about a query with
|
||||
// small results count (that we don't need the second request).
|
||||
// So we don't wait for empty list unlike the non-search case.
|
||||
_allLoaded = true;
|
||||
}
|
||||
delegate()->peerListSearchRefreshRows();
|
||||
}
|
108
Telegram/SourceFiles/boxes/peers/edit_peer_requests_box.h
Normal file
108
Telegram/SourceFiles/boxes/peers/edit_peer_requests_box.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "boxes/peer_list_box.h"
|
||||
|
||||
namespace Window {
|
||||
class SessionNavigation;
|
||||
} // namespace Window
|
||||
|
||||
class RequestsBoxController final : public PeerListController {
|
||||
public:
|
||||
RequestsBoxController(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
Main::Session &session() const override;
|
||||
void prepare() override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
void loadMoreRows() override;
|
||||
|
||||
std::unique_ptr<PeerListRow> createSearchRow(
|
||||
not_null<PeerData*> peer) override;
|
||||
|
||||
bool searchInLocal() override {
|
||||
AssertIsDebug();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::unique_ptr<PeerListSearchController> CreateSearchController(
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<PeerListRow> createRow(
|
||||
not_null<UserData*> user,
|
||||
TimeId date = 0);
|
||||
|
||||
void appendRow(not_null<UserData*> user, TimeId date);
|
||||
void refreshDescription();
|
||||
void processRequest(not_null<UserData*> user, bool approved);
|
||||
|
||||
void subscribeToMigration();
|
||||
void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel);
|
||||
|
||||
const not_null<Window::SessionNavigation*> _navigation;
|
||||
not_null<PeerData*> _peer;
|
||||
MTP::Sender _api;
|
||||
|
||||
TimeId _offsetDate = 0;
|
||||
UserData *_offsetUser = nullptr;
|
||||
mtpRequestId _loadRequestId = 0;
|
||||
bool _allLoaded = false;
|
||||
|
||||
};
|
||||
|
||||
// Members, banned and restricted users server side search.
|
||||
class RequestsBoxSearchController final : public PeerListSearchController {
|
||||
public:
|
||||
RequestsBoxSearchController(not_null<PeerData*> peer);
|
||||
|
||||
void searchQuery(const QString &query) override;
|
||||
bool isLoading() override;
|
||||
bool loadMoreRows() override;
|
||||
|
||||
void removeFromCache(not_null<UserData*> user);
|
||||
[[nodiscard]] TimeId dateForUser(not_null<UserData*> user);
|
||||
|
||||
private:
|
||||
struct Item {
|
||||
not_null<UserData*> user;
|
||||
TimeId date = 0;
|
||||
};
|
||||
struct CacheEntry {
|
||||
std::vector<Item> items;
|
||||
int requestedCount = 0;
|
||||
};
|
||||
struct Query {
|
||||
QString text;
|
||||
TimeId offsetDate = 0;
|
||||
UserData *offsetUser = nullptr;
|
||||
};
|
||||
|
||||
void searchOnServer();
|
||||
bool searchInCache();
|
||||
void searchDone(
|
||||
mtpRequestId requestId,
|
||||
const std::vector<Item> &items,
|
||||
int requestedCount);
|
||||
|
||||
not_null<PeerData*> _peer;
|
||||
MTP::Sender _api;
|
||||
|
||||
base::Timer _timer;
|
||||
QString _query;
|
||||
mtpRequestId _requestId = 0;
|
||||
TimeId _offsetDate = 0;
|
||||
UserData *_offsetUser = nullptr;
|
||||
bool _allLoaded = false;
|
||||
base::flat_map<QString, CacheEntry> _cache;
|
||||
base::flat_map<mtpRequestId, Query> _queries;
|
||||
base::flat_map<not_null<UserData*>, TimeId> _dates;
|
||||
|
||||
};
|
Loading…
Add table
Reference in a new issue