From 65b1a0c9a49a340d679d12efac2745ac8431b545 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 24 Jan 2023 17:08:35 +0400 Subject: [PATCH] Use TabbedSearch control for stickers panel. --- Telegram/Resources/langs/lang.strings | 1 - .../chat_helpers/chat_helpers.style | 9 -- .../chat_helpers/emoji_list_widget.cpp | 22 +-- .../chat_helpers/emoji_list_widget.h | 1 - .../chat_helpers/gifs_list_widget.cpp | 32 +--- .../chat_helpers/stickers_list_footer.cpp | 148 ++---------------- .../chat_helpers/stickers_list_footer.h | 24 +-- .../chat_helpers/stickers_list_widget.cpp | 76 +++++---- .../chat_helpers/stickers_list_widget.h | 3 + .../chat_helpers/tabbed_selector.cpp | 28 ++++ .../chat_helpers/tabbed_selector.h | 8 + .../support/support_autocomplete.cpp | 2 +- 12 files changed, 104 insertions(+), 250 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 7b8ff9622..4f90377c4 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2001,7 +2001,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_stickers_remove_group_set" = "Remove group sticker set?"; "lng_stickers_group_from_your" = "Choose from your stickers"; "lng_stickers_group_from_featured" = "Choose from trending stickers"; -"lng_stickers_search_sets" = "Search sticker sets"; "lng_stickers_nothing_found" = "No stickers found"; "lng_stickers_remove_pack_confirm" = "Remove"; "lng_stickers_archive_pack" = "Archive Stickers"; diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index f2e6ae5c4..78623051f 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -321,11 +321,6 @@ stickerPanRemoveSet: IconButton(hashtagClose) { iconPosition: point(-1px, -1px); rippleAreaPosition: point(0px, 0px); } -stickerIconWidth: 42px; -stickerIconPadding: 5px; -stickerIconOpacity: 0.7; -stickerIconSel: 2px; -stickerIconSelColor: emojiIconFgActive; stickerIconMove: 400; stickerPreviewDuration: 150; stickerPreviewMin: 0.1; @@ -349,10 +344,6 @@ inlineBotsScroll: ScrollArea(defaultSolidScroll) { } gifsPadding: margins(9px, 5px, 3px, 9px); -gifsSearchField: defaultMultiSelectSearchField; -gifsSearchFieldPosition: point(42px, 7px); -gifsSearchCancel: defaultMultiSelectSearchCancel; -gifsSearchCancelPosition: point(1px, 1px); emojiSuggestionsDropdown: InnerDropdown(defaultInnerDropdown) { scrollMargin: margins(0px, emojiColorsPadding, 0px, emojiColorsPadding); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index 177b16caf..dda4dda40 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -24,7 +24,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/sticker_set_box.h" #include "lang/lang_keys.h" #include "layout/layout_position.h" -#include "data/data_emoji_statuses.h" #include "data/data_session.h" #include "data/data_document.h" #include "data/data_peer_values.h" @@ -414,9 +413,6 @@ EmojiListWidget::EmojiListWidget( _customSingleSize = Data::FrameSizeFromTag( Data::CustomEmojiManager::SizeTag::Large ) / style::DevicePixelRatio(); - _customSetIconSize = Data::FrameSizeFromTag( - Data::CustomEmojiManager::SizeTag::SetIcon - ) / style::DevicePixelRatio(); _picker->hide(); @@ -470,23 +466,13 @@ EmojiListWidget::~EmojiListWidget() { } void EmojiListWidget::setupSearch() { - using Descriptor = Ui::SearchDescriptor; - _search = std::make_unique(this, st(), Descriptor{ - .st = st().search, - .groups = (_mode == Mode::EmojiStatus - ? session().data().emojiStatuses().statusGroupsValue() - : session().data().emojiStatuses().emojiGroupsValue()), - .customEmojiFactory = session().data().customEmojiManager().factory( - Data::CustomEmojiManager::SizeTag::SetIcon, - Ui::SearchWithGroups::IconSizeOverride()) - }); - _search->queryValue( - ) | rpl::start_with_next([=](std::vector &&query) { + const auto session = &_controller->session(); + _search = MakeSearch(this, st(), [=](std::vector &&query) { _nextSearchQuery = std::move(query); InvokeQueued(this, [=] { applyNextSearchQuery(); }); - }, lifetime()); + }, session, (_mode == Mode::EmojiStatus)); } void EmojiListWidget::applyNextSearchQuery() { @@ -1940,7 +1926,7 @@ std::vector EmojiListWidget::fillIcons() { } else { result.emplace_back(AllEmojiSectionSetId()); } - const auto esize = _customSetIconSize; + const auto esize = StickersListFooter::IconFrameSize(); for (const auto &custom : _custom) { const auto set = custom.set; result.emplace_back(set, custom.thumbnailDocument, esize, esize); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h index 2f11b981f..f33eda32d 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h @@ -359,7 +359,6 @@ private: DocumentId, std::unique_ptr> _customRecent; int _customSingleSize = 0; - int _customSetIconSize = 0; bool _allowWithoutPremium = false; Ui::RoundRect _overBg; diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 2d3f87f94..38ee14b69 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -13,7 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/stickers_list_footer.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" @@ -199,26 +198,16 @@ std::vector GifsListWidget::fillIcons() { auto result = std::vector(); result.reserve(_sections.size() + 1); result.emplace_back(Data::Stickers::RecentSetId); + const auto side = StickersListFooter::IconFrameSize(); for (const auto §ion : _sections) { const auto s = section.document; const auto id = s->id; - const auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding; - const auto availh = st().footer - 2 * st::stickerIconPadding; const auto size = s->hasThumbnail() ? QSize( s->thumbnailLocation().width(), s->thumbnailLocation().height()) : QSize(); - auto thumbw = size.width(), thumbh = size.height(), pixw = 1, pixh = 1; - if (availw * thumbh > availh * thumbw) { - pixh = availh; - pixw = (pixh * thumbw) / thumbh; - } else { - pixw = availw; - pixh = thumbw ? ((pixw * thumbh) / thumbw) : 1; - } - if (pixw < 1) pixw = 1; - if (pixh < 1) pixh = 1; + const auto pix = size.scaled(side, side, Qt::KeepAspectRatio); const auto owner = &s->owner(); const auto already = _fakeSets.find(id); const auto set = (already != end(_fakeSets)) @@ -235,7 +224,7 @@ std::vector GifsListWidget::fillIcons() { 0, Data::StickersSetFlag::Special, 0)).first; - result.emplace_back(set->second.get(), s, pixw, pixh); + result.emplace_back(set->second.get(), s, pix.width(), pix.height()); } return result; } @@ -802,17 +791,8 @@ bool GifsListWidget::refreshInlineRows(int32 *added) { } 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) { + const auto session = &_controller->session(); + _search = MakeSearch(this, st(), [=](std::vector &&query) { _chosenSetId = Data::Stickers::RecentSetId; refreshIcons(); searchForGifs(ranges::accumulate(query, QString(), []( @@ -820,7 +800,7 @@ void GifsListWidget::setupSearch() { QString b) { return a.isEmpty() ? b : (a + ' ' + b); })); - }, lifetime()); + }, session); } int32 GifsListWidget::showInlineRows(bool newResults) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp index 5fd65bdbe..70e3eec83 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp @@ -156,8 +156,8 @@ StickerIcon::StickerIcon( : setId(set->id) , set(set) , sticker(sticker) -, pixw(pixw) -, pixh(pixh) { +, pixw(std::max(pixw, 1)) +, pixh(std::max(pixh, 1)) { } StickerIcon::StickerIcon(StickerIcon&&) = default; @@ -255,14 +255,12 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor) , _iconState([=] { update(); }) , _subiconState([=] { update(); }) , _selectionBg(st::emojiPanRadius, st::windowBgRipple) -, _subselectionBg(st().iconArea / 2, st::windowBgRipple) -, _barSelection(descriptor.barSelection) { +, _subselectionBg(st().iconArea / 2, st::windowBgRipple) { setMouseTracking(true); - _iconsLeft = st().iconSkip; - _iconsRight = st().iconSkip + (_settingsButtonVisible - ? st::stickerIconWidth - : 0); + _iconsLeft = st().iconSkip + + (_settingsButtonVisible ? st().iconWidth : 0); + _iconsRight = st().iconSkip; _session->downloaderTaskFinished( ) | rpl::start_with_next([=] { @@ -305,72 +303,10 @@ void StickersListFooter::paintExpanding( p.setClipping(false); } -void StickersListFooter::initSearch() { - _searchField.create( - this, - st::gifsSearchField, - tr::lng_stickers_search_sets()); - _searchCancel.create(this, st::gifsSearchCancel); - _searchField->show(); - _searchCancel->show(anim::type::instant); - - const auto cancelSearch = [=] { - if (_searchField->getLastText().isEmpty()) { - toggleSearch(false); - } else { - _searchField->setText(QString()); - } - }; - connect(_searchField, &Ui::InputField::submitted, [=] { - _searchRequests.fire({ - .text = _searchField->getLastText(), - .forced = true, - }); - }); - connect(_searchField, &Ui::InputField::cancelled, cancelSearch); - connect(_searchField, &Ui::InputField::changed, [=] { - _searchRequests.fire({ - .text = _searchField->getLastText(), - }); - }); - _searchCancel->setClickedCallback(cancelSearch); - - resizeSearchControls(); -} - -void StickersListFooter::toggleSearch(bool visible) { - if (_searchShown == visible) { - return; - } - _searchShown = visible; - if (_searchShown) { - initSearch(); - stealFocus(); - } else if (_searchField) { - returnFocus(); - _searchField.destroy(); - _searchCancel.destroy(); - _focusTakenFrom = nullptr; - } - update(); -} - -void StickersListFooter::stealFocus() { - if (_searchField) { - if (!_focusTakenFrom) { - _focusTakenFrom = QApplication::focusWidget(); - } - _searchField->setFocus(); - } -} - -void StickersListFooter::returnFocus() { - if (_searchField && _focusTakenFrom) { - if (_searchField->hasFocus()) { - _focusTakenFrom->setFocus(); - } - _focusTakenFrom = nullptr; - } +int StickersListFooter::IconFrameSize() { + return Data::FrameSizeFromTag( + Data::CustomEmojiManager::SizeTag::SetIcon + ) / style::DevicePixelRatio(); } void StickersListFooter::enumerateVisibleIcons( @@ -611,12 +547,6 @@ void StickersListFooter::leaveToChildEvent(QEvent *e, QWidget *child) { updateSelected(); } -void StickersListFooter::setLoading(bool loading) { - if (_searchCancel) { - _searchCancel->setLoadingAnimation(loading); - } -} - void StickersListFooter::paintEvent(QPaintEvent *e) { auto p = Painter(this); @@ -627,7 +557,7 @@ void StickersListFooter::paintEvent(QPaintEvent *e) { void StickersListFooter::paint( Painter &p, const ExpandingContext &context) const { - if (_icons.empty() || _searchShown) { + if (_icons.empty()) { return; } @@ -654,10 +584,7 @@ void StickersListFooter::paint( } else { p.setClipRect(clip); } - - if (!_barSelection) { - paintSelectionBg(p, context); - } + paintSelectionBg(p, context); const auto iconCacheSize = QSize(_singleWidth, st().footer); const auto full = iconCacheSize * style::DevicePixelRatio(); @@ -672,10 +599,6 @@ void StickersListFooter::paint( enumerateVisibleIcons([&](const IconInfo &info) { paintSetIcon(p, context, info, now, paused); }); - - if (_barSelection) { - paintSelectionBar(p); - } paintLeftRightFading(p, context); } @@ -720,21 +643,6 @@ void StickersListFooter::paintSelectionBg( } } -void StickersListFooter::paintSelectionBar(QPainter &p) const { - auto selxrel = _iconsLeft + qRound(_iconState.selectionX.current()); - auto selx = selxrel - qRound(_iconState.x.current()); - const auto selw = qRound(_iconState.selectionWidth.current()); - if (rtl()) { - selx = width() - selx - selw; - } - p.fillRect( - selx, - _iconsTop + st().footer - st::stickerIconPadding, - selw, - st::stickerIconSel, - st::stickerIconSelColor); -} - void StickersListFooter::paintLeftRightFading( QPainter &p, const ExpandingContext &context) const { @@ -844,25 +752,9 @@ void StickersListFooter::validateFadeMask() const { } void StickersListFooter::resizeEvent(QResizeEvent *e) { - if (_searchField) { - resizeSearchControls(); - } refreshIconsGeometry(_activeByScrollId, ValidateIconAnimations::None); } -void StickersListFooter::resizeSearchControls() { - Expects(_searchField != nullptr); - Expects(_searchCancel != nullptr); - - const auto fieldWidth = width() - - st::gifsSearchFieldPosition.x() - - st::gifsSearchCancelPosition.x() - - st::gifsSearchCancel.width; - _searchField->resizeToWidth(fieldWidth); - _searchField->moveToLeft(st::gifsSearchFieldPosition.x(), st::gifsSearchFieldPosition.y()); - _searchCancel->moveToRight(st::gifsSearchCancelPosition.x(), st::gifsSearchCancelPosition.y()); -} - rpl::producer StickersListFooter::setChosen() const { return _setChosen.events(); } @@ -871,10 +763,6 @@ rpl::producer<> StickersListFooter::openSettingsRequests() const { return _openSettingsRequests.events(); } -rpl::producer StickersListFooter::searchRequests() const { - return _searchRequests.events(); -} - void StickersListFooter::mousePressEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton) { return; @@ -1065,8 +953,7 @@ void StickersListFooter::updateSelected() { auto p = mapFromGlobal(_iconsMousePos); auto x = p.x(), y = p.y(); if (rtl()) x = width() - x; - const auto settingsLeft = width() - _iconsRight; - const auto searchLeft = _iconsLeft - _singleWidth; + const auto settingsLeft = _iconsLeft - _singleWidth; auto newOver = OverState(SpecialOver::None); if (_settingsButtonVisible && x >= settingsLeft @@ -1174,9 +1061,7 @@ void StickersListFooter::refreshIconsGeometry( _iconState.selectionWidth.finish(); _iconState.animationStart = 0; _iconState.animation.stop(); - if (_barSelection) { - _singleWidth = st::stickerIconWidth; - } else if (_icons.size() > 1 + if (_icons.size() > 1 && _icons[1].setId == EmojiSectionSetId(EmojiSection::People)) { _singleWidth = (width() - _iconsLeft - _iconsRight) / _icons.size(); } else { @@ -1193,9 +1078,6 @@ void StickersListFooter::refreshIconsGeometry( } void StickersListFooter::refreshSubiconsGeometry() { - if (_barSelection) { - return; - } using Section = Ui::Emoji::Section; _subiconState.x.finish(); _subiconState.animationStart = 0; @@ -1228,7 +1110,7 @@ bool StickersListFooter::hasOnlyFeaturedSets() const { } void StickersListFooter::paintStickerSettingsIcon(QPainter &p) const { - const auto settingsLeft = width() - _iconsRight; + const auto settingsLeft = _iconsLeft - _singleWidth; st::stickersSettings.paint( p, settingsLeft diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h index 6b51106ee..b9938362c 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h @@ -113,7 +113,6 @@ public: Fn paused; not_null parent; bool settingsButtonVisible = false; - bool barSelection = false; const style::EmojiPan *st = nullptr; }; explicit StickersListFooter(Descriptor &&descriptor); @@ -131,27 +130,19 @@ public: void leaveToChildEvent(QEvent *e, QWidget *child) override; - void stealFocus(); - void returnFocus(); - void setLoading(bool loading); - void clearHeavyData(); [[nodiscard]] rpl::producer setChosen() const; [[nodiscard]] rpl::producer<> openSettingsRequests() const; - struct SearchRequest { - QString text; - bool forced = false; - }; - [[nodiscard]] rpl::producer searchRequests() const; - void paintExpanding( Painter &p, QRect clip, float64 radius, RectPart origin); + [[nodiscard]] static int IconFrameSize(); + protected: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; @@ -258,7 +249,6 @@ private: void paintSelectionBg( QPainter &p, const ExpandingContext &context) const; - void paintSelectionBar(QPainter &p) const; void paintLeftRightFading( QPainter &p, const ExpandingContext &context) const; @@ -266,9 +256,6 @@ private: void updateEmojiSectionWidth(); void updateEmojiWidthCallback(); - void initSearch(); - void toggleSearch(bool visible); - void resizeSearchControls(); void scrollByWheelEvent(not_null e); void validateFadeLeft(int leftWidth) const; @@ -311,17 +298,10 @@ private: Ui::Animations::Simple _subiconsWidthAnimation; int _subiconsWidth = 0; bool _subiconsExpanded = false; - bool _barSelection = false; bool _repaintScheduled = false; - bool _searchShown = false; - object_ptr _searchField = { nullptr }; - object_ptr _searchCancel = { nullptr }; - QPointer _focusTakenFrom; - rpl::event_stream<> _openSettingsRequests; rpl::event_stream _setChosen; - rpl::event_stream _searchRequests; }; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index a00aaaa36..2fe2e53b4 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "menu/menu_send.h" // SendMenu::FillSendMenu #include "chat_helpers/stickers_lottie.h" #include "chat_helpers/stickers_list_footer.h" +#include "ui/controls/tabbed_search.h" #include "ui/widgets/buttons.h" #include "ui/widgets/popup_menu.h" #include "ui/effects/animations.h" @@ -201,6 +202,10 @@ StickersListWidget::StickersListWidget( setMouseTracking(true); setAttribute(Qt::WA_OpaquePaintEvent); + if (!_isMasks) { + setupSearch(); + } + _settings->addClickHandler([=] { using Section = StickersBox::Section; controller->show( @@ -265,7 +270,6 @@ object_ptr StickersListWidget::createFooter() { .paused = pausedMethod(), .parent = this, .settingsButtonVisible = true, - .barSelection = true, }); _footer = result; @@ -288,15 +292,6 @@ object_ptr StickersListWidget::createFooter() { Ui::LayerOption::KeepOther); }, _footer->lifetime()); - _footer->searchRequests( - ) | rpl::start_with_next([=](StickersListFooter::SearchRequest request) { - if (request.forced) { - sendSearchRequest(); - } else { - searchForSets(request.text); - } - }, _footer->lifetime()); - return result; } @@ -417,6 +412,7 @@ int StickersListWidget::featuredRowHeight() const { template bool StickersListWidget::enumerateSections(Callback callback) const { auto info = SectionInfo(); + info.top = _search ? _search->height() : 0; const auto &sets = shownSets(); for (auto i = 0; i != sets.size(); ++i) { auto &set = sets[i]; @@ -517,11 +513,11 @@ void StickersListWidget::sendSearchRequest() { auto it = _searchCache.find(_searchQuery); if (it != _searchCache.cend()) { - _footer->setLoading(false); + _search->setLoading(false); return; } - _footer->setLoading(true); + _search->setLoading(true); const auto hash = uint64(0); _searchRequestId = _api.request(MTPmessages_SearchStickerSets( MTP_flags(0), @@ -531,7 +527,7 @@ void StickersListWidget::sendSearchRequest() { searchResultsDone(result); }).fail([=] { // show error? - _footer->setLoading(false); + _search->setLoading(false); _searchRequestId = 0; }).handleAllErrors().send(); } @@ -544,7 +540,7 @@ void StickersListWidget::searchForSets(const QString &query) { } if (_searchQuery != cleaned) { - _footer->setLoading(false); + _search->setLoading(false); if (const auto requestId = base::take(_searchRequestId)) { _api.request(requestId).cancel(); } @@ -560,7 +556,7 @@ void StickersListWidget::searchForSets(const QString &query) { } void StickersListWidget::cancelSetsSearch() { - _footer->setLoading(false); + _search->setLoading(false); if (const auto requestId = base::take(_searchRequestId)) { _api.request(requestId).cancel(); } @@ -758,7 +754,7 @@ auto StickersListWidget::shownSets() -> std::vector & { void StickersListWidget::searchResultsDone( const MTPmessages_FoundStickerSets &result) { - _footer->setLoading(false); + _search->setLoading(false); _searchRequestId = 0; if (result.type() == mtpc_messages_foundStickerSetsNotModified) { @@ -926,7 +922,12 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { set.ripple.reset(); } } - (selected ? st::stickerPanRemoveSet.iconOver : st::stickerPanRemoveSet.icon).paint(p, remove.topLeft() + st::stickerPanRemoveSet.iconPosition, width()); + const auto &icon = selected ? st::stickerPanRemoveSet.iconOver : st::stickerPanRemoveSet.icon; + icon.paint( + p, + remove.x() + (remove.width() - icon.width()) / 2, + remove.y() + (remove.height() - icon.height()) / 2, + width()); widthForTitle -= remove.width(); } @@ -2253,10 +2254,6 @@ void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) { std::vector StickersListWidget::fillIcons() { auto result = std::vector(); result.reserve(_mySets.size() + 1); - if (!_officialSets.empty() && !_isMasks) { - result.emplace_back(Data::Stickers::FeaturedSetId); - } - auto i = 0; if (i != _mySets.size() && _mySets[i].id == Data::Stickers::FavedSetId) { ++i; @@ -2268,6 +2265,7 @@ std::vector StickersListWidget::fillIcons() { result.emplace_back(Data::Stickers::RecentSetId); } } + const auto side = StickersListFooter::IconFrameSize(); for (auto l = _mySets.size(); i != l; ++i) { if (_mySets[i].id == Data::Stickers::MegagroupSetId) { result.emplace_back(Data::Stickers::MegagroupSetId); @@ -2277,8 +2275,6 @@ std::vector StickersListWidget::fillIcons() { const auto set = _mySets[i].set; Assert(set != nullptr); const auto s = _mySets[i].thumbnailDocument; - const auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding; - const auto availh = st().footer - 2 * st::stickerIconPadding; const auto size = set->hasThumbnail() ? QSize( set->thumbnailLocation().width(), @@ -2288,17 +2284,8 @@ std::vector StickersListWidget::fillIcons() { s->thumbnailLocation().width(), s->thumbnailLocation().height()) : QSize(); - auto thumbw = size.width(), thumbh = size.height(), pixw = 1, pixh = 1; - if (availw * thumbh > availh * thumbw) { - pixh = availh; - pixw = (pixh * thumbw) / thumbh; - } else { - pixw = availw; - pixh = thumbw ? ((pixw * thumbh) / thumbw) : 1; - } - if (pixw < 1) pixw = 1; - if (pixh < 1) pixh = 1; - result.emplace_back(set, s, pixw, pixh); + const auto pix = size.scaled(side, side, Qt::KeepAspectRatio); + result.emplace_back(set, s, pix.width(), pix.height()); } return result; } @@ -2471,7 +2458,7 @@ void StickersListWidget::showStickerSet(uint64 setId) { auto y = 0; enumerateSections([this, setId, &y](const SectionInfo &info) { if (shownSets()[info.section].id == setId) { - y = info.top; + y = info.section ? info.top : 0; return false; } return true; @@ -2527,17 +2514,28 @@ void StickersListWidget::showMegagroupSet(ChannelData *megagroup) { } void StickersListWidget::afterShown() { - if (_footer) { - _footer->stealFocus(); + if (_search) { + _search->stealFocus(); } } void StickersListWidget::beforeHiding() { - if (_footer) { - _footer->returnFocus(); + if (_search) { + _search->returnFocus(); } } +void StickersListWidget::setupSearch() { + const auto session = &_controller->session(); + _search = MakeSearch(this, st(), [=](std::vector &&query) { + searchForSets(ranges::accumulate(query, QString(), []( + QString a, + QString b) { + return a.isEmpty() ? b : (a + ' ' + b); + })); + }, session); +} + void StickersListWidget::displaySet(uint64 setId) { if (setId == Data::Stickers::MegagroupSetId) { if (_megagroupSet->canEditStickers()) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index 594cf06c1..f3769aa25 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -29,6 +29,7 @@ class PopupMenu; class RippleAnimation; class BoxContent; class PathShiftGradient; +class TabbedSearch; } // namespace Ui namespace Lottie { @@ -196,6 +197,7 @@ private: const QVector &pack, bool skipPremium); + void setupSearch(); void preloadMoreOfficial(); QSize boundingBoxSize() const; @@ -329,6 +331,7 @@ private: not_null document); not_null _controller; + std::unique_ptr _search; MTP::Sender _api; std::unique_ptr _localSetsManager; ChannelData *_megagroupSet = nullptr; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index 4fdc50338..83d033b7d 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/stickers_list_widget.h" #include "chat_helpers/gifs_list_widget.h" #include "menu/menu_send.h" +#include "ui/controls/tabbed_search.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "ui/widgets/shadow.h" @@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session_settings.h" #include "storage/localstorage.h" #include "data/data_channel.h" +#include "data/data_emoji_statuses.h" #include "data/data_session.h" #include "data/data_changes.h" #include "data/stickers/data_stickers.h" @@ -288,6 +290,32 @@ void TabbedSelector::Tab::saveScrollTop() { _scrollTop = widget()->getVisibleTop(); } +std::unique_ptr MakeSearch( + not_null parent, + const style::EmojiPan &st, + Fn&&)> callback, + not_null session, + bool statusCategories) { + using Descriptor = Ui::SearchDescriptor; + const auto owner = &session->data(); + auto result = std::make_unique(parent, st, Descriptor{ + .st = st.search, + .groups = (statusCategories + ? owner->emojiStatuses().statusGroupsValue() + : owner->emojiStatuses().emojiGroupsValue()), + .customEmojiFactory = owner->customEmojiManager().factory( + Data::CustomEmojiManager::SizeTag::SetIcon, + Ui::SearchWithGroups::IconSizeOverride()) + }); + + result->queryValue( + ) | rpl::skip(1) | rpl::start_with_next( + std::move(callback), + parent->lifetime()); + + return result; +} + TabbedSelector::TabbedSelector( QWidget *parent, not_null controller, diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h index f9e72cfb3..a57ee2efa 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h @@ -31,6 +31,7 @@ class ScrollArea; class SettingsSlider; class FlatLabel; class BoxContent; +class TabbedSearch; } // namespace Ui namespace Window { @@ -77,6 +78,13 @@ struct EmojiChosen { using InlineChosen = InlineBots::ResultSelected; +[[nodiscard]] std::unique_ptr MakeSearch( + not_null parent, + const style::EmojiPan &st, + Fn&&)> callback, + not_null session, + bool statusCategories = false); + class TabbedSelector : public Ui::RpWidget { public: static constexpr auto kPickCustomTimeId = -1; diff --git a/Telegram/SourceFiles/support/support_autocomplete.cpp b/Telegram/SourceFiles/support/support_autocomplete.cpp index 6561b8bfd..3ebec4074 100644 --- a/Telegram/SourceFiles/support/support_autocomplete.cpp +++ b/Telegram/SourceFiles/support/support_autocomplete.cpp @@ -397,7 +397,7 @@ void Autocomplete::setupContent() { this, object_ptr( this, - st::gifsSearchField, + st::defaultMultiSelectSearchField, rpl::single(u"Search for templates"_q)), // #TODO hard_lang st::autocompleteSearchPadding); const auto input = inputWrap->entity();