diff --git a/Telegram/Resources/icons/emoji/emoji_activities.png b/Telegram/Resources/icons/emoji/emoji_activities.png new file mode 100644 index 0000000000..c4ac15d3d3 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_activities.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_activities@2x.png b/Telegram/Resources/icons/emoji/emoji_activities@2x.png new file mode 100644 index 0000000000..21f7053762 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_activities@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_activities@3x.png b/Telegram/Resources/icons/emoji/emoji_activities@3x.png new file mode 100644 index 0000000000..530cabe633 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_activities@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_activity.png b/Telegram/Resources/icons/emoji/emoji_activity.png deleted file mode 100644 index 8f5dc60a2f..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_activity.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_activity@2x.png b/Telegram/Resources/icons/emoji/emoji_activity@2x.png deleted file mode 100644 index 8ba2f956fd..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_activity@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_activity@3x.png b/Telegram/Resources/icons/emoji/emoji_activity@3x.png deleted file mode 100644 index e017b83ffe..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_activity@3x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_back.png b/Telegram/Resources/icons/emoji/emoji_back.png new file mode 100644 index 0000000000..31c82fc34d Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_back.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_back@2x.png b/Telegram/Resources/icons/emoji/emoji_back@2x.png new file mode 100644 index 0000000000..ff0e0f5562 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_back@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_back@3x.png b/Telegram/Resources/icons/emoji/emoji_back@3x.png new file mode 100644 index 0000000000..b45d24e3b4 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_back@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_faved.png b/Telegram/Resources/icons/emoji/emoji_faved.png deleted file mode 100644 index 6443a63098..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_faved.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_faved@2x.png b/Telegram/Resources/icons/emoji/emoji_faved@2x.png deleted file mode 100644 index 6f757994e0..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_faved@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_faved@3x.png b/Telegram/Resources/icons/emoji/emoji_faved@3x.png deleted file mode 100644 index c41e112590..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_faved@3x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_food.png b/Telegram/Resources/icons/emoji/emoji_food.png index 364b60eb94..245bd448d5 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_food.png and b/Telegram/Resources/icons/emoji/emoji_food.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_food@2x.png b/Telegram/Resources/icons/emoji/emoji_food@2x.png index 4b55ed1fcc..d65918c909 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_food@2x.png and b/Telegram/Resources/icons/emoji/emoji_food@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_food@3x.png b/Telegram/Resources/icons/emoji/emoji_food@3x.png index b38deb2bd3..6072c340eb 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_food@3x.png and b/Telegram/Resources/icons/emoji/emoji_food@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_love.png b/Telegram/Resources/icons/emoji/emoji_love.png new file mode 100644 index 0000000000..0119168655 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_love.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_love@2x.png b/Telegram/Resources/icons/emoji/emoji_love@2x.png new file mode 100644 index 0000000000..1bf0d31ca3 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_love@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_love@3x.png b/Telegram/Resources/icons/emoji/emoji_love@3x.png new file mode 100644 index 0000000000..098a421560 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_love@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_nature.png b/Telegram/Resources/icons/emoji/emoji_nature.png index 70a8deeaea..4848d3d4c6 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_nature.png and b/Telegram/Resources/icons/emoji/emoji_nature.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_nature@2x.png b/Telegram/Resources/icons/emoji/emoji_nature@2x.png index ff40de6450..e2927607bf 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_nature@2x.png and b/Telegram/Resources/icons/emoji/emoji_nature@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_nature@3x.png b/Telegram/Resources/icons/emoji/emoji_nature@3x.png index 39ce2c8634..f72fbe8fec 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_nature@3x.png and b/Telegram/Resources/icons/emoji/emoji_nature@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_objects.png b/Telegram/Resources/icons/emoji/emoji_objects.png index 4b15d24dae..733db2699b 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_objects.png and b/Telegram/Resources/icons/emoji/emoji_objects.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_objects@2x.png b/Telegram/Resources/icons/emoji/emoji_objects@2x.png index 2ed2a56274..5a16634914 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_objects@2x.png and b/Telegram/Resources/icons/emoji/emoji_objects@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_objects@3x.png b/Telegram/Resources/icons/emoji/emoji_objects@3x.png index 4c914be728..12525379e0 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_objects@3x.png and b/Telegram/Resources/icons/emoji/emoji_objects@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_people.png b/Telegram/Resources/icons/emoji/emoji_people.png deleted file mode 100644 index 57b4bed914..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_people.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_people@2x.png b/Telegram/Resources/icons/emoji/emoji_people@2x.png deleted file mode 100644 index 39cd6d9a00..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_people@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_people@3x.png b/Telegram/Resources/icons/emoji/emoji_people@3x.png deleted file mode 100644 index 8492c9b1b2..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_people@3x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_recent.png b/Telegram/Resources/icons/emoji/emoji_recent.png index eaa98cf93a..f260f7cb65 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_recent.png and b/Telegram/Resources/icons/emoji/emoji_recent.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_recent@2x.png b/Telegram/Resources/icons/emoji/emoji_recent@2x.png index 95adf7e7db..a61bef009e 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_recent@2x.png and b/Telegram/Resources/icons/emoji/emoji_recent@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_recent@3x.png b/Telegram/Resources/icons/emoji/emoji_recent@3x.png index 03ad6fc84b..2b10fc362a 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_recent@3x.png and b/Telegram/Resources/icons/emoji/emoji_recent@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_search_input.png b/Telegram/Resources/icons/emoji/emoji_search_input.png new file mode 100644 index 0000000000..8ee7bdce94 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_search_input.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_search_input@2x.png b/Telegram/Resources/icons/emoji/emoji_search_input@2x.png new file mode 100644 index 0000000000..9b7798f008 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_search_input@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_search_input@3x.png b/Telegram/Resources/icons/emoji/emoji_search_input@3x.png new file mode 100644 index 0000000000..af792f172b Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_search_input@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_settings.png b/Telegram/Resources/icons/emoji/emoji_settings.png index fa77adf096..5ae663fd4c 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_settings.png and b/Telegram/Resources/icons/emoji/emoji_settings.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_settings@2x.png b/Telegram/Resources/icons/emoji/emoji_settings@2x.png index 591d1164a3..eb081d4c66 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_settings@2x.png and b/Telegram/Resources/icons/emoji/emoji_settings@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_settings@3x.png b/Telegram/Resources/icons/emoji/emoji_settings@3x.png index 70c9bfaa2b..2fcaf619bd 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_settings@3x.png and b/Telegram/Resources/icons/emoji/emoji_settings@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_smile.png b/Telegram/Resources/icons/emoji/emoji_smile.png new file mode 100644 index 0000000000..3b868e80bc Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_smile.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_smile@2x.png b/Telegram/Resources/icons/emoji/emoji_smile@2x.png new file mode 100644 index 0000000000..d6edb73478 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_smile@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_smile@3x.png b/Telegram/Resources/icons/emoji/emoji_smile@3x.png new file mode 100644 index 0000000000..3d198a5e36 Binary files /dev/null and b/Telegram/Resources/icons/emoji/emoji_smile@3x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_switch.png b/Telegram/Resources/icons/emoji/emoji_switch.png deleted file mode 100644 index c5e7e30399..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_switch.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_switch@2x.png b/Telegram/Resources/icons/emoji/emoji_switch@2x.png deleted file mode 100644 index d52a9cdade..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_switch@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_switch@3x.png b/Telegram/Resources/icons/emoji/emoji_switch@3x.png deleted file mode 100644 index 4debce918e..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_switch@3x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_symbols.png b/Telegram/Resources/icons/emoji/emoji_symbols.png deleted file mode 100644 index 5e651903f0..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_symbols.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_symbols@2x.png b/Telegram/Resources/icons/emoji/emoji_symbols@2x.png deleted file mode 100644 index 2ecae9bd89..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_symbols@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_symbols@3x.png b/Telegram/Resources/icons/emoji/emoji_symbols@3x.png deleted file mode 100644 index 9d90174240..0000000000 Binary files a/Telegram/Resources/icons/emoji/emoji_symbols@3x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/emoji_travel.png b/Telegram/Resources/icons/emoji/emoji_travel.png index 315acc6f19..824d92d0f3 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_travel.png and b/Telegram/Resources/icons/emoji/emoji_travel.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_travel@2x.png b/Telegram/Resources/icons/emoji/emoji_travel@2x.png index e644cbf97f..2cbf8fbaec 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_travel@2x.png and b/Telegram/Resources/icons/emoji/emoji_travel@2x.png differ diff --git a/Telegram/Resources/icons/emoji/emoji_travel@3x.png b/Telegram/Resources/icons/emoji/emoji_travel@3x.png index 0d6e1babba..b2b8f9007a 100644 Binary files a/Telegram/Resources/icons/emoji/emoji_travel@3x.png and b/Telegram/Resources/icons/emoji/emoji_travel@3x.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add.png b/Telegram/Resources/icons/emoji/stickers_add.png index 7e24cc25ef..d4c77a202c 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add.png and b/Telegram/Resources/icons/emoji/stickers_add.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add@2x.png b/Telegram/Resources/icons/emoji/stickers_add@2x.png index 13501cc408..f188f440d5 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add@2x.png and b/Telegram/Resources/icons/emoji/stickers_add@2x.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add@3x.png b/Telegram/Resources/icons/emoji/stickers_add@3x.png index 464456ff1f..48de8115e3 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add@3x.png and b/Telegram/Resources/icons/emoji/stickers_add@3x.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot.png b/Telegram/Resources/icons/emoji/stickers_add_dot.png index a825339080..1bb4078f4e 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot.png and b/Telegram/Resources/icons/emoji/stickers_add_dot.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png b/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png index 732d286272..1723a7f362 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png and b/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png b/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png index 6f0658b5ad..ce7f1aa76e 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png and b/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread.png b/Telegram/Resources/icons/emoji/stickers_add_unread.png index 8d603947da..d8172e22b3 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread.png and b/Telegram/Resources/icons/emoji/stickers_add_unread.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png b/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png index b56e63d3e3..c48562529e 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png and b/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png b/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png index c26c0c132f..46a03b994c 100644 Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png and b/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png differ diff --git a/Telegram/Resources/icons/emoji/stickers_recent.png b/Telegram/Resources/icons/emoji/stickers_recent.png deleted file mode 100644 index 51041d0c54..0000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_recent.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_recent@2x.png b/Telegram/Resources/icons/emoji/stickers_recent@2x.png deleted file mode 100644 index 3751aec4d1..0000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_recent@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_recent@3x.png b/Telegram/Resources/icons/emoji/stickers_recent@3x.png deleted file mode 100644 index ca796771fb..0000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_recent@3x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_search.png b/Telegram/Resources/icons/emoji/stickers_search.png deleted file mode 100644 index 9645d1c9b5..0000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_search.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_search@2x.png b/Telegram/Resources/icons/emoji/stickers_search@2x.png deleted file mode 100644 index fedddd5a50..0000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_search@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_search@3x.png b/Telegram/Resources/icons/emoji/stickers_search@3x.png deleted file mode 100644 index f3d5cef32e..0000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_search@3x.png and /dev/null differ diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 29d4b0f47b..d90463c281 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -10,6 +10,22 @@ using "ui/basic.style"; using "boxes/boxes.style"; using "ui/widgets/widgets.style"; +TabbedSearch { + outer: color; + bg: color; + fg: color; + fgActive: color; + fadeLeft: icon; + fadeRight: icon; + field: InputField; + search: IconButton; + back: IconButton; + cancel: CrossButton; + defaultFieldWidth: pixels; + groupWidth: pixels; + height: pixels; +} + EmojiPan { margin: margins; padding: margins; @@ -28,6 +44,8 @@ EmojiPan { overBg: color; fadeLeft: icon; fadeRight: icon; + search: TabbedSearch; + searchMargin: margins; } switchPmButton: RoundButton(defaultBoxButton) { @@ -132,8 +150,7 @@ stickersTrendingUnread: icon { { "emoji/stickers_add_dot", dialogsUnreadBg } }; stickersRecent: icon {{ "emoji/emoji_recent", emojiIconFg }}; -stickersSearch: icon {{ "emoji/stickers_search", emojiIconFg }}; -stickersPremium: icon {{ "emoji/stickers_premium", emojiIconFg }}; +emojiStatusDefault: icon {{ "emoji/stickers_premium", emojiIconFg }}; stickersSettingsUnreadSize: 6px; stickersSettingsUnreadPosition: point(6px, 10px); @@ -145,27 +162,27 @@ filtersRemove: IconButton(stickersRemove) { emojiPanMargins: margins(10px, 10px, 10px, 10px); emojiTabs: SettingsSlider(defaultTabsSlider) { - height: 55px; - barTop: 52px; - labelTop: 19px; + height: 45px; + barTop: 42px; + labelTop: 13px; } emojiScroll: defaultSolidScroll; emojiRecent: icon {{ "emoji/emoji_recent", emojiIconFg }}; emojiRecentActive: icon {{ "emoji/emoji_recent", emojiSubIconFgActive }}; -emojiPeople: icon {{ "emoji/emoji_people", emojiIconFg }}; -emojiPeopleActive: icon {{ "emoji/emoji_people", emojiSubIconFgActive }}; +emojiPeople: icon {{ "emoji/emoji_smile", emojiIconFg }}; +emojiPeopleActive: icon {{ "emoji/emoji_smile", emojiSubIconFgActive }}; emojiNature: icon {{ "emoji/emoji_nature", emojiIconFg }}; emojiNatureActive: icon {{ "emoji/emoji_nature", emojiSubIconFgActive }}; emojiFood: icon {{ "emoji/emoji_food", emojiIconFg }}; emojiFoodActive: icon {{ "emoji/emoji_food", emojiSubIconFgActive }}; -emojiActivity: icon {{ "emoji/emoji_activity", emojiIconFg }}; -emojiActivityActive: icon {{ "emoji/emoji_activity", emojiSubIconFgActive }}; +emojiActivity: icon {{ "emoji/emoji_activities", emojiIconFg }}; +emojiActivityActive: icon {{ "emoji/emoji_activities", emojiSubIconFgActive }}; emojiTravel: icon {{ "emoji/emoji_travel", emojiIconFg }}; emojiTravelActive: icon {{ "emoji/emoji_travel", emojiSubIconFgActive }}; emojiObjects: icon {{ "emoji/emoji_objects", emojiIconFg }}; emojiObjectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }}; -emojiSymbols: icon {{ "emoji/emoji_symbols", emojiIconFg }}; -emojiSymbolsActive: icon {{ "emoji/emoji_symbols", emojiSubIconFgActive }}; +emojiSymbols: icon {{ "emoji/emoji_love", emojiIconFg }}; +emojiSymbolsActive: icon {{ "emoji/emoji_love", emojiSubIconFgActive }}; emojiCategoryIconTop: 6px; emojiPanAnimation: PanelAnimation(defaultPanelAnimation) { @@ -185,6 +202,37 @@ emojiPanLeft: 13px; emojiPanRight: 17px; emojiPanRadius: 8px; +defaultTabbedSearch: TabbedSearch { + outer: emojiPanBg; + bg: emojiPanCategories; + fg: emojiIconFg; + fgActive: emojiSubIconFgActive; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }}; + fadeRight: icon {{ "fade_horizontal", emojiPanCategories }}; + field: InputField(defaultMultiSelectSearchField) { + textMargins: margins(2px, 7px, 2px, 0px); + } + search: IconButton(defaultIconButton) { + width: 33px; + height: 33px; + icon: icon{{ "emoji/emoji_search_input", emojiIconFg }}; + iconOver: icon{{ "emoji/emoji_search_input", emojiIconFg }}; + iconPosition: point(12px, -1px); + ripple: emptyRippleAnimation; + } + back: IconButton(defaultIconButton) { + width: 33px; + height: 33px; + icon: icon{{ "emoji/emoji_back", menuIconFg }}; + iconOver: icon{{ "emoji/emoji_back", menuIconFg }}; + iconPosition: point(12px, -1px); + ripple: emptyRippleAnimation; + } + cancel: defaultMultiSelectSearchCancel; + defaultFieldWidth: 95px; + groupWidth: 30px; + height: 33px; +} defaultEmojiPan: EmojiPan { margin: margins(roundRadiusSmall, 0px, 14px, 0px); padding: margins(13px, 12px, 17px, 12px); @@ -203,6 +251,8 @@ defaultEmojiPan: EmojiPan { overBg: emojiPanHover; fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }}; fadeRight: icon {{ "fade_horizontal", emojiPanCategories }}; + search: defaultTabbedSearch; + searchMargin: margins(6px, 10px, 6px, 10px); } inlineResultsMinHeight: 278px; @@ -215,13 +265,6 @@ emojiColorsPadding: 5px; emojiColorsSep: 1px; emojiColorsSepColor: shadowFg; -emojiSwitchSkip: 27px; -emojiSwitchImgSkip: 21px; -emojiSwitchColor: windowActiveTextFg; -emojiSwitchStickers: icon {{ "emoji/emoji_switch", emojiSwitchColor }}; -emojiSwitchEmoji: icon {{ "emoji/emoji_switch-flip_horizontal", emojiSwitchColor }}; - -emojiIconPadding: 7px; emojiIconSelectSkip: 3px; emojiPremiumRequired: icon{{ "emoji/premium_lock", windowSubTextFg }}; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_keywords.cpp b/Telegram/SourceFiles/chat_helpers/emoji_keywords.cpp index fcb8bd8f7d..6840276246 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_keywords.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_keywords.cpp @@ -17,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_domain.h" #include "main/main_session.h" #include "apiwrap.h" +#include "core/application.h" +#include "core/core_settings.h" #include @@ -639,6 +641,52 @@ std::vector EmojiKeywords::query( return result; } +std::vector EmojiKeywords::queryMine( + const QString &query, + bool exact) const { + return ApplyVariants(PrioritizeRecent(this->query(query, exact))); +} + +std::vector EmojiKeywords::PrioritizeRecent( + std::vector list) { + using Entry = Result; + auto lastRecent = begin(list); + const auto &recent = Core::App().settings().recentEmoji(); + for (const auto &item : recent) { + const auto emoji = std::get_if(&item.id.data); + if (!emoji) { + continue; + } + const auto original = (*emoji)->original() + ? (*emoji)->original() + : (*emoji); + const auto it = ranges::find(list, original, [](const Entry &entry) { + return entry.emoji; + }); + if (it > lastRecent && it != end(list)) { + std::rotate(lastRecent, it, it + 1); + ++lastRecent; + } + } + return list; +} + +std::vector EmojiKeywords::ApplyVariants(std::vector list) { + for (auto &item : list) { + item.emoji = [&] { + const auto result = item.emoji; + const auto &variants = Core::App().settings().emojiVariants(); + const auto i = result->hasVariants() + ? variants.find(result->nonColoredId()) + : end(variants); + return (i != end(variants)) + ? result->variant(i->second) + : result; + }(); + } + return list; +} + int EmojiKeywords::maxQueryLength() const { if (_data.empty()) { return 0; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_keywords.h b/Telegram/SourceFiles/chat_helpers/emoji_keywords.h index 7c9509b86c..3df6c497db 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_keywords.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_keywords.h @@ -43,6 +43,9 @@ public: [[nodiscard]] std::vector query( const QString &query, bool exact = false) const; + [[nodiscard]] std::vector queryMine( + const QString &query, + bool exact = false) const; [[nodiscard]] int maxQueryLength() const; private: @@ -52,6 +55,11 @@ private: ApiWrap *api() override; void langPackRefreshed() override; + [[nodiscard]] static std::vector PrioritizeRecent( + std::vector list); + [[nodiscard]] static std::vector ApplyVariants( + std::vector list); + void handleSessionChanges(); void apiChanged(ApiWrap *api); void refreshInputLanguages(); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index f2fa2d760a..3a59f4fbff 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/emoji_list_widget.h" #include "base/unixtime.h" +#include "ui/controls/tabbed_search.h" #include "ui/text/format_values.h" #include "ui/effects/animations.h" #include "ui/widgets/buttons.h" @@ -23,11 +24,13 @@ 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" #include "data/stickers/data_stickers.h" #include "data/stickers/data_custom_emoji.h" +#include "chat_helpers/emoji_keywords.h" #include "chat_helpers/stickers_list_widget.h" #include "chat_helpers/stickers_list_footer.h" #include "emoji_suggestions_data.h" @@ -44,6 +47,8 @@ namespace { constexpr auto kCollapsedRows = 3; constexpr auto kAppearDuration = 0.3; +constexpr auto kPlainSearchLimit = 32; +constexpr auto kCustomSearchLimit = 256; using Core::RecentEmojiId; using Core::RecentEmojiDocument; @@ -402,6 +407,10 @@ EmojiListWidget::EmojiListWidget( setAttribute(Qt::WA_OpaquePaintEvent); } + if (_mode != Mode::RecentReactions) { + setupSearch(); + } + _customSingleSize = Data::FrameSizeFromTag( Data::CustomEmojiManager::SizeTag::Large ) / style::DevicePixelRatio(); @@ -457,6 +466,142 @@ EmojiListWidget::~EmojiListWidget() { base::take(_customEmoji); } +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() + }); + _search->queryValue( + ) | rpl::start_with_next([=](std::vector &&query) { + _nextSearchQuery = std::move(query); + InvokeQueued(this, [=] { + applyNextSearchQuery(); + }); + }, lifetime()); +} + +void EmojiListWidget::applyNextSearchQuery() { + if (_searchQuery == _nextSearchQuery) { + return; + } + _searchQuery = _nextSearchQuery; + std::swap(_searchEmoji, _searchEmojiPrevious); + _searchEmoji.clear(); + const auto finish = [&](bool searching = true) { + if (!_searchMode && !searching) { + return; + } + _searchMode = searching; + if (!searching) { + _searchResults.clear(); + _searchCustomIds.clear(); + } + clearSelection(); + resizeToWidth(width()); + update(); + }; + if (_searchQuery.empty()) { + finish(false); + return; + } + const auto guard = gsl::finally([&] { finish(); }); + auto plain = collectPlainSearchResults(); + if (_searchEmoji == _searchEmojiPrevious) { + return; + } + _searchResults.clear(); + _searchCustomIds.clear(); + if (_mode == Mode::EmojiStatus || session().premium()) { + appendPremiumSearchResults(); + } + if (_mode != Mode::EmojiStatus) { + for (const auto emoji : plain) { + _searchResults.push_back({ + .id = { emoji }, + }); + } + } +} + +std::vector EmojiListWidget::collectPlainSearchResults() { + auto result = std::vector(); + const auto pushPlain = [&](EmojiPtr emoji) { + if (result.size() < kPlainSearchLimit + && _searchEmoji.emplace(emoji).second) { + result.push_back(emoji); + } + if (const auto original = emoji->original(); original != emoji) { + _searchEmoji.emplace(original); + } + }; + auto refreshed = false; + auto &keywords = Core::App().emojiKeywords(); + for (const auto &entry : _searchQuery) { + if (const auto emoji = Ui::Emoji::Find(entry)) { + pushPlain(emoji); + if (result.size() >= kPlainSearchLimit) { + return result; + } + } else if (!entry.isEmpty()) { + if (!refreshed) { + refreshed = true; + keywords.refresh(); + } + const auto list = keywords.queryMine(entry); + for (const auto &entry : list) { + pushPlain(entry.emoji); + if (result.size() >= kPlainSearchLimit) { + return result; + } + } + } + } + return result; +} + +void EmojiListWidget::appendPremiumSearchResults() { + const auto test = session().isTestMode(); + auto &owner = session().data(); + const auto checkCustom = [&](EmojiPtr emoji, DocumentId id) { + return emoji + && _searchEmoji.contains(emoji) + && (_searchResults.size() < kCustomSearchLimit) + && _searchCustomIds.emplace(id).second; + }; + for (const auto &recent : _recent) { + if (!recent.custom) { + continue; + } + const auto &idData = recent.id.data; + const auto id = std::get_if(&idData); + if (!id || id->test != test) { + continue; + } + const auto sticker = owner.document(id->id)->sticker(); + const auto emoji = sticker + ? Ui::Emoji::Find(sticker->alt) + : nullptr; + if (checkCustom(emoji, id->id)) { + _searchResults.push_back(recent); + } + } + for (const auto &set : _custom) { + for (const auto &one : set.list) { + const auto id = one.document->id; + if (checkCustom(one.emoji, id)) { + _searchResults.push_back({ + .custom = one.custom, + .id = { RecentEmojiDocument{ .id = id, .test = test } }, + }); + } + } + } +} + void EmojiListWidget::provideRecent( const std::vector &customRecentList) { clearSelection(); @@ -468,6 +613,13 @@ void EmojiListWidget::repaintCustom(uint64 setId) { if (!_repaintsScheduled.emplace(setId).second) { return; } + const auto repaintSearch = (setId == SearchEmojiSectionSetId()); + if (_searchMode) { + if (repaintSearch) { + update(); + } + return; + } const auto repaintRecent = (setId == RecentEmojiSectionSetId()); enumerateSections([&](const SectionInfo &info) { const auto repaint1 = repaintRecent @@ -600,7 +752,7 @@ bool EmojiListWidget::enumerateSections(Callback callback) const { ? kCollapsedRows : (info.count + _columnCount - 1) / _columnCount; info.rowsTop = info.top - + (i == 0 ? st().padding.top() : st().header); + + (i == 0 ? _rowsTop : st().header); info.rowsBottom = info.rowsTop + (info.rowsCount * _singleSize.height()) + st::roundRadiusSmall; @@ -610,6 +762,11 @@ bool EmojiListWidget::enumerateSections(Callback callback) const { info.top = info.rowsBottom; return true; }; + if (_searchMode) { + info.section = i; + info.count = _searchResults.size(); + return next(); + } for (; i != _staticCount; ++i) { info.section = i; info.count = i ? _counts[i] : _recent.size(); @@ -660,7 +817,7 @@ EmojiListWidget::SectionInfo EmojiListWidget::sectionInfoByOffset( } int EmojiListWidget::sectionsCount() const { - return _staticCount + int(_custom.size()); + return _searchMode ? 1 : (_staticCount + int(_custom.size())); } void EmojiListWidget::setSingleSize(QSize size) { @@ -686,6 +843,7 @@ int EmojiListWidget::countDesiredHeight(int newWidth) { const auto innerWidth = fullWidth - padding.left() - padding.right(); _columnCount = std::max(innerWidth / st().desiredSize, 1); const auto singleWidth = innerWidth / _columnCount; + _rowsTop = _search ? _search->height() : padding.top(); _rowsLeft = padding.left() + (innerWidth - _columnCount * singleWidth) / 2 - st().margin.left(); @@ -698,9 +856,12 @@ int EmojiListWidget::countDesiredHeight(int newWidth) { return info.top + qMax(info.rowsBottom - info.top, minimalLastHeight); }; - const auto minimalLastHeight = minimalHeight; - return qMax(minimalHeight, countResult(minimalLastHeight)) - + padding.bottom(); + const auto minimalLastHeight = std::max( + minimalHeight - padding.bottom(), + 0); + return qMax( + minimalHeight, + countResult(minimalLastHeight) + padding.bottom()); } int EmojiListWidget::defaultMinimalHeight() const { @@ -953,7 +1114,7 @@ void EmojiListWidget::paint( ); const auto w = position + _areaPosition; if (context.expanding) { - const auto y = (position.y() - st().padding.top()); + const auto y = (position.y() - _rowsTop); const auto x = (position.x() - _rowsLeft); const auto sum = y + std::max(std::min(y, width()) - x, 0); @@ -981,8 +1142,10 @@ void EmojiListWidget::paint( } _overBg.paint(p, QRect(tl, st::emojiPanArea)); } - if (info.section == int(Section::Recent)) { - drawRecent(p, context, w, index); + if (_searchMode) { + drawRecent(p, context, w, _searchResults[index]); + } else if (info.section == int(Section::Recent)) { + drawRecent(p, context, w, _recent[index]); } else if (info.section < _staticCount) { drawEmoji(p, context, w, _emoji[info.section][index]); } else { @@ -1020,9 +1183,8 @@ void EmojiListWidget::drawRecent( QPainter &p, const ExpandingContext &context, QPoint position, - int index) { + const RecentOne &recent) { _recentPainted = true; - auto &recent = _recent[index]; if (const auto custom = recent.custom) { _emojiPaintContext->scale = context.progress; _emojiPaintContext->position = position @@ -1032,8 +1194,8 @@ void EmojiListWidget::drawRecent( } else if (const auto emoji = std::get_if(&recent.id.data)) { if (_mode == Mode::EmojiStatus) { position += QPoint( - (_singleSize.width() - st::stickersPremium.width()) / 2, - (_singleSize.height() - st::stickersPremium.height()) / 2 + (_singleSize.width() - st::emojiStatusDefault.width()) / 2, + (_singleSize.height() - st::emojiStatusDefault.height()) / 2 ) - _areaPosition; p.drawImage(position, _premiumIcon->image()); } else { @@ -1087,7 +1249,16 @@ bool EmojiListWidget::checkPickerHide() { DocumentData *EmojiListWidget::lookupCustomEmoji( int index, int section) const { - if (section == int(Section::Recent) && index < _recent.size()) { + if (_searchMode) { + if (index < _searchResults.size()) { + const auto document = std::get_if( + &_searchResults[index].id.data); + if (document) { + return session().data().document(document->id); + } + } + return nullptr; + } else if (section == int(Section::Recent) && index < _recent.size()) { const auto document = std::get_if( &_recent[index].id.data); if (document) { @@ -1104,9 +1275,14 @@ DocumentData *EmojiListWidget::lookupCustomEmoji( EmojiPtr EmojiListWidget::lookupOverEmoji(const OverEmoji *over) const { const auto section = over ? over->section : -1; const auto index = over ? over->index : -1; - return (section == int(Section::Recent) - && index < _recent.size() - && v::is(_recent[index].id.data)) + return _searchMode + ? ((index < _searchResults.size() + && v::is(_searchResults[index].id.data)) + ? v::get(_searchResults[index].id.data) + : nullptr) + : (section == int(Section::Recent) + && index < _recent.size() + && v::is(_recent[index].id.data)) ? v::get(_recent[index].id.data) : (section > int(Section::Recent) && section < _staticCount @@ -1119,9 +1295,10 @@ EmojiChosen EmojiListWidget::lookupChosen( EmojiPtr emoji, not_null over) { const auto rect = emojiRect(over->section, over->index); + const auto size = st::emojiStatusDefault.size(); const auto icon = QRect( - rect.x() + (_singleSize.width() - st::stickersPremium.width()) / 2, - rect.y() + (_singleSize.height() - st::stickersPremium.height()) / 2, + rect.x() + (_singleSize.width() - size.width()) / 2, + rect.y() + (_singleSize.height() - size.height()) / 2, rect.width(), rect.height()); return { @@ -1622,10 +1799,11 @@ void EmojiListWidget::refreshCustom() { auto set = std::vector(); set.reserve(list.size()); for (const auto document : list) { - if (document->sticker()) { + if (const auto sticker = document->sticker()) { set.push_back({ .custom = resolveCustomEmoji(document, setId), .document = document, + .emoji = Ui::Emoji::Find(sticker->alt), }); if (!premium && document->isPremiumEmoji()) { premium = true; @@ -1668,6 +1846,9 @@ Fn EmojiListWidget::repaintCallback( if (_recentCustomIds.contains(documentId)) { repaintCustom(RecentEmojiSectionSetId()); } + if (_searchCustomIds.contains(documentId)) { + repaintCustom(SearchEmojiSectionSetId()); + } }; } diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h index 83a4eaa5bc..f33eda32d3 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h @@ -31,6 +31,7 @@ struct phrase; namespace Ui { class RippleAnimation; +class TabbedSearch; } // namespace Ui namespace Ui::Emoji { @@ -162,6 +163,7 @@ private: struct CustomOne { not_null custom; not_null document; + EmojiPtr emoji = nullptr; }; struct CustomSet { uint64 id = 0; @@ -243,6 +245,9 @@ private: void unloadAllCustom(); void unloadCustomIn(const SectionInfo &info); + void setupSearch(); + [[nodiscard]] std::vector collectPlainSearchResults(); + void appendPremiumSearchResults(); void ensureLoaded(int section); void updateSelected(); void setSelected(OverState newSelected); @@ -267,7 +272,7 @@ private: QPainter &p, const ExpandingContext &context, QPoint position, - int index); + const RecentOne &recent); void drawEmoji( QPainter &p, const ExpandingContext &context, @@ -307,7 +312,6 @@ private: void displaySet(uint64 setId); void removeSet(uint64 setId); - void refreshColoredStatuses(); void initButton(RightButton &button, const QString &text, bool gradient); [[nodiscard]] std::unique_ptr createButtonRipple( int section); @@ -328,8 +332,11 @@ private: DocumentId documentId, uint64 setId); + void applyNextSearchQuery(); + Window::SessionController *_controller = nullptr; Mode _mode = Mode::Full; + std::unique_ptr _search; const int _staticCount = 0; StickersListFooter *_footer = nullptr; std::unique_ptr _premiumIcon; @@ -355,6 +362,15 @@ private: bool _allowWithoutPremium = false; Ui::RoundRect _overBg; + std::vector _nextSearchQuery; + std::vector _searchQuery; + base::flat_set _searchEmoji; + base::flat_set _searchEmojiPrevious; + base::flat_set _searchCustomIds; + std::vector _searchResults; + bool _searchMode = false; + + int _rowsTop = 0; int _rowsLeft = 0; int _columnCount = 1; QSize _singleSize; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp index 26e40142e1..b74e377087 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp @@ -213,49 +213,13 @@ auto SuggestionsWidget::getRowsByQuery(const QString &text) const return ranges::none_of(text, [](QChar ch) { return ch.isLower(); }); }(); const auto exact = !middle || simple; - const auto list = Core::App().emojiKeywords().query(real, exact); - if (list.empty()) { - return {}; - } + const auto list = Core::App().emojiKeywords().queryMine(real, exact); using Entry = ChatHelpers::EmojiKeywords::Result; - auto result = ranges::views::all( + return ranges::views::all( list ) | ranges::views::transform([](const Entry &result) { return Row(result.emoji, result.replacement); }) | ranges::to_vector; - - auto lastRecent = begin(result); - const auto &recent = Core::App().settings().recentEmoji(); - for (const auto &item : recent) { - const auto emoji = std::get_if(&item.id.data); - if (!emoji) { - continue; - } - const auto original = (*emoji)->original() - ? (*emoji)->original() - : (*emoji); - const auto it = ranges::find(result, original, [](const Row &row) { - return row.emoji.get(); - }); - if (it > lastRecent && it != end(result)) { - std::rotate(lastRecent, it, it + 1); - ++lastRecent; - } - } - - for (auto &item : result) { - item.emoji = [&] { - const auto result = item.emoji; - const auto &variants = Core::App().settings().emojiVariants(); - const auto i = result->hasVariants() - ? variants.find(result->nonColoredId()) - : end(variants); - return (i != end(variants)) - ? result->variant(i->second) - : result.get(); - }(); - } - return result; } void SuggestionsWidget::resizeToRows() { diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 5d5a3b7f31..3546573236 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -322,11 +322,9 @@ void InitMessageFieldHandlers( const style::InputField *fieldStyle) { field->setTagMimeProcessor( FieldTagMimeProcessor(session, allowPremiumEmoji)); - field->setCustomEmojiFactory([=](QStringView data, Fn update) { - return session->data().customEmojiManager().create( - data, - std::move(update)); - }, std::move(customEmojiPaused)); + field->setCustomEmojiFactory( + session->data().customEmojiManager().factory(), + std::move(customEmojiPaused)); field->setInstantReplaces(Ui::InstantReplaces::Default()); field->setInstantReplacesEnabled( Core::App().settings().replaceEmojiValue()); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp index 7f810ac3b3..24e610c2f9 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp @@ -71,6 +71,12 @@ uint64 AllEmojiSectionSetId() { return kEmojiSectionSetIdBase; } +uint64 SearchEmojiSectionSetId() { + return kEmojiSectionSetIdBase + + static_cast(EmojiSection::Symbols) + + 2; +} + std::optional SetIdEmojiSection(uint64 id) { const auto base = RecentEmojiSectionSetId(); if (id < base) { @@ -161,8 +167,8 @@ QImage GradientPremiumStar::image() const { } void GradientPremiumStar::renderOnDemand() const { - const auto size = st::stickersPremium.size(); - const auto mask = st::stickersPremium.instance(Qt::white); + const auto size = st::emojiStatusDefault.size(); + const auto mask = st::emojiStatusDefault.instance(Qt::white); const auto factor = style::DevicePixelRatio(); _image = QImage( size * factor, @@ -188,7 +194,6 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor) descriptor.st ? *descriptor.st : st::defaultEmojiPan) , _session(descriptor.session) , _paused(descriptor.paused) -, _searchButtonVisible(descriptor.searchButtonVisible) , _settingsButtonVisible(descriptor.settingsButtonVisible) , _iconState([=] { update(); }) , _subiconState([=] { update(); }) @@ -197,9 +202,7 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor) , _barSelection(descriptor.barSelection) { setMouseTracking(true); - _iconsLeft = st().iconSkip + (_searchButtonVisible - ? st::stickerIconWidth - : 0); + _iconsLeft = st().iconSkip; _iconsRight = st().iconSkip + (_settingsButtonVisible ? st::stickerIconWidth : 0); @@ -568,9 +571,6 @@ void StickersListFooter::paintEvent(QPaintEvent *e) { void StickersListFooter::paint( Painter &p, const ExpandingContext &context) const { - if (_searchButtonVisible) { - paintSearchIcon(p); - } if (_icons.empty() || _searchShown) { return; } @@ -751,8 +751,6 @@ void StickersListFooter::mousePressEvent(QMouseEvent *e) { if (_selected == SpecialOver::Settings) { _openSettingsRequests.fire({}); - } else if (_selected == SpecialOver::Search) { - toggleSearch(true); } else { _pressed = _selected; _iconsMouseDown = _iconsMousePos; @@ -940,13 +938,7 @@ void StickersListFooter::updateSelected() { const auto settingsLeft = width() - _iconsRight; const auto searchLeft = _iconsLeft - _singleWidth; auto newOver = OverState(SpecialOver::None); - if (_searchButtonVisible - && x >= searchLeft - && x < searchLeft + _singleWidth - && y >= _iconsTop - && y < _iconsTop + st().footer) { - newOver = SpecialOver::Search; - } else if (_settingsButtonVisible + if (_settingsButtonVisible && x >= settingsLeft && x < settingsLeft + _singleWidth && y >= _iconsTop @@ -1115,15 +1107,6 @@ void StickersListFooter::paintStickerSettingsIcon(QPainter &p) const { width()); } -void StickersListFooter::paintSearchIcon(QPainter &p) const { - const auto searchLeft = _iconsLeft - _singleWidth; - st::stickersSearch.paint( - p, - searchLeft + (_singleWidth - st::stickersSearch.width()) / 2, - _iconsTop + st::emojiCategoryIconTop, - width()); -} - void StickersListFooter::customEmojiRepaint() { if (!_repaintScheduled) { _repaintScheduled = true; @@ -1309,7 +1292,7 @@ void StickersListFooter::paintSetIcon( width(), st::stickerGroupCategorySize); } else if (icon.setId == Data::Stickers::PremiumSetId) { - const auto size = st::stickersPremium.size(); + const auto size = st::emojiStatusDefault.size(); p.drawImage( info.adjustedLeft + (_singleWidth - size.width()) / 2, _iconsTop + (st().footer - size.height()) / 2, diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h index 78448a9cdb..29248b9938 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h @@ -48,6 +48,7 @@ enum class ValidateIconAnimations { [[nodiscard]] uint64 EmojiSectionSetId(Ui::Emoji::Section section); [[nodiscard]] uint64 RecentEmojiSectionSetId(); [[nodiscard]] uint64 AllEmojiSectionSetId(); +[[nodiscard]] uint64 SearchEmojiSectionSetId(); [[nodiscard]] std::optional SetIdEmojiSection(uint64 id); struct StickerIcon { @@ -99,7 +100,6 @@ public: not_null session; Fn paused; not_null parent; - bool searchButtonVisible = false; bool settingsButtonVisible = false; bool barSelection = false; const style::EmojiPan *st = nullptr; @@ -153,7 +153,6 @@ protected: private: enum class SpecialOver { None, - Search, Settings, }; struct IconId { @@ -227,7 +226,6 @@ private: void paint(Painter &p, const ExpandingContext &context) const; void paintStickerSettingsIcon(QPainter &p) const; - void paintSearchIcon(QPainter &p) const; void paintSetIcon( Painter &p, const ExpandingContext &context, @@ -254,7 +252,6 @@ private: const not_null _session; const Fn _paused; - const bool _searchButtonVisible = false; const bool _settingsButtonVisible = false; static constexpr auto kVisibleIconsCount = 8; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index 9f059c9a9b..900a6a95df 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -264,7 +264,6 @@ object_ptr StickersListWidget::createFooter() { .session = &session(), .paused = pausedMethod(), .parent = this, - .searchButtonVisible = !_isMasks, .settingsButtonVisible = true, .barSelection = true, }); diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index 8da279f6cd..09817f9acd 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -1020,7 +1020,7 @@ void TabbedSelector::fillTabsSliderSections() { return tr::lng_switch_masks; } Unexpected("SelectorTab value in fillTabsSliderSections."); - }()(tr::now).toUpper(); + }()(tr::now); }) | ranges::to_vector; _tabsSlider->setSections(sections); } diff --git a/Telegram/SourceFiles/data/data_emoji_statuses.cpp b/Telegram/SourceFiles/data/data_emoji_statuses.cpp index 6000145d06..cf0ac3040e 100644 --- a/Telegram/SourceFiles/data/data_emoji_statuses.cpp +++ b/Telegram/SourceFiles/data/data_emoji_statuses.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer_rpl.h" #include "base/call_delayed.h" #include "apiwrap.h" +#include "ui/controls/tabbed_search.h" namespace Data { namespace { @@ -126,6 +127,70 @@ void EmojiStatuses::registerAutomaticClear( } } +auto EmojiStatuses::emojiGroupsValue() const -> rpl::producer { + const_cast(this)->requestEmojiGroups(); + return _emojiGroups.data.value(); +} + +auto EmojiStatuses::statusGroupsValue() const -> rpl::producer { + const_cast(this)->requestStatusGroups(); + return _statusGroups.data.value(); +} + +void EmojiStatuses::requestEmojiGroups() { + requestGroups( + &_emojiGroups, + MTPmessages_GetEmojiGroups(MTP_int(_emojiGroups.hash))); + +} + +void EmojiStatuses::requestStatusGroups() { + requestGroups( + &_statusGroups, + MTPmessages_GetEmojiStatusGroups(MTP_int(_statusGroups.hash))); +} + +[[nodiscard]] std::vector GroupsFromTL( + const MTPDmessages_emojiGroups &data) { + const auto &list = data.vgroups().v; + auto result = std::vector(); + result.reserve(list.size()); + for (const auto &group : list) { + const auto &data = group.data(); + auto emoticons = ranges::views::all( + data.vemoticons().v + ) | ranges::view::transform([](const MTPstring &emoticon) { + return qs(emoticon); + }) | ranges::to_vector; + result.push_back({ + .iconId = QString::number(data.vicon_emoji_id().v), + .emoticons = std::move(emoticons), + }); + } + return result; +} + +template +void EmojiStatuses::requestGroups( + not_null type, + Request &&request) { + if (type->requestId) { + return; + } + type->requestId = _owner->session().api().request( + std::forward(request) + ).done([=](const MTPmessages_EmojiGroups &result) { + type->requestId = 0; + result.match([&](const MTPDmessages_emojiGroups &data) { + type->hash = data.vhash().v; + type->data = GroupsFromTL(data); + }, [](const MTPDmessages_emojiGroupsNotModified&) { + }); + }).fail([=] { + type->requestId = 0; + }).send(); +} + void EmojiStatuses::processClearing() { auto minWait = TimeId(0); const auto now = base::unixtime::now(); diff --git a/Telegram/SourceFiles/data/data_emoji_statuses.h b/Telegram/SourceFiles/data/data_emoji_statuses.h index 26f9f716d1..c44678785b 100644 --- a/Telegram/SourceFiles/data/data_emoji_statuses.h +++ b/Telegram/SourceFiles/data/data_emoji_statuses.h @@ -13,6 +13,10 @@ namespace Main { class Session; } // namespace Main +namespace Ui { +struct EmojiGroup; +} // namespace Ui + namespace Data { class DocumentMedia; @@ -49,7 +53,19 @@ public: void registerAutomaticClear(not_null user, TimeId until); + using Groups = std::vector; + [[nodiscard]] rpl::producer emojiGroupsValue() const; + [[nodiscard]] rpl::producer statusGroupsValue() const; + void requestEmojiGroups(); + void requestStatusGroups(); + private: + struct GroupsType { + rpl::variable data; + mtpRequestId requestId = 0; + int32 hash = 0; + }; + void requestRecent(); void requestDefault(); void requestColored(); @@ -61,6 +77,9 @@ private: void processClearingIn(TimeId wait); void processClearing(); + template + void requestGroups(not_null type, Request &&request); + const not_null _owner; std::vector _recent; @@ -84,6 +103,9 @@ private: base::flat_map, TimeId> _clearing; base::Timer _clearingTimer; + GroupsType _emojiGroups; + GroupsType _statusGroups; + rpl::lifetime _lifetime; }; diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp index f115937efd..30cd36fbfe 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp @@ -474,6 +474,14 @@ std::unique_ptr CustomEmojiManager::create( std::move(update)); } +Ui::Text::CustomEmojiFactory CustomEmojiManager::factory( + SizeTag tag, + int sizeOverride) { + return [=](QStringView data, Fn update) { + return create(data, std::move(update), tag, sizeOverride); + }; +} + Ui::CustomEmoji::Preview CustomEmojiManager::prepareNonExactPreview( DocumentId documentId, SizeTag tag, diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h index 15d5166719..4618340dab 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h @@ -52,6 +52,10 @@ public: SizeTag tag = SizeTag::Normal, int sizeOverride = 0); + [[nodiscard]] Ui::Text::CustomEmojiFactory factory( + SizeTag tag = SizeTag::Normal, + int sizeOverride = 0); + class Listener { public: virtual void customEmojiResolveDone( diff --git a/Telegram/SourceFiles/ui/controls/tabbed_search.cpp b/Telegram/SourceFiles/ui/controls/tabbed_search.cpp new file mode 100644 index 0000000000..fccc891f46 --- /dev/null +++ b/Telegram/SourceFiles/ui/controls/tabbed_search.cpp @@ -0,0 +1,419 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "ui/controls/tabbed_search.h" + +#include "lang/lang_keys.h" +#include "ui/widgets/input_fields.h" +#include "ui/wrap/fade_wrap.h" +#include "ui/widgets/buttons.h" +#include "ui/painter.h" +#include "ui/rect.h" +#include "styles/style_chat_helpers.h" + +namespace Ui { +namespace { + +constexpr auto kDebounceTimeout = crl::time(400); + +class GroupsStrip final : public RpWidget { +public: + GroupsStrip( + QWidget *parent, + const style::TabbedSearch &st, + rpl::producer> groups, + Text::CustomEmojiFactory factory); + + [[nodiscard]] rpl::producer chosen() const; + void clearChosen(); + +private: + struct Button { + EmojiGroup group; + QString iconId; + std::unique_ptr icon; + }; + + void init(rpl::producer> groups); + void set(std::vector list); + + void paintEvent(QPaintEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + + static inline auto FindById(auto &&buttons, QStringView id) { + return ranges::find(buttons, id, &Button::iconId); + } + + const style::TabbedSearch &_st; + const Text::CustomEmojiFactory _factory; + + std::vector