Start chats search rewrite.

This commit is contained in:
John Preston 2024-05-17 14:56:56 +04:00
parent 787cf7853e
commit dd5643ac67
9 changed files with 474 additions and 491 deletions

View file

@ -157,13 +157,11 @@ InnerWidget::InnerWidget(
, _narrowWidth(st::defaultDialogRow.padding.left() , _narrowWidth(st::defaultDialogRow.padding.left()
+ st::defaultDialogRow.photoSize + st::defaultDialogRow.photoSize
+ st::defaultDialogRow.padding.left()) + st::defaultDialogRow.padding.left())
, _cancelSearchInChat(this, st::dialogsCancelSearchInPeer)
, _cancelSearchFromUser(this, st::dialogsCancelSearchInPeer) , _cancelSearchFromUser(this, st::dialogsCancelSearchInPeer)
, _chatPreviewTimer([=] { showChatPreview(true); }) , _chatPreviewTimer([=] { showChatPreview(true); })
, _childListShown(std::move(childListShown)) { , _childListShown(std::move(childListShown)) {
setAttribute(Qt::WA_OpaquePaintEvent, true); setAttribute(Qt::WA_OpaquePaintEvent, true);
_cancelSearchInChat->hide();
_cancelSearchFromUser->hide(); _cancelSearchFromUser->hide();
style::PaletteChanged( style::PaletteChanged(
@ -509,13 +507,7 @@ int InnerWidget::searchInChatSkip() const {
if (_searchTags) { if (_searchTags) {
result += _searchTags->height(); result += _searchTags->height();
} }
if (_searchInChat) {
result += st::searchedBarHeight + st::dialogsSearchInHeight;
}
if (_searchFromShown) { if (_searchFromShown) {
if (_searchInChat) {
result += st::lineWidth;
}
result += st::dialogsSearchInHeight; result += st::dialogsSearchInHeight;
} }
return result; return result;
@ -856,7 +848,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
} }
} }
if (_searchInChat || _searchFromPeer) { if (_searchFromShown) {
paintSearchInChat(p, { paintSearchInChat(p, {
.st = &st::forumTopicRow, .st = &st::forumTopicRow,
.currentBg = currentBg(), .currentBg = currentBg(),
@ -1141,37 +1133,8 @@ void InnerWidget::paintSearchInChat(
top += height; top += height;
} }
p.setFont(st::searchedBarFont); p.setFont(st::searchedBarFont);
if (_searchInChat) {
const auto bar = st::searchedBarHeight;
p.fillRect(0, top, width(), top + bar, st::searchedBarBg);
p.setPen(st::searchedBarFg);
p.drawTextLeft(st::searchedBarPosition.x(), top + st::searchedBarPosition.y(), width(), tr::lng_dlg_search_in(tr::now));
top += bar;
}
auto fullRect = QRect(0, top, width(), height - top); auto fullRect = QRect(0, top, width(), height - top);
p.fillRect(fullRect, currentBg()); p.fillRect(fullRect, currentBg());
if (_searchInChat) {
if (_searchFromShown) {
p.fillRect(QRect(0, top + st::dialogsSearchInHeight, width(), st::lineWidth), st::shadowFg);
}
p.setPen(st::dialogsNameFg);
if (const auto topic = _searchInChat.topic()) {
paintSearchInTopic(p, context, topic, _searchInChatUserpic, top, _searchInChatText);
} else if (const auto peer = _searchInChat.peer()) {
if (peer->isSelf()) {
paintSearchInSaved(p, top, _searchInChatText);
} else if (peer->isRepliesChat()) {
paintSearchInReplies(p, top, _searchInChatText);
} else {
paintSearchInPeer(p, peer, _searchInChatUserpic, top, _searchInChatText);
}
} else if (const auto sublist = _searchInChat.sublist()) {
paintSearchInSaved(p, top, _searchInChatText);
} else {
Unexpected("Empty Key in paintSearchInChat.");
}
top += st::dialogsSearchInHeight + st::lineWidth;
}
if (_searchFromShown) { if (_searchFromShown) {
p.setPen(st::dialogsTextFg); p.setPen(st::dialogsTextFg);
p.setTextPalette(st::dialogsSearchFromPalette); p.setTextPalette(st::dialogsSearchFromPalette);
@ -1930,12 +1893,10 @@ void InnerWidget::moveCancelSearchButtons() {
const auto widthForCancelButton = qMax( const auto widthForCancelButton = qMax(
width(), width(),
st::columnMinimalWidthLeft - _narrowWidth); st::columnMinimalWidthLeft - _narrowWidth);
const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInChat->width(); const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchFromUser->width();
const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2; const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2;
const auto skip = st::searchedBarHeight + (_searchTags ? _searchTags->height() : 0); const auto skip = st::searchedBarHeight + (_searchTags ? _searchTags->height() : 0);
_cancelSearchInChat->moveToLeft(left, skip + top); _cancelSearchFromUser->moveToLeft(left, skip + top);
const auto next = _searchInChat ? (skip + st::dialogsSearchInHeight + st::lineWidth) : 0;
_cancelSearchFromUser->moveToLeft(left, next + top);
} }
void InnerWidget::dialogRowReplaced( void InnerWidget::dialogRowReplaced(
@ -2334,7 +2295,7 @@ void InnerWidget::fillArchiveSearchMenu(not_null<Ui::PopupMenu*> menu) {
const auto folder = session().data().folderLoaded(Data::Folder::kId); const auto folder = session().data().folderLoaded(Data::Folder::kId);
if (!folder if (!folder
|| !folder->chatsList()->fullSize().current() || !folder->chatsList()->fullSize().current()
|| _searchInChat) { || _searchState.inChat) {
return; return;
} }
const auto skip = session().settings().skipArchiveInSearch(); const auto skip = session().settings().skipArchiveInSearch();
@ -2491,17 +2452,26 @@ void InnerWidget::parentGeometryChanged() {
} }
} }
void InnerWidget::applyFilterUpdate(QString newFilter, bool force) { void InnerWidget::applySearchState(SearchState state) {
if (_searchState == state) {
return;
}
auto withSameQuery = state;
withSameQuery.query = _searchState.query;
const auto otherChanged = (_searchState != withSameQuery);
_searchState = std::move(state);
auto newFilter = _searchState.query;
const auto mentionsSearch = (newFilter == u"@"_q); const auto mentionsSearch = (newFilter == u"@"_q);
const auto words = mentionsSearch const auto words = mentionsSearch
? QStringList(newFilter) ? QStringList(newFilter)
: TextUtilities::PrepareSearchWords(newFilter); : TextUtilities::PrepareSearchWords(newFilter);
newFilter = words.isEmpty() ? QString() : words.join(' '); newFilter = words.isEmpty() ? QString() : words.join(' ');
if (newFilter != _filter || force) { if (newFilter != _filter || otherChanged) {
_filter = newFilter; _filter = newFilter;
if (_filter.isEmpty() if (_filter.isEmpty()
&& !_searchFromPeer && !_searchState.fromPeer
&& _searchTagsSelected.empty()) { && _searchState.tags.empty()) {
clearFilter(); clearFilter();
} else { } else {
setState(WidgetState::Filtered); setState(WidgetState::Filtered);
@ -2521,9 +2491,7 @@ void InnerWidget::applyFilterUpdate(QString newFilter, bool force) {
top += i->row->height(); top += i->row->height();
} }
}; };
if (!_searchInChat if (_searchState.filterChatsList() && !words.isEmpty()) {
&& !_searchFromPeer
&& !words.isEmpty()) {
if (_savedSublists) { if (_savedSublists) {
const auto owner = &session().data(); const auto owner = &session().data();
append(owner->savedMessages().chatsList()->indexed()); append(owner->savedMessages().chatsList()->indexed());
@ -2549,7 +2517,9 @@ void InnerWidget::applyFilterUpdate(QString newFilter, bool force) {
} }
void InnerWidget::onHashtagFilterUpdate(QStringView newFilter) { void InnerWidget::onHashtagFilterUpdate(QStringView newFilter) {
if (newFilter.isEmpty() || newFilter.at(0) != '#' || _searchInChat) { if (newFilter.isEmpty()
|| newFilter.at(0) != '#'
|| _searchState.inChat) {
_hashtagFilter = QString(); _hashtagFilter = QString();
if (!_hashtagResults.empty()) { if (!_hashtagResults.empty()) {
_hashtagResults.clear(); _hashtagResults.clear();
@ -2751,10 +2721,6 @@ rpl::producer<> InnerWidget::searchMessages() const {
return _searchMessages.events(); return _searchMessages.events();
} }
rpl::producer<> InnerWidget::cancelSearchInChatRequests() const {
return _cancelSearchInChat->clicks() | rpl::to_empty;
}
rpl::producer<QString> InnerWidget::completeHashtagRequests() const { rpl::producer<QString> InnerWidget::completeHashtagRequests() const {
return _completeHashtagRequests.events(); return _completeHashtagRequests.events();
} }
@ -2847,12 +2813,12 @@ void InnerWidget::searchReceived(
const auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart) const auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart)
|| (type == SearchRequestType::MigratedFromOffset); || (type == SearchRequestType::MigratedFromOffset);
const auto key = (!_openedForum || _searchInChat.topic()) const auto key = (!_openedForum || _searchState.inChat.topic())
? _searchInChat ? _searchState.inChat
: Key(_openedForum->history()); : Key(_openedForum->history());
if (inject if (inject
&& (!_searchInChat && (!_searchState.inChat
|| inject->history() == _searchInChat.history())) { || inject->history() == _searchState.inChat.history())) {
Assert(_searchResults.empty()); Assert(_searchResults.empty());
const auto index = int(_searchResults.size()); const auto index = int(_searchResults.size());
_searchResults.push_back( _searchResults.push_back(
@ -2984,7 +2950,7 @@ void InnerWidget::refresh(bool toTop) {
} }
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
if (_waitingForSearch) { if (_waitingForSearch) {
h = searchedOffset() + (_searchResults.size() * _st->height) + ((_searchResults.empty() && !_searchInChat) ? -st::searchedBarHeight : 0); h = searchedOffset() + (_searchResults.size() * _st->height) + ((_searchResults.empty() && !_searchState.inChat) ? -st::searchedBarHeight : 0);
} else { } else {
h = searchedOffset() + (_searchResults.size() * _st->height); h = searchedOffset() + (_searchResults.size() * _st->height);
} }
@ -3124,7 +3090,7 @@ void InnerWidget::searchInChat(
_searchTags->selectedChanges( _searchTags->selectedChanges(
) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) { ) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) {
_searchTagsSelected = std::move(list); _searchState.tags = std::move(list);
}, _searchTags->lifetime()); }, _searchTags->lifetime());
_searchTags->repaintRequests() | rpl::start_with_next([=] { _searchTags->repaintRequests() | rpl::start_with_next([=] {
@ -3150,20 +3116,17 @@ void InnerWidget::searchInChat(
}, _searchTags->lifetime()); }, _searchTags->lifetime());
} else { } else {
_searchTags = nullptr; _searchTags = nullptr;
_searchTagsSelected.clear(); _searchState.tags.clear();
} }
} else { } else {
_searchTags = nullptr; _searchTags = nullptr;
_searchTagsSelected.clear(); _searchState.tags.clear();
} }
_searchInChat = key; _searchState.inChat = key;
_searchFromPeer = from; _searchState.fromPeer = from;
_searchFromShown = key.sublist() ? key.sublist()->peer().get() : from; _searchFromShown = key.sublist() ? key.sublist()->peer().get() : from;
if (_searchInChat) { if (_searchState.inChat) {
onHashtagFilterUpdate(QStringView()); onHashtagFilterUpdate(QStringView());
_cancelSearchInChat->show();
} else {
_cancelSearchInChat->hide();
} }
if (_searchFromShown) { if (_searchFromShown) {
_cancelSearchFromUser->show(); _cancelSearchFromUser->show();
@ -3172,15 +3135,9 @@ void InnerWidget::searchInChat(
_cancelSearchFromUser->hide(); _cancelSearchFromUser->hide();
_searchFromUserUserpic = {}; _searchFromUserUserpic = {};
} }
if (_searchInChat || _searchFromPeer) { if (_searchState.inChat || _searchState.fromPeer) {
refreshSearchInChatLabel(); refreshSearchInChatLabel();
} }
if (peer) {
_searchInChatUserpic = peer->createUserpicView();
} else {
_searchInChatUserpic = {};
}
moveCancelSearchButtons(); moveCancelSearchButtons();
} }
@ -3192,27 +3149,6 @@ auto InnerWidget::searchTagsChanges() const
} }
void InnerWidget::refreshSearchInChatLabel() { void InnerWidget::refreshSearchInChatLabel() {
const auto dialog = [&] {
if (const auto topic = _searchInChat.topic()) {
return topic->title();
} else if (const auto peer = _searchInChat.peer()) {
if (peer->isSelf()) {
return tr::lng_saved_messages(tr::now);
} else if (peer->isRepliesChat()) {
return tr::lng_replies_messages(tr::now);
}
return peer->name();
} else if (_searchInChat.sublist()) {
return tr::lng_saved_messages(tr::now);
}
return QString();
}();
if (!dialog.isEmpty()) {
_searchInChatText.setText(
st::semiboldTextStyle,
dialog,
Ui::DialogTextOptions());
}
const auto from = _searchFromShown ? _searchFromShown->name() : u""_q; const auto from = _searchFromShown ? _searchFromShown->name() : u""_q;
if (!from.isEmpty()) { if (!from.isEmpty()) {
const auto fromUserText = tr::lng_dlg_search_from( const auto fromUserText = tr::lng_dlg_search_from(
@ -3236,8 +3172,8 @@ void InnerWidget::repaintSearchResult(int index) {
} }
void InnerWidget::clearFilter() { void InnerWidget::clearFilter() {
if (_state == WidgetState::Filtered || _searchInChat) { if (_state == WidgetState::Filtered || _searchState.inChat) {
if (_searchInChat) { if (_searchState.inChat) {
setState(WidgetState::Filtered); setState(WidgetState::Filtered);
_waitingForSearch = true; _waitingForSearch = true;
} else { } else {

View file

@ -145,6 +145,7 @@ public:
} }
[[nodiscard]] bool hasFilteredResults() const; [[nodiscard]] bool hasFilteredResults() const;
void applySearchState(SearchState state);
void searchInChat( void searchInChat(
Key key, Key key,
PeerData *from, PeerData *from,
@ -152,7 +153,6 @@ public:
[[nodiscard]] auto searchTagsChanges() const [[nodiscard]] auto searchTagsChanges() const
-> rpl::producer<std::vector<Data::ReactionId>>; -> rpl::producer<std::vector<Data::ReactionId>>;
void applyFilterUpdate(QString newFilter, bool force = false);
void onHashtagFilterUpdate(QStringView newFilter); void onHashtagFilterUpdate(QStringView newFilter);
void appendToFiltered(Key key); void appendToFiltered(Key key);
@ -169,7 +169,6 @@ public:
[[nodiscard]] rpl::producer<Ui::ScrollToRequest> mustScrollTo() const; [[nodiscard]] rpl::producer<Ui::ScrollToRequest> mustScrollTo() const;
[[nodiscard]] rpl::producer<Ui::ScrollToRequest> dialogMoved() const; [[nodiscard]] rpl::producer<Ui::ScrollToRequest> dialogMoved() const;
[[nodiscard]] rpl::producer<> searchMessages() const; [[nodiscard]] rpl::producer<> searchMessages() const;
[[nodiscard]] rpl::producer<> cancelSearchInChatRequests() const;
[[nodiscard]] rpl::producer<QString> completeHashtagRequests() const; [[nodiscard]] rpl::producer<QString> completeHashtagRequests() const;
[[nodiscard]] rpl::producer<> refreshHashtagsRequests() const; [[nodiscard]] rpl::producer<> refreshHashtagsRequests() const;
@ -486,21 +485,16 @@ private:
WidgetState _state = WidgetState::Default; WidgetState _state = WidgetState::Default;
object_ptr<Ui::FlatLabel> _empty = { nullptr }; object_ptr<Ui::FlatLabel> _empty = { nullptr };
object_ptr<Ui::IconButton> _cancelSearchInChat;
object_ptr<Ui::IconButton> _cancelSearchFromUser; object_ptr<Ui::IconButton> _cancelSearchFromUser;
Ui::DraggingScrollManager _draggingScroll; Ui::DraggingScrollManager _draggingScroll;
Key _searchInChat; SearchState _searchState;
History *_searchInMigrated = nullptr; History *_searchInMigrated = nullptr;
PeerData *_searchFromPeer = nullptr;
PeerData *_searchFromShown = nullptr; PeerData *_searchFromShown = nullptr;
mutable Ui::PeerUserpicView _searchInChatUserpic;
mutable Ui::PeerUserpicView _searchFromUserUserpic; mutable Ui::PeerUserpicView _searchFromUserUserpic;
Ui::Text::String _searchInChatText;
Ui::Text::String _searchFromUserText; Ui::Text::String _searchFromUserText;
std::unique_ptr<SearchTags> _searchTags; std::unique_ptr<SearchTags> _searchTags;
std::vector<Data::ReactionId> _searchTagsSelected;
int _searchTagsLeft = 0; int _searchTagsLeft = 0;
RowDescriptor _menuRow; RowDescriptor _menuRow;

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_saved_sublist.h" #include "data/data_saved_sublist.h"
#include "dialogs/ui/chat_search_tabs.h"
#include "history/history.h" #include "history/history.h"
namespace Dialogs { namespace Dialogs {
@ -84,4 +85,21 @@ PeerData *Key::peer() const {
return nullptr; return nullptr;
} }
[[nodiscard]] bool SearchState::empty() const {
return !inChat
&& QStringView(query).trimmed().isEmpty();
}
ChatSearchTab SearchState::defaultTabForMe() const {
return inChat.topic()
? ChatSearchTab::ThisTopic
: inChat.history()
? ChatSearchTab::ThisPeer
: ChatSearchTab::MyMessages;
}
bool SearchState::filterChatsList() const {
return !inChat && (tab == ChatSearchTab::MyMessages);
}
} // namespace Dialogs } // namespace Dialogs

View file

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/qt/qt_compare.h"
class History; class History;
class PeerData; class PeerData;
@ -15,11 +17,13 @@ class Thread;
class Folder; class Folder;
class ForumTopic; class ForumTopic;
class SavedSublist; class SavedSublist;
struct ReactionId;
} // namespace Data } // namespace Data
namespace Dialogs { namespace Dialogs {
class Entry; class Entry;
enum class ChatSearchTab : uchar;
class Key { class Key {
public: public:
@ -120,4 +124,29 @@ struct EntryState {
= default; = default;
}; };
struct SearchState {
Key inChat;
PeerData *fromPeer = nullptr;
std::vector<Data::ReactionId> tags;
ChatSearchTab tab = {};
QString query;
[[nodiscard]] bool empty() const;
[[nodiscard]] ChatSearchTab defaultTabForMe() const;
[[nodiscard]] bool filterChatsList() const;
explicit operator bool() const {
return !empty();
}
friend inline auto operator<=>(
const SearchState&,
const SearchState&) noexcept = default;
friend inline bool operator==(
const SearchState&,
const SearchState&) = default;
};
;
} // namespace Dialogs } // namespace Dialogs

File diff suppressed because it is too large Load diff

View file

@ -100,7 +100,6 @@ public:
void showForum( void showForum(
not_null<Data::Forum*> forum, not_null<Data::Forum*> forum,
const Window::SectionShow &params); const Window::SectionShow &params);
void searchInChat(Key chat);
void setInnerFocus(bool unfocusSearch = false); void setInnerFocus(bool unfocusSearch = false);
[[nodiscard]] bool searchHasFocus() const; [[nodiscard]] bool searchHasFocus() const;
@ -122,9 +121,7 @@ public:
void scrollToEntry(const RowDescriptor &entry); void scrollToEntry(const RowDescriptor &entry);
void searchMessages(QString query, Key inChat = {}); void searchMessages(SearchState state);
void searchTopics();
void searchMore();
[[nodiscard]] RowDescriptor resolveChatNext(RowDescriptor from = {}) const; [[nodiscard]] RowDescriptor resolveChatNext(RowDescriptor from = {}) const;
[[nodiscard]] RowDescriptor resolveChatPrevious(RowDescriptor from = {}) const; [[nodiscard]] RowDescriptor resolveChatPrevious(RowDescriptor from = {}) const;
@ -154,14 +151,16 @@ protected:
private: private:
void chosenRow(const ChosenRow &row); void chosenRow(const ChosenRow &row);
void listScrollUpdated(); void listScrollUpdated();
void cancelSearchInChat();
void searchCursorMoved(); void searchCursorMoved();
void completeHashtag(QString tag); void completeHashtag(QString tag);
[[nodiscard]] QString currentSearchQuery() const; [[nodiscard]] QString currentSearchQuery() const;
[[nodiscard]] int currentSearchQueryCursorPosition() const;
void clearSearchField(); void clearSearchField();
bool searchMessages(bool searchCache = false); void searchRequested();
void needSearchMessages(); bool search(bool inCache = false);
void searchTopics();
void searchMore();
void slideFinished(); void slideFinished();
void searchReceived( void searchReceived(
@ -176,6 +175,8 @@ private:
void cancelSearchRequest(); void cancelSearchRequest();
[[nodiscard]] PeerData *searchInPeer() const; [[nodiscard]] PeerData *searchInPeer() const;
[[nodiscard]] Data::ForumTopic *searchInTopic() const; [[nodiscard]] Data::ForumTopic *searchInTopic() const;
[[nodiscard]] PeerData *searchFromPeer() const;
[[nodiscard]] const std::vector<Data::ReactionId> &searchInTags() const;
void setupSupportMode(); void setupSupportMode();
void setupConnectingWidget(); void setupConnectingWidget();
@ -190,18 +191,15 @@ private:
void trackScroll(not_null<Ui::RpWidget*> widget); void trackScroll(not_null<Ui::RpWidget*> widget);
[[nodiscard]] bool searchForPeersRequired(const QString &query) const; [[nodiscard]] bool searchForPeersRequired(const QString &query) const;
[[nodiscard]] bool searchForTopicsRequired(const QString &query) const; [[nodiscard]] bool searchForTopicsRequired(const QString &query) const;
bool setSearchInChat(
Key chat, // Child list may be unable to set specific search state.
PeerData *from, bool applySearchState(SearchState state);
std::vector<Data::ReactionId> tags);
bool setSearchInChat(
Key chat,
PeerData *from = nullptr);
void showCalendar(); void showCalendar();
void showSearchFrom(); void showSearchFrom();
void showMainMenu(); void showMainMenu();
void clearSearchCache(); void clearSearchCache();
void setSearchQuery(const QString &query); void setSearchQuery(const QString &query, int cursorPosition = -1);
void updateControlsVisibility(bool fast = false); void updateControlsVisibility(bool fast = false);
void updateLockUnlockVisibility( void updateLockUnlockVisibility(
anim::type animated = anim::type::instant); anim::type animated = anim::type::instant);
@ -227,7 +225,6 @@ private:
QPixmap newContentCache, QPixmap newContentCache,
Window::SlideDirection direction); Window::SlideDirection direction);
void applySearchTab();
void openChildList( void openChildList(
not_null<Data::Forum*> forum, not_null<Data::Forum*> forum,
const Window::SectionShow &params); const Window::SectionShow &params);
@ -236,7 +233,7 @@ private:
void fullSearchRefreshOn(rpl::producer<> events); void fullSearchRefreshOn(rpl::producer<> events);
void updateCancelSearch(); void updateCancelSearch();
bool fixSearchQuery(); bool fixSearchQuery();
void applySearchUpdate(bool force = false); void applySearchUpdate();
void refreshLoadMoreButton(bool mayBlock, bool isBlocked); void refreshLoadMoreButton(bool mayBlock, bool isBlocked);
void loadMoreBlockedByDate(); void loadMoreBlockedByDate();
@ -271,7 +268,7 @@ private:
Layout _layout = Layout::Main; Layout _layout = Layout::Main;
int _narrowWidth = 0; int _narrowWidth = 0;
object_ptr<Ui::RpWidget> _searchControls; object_ptr<Ui::RpWidget> _searchControls;
object_ptr<HistoryView::TopBarWidget> _subsectionTopBar = { nullptr } ; object_ptr<HistoryView::TopBarWidget> _subsectionTopBar = { nullptr };
struct { struct {
object_ptr<Ui::IconButton> toggle; object_ptr<Ui::IconButton> toggle;
object_ptr<Ui::AbstractButton> under; object_ptr<Ui::AbstractButton> under;
@ -312,23 +309,16 @@ private:
bool _forumSearchRequested = false; bool _forumSearchRequested = false;
bool _fixingSearchQuery = false; bool _fixingSearchQuery = false;
bool _searchingHashtag = false; bool _searchingHashtag = false;
ChatSearchTab _searchTab = ChatSearchTab();
Data::Folder *_openedFolder = nullptr; Data::Folder *_openedFolder = nullptr;
Data::Forum *_openedForum = nullptr; Data::Forum *_openedForum = nullptr;
Key _searchInChat; SearchState _searchState;
History *_searchInMigrated = nullptr; History *_searchInMigrated = nullptr;
PeerData *_searchFromAuthor = nullptr;
std::vector<Data::ReactionId> _searchTags;
rpl::lifetime _searchTagsLifetime; rpl::lifetime _searchTagsLifetime;
QString _lastSearchText; QString _lastSearchText;
bool _searchSuggestionsLocked = false; bool _searchSuggestionsLocked = false;
bool _searchHasFocus = false; bool _searchHasFocus = false;
Key _hiddenSearchInChat;
PeerData *_hiddenSearchFromAuthor = nullptr;
std::vector<Data::ReactionId> _hiddenSearchTags;
rpl::event_stream<rpl::producer<Stories::Content>> _storiesContents; rpl::event_stream<rpl::producer<Stories::Content>> _storiesContents;
base::flat_map<PeerId, Ui::PeerUserpicView> _storiesUserpicsViewsHidden; base::flat_map<PeerId, Ui::PeerUserpicView> _storiesUserpicsViewsHidden;
base::flat_map<PeerId, Ui::PeerUserpicView> _storiesUserpicsViewsShown; base::flat_map<PeerId, Ui::PeerUserpicView> _storiesUserpicsViewsShown;
@ -357,6 +347,7 @@ private:
QString _searchQuery; QString _searchQuery;
PeerData *_searchQueryFrom = nullptr; PeerData *_searchQueryFrom = nullptr;
std::vector<Data::ReactionId> _searchQueryTags; std::vector<Data::ReactionId> _searchQueryTags;
ChatSearchTab _searchQueryTab = {};
int32 _searchNextRate = 0; int32 _searchNextRate = 0;
bool _searchFull = false; bool _searchFull = false;
bool _searchFullMigrated = false; bool _searchFullMigrated = false;

View file

@ -1412,15 +1412,25 @@ QString TopBarWidget::searchQueryCurrent() const {
return _searchQuery.current(); return _searchQuery.current();
} }
int TopBarWidget::searchQueryCursorPosition() const {
return _searchMode
? _searchField->textCursor().position()
: _searchQuery.current().size();
}
void TopBarWidget::searchClear() { void TopBarWidget::searchClear() {
if (_searchMode) { if (_searchMode) {
_searchField->clear(); _searchField->clear();
} }
} }
void TopBarWidget::searchSetText(const QString &query) { void TopBarWidget::searchSetText(const QString &query, int cursorPosition) {
if (_searchMode) { if (_searchMode) {
if (cursorPosition < 0) {
cursorPosition = query.size();
}
_searchField->setText(query); _searchField->setText(query);
_searchField->setCursorPosition(cursorPosition);
} }
} }

View file

@ -88,8 +88,9 @@ public:
[[nodiscard]] rpl::producer<> searchSubmitted() const; [[nodiscard]] rpl::producer<> searchSubmitted() const;
[[nodiscard]] rpl::producer<QString> searchQuery() const; [[nodiscard]] rpl::producer<QString> searchQuery() const;
[[nodiscard]] QString searchQueryCurrent() const; [[nodiscard]] QString searchQueryCurrent() const;
[[nodiscard]] int searchQueryCursorPosition() const;
void searchClear(); void searchClear();
void searchSetText(const QString &query); void searchSetText(const QString &query, int cursorPosition = -1);
[[nodiscard]] rpl::producer<> forwardSelectionRequest() const { [[nodiscard]] rpl::producer<> forwardSelectionRequest() const {
return _forwardSelection.events(); return _forwardSelection.events();

View file

@ -731,8 +731,18 @@ void MainWidget::hideSingleUseKeyboard(FullMsgId replyToId) {
} }
void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) { void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
auto tags = Data::SearchTagsFromQuery(query);
if (controller()->isPrimary()) { if (controller()->isPrimary()) {
_dialogs->searchMessages(query, inChat); using Tab = Dialogs::ChatSearchTab;
auto state = Dialogs::SearchState{
.inChat = ((tags.empty() || inChat.sublist())
? inChat
: session().data().history(session().user())),
.tags = tags,
.query = tags.empty() ? query : QString(),
};
state.tab = state.defaultTabForMe();
_dialogs->searchMessages(std::move(state));
if (isOneColumn()) { if (isOneColumn()) {
_controller->clearSectionStack(); _controller->clearSectionStack();
} else { } else {
@ -742,7 +752,7 @@ void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
if (const auto sublist = inChat.sublist()) { if (const auto sublist = inChat.sublist()) {
controller()->showSection( controller()->showSection(
std::make_shared<HistoryView::SublistMemento>(sublist)); std::make_shared<HistoryView::SublistMemento>(sublist));
} else if (!Data::SearchTagsFromQuery(query).empty()) { } else if (!tags.empty()) {
inChat = controller()->session().data().history( inChat = controller()->session().data().history(
controller()->session().user()); controller()->session().user());
} }