mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 13:47:05 +02:00
Add cache for global media search requests.
This commit is contained in:
parent
d59eb8e731
commit
3f0d687656
9 changed files with 119 additions and 110 deletions
|
@ -1427,6 +1427,9 @@ void Widget::updateSuggestions(anim::type animated) {
|
|||
controller(),
|
||||
TopPeersContent(&session()),
|
||||
RecentPeersContent(&session()));
|
||||
_suggestions->clearSearchQueryRequests() | rpl::start_with_next([=] {
|
||||
setSearchQuery(QString());
|
||||
}, _suggestions->lifetime());
|
||||
_searchSuggestionsLocked = false;
|
||||
|
||||
rpl::merge(
|
||||
|
@ -2934,7 +2937,11 @@ void Widget::updateCancelSearch() {
|
|||
|
||||
QString Widget::validateSearchQuery() {
|
||||
const auto query = currentSearchQuery();
|
||||
if (_searchState.tab == ChatSearchTab::PublicPosts) {
|
||||
if (!_subsectionTopBar
|
||||
&& _suggestions
|
||||
&& _suggestions->consumeSearchQuery(query)) {
|
||||
return QString();
|
||||
} else if (_searchState.tab == ChatSearchTab::PublicPosts) {
|
||||
if (_searchHashOrCashtag == HashOrCashtag::None) {
|
||||
_searchHashOrCashtag = HashOrCashtag::Hashtag;
|
||||
}
|
||||
|
@ -3932,9 +3939,18 @@ void Widget::setSearchQuery(const QString &query, int cursorPosition) {
|
|||
}
|
||||
|
||||
bool Widget::cancelSearch(CancelSearchOptions options) {
|
||||
const auto clearingSuggestionsQuery = _suggestions
|
||||
&& _suggestions->consumeSearchQuery(QString());
|
||||
if (clearingSuggestionsQuery) {
|
||||
setSearchQuery(QString());
|
||||
if (!options.forceFullCancel) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cancelSearchRequest();
|
||||
auto updatedState = _searchState;
|
||||
const auto clearingQuery = !updatedState.query.isEmpty();
|
||||
const auto clearingQuery = clearingSuggestionsQuery
|
||||
|| !updatedState.query.isEmpty();
|
||||
const auto forceFullCancel = options.forceFullCancel;
|
||||
auto clearingInChat = (forceFullCancel || !clearingQuery)
|
||||
&& (updatedState.inChat
|
||||
|
|
|
@ -48,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/delayed_activation.h"
|
||||
#include "ui/dynamic_thumbnails.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/search_field_controller.h"
|
||||
#include "ui/unread_badge_paint.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "window/window_separate_id.h"
|
||||
|
@ -66,6 +67,7 @@ constexpr auto kCollapsedChannelsCount = 5;
|
|||
constexpr auto kProbablyMaxChannels = 1000;
|
||||
constexpr auto kCollapsedAppsCount = 5;
|
||||
constexpr auto kProbablyMaxApps = 100;
|
||||
constexpr auto kSearchQueryDelay = crl::time(900);
|
||||
|
||||
class RecentRow final : public PeerListRow {
|
||||
public:
|
||||
|
@ -1335,7 +1337,8 @@ Suggestions::Suggestions(
|
|||
, _appsContent(
|
||||
_appsScroll->setOwnedWidget(object_ptr<Ui::VerticalLayout>(this)))
|
||||
, _recentApps(setupRecentApps())
|
||||
, _popularApps(setupPopularApps()) {
|
||||
, _popularApps(setupPopularApps())
|
||||
, _searchQueryTimer([=] { applySearchQuery(); }) {
|
||||
setupTabs();
|
||||
setupChats();
|
||||
setupChannels();
|
||||
|
@ -1754,6 +1757,43 @@ void Suggestions::chooseRow() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Suggestions::consumeSearchQuery(const QString &query) {
|
||||
using Type = MediaType;
|
||||
const auto key = _key.current();
|
||||
const auto tab = key.tab;
|
||||
const auto type = (key.tab == Tab::Media) ? key.mediaType : Type::kCount;
|
||||
if (tab != Tab::Downloads
|
||||
&& type != Type::File
|
||||
&& type != Type::Link
|
||||
&& type != Type::MusicFile) {
|
||||
return false;
|
||||
} else if (_searchQuery == query) {
|
||||
return false;
|
||||
}
|
||||
_searchQuery = query;
|
||||
_persist = !_searchQuery.isEmpty();
|
||||
if (query.isEmpty() || tab == Tab::Downloads) {
|
||||
_searchQueryTimer.cancel();
|
||||
applySearchQuery();
|
||||
} else {
|
||||
_searchQueryTimer.callOnce(kSearchQueryDelay);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Suggestions::applySearchQuery() {
|
||||
const auto key = _key.current();
|
||||
const auto controller = _mediaLists[key].wrap->controller();
|
||||
const auto search = controller->searchFieldController();
|
||||
if (search->query() != _searchQuery) {
|
||||
search->setQuery(_searchQuery);
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<> Suggestions::clearSearchQueryRequests() const {
|
||||
return _clearSearchQueryRequests.events();
|
||||
}
|
||||
|
||||
Data::Thread *Suggestions::updateFromParentDrag(QPoint globalPosition) {
|
||||
switch (_key.current().tab) {
|
||||
case Tab::Chats: return updateFromChatsDrag(globalPosition);
|
||||
|
@ -1825,8 +1865,10 @@ void Suggestions::switchTab(Key key) {
|
|||
if (was == key) {
|
||||
return;
|
||||
}
|
||||
consumeSearchQuery(QString());
|
||||
_key = key;
|
||||
_persist = false;
|
||||
_clearSearchQueryRequests.fire({});
|
||||
if (_tabs->isHidden()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "base/object_ptr.h"
|
||||
#include "base/timer.h"
|
||||
#include "dialogs/ui/top_peers_strip.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
@ -64,6 +65,9 @@ public:
|
|||
void selectJump(Qt::Key direction, int pageSize = 0);
|
||||
void chooseRow();
|
||||
|
||||
bool consumeSearchQuery(const QString &query);
|
||||
[[nodiscard]] rpl::producer<> clearSearchQueryRequests() const;
|
||||
|
||||
[[nodiscard]] Data::Thread *updateFromParentDrag(QPoint globalPosition);
|
||||
void dragLeft();
|
||||
|
||||
|
@ -193,6 +197,7 @@ private:
|
|||
|
||||
void handlePressForChatPreview(PeerId id, Fn<void(bool)> callback);
|
||||
void updateControlsGeometry();
|
||||
void applySearchQuery();
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
|
||||
|
@ -231,6 +236,9 @@ private:
|
|||
const std::unique_ptr<ObjectList> _popularApps;
|
||||
|
||||
base::flat_map<Key, MediaList> _mediaLists;
|
||||
rpl::event_stream<> _clearSearchQueryRequests;
|
||||
QString _searchQuery;
|
||||
base::Timer _searchQueryTimer;
|
||||
|
||||
Ui::Animations::Simple _shownAnimation;
|
||||
Fn<void()> _showFinished;
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "info/global_media/info_global_media_provider.h"
|
||||
#include "info/global_media/info_global_media_widget.h"
|
||||
#include "info/media/info_media_empty_widget.h"
|
||||
#include "info/media/info_media_list_widget.h"
|
||||
#include "info/info_controller.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
@ -18,75 +19,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Info::GlobalMedia {
|
||||
|
||||
class EmptyWidget : public Ui::RpWidget {
|
||||
public:
|
||||
EmptyWidget(QWidget *parent);
|
||||
|
||||
void setFullHeight(rpl::producer<int> fullHeightValue);
|
||||
void setSearchQuery(const QString &query);
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
object_ptr<Ui::FlatLabel> _text;
|
||||
int _height = 0;
|
||||
|
||||
};
|
||||
|
||||
EmptyWidget::EmptyWidget(QWidget *parent)
|
||||
: RpWidget(parent)
|
||||
, _text(this, st::infoEmptyLabel) {
|
||||
}
|
||||
|
||||
void EmptyWidget::setFullHeight(rpl::producer<int> fullHeightValue) {
|
||||
std::move(
|
||||
fullHeightValue
|
||||
) | rpl::start_with_next([this](int fullHeight) {
|
||||
// Make icon center be on 1/3 height.
|
||||
auto iconCenter = fullHeight / 3;
|
||||
auto iconHeight = st::infoEmptyFile.height();
|
||||
auto iconTop = iconCenter - iconHeight / 2;
|
||||
_height = iconTop + st::infoEmptyIconTop;
|
||||
resizeToWidth(width());
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void EmptyWidget::setSearchQuery(const QString &query) {
|
||||
_text->setText(query.isEmpty()
|
||||
? tr::lng_media_file_empty(tr::now)
|
||||
: tr::lng_media_file_empty_search(tr::now));
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
int EmptyWidget::resizeGetHeight(int newWidth) {
|
||||
auto labelTop = _height - st::infoEmptyLabelTop;
|
||||
auto labelWidth = newWidth - 2 * st::infoEmptyLabelSkip;
|
||||
_text->resizeToNaturalWidth(labelWidth);
|
||||
|
||||
auto labelLeft = (newWidth - _text->width()) / 2;
|
||||
_text->moveToLeft(labelLeft, labelTop, newWidth);
|
||||
|
||||
update();
|
||||
return _height;
|
||||
}
|
||||
|
||||
void EmptyWidget::paintEvent(QPaintEvent *e) {
|
||||
auto p = QPainter(this);
|
||||
|
||||
const auto iconLeft = (width() - st::infoEmptyFile.width()) / 2;
|
||||
const auto iconTop = height() - st::infoEmptyIconTop;
|
||||
st::infoEmptyFile.paint(p, iconLeft, iconTop, width());
|
||||
}
|
||||
|
||||
InnerWidget::InnerWidget(
|
||||
QWidget *parent,
|
||||
not_null<Controller*> controller)
|
||||
: RpWidget(parent)
|
||||
, _controller(controller)
|
||||
, _empty(this) {
|
||||
_empty->setType(type());
|
||||
_empty->heightValue(
|
||||
) | rpl::start_with_next(
|
||||
[this] { refreshHeight(); },
|
||||
|
|
|
@ -21,16 +21,17 @@ enum class SharedMediaType : signed char;
|
|||
} // namespace Storage
|
||||
|
||||
namespace Info {
|
||||
|
||||
class Controller;
|
||||
struct SelectedItems;
|
||||
enum class SelectionAction;
|
||||
} // namespace Info
|
||||
|
||||
namespace Media {
|
||||
namespace Info::Media {
|
||||
class ListWidget;
|
||||
} // namespace Media
|
||||
class EmptyWidget;
|
||||
} // namespace Info::Media
|
||||
|
||||
namespace GlobalMedia {
|
||||
namespace Info::GlobalMedia {
|
||||
|
||||
class Memento;
|
||||
class EmptyWidget;
|
||||
|
@ -71,7 +72,7 @@ private:
|
|||
const not_null<Controller*> _controller;
|
||||
|
||||
object_ptr<Media::ListWidget> _list = { nullptr };
|
||||
object_ptr<EmptyWidget> _empty;
|
||||
object_ptr<Media::EmptyWidget> _empty;
|
||||
|
||||
bool _inResize = false;
|
||||
|
||||
|
@ -81,5 +82,4 @@ private:
|
|||
|
||||
};
|
||||
|
||||
} // namespace GlobalMedia
|
||||
} // namespace Info
|
||||
} // namespace Info::GlobalMedia
|
||||
|
|
|
@ -227,18 +227,6 @@ void Provider::checkPreload(
|
|||
}
|
||||
}
|
||||
|
||||
void Provider::applyListQuery(const QString &query) {
|
||||
if (_totalListQuery == query) {
|
||||
return;
|
||||
}
|
||||
_totalListQuery = query;
|
||||
_totalList.clear();
|
||||
_totalOffsetPosition = Data::MessagePosition();
|
||||
_totalOffsetRate = 0;
|
||||
_totalFullCount = 0;
|
||||
_totalLoaded = false;
|
||||
}
|
||||
|
||||
rpl::producer<GlobalMediaSlice> Provider::source(
|
||||
Type type,
|
||||
Data::MessagePosition aroundId,
|
||||
|
@ -247,7 +235,7 @@ rpl::producer<GlobalMediaSlice> Provider::source(
|
|||
int limitAfter) {
|
||||
Expects(_type == type);
|
||||
|
||||
applyListQuery(query);
|
||||
_totalListQuery = query;
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
const auto session = &_controller->session();
|
||||
|
@ -268,7 +256,7 @@ rpl::producer<GlobalMediaSlice> Provider::source(
|
|||
state->pushAndLoadMore = [=] {
|
||||
auto result = fillRequest(aroundId, limitBefore, limitAfter);
|
||||
consumer.put_next(std::move(result.slice));
|
||||
if (!_totalLoaded && result.notEnough) {
|
||||
if (!currentList()->loaded && result.notEnough) {
|
||||
state->requestId = requestMore(state->pushAndLoadMore);
|
||||
}
|
||||
};
|
||||
|
@ -280,30 +268,32 @@ rpl::producer<GlobalMediaSlice> Provider::source(
|
|||
|
||||
mtpRequestId Provider::requestMore(Fn<void()> loaded) {
|
||||
const auto done = [=](const Api::GlobalMediaResult &result) {
|
||||
const auto list = currentList();
|
||||
if (result.messageIds.empty()) {
|
||||
_totalLoaded = true;
|
||||
_totalFullCount = _totalList.size();
|
||||
list->loaded = true;
|
||||
list->fullCount = list->list.size();
|
||||
} else {
|
||||
_totalList.reserve(_totalList.size() + result.messageIds.size());
|
||||
_totalFullCount = result.fullCount;
|
||||
list->list.reserve(list->list.size() + result.messageIds.size());
|
||||
list->fullCount = result.fullCount;
|
||||
for (const auto &position : result.messageIds) {
|
||||
_seenIds.emplace(position.fullId);
|
||||
_totalOffsetPosition = position;
|
||||
_totalList.push_back(position);
|
||||
list->offsetPosition = position;
|
||||
list->list.push_back(position);
|
||||
}
|
||||
}
|
||||
if (!result.offsetRate) {
|
||||
_totalLoaded = true;
|
||||
list->loaded = true;
|
||||
} else {
|
||||
_totalOffsetRate = result.offsetRate;
|
||||
list->offsetRate = result.offsetRate;
|
||||
}
|
||||
loaded();
|
||||
};
|
||||
const auto list = currentList();
|
||||
return _controller->session().api().requestGlobalMedia(
|
||||
_type,
|
||||
_totalListQuery,
|
||||
_totalOffsetRate,
|
||||
_totalOffsetPosition,
|
||||
list->offsetRate,
|
||||
list->offsetPosition,
|
||||
done);
|
||||
}
|
||||
|
||||
|
@ -311,24 +301,25 @@ Provider::FillResult Provider::fillRequest(
|
|||
Data::MessagePosition aroundId,
|
||||
int limitBefore,
|
||||
int limitAfter) {
|
||||
const auto list = currentList();
|
||||
const auto i = ranges::lower_bound(
|
||||
_totalList,
|
||||
list->list,
|
||||
aroundId,
|
||||
std::greater<>());
|
||||
const auto hasAfter = int(i - begin(_totalList));
|
||||
const auto hasBefore = int(end(_totalList) - i);
|
||||
const auto hasAfter = int(i - begin(list->list));
|
||||
const auto hasBefore = int(end(list->list) - i);
|
||||
const auto takeAfter = std::min(limitAfter, hasAfter);
|
||||
const auto takeBefore = std::min(limitBefore, hasBefore);
|
||||
auto list = std::vector<Data::MessagePosition>{
|
||||
auto messages = std::vector<Data::MessagePosition>{
|
||||
i - takeAfter,
|
||||
i + takeBefore,
|
||||
};
|
||||
return FillResult{
|
||||
.slice = GlobalMediaSlice(
|
||||
GlobalMediaKey{ aroundId },
|
||||
std::move(list),
|
||||
((!_totalList.empty() || _totalLoaded)
|
||||
? _totalFullCount
|
||||
std::move(messages),
|
||||
((!list->list.empty() || list->loaded)
|
||||
? list->fullCount
|
||||
: std::optional<int>()),
|
||||
hasAfter - takeAfter),
|
||||
.notEnough = (takeBefore < limitBefore),
|
||||
|
@ -400,6 +391,10 @@ void Provider::clearStaleLayouts() {
|
|||
}
|
||||
}
|
||||
|
||||
Provider::List *Provider::currentList() {
|
||||
return &_totalLists[_totalListQuery];
|
||||
}
|
||||
|
||||
rpl::producer<not_null<Media::BaseLayout*>> Provider::layoutRemoved() {
|
||||
return _layoutRemoved.events();
|
||||
}
|
||||
|
|
|
@ -126,6 +126,13 @@ private:
|
|||
GlobalMediaSlice slice;
|
||||
bool notEnough = false;
|
||||
};
|
||||
struct List {
|
||||
std::vector<Data::MessagePosition> list;
|
||||
Data::MessagePosition offsetPosition;
|
||||
int32 offsetRate = 0;
|
||||
int fullCount = 0;
|
||||
bool loaded = false;
|
||||
};
|
||||
|
||||
bool sectionHasFloatingHeader() override;
|
||||
QString sectionTitle(not_null<const BaseLayout*> item) override;
|
||||
|
@ -154,7 +161,7 @@ private:
|
|||
void itemRemoved(not_null<const HistoryItem*> item);
|
||||
void markLayoutsStale();
|
||||
void clearStaleLayouts();
|
||||
void applyListQuery(const QString &query);
|
||||
[[nodiscard]] List *currentList();
|
||||
[[nodiscard]] FillResult fillRequest(
|
||||
Data::MessagePosition aroundId,
|
||||
int limitBefore,
|
||||
|
@ -174,11 +181,7 @@ private:
|
|||
rpl::event_stream<> _refreshed;
|
||||
|
||||
QString _totalListQuery;
|
||||
std::vector<Data::MessagePosition> _totalList;
|
||||
Data::MessagePosition _totalOffsetPosition;
|
||||
int32 _totalOffsetRate = 0;
|
||||
int _totalFullCount = 0;
|
||||
bool _totalLoaded = false;
|
||||
base::flat_map<QString, List> _totalLists;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
rpl::lifetime _viewerLifetime;
|
||||
|
|
|
@ -92,6 +92,10 @@ rpl::producer<QString> SearchFieldController::queryChanges() const {
|
|||
return _query.changes();
|
||||
}
|
||||
|
||||
void SearchFieldController::setQuery(const QString &query) {
|
||||
_query = query;
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::InputField> SearchFieldController::createField(
|
||||
QWidget *parent,
|
||||
const style::InputField &st) {
|
||||
|
|
|
@ -40,6 +40,8 @@ public:
|
|||
rpl::producer<QString> queryValue() const;
|
||||
rpl::producer<QString> queryChanges() const;
|
||||
|
||||
void setQuery(const QString &query);
|
||||
|
||||
rpl::lifetime &lifetime() {
|
||||
return _lifetime;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue