diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index fba45fefb..7edb22d7a 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -348,6 +348,7 @@ inlineBotsScroll: ScrollArea(defaultSolidScroll) { deltab: stickerPanPadding; } +gifsPadding: margins(9px, 5px, 3px, 9px); gifsSearchField: defaultMultiSelectSearchField; gifsSearchFieldPosition: point(42px, 7px); gifsSearchCancel: defaultMultiSelectSearchCancel; diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 297b4837f..19bc50c75 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/qt/qt_key_modifiers.h" #include "data/data_photo.h" #include "data/data_document.h" +#include "data/data_emoji_statuses.h" +#include "data/stickers/data_custom_emoji.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/data_file_origin.h" @@ -20,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/stickers/data_stickers.h" #include "menu/menu_send.h" // SendMenu::FillSendMenu #include "core/click_handler_types.h" +#include "ui/controls/tabbed_search.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" #include "ui/widgets/popup_menu.h" @@ -186,6 +189,8 @@ GifsListWidget::GifsListWidget( setMouseTracking(true); setAttribute(Qt::WA_OpaquePaintEvent); + setupSearch(); + _inlineRequestTimer.setSingleShot(true); connect( &_inlineRequestTimer, @@ -215,9 +220,8 @@ GifsListWidget::GifsListWidget( _mosaic.setFullWidth(s.width()); }, lifetime()); - _mosaic.setOffset( - st::inlineResultsLeft - st::roundRadiusSmall, - st::stickerPanPadding); + _mosaic.setPadding(st::gifsPadding + + QMargins(-st::emojiPanRadius, _search->height(), 0, 0)); _mosaic.setRightSkip(st::inlineResultsSkip); } @@ -262,7 +266,7 @@ void GifsListWidget::checkLoadMore() { } int GifsListWidget::countDesiredHeight(int newWidth) { - return _mosaic.countDesiredHeight(newWidth) + st::stickerPanPadding * 2; + return _mosaic.countDesiredHeight(newWidth); } GifsListWidget::~GifsListWidget() { @@ -272,7 +276,7 @@ GifsListWidget::~GifsListWidget() { } void GifsListWidget::cancelGifsSearch() { - _footer->setLoading(false); + _search->setLoading(false); if (_inlineRequestId) { _api.request(_inlineRequestId).cancel(); _inlineRequestId = 0; @@ -284,7 +288,7 @@ void GifsListWidget::cancelGifsSearch() { } void GifsListWidget::inlineResultsDone(const MTPmessages_BotResults &result) { - _footer->setLoading(false); + _search->setLoading(false); _inlineRequestId = 0; auto it = _inlineCache.find(_inlineQuery); @@ -774,14 +778,14 @@ Data::FileOrigin GifsListWidget::inlineItemFileOrigin() { } void GifsListWidget::afterShown() { - if (_footer) { - _footer->stealFocus(); + if (_search) { + _search->stealFocus(); } } void GifsListWidget::beforeHiding() { - if (_footer) { - _footer->returnFocus(); + if (_search) { + _search->returnFocus(); } } @@ -797,6 +801,26 @@ bool GifsListWidget::refreshInlineRows(int32 *added) { return (entry != nullptr); } +void GifsListWidget::setupSearch() { + const auto owner = &_controller->session().data(); + using Descriptor = Ui::SearchDescriptor; + _search = std::make_unique(this, st(), Descriptor{ + .st = st().search, + .groups = owner->emojiStatuses().emojiGroupsValue(), + .customEmojiFactory = owner->customEmojiManager().factory( + Data::CustomEmojiManager::SizeTag::SetIcon, + Ui::SearchWithGroups::IconSizeOverride()) + }); + _search->queryValue( + ) | rpl::start_with_next([=](std::vector &&query) { + searchForGifs(ranges::accumulate(query, QString(), []( + QString a, + QString b) { + return a.isEmpty() ? b : (a + ' ' + b); + })); + }, lifetime()); +} + int32 GifsListWidget::showInlineRows(bool newResults) { auto added = 0; refreshInlineRows(&added); @@ -813,7 +837,7 @@ void GifsListWidget::searchForGifs(const QString &query) { } if (_inlineQuery != query) { - _footer->setLoading(false); + _search->setLoading(false); if (_inlineRequestId) { _api.request(_inlineRequestId).cancel(); _inlineRequestId = 0; @@ -862,7 +886,7 @@ void GifsListWidget::sendInlineRequest() { if (!_searchBot) { // Wait for the bot being resolved. - _footer->setLoading(true); + _search->setLoading(true); _inlineRequestTimer.start(kSearchRequestDelay); return; } @@ -874,12 +898,12 @@ void GifsListWidget::sendInlineRequest() { if (it != _inlineCache.cend()) { nextOffset = it->second->nextOffset; if (nextOffset.isEmpty()) { - _footer->setLoading(false); + _search->setLoading(false); return; } } - _footer->setLoading(true); + _search->setLoading(true); _inlineRequestId = _api.request(MTPmessages_GetInlineBotResults( MTP_flags(0), _searchBot->inputUser, @@ -891,7 +915,7 @@ void GifsListWidget::sendInlineRequest() { inlineResultsDone(result); }).fail([this] { // show error? - _footer->setLoading(false); + _search->setLoading(false); _inlineRequestId = 0; }).handleAllErrors().send(); } diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h index 4571a9e6b..ad04d23c9 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h @@ -28,6 +28,7 @@ class Result; namespace Ui { class PopupMenu; class RoundButton; +class TabbedSearch; } // namespace Ui namespace Window { @@ -119,6 +120,7 @@ private: InlineResults results; }; + void setupSearch(); void clearHeavyData(); void cancelGifsSearch(); void switchToSavedGifs(); @@ -152,6 +154,7 @@ private: bool forceSend = false); not_null _controller; + std::unique_ptr _search; MTP::Sender _api; diff --git a/Telegram/SourceFiles/info/media/info_media_list_section.cpp b/Telegram/SourceFiles/info/media/info_media_list_section.cpp index 323238527..d956d4d76 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_section.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_section.cpp @@ -65,7 +65,12 @@ bool ListSection::addItem(not_null item) { void ListSection::finishSection() { if (_type == Type::GIF) { - _mosaic.setOffset(st::infoMediaSkip, headerHeight()); + _mosaic.setPadding({ + st::infoMediaSkip, + headerHeight(), + st::infoMediaSkip, + st::stickerPanPadding, + }); _mosaic.setRightSkip(st::infoMediaSkip); _mosaic.addItems(_items); } @@ -390,7 +395,7 @@ int ListSection::recountHeight() { } break; case Type::GIF: { - return _mosaic.countDesiredHeight(0) + result; + return _mosaic.countDesiredHeight(0); } break; case Type::RoundVoiceFile: diff --git a/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp b/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp index 96ad691e3..419779480 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp @@ -443,13 +443,10 @@ void Inner::clearInlineRowsPanel() { } void Inner::refreshMosaicOffset() { - const auto top = st::stickerPanPadding - + (_switchPmButton - ? _switchPmButton->height() + st::inlineResultsSkip - : 0); - _mosaic.setOffset( - st::inlineResultsLeft - st::roundRadiusSmall, - top); + const auto top = _switchPmButton + ? (_switchPmButton->height() + st::inlineResultsSkip) + : 0; + _mosaic.setPadding(st::gifsPadding + QMargins(0, top, 0, 0)); } void Inner::refreshSwitchPmButton(const CacheEntry *entry) { diff --git a/Telegram/SourceFiles/layout/layout_mosaic.cpp b/Telegram/SourceFiles/layout/layout_mosaic.cpp index d9eb05e09..7ffe926d4 100644 --- a/Telegram/SourceFiles/layout/layout_mosaic.cpp +++ b/Telegram/SourceFiles/layout/layout_mosaic.cpp @@ -27,12 +27,12 @@ int AbstractMosaicLayout::countDesiredHeight(int newWidth) { layoutRow(row, newWidth ? newWidth : _width); result += row.height; } - return result; + return _padding.top() + result + _padding.bottom(); } FoundItem AbstractMosaicLayout::findByPoint(const QPoint &globalPoint) const { - auto sx = globalPoint.x() - _offset.x(); - auto sy = globalPoint.y() - _offset.y(); + auto sx = globalPoint.x() - _padding.left(); + auto sy = globalPoint.y() - _padding.top(); auto row = -1; auto col = -1; auto sel = -1; @@ -108,8 +108,8 @@ QRect AbstractMosaicLayout::findRect(int index) const { if ((left + w) > fromX) { if (item->position() == index) { return QRect( - left + _offset.x(), - top + _offset.y(), + left + _padding.left(), + top + _padding.top(), item->width(), item->height()); } @@ -139,8 +139,8 @@ void AbstractMosaicLayout::setRightSkip(int rightSkip) { _rightSkip = rightSkip; } -void AbstractMosaicLayout::setOffset(int left, int top) { - _offset = { left, top }; +void AbstractMosaicLayout::setPadding(QMargins padding) { + _padding = padding; } void AbstractMosaicLayout::setFullWidth(int w) { @@ -211,7 +211,7 @@ void AbstractMosaicLayout::forEach( void AbstractMosaicLayout::paint( Fn, QPoint)> paintItem, const QRect &clip) const { - auto top = _offset.y(); + auto top = _padding.top(); const auto fromX = style::RightToLeft() ? (_width - clip.x() - clip.width()) : clip.x(); @@ -225,7 +225,7 @@ void AbstractMosaicLayout::paint( } auto &inlineRow = _rows[row]; if ((top + inlineRow.height) > clip.top()) { - auto left = _offset.x(); + auto left = _padding.left(); if (row == (rows - 1)) { // context.lastRow = true; } @@ -366,8 +366,7 @@ void AbstractMosaicLayout::layoutRow(Row &row, int fullWidth) { auto desiredWidth = row.maxWidth; row.height = 0; - auto availableWidth = fullWidth - - (st::inlineResultsLeft - st::roundRadiusSmall); + auto availableWidth = fullWidth - _padding.left() - _padding.right(); for (auto i = 0; i < count; ++i) { const auto index = indices[i]; const auto &item = row.items[index]; diff --git a/Telegram/SourceFiles/layout/layout_mosaic.h b/Telegram/SourceFiles/layout/layout_mosaic.h index 773f4abe4..b8730f84c 100644 --- a/Telegram/SourceFiles/layout/layout_mosaic.h +++ b/Telegram/SourceFiles/layout/layout_mosaic.h @@ -32,7 +32,7 @@ public: [[nodiscard]] QRect findRect(int index) const; void setRightSkip(int rightSkip); - void setOffset(int left, int top); + void setPadding(QMargins padding); void setFullWidth(int w); [[nodiscard]] bool empty() const; @@ -73,7 +73,7 @@ private: int _bigWidth; int _width = 0; int _rightSkip = 0; - QPoint _offset; + QMargins _padding; std::vector _rows; }; diff --git a/Telegram/SourceFiles/ui/controls/tabbed_search.cpp b/Telegram/SourceFiles/ui/controls/tabbed_search.cpp index 3cfacb680..57744ccd6 100644 --- a/Telegram/SourceFiles/ui/controls/tabbed_search.cpp +++ b/Telegram/SourceFiles/ui/controls/tabbed_search.cpp @@ -316,6 +316,7 @@ void SearchWithGroups::initField() { } else { _debounceTimer.callOnce(kDebounceTimeout); _chosenGroup = QString(); + scrollGroupsToStart(); } }); @@ -518,6 +519,26 @@ auto SearchWithGroups::debouncedQueryValue() const return _debouncedQuery.value(); } +void SearchWithGroups::setLoading(bool loading) { + _cancel->setLoadingAnimation(loading); +} + +void SearchWithGroups::stealFocus() { + if (!_focusTakenFrom) { + _focusTakenFrom = QApplication::focusWidget(); + } + _field->setFocus(); +} + +void SearchWithGroups::returnFocus() { + if (_field && _focusTakenFrom) { + if (_field->hasFocus()) { + _focusTakenFrom->setFocus(); + } + _focusTakenFrom = nullptr; + } +} + int SearchWithGroups::IconSizeOverride() { return style::ConvertScale(kCategoryIconSizeOverride); } @@ -600,6 +621,18 @@ int TabbedSearch::height() const { return _search.height() + rect::m::sum::v(_st.searchMargin); } +void TabbedSearch::setLoading(bool loading) { + _search.setLoading(loading); +} + +void TabbedSearch::stealFocus() { + _search.stealFocus(); +} + +void TabbedSearch::returnFocus() { + _search.returnFocus(); +} + rpl::producer> TabbedSearch::queryValue() const { return _search.queryValue(); } diff --git a/Telegram/SourceFiles/ui/controls/tabbed_search.h b/Telegram/SourceFiles/ui/controls/tabbed_search.h index 7bbb910d8..39c871ade 100644 --- a/Telegram/SourceFiles/ui/controls/tabbed_search.h +++ b/Telegram/SourceFiles/ui/controls/tabbed_search.h @@ -53,6 +53,10 @@ public: [[nodiscard]] auto debouncedQueryValue() const -> rpl::producer>; + void setLoading(bool loading); + void stealFocus(); + void returnFocus(); + [[nodiscard]] static int IconSizeOverride(); private: @@ -79,6 +83,7 @@ private: not_null*> _back; not_null _cancel; not_null _field; + QPointer _focusTakenFrom; not_null*> _groups; not_null _fade; rpl::variable _fadeOpacity = 0.; @@ -111,6 +116,10 @@ public: [[nodiscard]] auto debouncedQueryValue() const ->rpl::producer>; + void setLoading(bool loading); + void stealFocus(); + void returnFocus(); + private: const style::EmojiPan &_st; SearchWithGroups _search;