mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 23:53:58 +02:00
Add search to the Downloads section.
This commit is contained in:
parent
5be72e8ce2
commit
95f5f28906
9 changed files with 148 additions and 16 deletions
|
@ -127,7 +127,7 @@ object_ptr<Media::ListWidget> InnerWidget::setupList() {
|
|||
result->lifetime());
|
||||
_selectedLists.fire(result->selectedListValue());
|
||||
_listTops.fire(result->topValue());
|
||||
_controller->mediaSourceQueryValue(
|
||||
_controller->searchQueryValue(
|
||||
) | rpl::start_with_next([this](const QString &query) {
|
||||
_empty->setSearchQuery(query);
|
||||
}, result->lifetime());
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "info/media/info_media_widget.h"
|
||||
#include "info/media/info_media_list_section.h"
|
||||
#include "info/info_controller.h"
|
||||
#include "ui/text/format_song_document_name.h"
|
||||
#include "data/data_download_manager.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_media_types.h"
|
||||
|
@ -70,7 +71,11 @@ bool Provider::isPossiblyMyItem(not_null<const HistoryItem*> item) {
|
|||
}
|
||||
|
||||
std::optional<int> Provider::fullCount() {
|
||||
return _fullCount;
|
||||
return _queryWords.empty()
|
||||
? _fullCount
|
||||
: (_foundCount || _fullCount.has_value())
|
||||
? _foundCount
|
||||
: std::optional<int>();
|
||||
}
|
||||
|
||||
void Provider::restart() {
|
||||
|
@ -84,6 +89,27 @@ void Provider::checkPreload(
|
|||
bool preloadBottom) {
|
||||
}
|
||||
|
||||
void Provider::setSearchQuery(QString query) {
|
||||
if (_query == query) {
|
||||
return;
|
||||
}
|
||||
_query = query;
|
||||
auto words = TextUtilities::PrepareSearchWords(_query);
|
||||
if (!_started || _queryWords == words) {
|
||||
return;
|
||||
}
|
||||
_queryWords = std::move(words);
|
||||
if (searchMode()) {
|
||||
_foundCount = 0;
|
||||
for (auto &element : _elements) {
|
||||
if ((element.found = computeIsFound(element))) {
|
||||
++_foundCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
_refreshed.fire({});
|
||||
}
|
||||
|
||||
void Provider::refreshViewer() {
|
||||
if (_started) {
|
||||
return;
|
||||
|
@ -99,7 +125,7 @@ void Provider::refreshViewer() {
|
|||
const auto item = id->object.item;
|
||||
if (!copy.remove(item) && !_downloaded.contains(item)) {
|
||||
_downloading.emplace(item);
|
||||
_elements.push_back({
|
||||
addElementNow({
|
||||
.item = item,
|
||||
.started = id->started,
|
||||
.path = id->path,
|
||||
|
@ -180,21 +206,37 @@ void Provider::performAdd() {
|
|||
for (auto &element : base::take(_addPostponed)) {
|
||||
_downloaded.emplace(element.item);
|
||||
if (!_downloading.remove(element.item)) {
|
||||
_elements.push_back(std::move(element));
|
||||
addElementNow(std::move(element));
|
||||
}
|
||||
}
|
||||
refreshPostponed(true);
|
||||
}
|
||||
|
||||
void Provider::addElementNow(Element &&element) {
|
||||
_elements.push_back(std::move(element));
|
||||
auto &added = _elements.back();
|
||||
fillSearchIndex(added);
|
||||
added.found = searchMode() && computeIsFound(added);
|
||||
if (added.found) {
|
||||
++_foundCount;
|
||||
}
|
||||
}
|
||||
|
||||
void Provider::remove(not_null<const HistoryItem*> item) {
|
||||
_addPostponed.erase(
|
||||
ranges::remove(_addPostponed, item, &Element::item),
|
||||
end(_addPostponed));
|
||||
_downloading.remove(item);
|
||||
_downloaded.remove(item);
|
||||
_elements.erase(
|
||||
ranges::remove(_elements, item, &Element::item),
|
||||
end(_elements));
|
||||
const auto proj = [&](const Element &element) {
|
||||
if (element.item != item) {
|
||||
return false;
|
||||
} else if (element.found && searchMode()) {
|
||||
--_foundCount;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
_elements.erase(ranges::remove_if(_elements, proj), end(_elements));
|
||||
if (const auto i = _layouts.find(item); i != end(_layouts)) {
|
||||
_layoutRemoved.fire(i->second.item.get());
|
||||
_layouts.erase(i);
|
||||
|
@ -252,10 +294,14 @@ rpl::producer<> Provider::refreshed() {
|
|||
|
||||
std::vector<ListSection> Provider::fillSections(
|
||||
not_null<Overview::Layout::Delegate*> delegate) {
|
||||
markLayoutsStale();
|
||||
const auto search = searchMode();
|
||||
|
||||
if (!search) {
|
||||
markLayoutsStale();
|
||||
}
|
||||
const auto guard = gsl::finally([&] { clearStaleLayouts(); });
|
||||
|
||||
if (_elements.empty()) {
|
||||
if (_elements.empty() || (search && !_foundCount)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -264,7 +310,9 @@ std::vector<ListSection> Provider::fillSections(
|
|||
ListSection(Type::File, sectionDelegate()));
|
||||
auto §ion = result.back();
|
||||
for (const auto &element : ranges::views::reverse(_elements)) {
|
||||
if (auto layout = getLayout(element, delegate)) {
|
||||
if (search && !element.found) {
|
||||
continue;
|
||||
} else if (auto layout = getLayout(element, delegate)) {
|
||||
section.addItem(layout);
|
||||
}
|
||||
}
|
||||
|
@ -316,6 +364,47 @@ bool Provider::isAfter(
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Provider::searchMode() const {
|
||||
return !_queryWords.empty();
|
||||
}
|
||||
|
||||
void Provider::fillSearchIndex(Element &element) {
|
||||
auto strings = QStringList(QFileInfo(element.path).fileName());
|
||||
if (const auto media = element.item->media()) {
|
||||
if (const auto document = media->document()) {
|
||||
strings.append(document->filename());
|
||||
strings.append(Ui::Text::FormatDownloadsName(document).text);
|
||||
}
|
||||
}
|
||||
element.words = TextUtilities::PrepareSearchWords(strings.join(' '));
|
||||
element.letters.clear();
|
||||
for (const auto &word : element.words) {
|
||||
element.letters.emplace(word.front());
|
||||
}
|
||||
}
|
||||
|
||||
bool Provider::computeIsFound(const Element &element) const {
|
||||
Expects(!_queryWords.empty());
|
||||
|
||||
const auto has = [&](const QString &queryWord) {
|
||||
if (!element.letters.contains(queryWord.front())) {
|
||||
return false;
|
||||
}
|
||||
for (const auto &word : element.words) {
|
||||
if (word.startsWith(queryWord)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (const auto &queryWord : _queryWords) {
|
||||
if (!has(queryWord)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Provider::itemRemoved(not_null<const HistoryItem*> item) {
|
||||
remove(item);
|
||||
}
|
||||
|
@ -393,9 +482,13 @@ void Provider::applyDragSelection(
|
|||
selected.clear();
|
||||
return;
|
||||
}
|
||||
const auto search = !_queryWords.isEmpty();
|
||||
auto chosen = base::flat_set<not_null<const HistoryItem*>>();
|
||||
chosen.reserve(till - from);
|
||||
for (auto i = from; i != till; ++i) {
|
||||
if (search && !i->found) {
|
||||
continue;
|
||||
}
|
||||
const auto item = i->item;
|
||||
chosen.emplace(item);
|
||||
ChangeItemSelection(
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
void refreshViewer() override;
|
||||
rpl::producer<> refreshed() override;
|
||||
|
||||
void setSearchQuery(QString query);
|
||||
|
||||
std::vector<Media::ListSection> fillSections(
|
||||
not_null<Overview::Layout::Delegate*> delegate) override;
|
||||
rpl::producer<not_null<Media::BaseLayout*>> layoutRemoved() override;
|
||||
|
@ -86,6 +88,10 @@ private:
|
|||
not_null<HistoryItem*> item;
|
||||
int64 started = 0; // unixtime * 1000
|
||||
QString path;
|
||||
|
||||
QStringList words;
|
||||
base::flat_set<QChar> letters;
|
||||
bool found = false;
|
||||
};
|
||||
|
||||
bool sectionHasFloatingHeader() override;
|
||||
|
@ -94,6 +100,10 @@ private:
|
|||
not_null<const Media::BaseLayout*> item,
|
||||
not_null<const Media::BaseLayout*> previous) override;
|
||||
|
||||
[[nodiscard]] bool searchMode() const;
|
||||
void fillSearchIndex(Element &element);
|
||||
[[nodiscard]] bool computeIsFound(const Element &element) const;
|
||||
|
||||
void itemRemoved(not_null<const HistoryItem*> item);
|
||||
void markLayoutsStale();
|
||||
void clearStaleLayouts();
|
||||
|
@ -102,6 +112,7 @@ private:
|
|||
void addPostponed(not_null<const Data::DownloadedId*> entry);
|
||||
void performRefresh();
|
||||
void performAdd();
|
||||
void addElementNow(Element &&element);
|
||||
void remove(not_null<const HistoryItem*> item);
|
||||
void trackItemSession(not_null<const HistoryItem*> item);
|
||||
|
||||
|
@ -127,6 +138,10 @@ private:
|
|||
rpl::event_stream<not_null<Media::BaseLayout*>> _layoutRemoved;
|
||||
rpl::event_stream<> _refreshed;
|
||||
|
||||
QString _query;
|
||||
QStringList _queryWords;
|
||||
int _foundCount = 0;
|
||||
|
||||
base::flat_map<not_null<Main::Session*>, rpl::lifetime> _trackedSessions;
|
||||
bool _postponedRefreshSort = false;
|
||||
bool _postponedRefresh = false;
|
||||
|
|
|
@ -108,6 +108,10 @@ rpl::producer<QString> AbstractController::mediaSourceQueryValue() const {
|
|||
return rpl::single(QString());
|
||||
}
|
||||
|
||||
rpl::producer<QString> AbstractController::searchQueryValue() const {
|
||||
return rpl::single(QString());
|
||||
}
|
||||
|
||||
AbstractController::AbstractController(
|
||||
not_null<Window::SessionController*> parent)
|
||||
: SessionNavigation(&parent->session())
|
||||
|
@ -221,8 +225,8 @@ void Controller::updateSearchControllers(
|
|||
: Section::MediaType::kCount;
|
||||
const auto hasMediaSearch = isMedia
|
||||
&& SharedMediaAllowSearch(mediaType);
|
||||
const auto hasCommonGroupsSearch
|
||||
= (type == Type::CommonGroups);
|
||||
const auto hasCommonGroupsSearch = (type == Type::CommonGroups);
|
||||
const auto hasDownloadsSearch = (type == Type::Downloads);
|
||||
const auto hasMembersSearch = (type == Type::Members)
|
||||
|| (type == Type::Profile);
|
||||
const auto searchQuery = memento->searchFieldQuery();
|
||||
|
@ -236,7 +240,10 @@ void Controller::updateSearchControllers(
|
|||
} else {
|
||||
_searchController = nullptr;
|
||||
}
|
||||
if (hasMediaSearch || hasCommonGroupsSearch || hasMembersSearch) {
|
||||
if (hasMediaSearch
|
||||
|| hasCommonGroupsSearch
|
||||
|| hasDownloadsSearch
|
||||
|| hasMembersSearch) {
|
||||
_searchFieldController
|
||||
= std::make_unique<Ui::SearchFieldController>(
|
||||
searchQuery);
|
||||
|
@ -300,9 +307,11 @@ rpl::producer<bool> Controller::searchEnabledByContent() const {
|
|||
}
|
||||
|
||||
rpl::producer<QString> Controller::mediaSourceQueryValue() const {
|
||||
return _searchController
|
||||
? _searchController->currentQueryValue()
|
||||
: rpl::single(QString()); // #TODO downloads search
|
||||
return _searchController->currentQueryValue();
|
||||
}
|
||||
|
||||
rpl::producer<QString> Controller::searchQueryValue() const {
|
||||
return searchFieldController()->queryValue();
|
||||
}
|
||||
|
||||
rpl::producer<SparseIdsMergedSlice> Controller::mediaSource(
|
||||
|
|
|
@ -141,6 +141,7 @@ public:
|
|||
int limitBefore,
|
||||
int limitAfter) const;
|
||||
virtual rpl::producer<QString> mediaSourceQueryValue() const;
|
||||
virtual rpl::producer<QString> searchQueryValue() const;
|
||||
|
||||
void showSection(
|
||||
std::shared_ptr<Window::SectionMemento> memento,
|
||||
|
@ -198,6 +199,7 @@ public:
|
|||
int limitBefore,
|
||||
int limitAfter) const override;
|
||||
rpl::producer<QString> mediaSourceQueryValue() const override;
|
||||
rpl::producer<QString> searchQueryValue() const override;
|
||||
bool takeSearchStartsFocused() {
|
||||
return base::take(_searchStartsFocused);
|
||||
}
|
||||
|
|
|
@ -158,6 +158,8 @@ public:
|
|||
not_null<const HistoryItem*> item,
|
||||
not_null<DocumentData*> document) = 0;
|
||||
|
||||
virtual void setSearchQuery(QString query) = 0;
|
||||
|
||||
[[nodiscard]] virtual int64 scrollTopStatePosition(
|
||||
not_null<HistoryItem*> item) = 0;
|
||||
[[nodiscard]] virtual HistoryItem *scrollTopStateItem(
|
||||
|
|
|
@ -162,6 +162,11 @@ void ListWidget::start() {
|
|||
|
||||
if (_controller->isDownloads()) {
|
||||
_provider->refreshViewer();
|
||||
|
||||
_controller->searchQueryValue(
|
||||
) | rpl::start_with_next([this](QString &&query) {
|
||||
_provider->setSearchQuery(std::move(query));
|
||||
}, lifetime());
|
||||
} else {
|
||||
trackSession(&session());
|
||||
|
||||
|
|
|
@ -341,6 +341,10 @@ bool Provider::isAfter(
|
|||
return (GetUniversalId(a) < GetUniversalId(b));
|
||||
}
|
||||
|
||||
void Provider::setSearchQuery(QString query) {
|
||||
Unexpected("Media::Provider::setSearchQuery.");
|
||||
}
|
||||
|
||||
SparseIdsMergedSlice::Key Provider::sliceKey(
|
||||
UniversalMsgId universalId) const {
|
||||
using Key = SparseIdsMergedSlice::Key;
|
||||
|
|
|
@ -46,6 +46,8 @@ public:
|
|||
not_null<const HistoryItem*> a,
|
||||
not_null<const HistoryItem*> b) override;
|
||||
|
||||
void setSearchQuery(QString query) override;
|
||||
|
||||
ListItemSelectionData computeSelectionData(
|
||||
not_null<const HistoryItem*> item,
|
||||
TextSelection selection) override;
|
||||
|
|
Loading…
Add table
Reference in a new issue