diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index e10544c6d..fe5651774 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -2655,7 +2655,7 @@ void InnerWidget::applySearchState(SearchState state) { onHashtagFilterUpdate(QStringView()); } _searchState = std::move(state); - _searchingHashtag = IsHashtagSearchQuery(_searchState.query); + _searchHashOrCashtag = IsHashOrCashtagSearchQuery(_searchState.query); updateSearchIn(); moveSearchIn(); @@ -3332,7 +3332,8 @@ auto InnerWidget::searchTagsChanges() const } void InnerWidget::updateSearchIn() { - if (!_searchState.inChat && !_searchingHashtag) { + if (!_searchState.inChat + && _searchHashOrCashtag == HashOrCashtag::None) { _searchIn = nullptr; return; } else if (!_searchIn) { @@ -3381,7 +3382,7 @@ void InnerWidget::updateSearchIn() { ? Ui::MakeUserpicThumbnail(sublist->peer()) : nullptr; const auto myIcon = Ui::MakeIconThumbnail(st::menuIconChats); - const auto publicIcon = _searchingHashtag + const auto publicIcon = (_searchHashOrCashtag != HashOrCashtag::None) ? Ui::MakeIconThumbnail(st::menuIconChannel) : nullptr; const auto peerTabType = (peer && peer->isBroadcast()) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 3adad0cf4..033418af1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -62,6 +62,7 @@ class IndexedList; class SearchTags; class SearchEmpty; class ChatSearchIn; +enum class HashOrCashtag : uchar; struct ChosenRow { Key key; @@ -514,7 +515,7 @@ private: Ui::DraggingScrollManager _draggingScroll; SearchState _searchState; - bool _searchingHashtag = false; + HashOrCashtag _searchHashOrCashtag = {}; History *_searchInMigrated = nullptr; PeerData *_searchFromShown = nullptr; Ui::Text::String _searchFromUserText; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 29e0400d7..913425a79 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -2125,14 +2125,14 @@ bool Widget::searchForPeersRequired(const QString &query) const { return _searchState.filterChatsList() && !_openedForum && !query.isEmpty() - && !IsHashtagSearchQuery(query); + && (IsHashOrCashtagSearchQuery(query) == HashOrCashtag::None); } bool Widget::searchForTopicsRequired(const QString &query) const { return _searchState.filterChatsList() && _openedForum && !query.isEmpty() - && !IsHashtagSearchQuery(query) + && (IsHashOrCashtagSearchQuery(query) == HashOrCashtag::None) && !_openedForum->topicsList()->loaded(); } @@ -2654,16 +2654,19 @@ void Widget::updateCancelSearch() { QString Widget::validateSearchQuery() { const auto query = currentSearchQuery(); if (_searchState.tab == ChatSearchTab::PublicPosts) { - _searchingHashtag = true; + if (_searchHashOrCashtag == HashOrCashtag::None) { + _searchHashOrCashtag = HashOrCashtag::Hashtag; + } const auto fixed = FixHashtagSearchQuery( query, - currentSearchQueryCursorPosition()); + currentSearchQueryCursorPosition(), + _searchHashOrCashtag); if (fixed.text != query) { setSearchQuery(fixed.text, fixed.cursorPosition); } return fixed.text; } else { - _searchingHashtag = IsHashtagSearchQuery(query); + _searchHashOrCashtag = IsHashOrCashtagSearchQuery(query); } return query; } @@ -2860,11 +2863,12 @@ bool Widget::applySearchState(SearchState state) { state.fromPeer = nullptr; } if (state.tab == ChatSearchTab::PublicPosts - && !IsHashtagSearchQuery(state.query)) { + && IsHashOrCashtagSearchQuery(state.query) == HashOrCashtag::None) { state.tab = (_openedForum && !state.inChat) ? ChatSearchTab::ThisPeer : ChatSearchTab::MyMessages; - } else if (!state.inChat && !_searchingHashtag) { + } else if (!state.inChat + && _searchHashOrCashtag == HashOrCashtag::None) { state.tab = (forum || _openedForum) ? ChatSearchTab::ThisPeer : ChatSearchTab::MyMessages; @@ -2904,7 +2908,7 @@ bool Widget::applySearchState(SearchState state) { && !state.inChat && !_openedForum) || (state.tab == ChatSearchTab::PublicPosts - && !_searchingHashtag)) { + && _searchHashOrCashtag == HashOrCashtag::None)) { state.tab = state.inChat.topic() ? ChatSearchTab::ThisTopic : (state.inChat.owningHistory() || state.inChat.sublist()) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 46e5b55e0..37fdcaae2 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -79,6 +79,7 @@ enum class SearchRequestDelay : uchar; class Suggestions; class ChatSearchIn; enum class ChatSearchTab : uchar; +enum class HashOrCashtag : uchar; class Widget final : public Window::AbstractSectionWidget { public: @@ -314,7 +315,7 @@ private: object_ptr _scrollToTop; bool _scrollToTopIsShown = false; bool _forumSearchRequested = false; - bool _searchingHashtag = false; + HashOrCashtag _searchHashOrCashtag = {}; Data::Folder *_openedFolder = nullptr; Data::Forum *_openedForum = nullptr; diff --git a/Telegram/SourceFiles/dialogs/ui/chat_search_in.cpp b/Telegram/SourceFiles/dialogs/ui/chat_search_in.cpp index 0524b3a63..310f687ba 100644 --- a/Telegram/SourceFiles/dialogs/ui/chat_search_in.cpp +++ b/Telegram/SourceFiles/dialogs/ui/chat_search_in.cpp @@ -199,12 +199,14 @@ void Action::handleKeyPress(not_null e) { FixedHashtagSearchQuery FixHashtagSearchQuery( const QString &query, - int cursorPosition) { + int cursorPosition, + HashOrCashtag tag) { const auto trimmed = query.trimmed(); const auto hash = int(trimmed.isEmpty() ? query.size() : query.indexOf(trimmed)); const auto start = std::min(cursorPosition, hash); + const auto first = QChar(tag == HashOrCashtag::Cashtag ? '$' : '#'); auto result = query.mid(0, start); for (const auto &ch : query.mid(start)) { if (ch.isSpace()) { @@ -213,33 +215,41 @@ FixedHashtagSearchQuery FixHashtagSearchQuery( } continue; } else if (result.size() == start) { - result += '#'; - if (ch != '#') { + result += first; + if (ch != first) { ++cursorPosition; } } - if (ch != '#') { + if (ch != first) { result += ch; } } if (result.size() == start) { - result += '#'; + result += first; ++cursorPosition; } return { result, cursorPosition }; } -bool IsHashtagSearchQuery(const QString &query) { +HashOrCashtag IsHashOrCashtagSearchQuery(const QString &query) { const auto trimmed = query.trimmed(); - if (trimmed.isEmpty() || trimmed[0] != '#') { - return false; - } - for (const auto &ch : trimmed) { - if (ch.isSpace()) { - return false; + const auto first = trimmed.isEmpty() ? QChar() : trimmed[0]; + if (first == '#') { + for (const auto &ch : trimmed) { + if (ch.isSpace()) { + return HashOrCashtag::None; + } } + return HashOrCashtag::Hashtag; + } else if (first == '$') { + for (const auto &ch : trimmed.midRef(1)) { + if (ch < 'A' || ch > 'Z') { + return HashOrCashtag::None; + } + } + return HashOrCashtag::Cashtag; } - return true; + return HashOrCashtag::None; } void ChatSearchIn::Section::update() { diff --git a/Telegram/SourceFiles/dialogs/ui/chat_search_in.h b/Telegram/SourceFiles/dialogs/ui/chat_search_in.h index 5e99f2d05..b5b742616 100644 --- a/Telegram/SourceFiles/dialogs/ui/chat_search_in.h +++ b/Telegram/SourceFiles/dialogs/ui/chat_search_in.h @@ -87,14 +87,21 @@ private: }; +enum class HashOrCashtag : uchar { + None, + Hashtag, + Cashtag, +}; + struct FixedHashtagSearchQuery { QString text; int cursorPosition = 0; }; [[nodiscard]] FixedHashtagSearchQuery FixHashtagSearchQuery( const QString &query, - int cursorPosition); + int cursorPosition, + HashOrCashtag tag); -[[nodiscard]] bool IsHashtagSearchQuery(const QString &query); +[[nodiscard]] HashOrCashtag IsHashOrCashtagSearchQuery(const QString &query); } // namespace Dialogs