diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 5c559e8a5..3ed0b31c8 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -348,6 +348,7 @@ PRIVATE calls/calls_video_bubble.h calls/calls_video_incoming.cpp calls/calls_video_incoming.h + chat_helpers/compose/compose_features.h chat_helpers/compose/compose_show.cpp chat_helpers/compose/compose_show.h chat_helpers/bot_command.cpp diff --git a/Telegram/Resources/icons/emoji/stickers_add.png b/Telegram/Resources/icons/emoji/stickers_add.png deleted file mode 100644 index d4c77a202..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_add@2x.png b/Telegram/Resources/icons/emoji/stickers_add@2x.png deleted file mode 100644 index f188f440d..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_add@3x.png b/Telegram/Resources/icons/emoji/stickers_add@3x.png deleted file mode 100644 index 48de8115e..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add@3x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot.png b/Telegram/Resources/icons/emoji/stickers_add_dot.png deleted file mode 100644 index 1bb4078f4..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png b/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png deleted file mode 100644 index 1723a7f36..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png b/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png deleted file mode 100644 index ce7f1aa76..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add_dot@3x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread.png b/Telegram/Resources/icons/emoji/stickers_add_unread.png deleted file mode 100644 index d8172e22b..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png b/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png deleted file mode 100644 index c48562529..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread@2x.png and /dev/null differ diff --git a/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png b/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png deleted file mode 100644 index 46a03b994..000000000 Binary files a/Telegram/Resources/icons/emoji/stickers_add_unread@3x.png and /dev/null differ diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index 0f661181a..82e4e3deb 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -606,6 +606,7 @@ void StickerSetBox::updateButtons() { const auto session = &_show->session(); auto box = ChatHelpers::MakeConfirmRemoveSetBox( session, + st::boxLabel, _inner->setId()); if (box) { _show->showBox(std::move(box)); diff --git a/Telegram/SourceFiles/boxes/translate_box.cpp b/Telegram/SourceFiles/boxes/translate_box.cpp index 662cf51e5..066ba855b 100644 --- a/Telegram/SourceFiles/boxes/translate_box.cpp +++ b/Telegram/SourceFiles/boxes/translate_box.cpp @@ -63,7 +63,7 @@ ShowButton::ShowButton(not_null parent) _button.sizeValue( ) | rpl::start_with_next([=](const QSize &s) { resize( - s.width() + st::emojiSuggestionsFadeRight.width(), + s.width() + st::defaultEmojiSuggestions.fadeRight.width(), s.height()); _button.moveToRight(0, 0); }, lifetime()); @@ -74,7 +74,7 @@ void ShowButton::paintEvent(QPaintEvent *e) { auto p = QPainter(this); const auto clip = e->rect(); - const auto &icon = st::emojiSuggestionsFadeRight; + const auto &icon = st::defaultEmojiSuggestions.fadeRight; const auto fade = QRect(0, 0, icon.width(), height()); if (fade.intersects(clip)) { icon.fill(p, fade); diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index ceec7e3ec..ba786876f 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -10,6 +10,7 @@ using "ui/basic.style"; using "boxes/boxes.style"; using "ui/layers/layers.style"; using "ui/widgets/widgets.style"; +using "ui/menu_icons.style"; GroupCallUserpics { size: pixels; @@ -36,9 +37,50 @@ TabbedSearch { height: pixels; } +ComposeIcons { + settings: icon; + + recent: icon; + recentActive: icon; + people: icon; + peopleActive: icon; + nature: icon; + natureActive: icon; + food: icon; + foodActive: icon; + activity: icon; + activityActive: icon; + travel: icon; + travelActive: icon; + objects: icon; + objectsActive: icon; + symbols: icon; + symbolsActive: icon; + + menuFave: icon; + menuUnfave: icon; + menuStickerSet: icon; + menuRecentRemove: icon; + menuGifAdd: icon; + menuGifRemove: icon; + menuMute: icon; + menuSchedule: icon; + menuWhenOnline: icon; +} + +EmojiSuggestions { + dropdown: InnerDropdown; + bg: color; + overBg: color; + textFg: color; + fadeLeft: icon; + fadeRight: icon; +} + EmojiPan { margin: margins; padding: margins; + showAnimation: PanelAnimation; desiredSize: pixels; verticalSizeSub: pixels; header: pixels; @@ -51,8 +93,12 @@ EmojiPan { iconWidth: pixels; iconArea: pixels; bg: color; + headerFg: color; + trendingHeaderFg: color; + trendingSubheaderFg: color; + trendingUnreadFg: color; + trendingInstalled: icon; overBg: color; - expandBg: color; pathBg: color; pathFg: color; textFg: color; @@ -60,9 +106,14 @@ EmojiPan { categoriesBgOver: color; fadeLeft: icon; fadeRight: icon; + menu: PopupMenu; tabs: SettingsSlider; search: TabbedSearch; searchMargin: margins; + removeSet: IconButton; + boxLabel: FlatLabel; + icons: ComposeIcons; + autocompleteBottomSkip: pixels; } MessageBar { @@ -96,6 +147,7 @@ ComposeControls { send: SendButton; attach: IconButton; emoji: EmojiButton; + suggestions: EmojiSuggestions; tabbed: EmojiPan; } @@ -191,12 +243,6 @@ stickersScroll: ScrollArea(boxScroll) { stickersRowDisabledOpacity: 0.4; stickersRowDuration: 200; -stickersSettings: icon {{ "emoji/emoji_settings", emojiIconFg }}; -stickersTrending: icon {{ "emoji/stickers_add", emojiIconFg }}; -stickersTrendingUnread: icon { - { "emoji/stickers_add_unread", emojiIconFg }, - { "emoji/stickers_add_dot", dialogsUnreadBg } -}; emojiStatusDefault: icon {{ "emoji/stickers_premium", emojiIconFg }}; filtersRemove: IconButton(stickersRemove) { @@ -210,22 +256,6 @@ emojiTabs: SettingsSlider(defaultTabsSlider) { barTop: 40px; labelTop: 12px; } -emojiRecent: icon {{ "emoji/emoji_recent", emojiIconFg }}; -emojiRecentActive: icon {{ "emoji/emoji_recent", 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_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_love", emojiIconFg }}; -emojiSymbolsActive: icon {{ "emoji/emoji_love", emojiSubIconFgActive }}; emojiCategoryIconTop: 6px; emojiPanAnimation: PanelAnimation(defaultPanelAnimation) { @@ -297,40 +327,6 @@ defaultTabbedSearch: TabbedSearch { groupSkip: 2px; height: 33px; } -defaultEmojiPan: EmojiPan { - margin: margins(7px, 0px, 7px, 0px); - padding: margins(7px, 0px, 4px, 7px); - desiredSize: 37px; - verticalSizeSub: 1px; - header: 33px; - headerLeft: 14px; - headerLockLeft: 7px; - headerLockedLeft: 26px; - headerTop: 10px; - footer: 36px; - iconSkip: 3px; - iconWidth: 30px; - iconArea: 28px; - bg: emojiPanBg; - overBg: emojiPanHover; - expandBg: emojiPanHeaderFg; - pathBg: windowBgRipple; - pathFg: windowBgOver; - textFg: windowFg; - categoriesBg: emojiPanCategories; - categoriesBgOver: windowBgRipple; - fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }}; - fadeRight: icon {{ "fade_horizontal", emojiPanCategories }}; - tabs: emojiTabs; - search: defaultTabbedSearch; - searchMargin: margins(1px, 11px, 2px, 5px); -} -statusEmojiPan: EmojiPan(defaultEmojiPan) { - categoriesBg: windowBg; - categoriesBgOver: windowBgOver; - fadeLeft: icon {{ "fade_horizontal-flip_horizontal", windowBg }}; - fadeRight: icon {{ "fade_horizontal", windowBg }}; -} inlineResultsMinHeight: 278px; inlineResultsMaxHeight: 640px; @@ -394,6 +390,81 @@ stickersToast: Toast(defaultToast) { stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }}; emojiEmpty: icon {{ "emoji_empty", windowSubTextFg }}; +defaultComposeIcons: ComposeIcons { + settings: icon {{ "emoji/emoji_settings", emojiIconFg }}; + + recent: icon {{ "emoji/emoji_recent", emojiIconFg }}; + recentActive: icon {{ "emoji/emoji_recent", emojiSubIconFgActive }}; + people: icon {{ "emoji/emoji_smile", emojiIconFg }}; + peopleActive: icon {{ "emoji/emoji_smile", emojiSubIconFgActive }}; + nature: icon {{ "emoji/emoji_nature", emojiIconFg }}; + natureActive: icon {{ "emoji/emoji_nature", emojiSubIconFgActive }}; + food: icon {{ "emoji/emoji_food", emojiIconFg }}; + foodActive: icon {{ "emoji/emoji_food", emojiSubIconFgActive }}; + activity: icon {{ "emoji/emoji_activities", emojiIconFg }}; + activityActive: icon {{ "emoji/emoji_activities", emojiSubIconFgActive }}; + travel: icon {{ "emoji/emoji_travel", emojiIconFg }}; + travelActive: icon {{ "emoji/emoji_travel", emojiSubIconFgActive }}; + objects: icon {{ "emoji/emoji_objects", emojiIconFg }}; + objectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }}; + symbols: icon {{ "emoji/emoji_love", emojiIconFg }}; + symbolsActive: icon {{ "emoji/emoji_love", emojiSubIconFgActive }}; + + menuFave: menuIconFave; + menuUnfave: menuIconUnfave; + menuStickerSet: menuIconStickers; + menuRecentRemove: menuIconDelete; + menuGifAdd: menuIconGif; + menuGifRemove: menuIconDelete; + menuMute: menuIconMute; + menuSchedule: menuIconSchedule; + menuWhenOnline: menuIconWhenOnline; +} +defaultEmojiPan: EmojiPan { + margin: margins(7px, 0px, 7px, 0px); + padding: margins(7px, 0px, 4px, 7px); + showAnimation: emojiPanAnimation; + desiredSize: 37px; + verticalSizeSub: 1px; + header: 33px; + headerLeft: 14px; + headerLockLeft: 7px; + headerLockedLeft: 26px; + headerTop: 10px; + footer: 36px; + iconSkip: 3px; + iconWidth: 30px; + iconArea: 28px; + bg: emojiPanBg; + headerFg: emojiPanHeaderFg; + trendingHeaderFg: stickersTrendingHeaderFg; + trendingSubheaderFg: stickersTrendingSubheaderFg; + trendingUnreadFg: stickersFeaturedUnreadBg; + trendingInstalled: stickersFeaturedInstalled; + overBg: emojiPanHover; + pathBg: windowBgRipple; + pathFg: windowBgOver; + textFg: windowFg; + categoriesBg: emojiPanCategories; + categoriesBgOver: windowBgRipple; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }}; + fadeRight: icon {{ "fade_horizontal", emojiPanCategories }}; + menu: popupMenuWithIcons; + tabs: emojiTabs; + search: defaultTabbedSearch; + searchMargin: margins(1px, 11px, 2px, 5px); + removeSet: stickerPanRemoveSet; + boxLabel: boxLabel; + icons: defaultComposeIcons; + autocompleteBottomSkip: 0px; +} +statusEmojiPan: EmojiPan(defaultEmojiPan) { + categoriesBg: windowBg; + categoriesBgOver: windowBgOver; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", windowBg }}; + fadeRight: icon {{ "fade_horizontal", windowBg }}; +} + inlineBotsScroll: ScrollArea(defaultSolidScroll) { deltat: stickerPanPadding; deltab: stickerPanPadding; @@ -410,6 +481,15 @@ emojiSuggestionsScrolledWidth: 240px; emojiSuggestionsPadding: margins(emojiColorsPadding, 0px, emojiColorsPadding, 0px); emojiSuggestionsFadeAfter: 20px; +defaultEmojiSuggestions: EmojiSuggestions { + dropdown: emojiSuggestionsDropdown; + bg: menuBg; + overBg: emojiPanHover; + textFg: windowFg; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }}; + fadeRight: icon {{ "fade_horizontal", boxBg }}; +} + mentionHeight: 40px; mentionPadding: margins(8px, 5px, 8px, 5px); mentionTop: 11px; @@ -479,9 +559,6 @@ reactPanelScroll: ScrollArea(emojiScroll) { deltab: 7px; } -emojiSuggestionsFadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }}; -emojiSuggestionsFadeRight: icon {{ "fade_horizontal", boxBg }}; - choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }}; choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }}; choosePeerCreateIconLeft: 25px; @@ -857,5 +934,6 @@ defaultComposeControls: ComposeControls { send: historySend; attach: historyAttach; emoji: historyAttachEmoji; + suggestions: defaultEmojiSuggestions; tabbed: defaultEmojiPan; } diff --git a/Telegram/SourceFiles/chat_helpers/compose/compose_features.h b/Telegram/SourceFiles/chat_helpers/compose/compose_features.h new file mode 100644 index 000000000..2f9915679 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/compose/compose_features.h @@ -0,0 +1,27 @@ +/* +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 +*/ +#pragma once + +namespace ChatHelpers { + +struct ComposeFeatures { + bool sendAs = true; + bool ttlInfo = true; + bool botCommandSend = true; + bool silentBroadcastToggle = true; + bool attachBotsMenu = true; + bool inlineBots = true; + bool megagroupSet = true; + bool stickersSettings = true; + bool openStickerSets = true; + bool autocompleteHashtags = true; + bool autocompleteMentions = true; + bool autocompleteCommands = true; +}; + +} // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index a6ff9af75..3d5f35c57 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -99,6 +99,7 @@ private: QSize _singleSize; QPoint _areaPosition; QPoint _innerPosition; + Ui::RoundRect _backgroundRect; Ui::RoundRect _overBg; bool _hiding = false; @@ -125,6 +126,7 @@ EmojiColorPicker::EmojiColorPicker( const style::EmojiPan &st) : RpWidget(parent) , _st(st) +, _backgroundRect(st::emojiPanRadius, _st.bg) , _overBg(st::emojiPanRadius, _st.overBg) { setMouseTracking(true); } @@ -181,8 +183,8 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) { p.drawPixmap(0, 0, _cache); return; } - Ui::Shadow::paint(p, inner, width(), st::emojiPanAnimation.shadow); - Ui::FillRoundRect(p, inner, st::boxBg, Ui::BoxCorners); + Ui::Shadow::paint(p, inner, width(), _st.showAnimation.shadow); + _backgroundRect.paint(p, inner); auto x = st::emojiPanMargins.left() + 2 * st::emojiColorsPadding + _singleSize.width(); if (rtl()) x = width() - x - st::emojiColorsSep; @@ -393,6 +395,7 @@ EmojiListWidget::EmojiListWidget( descriptor.show, std::move(descriptor.paused)) , _show(std::move(descriptor.show)) +, _features(descriptor.features) , _mode(descriptor.mode) , _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1) , _premiumIcon(_mode == Mode::EmojiStatus @@ -402,7 +405,7 @@ EmojiListWidget::EmojiListWidget( std::make_unique(&session())) , _customRecentFactory(std::move(descriptor.customRecentFactory)) , _overBg(st::emojiPanRadius, st().overBg) -, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg) +, _collapsedBg(st::emojiPanExpand.height / 2, st().headerFg) , _picker(this, st()) , _showPickerTimer([=] { showPicker(); }) { setMouseTracking(true); @@ -1072,7 +1075,7 @@ void EmojiListWidget::paint( - paintButtonGetWidth(p, info, buttonSelected, clip); if (info.section > 0 && clip.top() < info.rowsTop) { p.setFont(st::emojiPanHeaderFont); - p.setPen(st::emojiPanHeaderFg); + p.setPen(st().headerFg); auto titleText = (info.section < _staticCount) ? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now) : _custom[info.section - _staticCount].title; @@ -1091,7 +1094,7 @@ void EmojiListWidget::paint( } const auto textBaseline = top + st::emojiPanHeaderFont->ascent; p.setFont(st::emojiPanHeaderFont); - p.setPen(st::emojiPanHeaderFg); + p.setPen(st().headerFg); p.drawText(titleLeft, textBaseline, titleText); } if (clip.top() + clip.height() > info.rowsTop) { @@ -1459,7 +1462,8 @@ void EmojiListWidget::displaySet(uint64 setId) { } void EmojiListWidget::removeSet(uint64 setId) { - if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) { + const auto &labelSt = st().boxLabel; + if (auto box = MakeConfirmRemoveSetBox(&session(), labelSt, setId)) { checkHideWithBox(std::move(box)); } } @@ -1532,9 +1536,10 @@ QRect EmojiListWidget::removeButtonRect(const SectionInfo &info) const { if (_mode != Mode::Full) { return QRect(); } - const auto buttonw = st::stickerPanRemoveSet.rippleAreaPosition.x() - + st::stickerPanRemoveSet.rippleAreaSize; - const auto buttonh = st::stickerPanRemoveSet.height; + const auto &removeSt = st().removeSet; + const auto buttonw = removeSt.rippleAreaPosition.x() + + removeSt.rippleAreaSize; + const auto buttonh = removeSt.height; const auto buttonx = emojiRight() - st::emojiPanRemoveSkip - buttonw; const auto buttony = info.top + st::emojiPanRemoveTop; return QRect(buttonx, buttony, buttonw, buttonh); @@ -1966,19 +1971,18 @@ int EmojiListWidget::paintButtonGetWidth( if (remove.isEmpty()) { return 0; } else if (remove.intersects(clip)) { + const auto &removeSt = st().removeSet; if (custom.ripple) { custom.ripple->paint( p, - remove.x() + st::stickerPanRemoveSet.rippleAreaPosition.x(), - remove.y() + st::stickerPanRemoveSet.rippleAreaPosition.y(), + remove.x() + removeSt.rippleAreaPosition.x(), + remove.y() + removeSt.rippleAreaPosition.y(), width()); if (custom.ripple->empty()) { custom.ripple.reset(); } } - const auto &icon = selected - ? st::stickerPanRemoveSet.iconOver - : st::stickerPanRemoveSet.icon; + const auto &icon = selected ? removeSt.iconOver : removeSt.icon; icon.paint( p, (remove.topLeft() @@ -2045,7 +2049,9 @@ void EmojiListWidget::updateSelected() { if (hasButton(section) && myrtlrect(buttonRect(section)).contains(p.x(), p.y())) { newSelected = OverButton{ section }; - } else if (section >= _staticCount && _mode == Mode::Full) { + } else if (_features.openStickerSets + && section >= _staticCount + && _mode == Mode::Full) { newSelected = OverSet{ section }; } } else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) { @@ -2159,13 +2165,12 @@ std::unique_ptr EmojiListWidget::createButtonRipple( && section < _staticCount + _custom.size()); const auto remove = hasRemoveButton(section); - const auto &st = remove - ? st::stickerPanRemoveSet.ripple - : st::emojiPanButton.ripple; + const auto &removeSt = st().removeSet; + const auto &st = remove ? removeSt.ripple : st::emojiPanButton.ripple; auto mask = remove ? Ui::RippleAnimation::EllipseMask(QSize( - st::stickerPanRemoveSet.rippleAreaSize, - st::stickerPanRemoveSet.rippleAreaSize)) + removeSt.rippleAreaSize, + removeSt.rippleAreaSize)) : rightButton(section).rippleMask; return std::make_unique( st, @@ -2179,7 +2184,7 @@ QPoint EmojiListWidget::buttonRippleTopLeft(int section) const { return myrtlrect(buttonRect(section)).topLeft() + (hasRemoveButton(section) - ? st::stickerPanRemoveSet.rippleAreaPosition + ? st().removeSet.rippleAreaPosition : QPoint()); } diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h index fd307eda8..cc97d64db 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "chat_helpers/compose/compose_features.h" #include "chat_helpers/tabbed_selector.h" #include "ui/widgets/tooltip.h" #include "ui/round_rect.h" @@ -84,6 +85,7 @@ struct EmojiListDescriptor { DocumentId, Fn)> customRecentFactory; const style::EmojiPan *st = nullptr; + ComposeFeatures features; }; class EmojiListWidget final @@ -345,6 +347,7 @@ private: void applyNextSearchQuery(); const std::shared_ptr _show; + const ComposeFeatures _features; Mode _mode = Mode::Full; std::unique_ptr _search; const int _staticCount = 0; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp index b74e37708..ccd235355 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/emoji_config.h" #include "ui/ui_utility.h" #include "ui/cached_round_corners.h" +#include "ui/round_rect.h" #include "platform/platform_specific.h" #include "core/application.h" #include "base/event_filter.h" @@ -41,15 +42,133 @@ constexpr auto kAnimationDuration = crl::time(120); } // namespace +class SuggestionsWidget final : public Ui::RpWidget { +public: + SuggestionsWidget( + QWidget *parent, + const style::EmojiSuggestions &st, + not_null session, + bool suggestCustomEmoji, + Fn)> allowCustomWithoutPremium); + ~SuggestionsWidget(); + + void showWithQuery(SuggestionsQuery query, bool force = false); + void selectFirstResult(); + bool handleKeyEvent(int key); + + [[nodiscard]] rpl::producer toggleAnimated() const; + + struct Chosen { + QString emoji; + QString customData; + }; + [[nodiscard]] rpl::producer triggered() const; + +private: + struct Row { + Row(not_null emoji, const QString &replacement); + + Ui::Text::CustomEmoji *custom = nullptr; + DocumentData *document = nullptr; + not_null emoji; + QString replacement; + }; + struct Custom { + not_null document; + not_null emoji; + QString replacement; + }; + + bool eventHook(QEvent *e) override; + void paintEvent(QPaintEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void enterEventHook(QEnterEvent *e) override; + void leaveEventHook(QEvent *e) override; + + void scrollByWheelEvent(not_null e); + void paintFadings(QPainter &p) const; + + [[nodiscard]] std::vector getRowsByQuery(const QString &text) const; + [[nodiscard]] base::flat_multi_map lookupCustom( + const std::vector &rows) const; + [[nodiscard]] std::vector appendCustom( + std::vector rows); + [[nodiscard]] std::vector appendCustom( + std::vector rows, + const base::flat_multi_map &custom); + void resizeToRows(); + void setSelected( + int selected, + anim::type animated = anim::type::instant); + void setPressed(int pressed); + void clearMouseSelection(); + void clearSelection(); + void updateSelectedItem(); + void updateItem(int index); + [[nodiscard]] QRect inner() const; + [[nodiscard]] QPoint innerShift() const; + [[nodiscard]] QPoint mapToInner(QPoint globalPosition) const; + void selectByMouse(QPoint globalPosition); + bool triggerSelectedRow() const; + void triggerRow(const Row &row) const; + + [[nodiscard]] int scrollCurrent() const; + void scrollTo(int value, anim::type animated = anim::type::instant); + void stopAnimations(); + + [[nodiscard]] not_null resolveCustomEmoji( + not_null document); + void customEmojiRepaint(); + + const style::EmojiSuggestions &_st; + const not_null _session; + SuggestionsQuery _query; + std::vector _rows; + bool _suggestCustomEmoji = false; + Fn)> _allowCustomWithoutPremium; + + Ui::RoundRect _overRect; + + base::flat_map< + not_null, + std::unique_ptr> _customEmoji; + bool _repaintScheduled = false; + + std::optional _lastMousePosition; + bool _mouseSelection = false; + int _selected = -1; + int _pressed = -1; + + int _scrollValue = 0; + Ui::Animations::Simple _scrollAnimation; + Ui::Animations::Simple _selectedAnimation; + int _scrollMax = 0; + int _oneWidth = 0; + QMargins _padding; + + QPoint _mousePressPosition; + int _dragScrollStart = -1; + + rpl::event_stream _toggleAnimated; + rpl::event_stream _triggered; + +}; + SuggestionsWidget::SuggestionsWidget( QWidget *parent, + const style::EmojiSuggestions &st, not_null session, bool suggestCustomEmoji, Fn)> allowCustomWithoutPremium) : RpWidget(parent) +, _st(st) , _session(session) , _suggestCustomEmoji(suggestCustomEmoji) , _allowCustomWithoutPremium(std::move(allowCustomWithoutPremium)) +, _overRect(st::roundRadiusSmall, _st.overBg) , _oneWidth(st::emojiSuggestionSize) , _padding(st::emojiSuggestionsPadding) { resize( @@ -284,7 +403,7 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) { _repaintScheduled = false; const auto clip = e->rect(); - p.fillRect(clip, st::boxBg); + p.fillRect(clip, _st.bg); const auto shift = innerShift(); p.translate(-shift); @@ -298,15 +417,13 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) { ? _pressed : _selectedAnimation.value(_selected); if (selected > -1.) { - Ui::FillRoundRect( + _overRect.paint( p, - QRect(selected * _oneWidth, 0, _oneWidth, _oneWidth), - st::emojiPanHover, - Ui::StickerHoverCorners); + QRect(selected * _oneWidth, 0, _oneWidth, _oneWidth)); } auto context = Ui::CustomEmoji::Context{ - .textColor = st::windowFg->c, + .textColor = _st.textFg->c, .now = crl::now(), }; for (auto i = from; i != till; ++i) { @@ -338,9 +455,9 @@ void SuggestionsWidget::paintFadings(QPainter &p) const { const auto rect = myrtlrect( shift.x(), 0, - st::emojiSuggestionsFadeLeft.width(), + _st.fadeLeft.width(), height()); - st::emojiSuggestionsFadeLeft.fill(p, rect); + _st.fadeLeft.fill(p, rect); p.setOpacity(1.); } const auto o_right = std::clamp( @@ -350,11 +467,11 @@ void SuggestionsWidget::paintFadings(QPainter &p) const { if (o_right > 0.) { p.setOpacity(o_right); const auto rect = myrtlrect( - shift.x() + width() - st::emojiSuggestionsFadeRight.width(), + shift.x() + width() - _st.fadeRight.width(), 0, - st::emojiSuggestionsFadeRight.width(), + _st.fadeRight.width(), height()); - st::emojiSuggestionsFadeRight.fill(p, rect); + _st.fadeRight.fill(p, rect); p.setOpacity(1.); } } @@ -601,17 +718,17 @@ SuggestionsController::SuggestionsController( not_null field, not_null session, const Options &options) -: _field(field) +: _st(options.st ? *options.st : st::defaultEmojiSuggestions) +, _field(field) , _session(session) , _showExactTimer([=] { showWithQuery(getEmojiQuery()); }) , _options(options) { - _container = base::make_unique_q( - outer, - st::emojiSuggestionsDropdown); + _container = base::make_unique_q(outer, _st.dropdown); _container->setAutoHiding(false); _suggestions = _container->setOwnedWidget( object_ptr( _container, + _st, session, _options.suggestCustomEmoji, _options.allowCustomWithoutPremium)); @@ -910,7 +1027,7 @@ void SuggestionsController::updateGeometry() { auto boundingRect = _container->parentWidget()->rect(); auto origin = rtl() ? PanelAnimation::Origin::BottomRight : PanelAnimation::Origin::BottomLeft; auto point = rtl() ? (aroundRect.topLeft() + QPoint(aroundRect.width(), 0)) : aroundRect.topLeft(); - const auto padding = st::emojiSuggestionsDropdown.padding; + const auto padding = _st.dropdown.padding; const auto shift = std::min(_container->width() - padding.left() - padding.right(), st::emojiSuggestionSize) / 2; point -= rtl() ? QPoint(_container->width() - padding.right() - shift, _container->height()) : QPoint(padding.left() + shift, _container->height()); if (rtl()) { diff --git a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.h index 513fb518d..b89de0ad9 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.h @@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +namespace style { +struct EmojiSuggestions; +} // namespace style + namespace Main { class Session; } // namespace Main @@ -29,125 +33,17 @@ class CustomEmoji; namespace Ui::Emoji { +class SuggestionsWidget; + using SuggestionsQuery = std::variant; -class SuggestionsWidget final : public Ui::RpWidget { -public: - SuggestionsWidget( - QWidget *parent, - not_null session, - bool suggestCustomEmoji, - Fn)> allowCustomWithoutPremium); - ~SuggestionsWidget(); - - void showWithQuery(SuggestionsQuery query, bool force = false); - void selectFirstResult(); - bool handleKeyEvent(int key); - - [[nodiscard]] rpl::producer toggleAnimated() const; - - struct Chosen { - QString emoji; - QString customData; - }; - [[nodiscard]] rpl::producer triggered() const; - -private: - struct Row { - Row(not_null emoji, const QString &replacement); - - Ui::Text::CustomEmoji *custom = nullptr; - DocumentData *document = nullptr; - not_null emoji; - QString replacement; - }; - struct Custom { - not_null document; - not_null emoji; - QString replacement; - }; - - bool eventHook(QEvent *e) override; - void paintEvent(QPaintEvent *e) override; - void keyPressEvent(QKeyEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void enterEventHook(QEnterEvent *e) override; - void leaveEventHook(QEvent *e) override; - - void scrollByWheelEvent(not_null e); - void paintFadings(QPainter &p) const; - - [[nodiscard]] std::vector getRowsByQuery(const QString &text) const; - [[nodiscard]] base::flat_multi_map lookupCustom( - const std::vector &rows) const; - [[nodiscard]] std::vector appendCustom( - std::vector rows); - [[nodiscard]] std::vector appendCustom( - std::vector rows, - const base::flat_multi_map &custom); - void resizeToRows(); - void setSelected( - int selected, - anim::type animated = anim::type::instant); - void setPressed(int pressed); - void clearMouseSelection(); - void clearSelection(); - void updateSelectedItem(); - void updateItem(int index); - [[nodiscard]] QRect inner() const; - [[nodiscard]] QPoint innerShift() const; - [[nodiscard]] QPoint mapToInner(QPoint globalPosition) const; - void selectByMouse(QPoint globalPosition); - bool triggerSelectedRow() const; - void triggerRow(const Row &row) const; - - [[nodiscard]] int scrollCurrent() const; - void scrollTo(int value, anim::type animated = anim::type::instant); - void stopAnimations(); - - [[nodiscard]] not_null resolveCustomEmoji( - not_null document); - void customEmojiRepaint(); - - const not_null _session; - SuggestionsQuery _query; - std::vector _rows; - bool _suggestCustomEmoji = false; - Fn)> _allowCustomWithoutPremium; - - base::flat_map< - not_null, - std::unique_ptr> _customEmoji; - bool _repaintScheduled = false; - - std::optional _lastMousePosition; - bool _mouseSelection = false; - int _selected = -1; - int _pressed = -1; - - int _scrollValue = 0; - Ui::Animations::Simple _scrollAnimation; - Ui::Animations::Simple _selectedAnimation; - int _scrollMax = 0; - int _oneWidth = 0; - QMargins _padding; - - QPoint _mousePressPosition; - int _dragScrollStart = -1; - - rpl::event_stream _toggleAnimated; - rpl::event_stream _triggered; - -}; - class SuggestionsController { public: struct Options { bool suggestExactFirstWord = true; bool suggestCustomEmoji = false; Fn)> allowCustomWithoutPremium; + const style::EmojiSuggestions *st = nullptr; }; SuggestionsController( @@ -189,6 +85,7 @@ private: bool fieldFilter(not_null event); bool outerFilter(not_null event); + const style::EmojiSuggestions &_st; bool _shown = false; bool _forceHidden = false; int _queryStartPosition = 0; diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index b78615721..6f312926f 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -685,6 +685,7 @@ void FieldAutocomplete::recount(bool resetScroll) { } else if (!_brows.empty()) { h = _brows.size() * st::mentionHeight; } + h += _st.autocompleteBottomSkip; if (_inner->width() != _boundings.width() || _inner->height() != h) { _inner->resize(_boundings.width(), h); @@ -1375,8 +1376,10 @@ void FieldAutocomplete::Inner::setSel(int sel, bool scroll) { int32 row = _sel / _stickersPerRow; const auto padding = st::stickerPanPadding; _scrollToRequested.fire({ - padding + row * st::stickerPanSize.height(), - padding + (row + 1) * st::stickerPanSize.height() }); + (row ? padding : 0) + row * st::stickerPanSize.height(), + (padding + + (row + 1) * st::stickerPanSize.height() + + _st.autocompleteBottomSkip) }); } } } diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 9ff10845d..48a0e9800 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -57,7 +57,8 @@ constexpr auto kMinAfterScrollDelay = crl::time(33); void AddGifAction( Fn &&, const style::icon*)> callback, std::shared_ptr show, - not_null document) { + not_null document, + const style::ComposeIcons *iconsOverride) { if (!document->isGifv()) { return; } @@ -67,6 +68,9 @@ void AddGifAction( const auto text = (saved ? tr::lng_context_delete_gif : tr::lng_context_save_gif)(tr::now); + const auto &icons = iconsOverride + ? *iconsOverride + : st::defaultComposeIcons; callback(text, [=] { Api::ToggleSavedGif( show, @@ -80,7 +84,7 @@ void AddGifAction( document->session().local().writeSavedGifs(); } data.stickers().notifySavedGifsUpdated(); - }, saved ? &st::menuIconDelete : &st::menuIconGif); + }, saved ? &icons.menuGifRemove : &icons.menuGifAdd); } GifsListWidget::GifsListWidget( @@ -380,18 +384,18 @@ base::unique_qptr GifsListWidget::fillContextMenu( return nullptr; } - auto menu = base::make_unique_q( - this, - st::popupMenuWithIcons); + auto menu = base::make_unique_q(this, st().menu); const auto send = [=, selected = _selected](Api::SendOptions options) { selectInlineResult(selected, options, true); }; + const auto icons = &st().icons; SendMenu::FillSendMenu( menu, type, SendMenu::DefaultSilentCallback(send), SendMenu::DefaultScheduleCallback(this, type, send), - SendMenu::DefaultWhenOnlineCallback(send)); + SendMenu::DefaultWhenOnlineCallback(send), + icons); if (const auto item = _mosaic.maybeItemAt(_selected)) { const auto document = item->getDocument() @@ -404,7 +408,7 @@ base::unique_qptr GifsListWidget::fillContextMenu( const style::icon *icon) { menu->addAction(text, std::move(done), icon); }; - AddGifAction(std::move(callback), _show, document); + AddGifAction(std::move(callback), _show, document, icons); } } return menu; diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h index d21c8e531..84e20c864 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h @@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +namespace style { +struct ComposeIcons; +} // namespace style + namespace Api { struct SendOptions; } // namespace Api @@ -48,7 +52,8 @@ namespace ChatHelpers { void AddGifAction( Fn &&, const style::icon*)> callback, std::shared_ptr show, - not_null document); + not_null document, + const style::ComposeIcons *iconsOverride = nullptr); class StickersListFooter; struct StickerIcon; diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 03430e3ab..b0e263c4a 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -498,7 +498,8 @@ InlineBotQuery ParseInlineBotQuery( } AutocompleteQuery ParseMentionHashtagBotCommandQuery( - not_null field) { + not_null field, + ChatHelpers::ComposeFeatures features) { auto result = AutocompleteQuery(); const auto cursor = field->textCursor(); @@ -530,6 +531,9 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery( const auto text = fragment.text(); for (auto i = position - fragmentPosition; i != 0; --i) { if (text[i - 1] == '@') { + if (!features.autocompleteMentions) { + return {}; + } if ((position - fragmentPosition - i < 1 || text[i].isLetter()) && (i < 2 || !(text[i - 2].isLetterOrNumber() || text[i - 2] == '_'))) { result.fromStart = (i == 1) && (fragmentPosition == 0); result.query = text.mid(i - 1, position - fragmentPosition - i + 1); @@ -540,12 +544,18 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery( } return result; } else if (text[i - 1] == '#') { + if (!features.autocompleteHashtags) { + return {}; + } if (i < 2 || !(text[i - 2].isLetterOrNumber() || text[i - 2] == '_')) { result.fromStart = (i == 1) && (fragmentPosition == 0); result.query = text.mid(i - 1, position - fragmentPosition - i + 1); } return result; } else if (text[i - 1] == '/') { + if (!features.autocompleteCommands) { + return {}; + } if (i < 2 && !fragmentPosition) { result.fromStart = (i == 1) && (fragmentPosition == 0); result.query = text.mid(i - 1, position - fragmentPosition - i + 1); diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h index 727e51a5b..13012557b 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.h +++ b/Telegram/SourceFiles/chat_helpers/message_field.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/input_fields.h" #include "base/timer.h" #include "base/qt_connection.h" +#include "chat_helpers/compose/compose_features.h" #ifndef TDESKTOP_DISABLE_SPELLCHECK #include "boxes/dictionaries_manager.h" @@ -90,7 +91,8 @@ struct AutocompleteQuery { bool fromStart = false; }; AutocompleteQuery ParseMentionHashtagBotCommandQuery( - not_null field); + not_null field, + ChatHelpers::ComposeFeatures features); class MessageLinksParser : private QObject { public: diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp index a9aa598d6..15e2e8c34 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp @@ -292,7 +292,7 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor) descriptor.st ? *descriptor.st : st::defaultEmojiPan) , _session(descriptor.session) , _paused(descriptor.paused) -, _settingsButtonVisible(descriptor.settingsButtonVisible) +, _features(descriptor.features) , _iconState([=] { update(); }) , _subiconState([=] { update(); }) , _selectionBg(st::emojiPanRadius, st().categoriesBgOver) @@ -300,7 +300,7 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor) setMouseTracking(true); _iconsLeft = st().iconSkip - + (_settingsButtonVisible ? st().iconWidth : 0); + + (_features.stickersSettings ? st().iconWidth : 0); _iconsRight = st().iconSkip; _session->downloaderTaskFinished( @@ -618,7 +618,7 @@ void StickersListFooter::paint( return; } - if (_settingsButtonVisible && !hasOnlyFeaturedSets()) { + if (_features.stickersSettings) { paintStickerSettingsIcon(p); } @@ -1012,12 +1012,12 @@ void StickersListFooter::updateSelected() { if (rtl()) x = width() - x; const auto settingsLeft = _iconsLeft - _singleWidth; auto newOver = OverState(SpecialOver::None); - if (_settingsButtonVisible + if (_features.stickersSettings && x >= settingsLeft && x < settingsLeft + _singleWidth && y >= _iconsTop && y < _iconsTop + st().footer) { - if (!_icons.empty() && !hasOnlyFeaturedSets()) { + if (!_icons.empty()) { newOver = SpecialOver::Settings; } } else if (!_icons.empty()) { @@ -1161,17 +1161,11 @@ void StickersListFooter::refreshSubiconsGeometry() { updateEmojiWidthCallback(); } -bool StickersListFooter::hasOnlyFeaturedSets() const { - return (_icons.size() == 1) - && (_icons[0].setId == Data::Stickers::FeaturedSetId); -} - void StickersListFooter::paintStickerSettingsIcon(QPainter &p) const { const auto settingsLeft = _iconsLeft - _singleWidth; - st::stickersSettings.paint( + st().icons.settings.paint( p, - settingsLeft - + (_singleWidth - st::stickersSettings.width()) / 2, + (settingsLeft + (_singleWidth - st().icons.settings.width()) / 2), _iconsTop + st::emojiCategoryIconTop, width()); } @@ -1411,22 +1405,22 @@ void StickersListFooter::paintSetIconToCache( using Section = Ui::Emoji::Section; const auto sectionIcon = [&](Section section, bool active) { const auto icons = std::array{ - &st::emojiRecent, - &st::emojiRecentActive, - &st::emojiPeople, - &st::emojiPeopleActive, - &st::emojiNature, - &st::emojiNatureActive, - &st::emojiFood, - &st::emojiFoodActive, - &st::emojiActivity, - &st::emojiActivityActive, - &st::emojiTravel, - &st::emojiTravelActive, - &st::emojiObjects, - &st::emojiObjectsActive, - &st::emojiSymbols, - &st::emojiSymbolsActive, + &st().icons.recent, + &st().icons.recentActive, + &st().icons.people, + &st().icons.peopleActive, + &st().icons.nature, + &st().icons.natureActive, + &st().icons.food, + &st().icons.foodActive, + &st().icons.activity, + &st().icons.activityActive, + &st().icons.travel, + &st().icons.travelActive, + &st().icons.objects, + &st().icons.objectsActive, + &st().icons.symbols, + &st().icons.symbolsActive, }; const auto index = int(section) * 2 + (active ? 1 : 0); @@ -1464,15 +1458,8 @@ void StickersListFooter::paintSetIconToCache( } else { paintOne(0, [&] { const auto selected = (info.index == _iconState.selected); - if (icon.setId == Data::Stickers::FeaturedSetId) { - const auto &stickers = _session->data().stickers(); - return stickers.featuredSetsUnreadCount() - ? &st::stickersTrendingUnread - : &st::stickersTrending; - //} else if (setId == Stickers::FavedSetId) { - // return &st::stickersFaved; - } else if (icon.setId == AllEmojiSectionSetId()) { - return &st::emojiPeople; + if (icon.setId == AllEmojiSectionSetId()) { + return &st().icons.people; } else if (const auto section = SetIdEmojiSection(icon.setId)) { return sectionIcon(*section, selected); } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h index 1a08f6853..f7a0afc1d 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h @@ -7,8 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "media/clip/media_clip_reader.h" +#include "chat_helpers/compose/compose_features.h" #include "chat_helpers/tabbed_selector.h" +#include "media/clip/media_clip_reader.h" #include "mtproto/sender.h" #include "ui/dpr/dpr_image.h" #include "ui/round_rect.h" @@ -116,8 +117,8 @@ public: not_null session; Fn paused; not_null parent; - bool settingsButtonVisible = false; const style::EmojiPan *st = nullptr; + ComposeFeatures features; }; explicit StickersListFooter(Descriptor &&descriptor); @@ -130,7 +131,6 @@ public: uint64 activeSetId, Fn()> renderer, ValidateIconAnimations animations); - [[nodiscard]] bool hasOnlyFeaturedSets() const; void leaveToChildEvent(QEvent *e, QWidget *child) override; @@ -270,7 +270,7 @@ private: const not_null _session; const Fn _paused; - const bool _settingsButtonVisible = false; + const ComposeFeatures _features; 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 40aae70eb..cf0dda5eb 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -184,12 +184,12 @@ StickersListWidget::StickersListWidget( descriptor.paused) , _mode(descriptor.mode) , _show(std::move(descriptor.show)) +, _features(descriptor.features) , _overBg(st::roundRadiusSmall, st().overBg) , _api(&session().mtp()) , _localSetsManager(std::make_unique(&session())) , _section(Section::Stickers) , _isMasks(_mode == Mode::Masks) -, _settingsHidden(descriptor.settingsHidden) , _updateItemsTimer([=] { updateItems(); }) , _updateSetsTimer([=] { updateSets(); }) , _trendingAddBgOver( @@ -286,8 +286,8 @@ object_ptr StickersListWidget::createFooter() { .session = &session(), .paused = footerPaused, .parent = this, - .settingsButtonVisible = !_settingsHidden, .st = &st(), + .features = _features, }); _footer = result; @@ -298,7 +298,7 @@ object_ptr StickersListWidget::createFooter() { _footer->openSettingsRequests( ) | rpl::start_with_next([=] { - const auto onlyFeatured = _footer->hasOnlyFeaturedSets(); + const auto onlyFeatured = !_isMasks && _mySets.empty(); _show->showBox(Box( _show, (onlyFeatured @@ -908,7 +908,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { auto add = featuredAddRect(info); int checkx = add.left() + (add.width() - st::stickersFeaturedInstalled.width()) / 2; int checky = add.top() + (add.height() - st::stickersFeaturedInstalled.height()) / 2; - st::stickersFeaturedInstalled.paint(p, QPoint(checkx, checky), width()); + st().trendingInstalled.paint(p, QPoint(checkx, checky), width()); } if (set.flags & SetFlag::Unread) { widthForTitle -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; @@ -921,12 +921,12 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { titleWidth = st::stickersTrendingHeaderFont->width(titleText); } p.setFont(st::stickersTrendingHeaderFont); - p.setPen(st::stickersTrendingHeaderFg); + p.setPen(st().trendingHeaderFg); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st::stickersTrendingHeaderTop, width(), titleText, titleWidth); if (set.flags & SetFlag::Unread) { p.setPen(Qt::NoPen); - p.setBrush(st::stickersFeaturedUnreadBg); + p.setBrush(st().trendingUnreadFg); { PainterHighQualityEnabler hq(p); @@ -936,7 +936,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { auto statusText = (count > 0) ? tr::lng_stickers_count(tr::now, lt_count, count) : tr::lng_contacts_loading(tr::now); p.setFont(st::stickersTrendingSubheaderFont); - p.setPen(st::stickersTrendingSubheaderFg); + p.setPen(st().trendingSubheaderFg); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st::stickersTrendingSubheaderTop, width(), statusText); if (info.rowsTop >= clip.y() + clip.height()) { @@ -963,13 +963,14 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { if (hasRemoveButton(info.section)) { auto remove = removeButtonRect(info); auto selected = selectedButton ? (selectedButton->section == info.section) : false; + const auto &removeSt = st().removeSet; if (set.ripple) { - set.ripple->paint(p, remove.x() + st::stickerPanRemoveSet.rippleAreaPosition.x(), remove.y() + st::stickerPanRemoveSet.rippleAreaPosition.y(), width()); + set.ripple->paint(p, remove.x() + removeSt.rippleAreaPosition.x(), remove.y() + removeSt.rippleAreaPosition.y(), width()); if (set.ripple->empty()) { set.ripple.reset(); } } - const auto &icon = selected ? st::stickerPanRemoveSet.iconOver : st::stickerPanRemoveSet.icon; + const auto &icon = selected ? removeSt.iconOver : removeSt.icon; icon.paint( p, remove.x() + (remove.width() - icon.width()) / 2, @@ -983,7 +984,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { titleWidth = st::stickersTrendingHeaderFont->width(titleText); } p.setFont(st::emojiPanHeaderFont); - p.setPen(st::emojiPanHeaderFg); + p.setPen(st().headerFg); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st().headerTop, width(), titleText, titleWidth); } if (clip.top() + clip.height() <= info.rowsTop) { @@ -1108,7 +1109,7 @@ int StickersListWidget::megagroupSetInfoLeft() const { } void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected) { - p.setPen(st::emojiPanHeaderFg); + p.setPen(st().headerFg); auto infoLeft = megagroupSetInfoLeft(); _megagroupSetAbout.drawLeft(p, infoLeft, y, width() - infoLeft, width()); @@ -1483,8 +1484,9 @@ QRect StickersListWidget::removeButtonRect(int index) const { } QRect StickersListWidget::removeButtonRect(const SectionInfo &info) const { - auto buttonw = st::stickerPanRemoveSet.width; - auto buttonh = st::stickerPanRemoveSet.height; + const auto &removeSt = st().removeSet; + auto buttonw = removeSt.width; + auto buttonh = removeSt.height; auto buttonx = stickersRight() - buttonw; auto buttony = info.top + (st().header - buttonh) / 2; return QRect(buttonx, buttony, buttonw, buttonh); @@ -1561,10 +1563,11 @@ std::unique_ptr StickersListWidget::createButtonRipple(int std::move(mask), [this, section] { rtlupdate(featuredAddRect(section)); }); } - auto maskSize = QSize(st::stickerPanRemoveSet.rippleAreaSize, st::stickerPanRemoveSet.rippleAreaSize); + const auto &removeSt = st().removeSet; + auto maskSize = QSize(removeSt.rippleAreaSize, removeSt.rippleAreaSize); auto mask = Ui::RippleAnimation::EllipseMask(maskSize); return std::make_unique( - st::stickerPanRemoveSet.ripple, + removeSt.ripple, std::move(mask), [this, section] { rtlupdate(removeButtonRect(section)); }); } @@ -1575,7 +1578,8 @@ QPoint StickersListWidget::buttonRippleTopLeft(int section) const { if (shownSets()[section].externalLayout) { return myrtlrect(featuredAddRect(section)).topLeft(); } - return myrtlrect(removeButtonRect(section)).topLeft() + st::stickerPanRemoveSet.rippleAreaPosition; + return myrtlrect(removeButtonRect(section)).topLeft() + + st().removeSet.rippleAreaPosition; } void StickersListWidget::showStickerSetBox(not_null document) { @@ -1604,9 +1608,7 @@ base::unique_qptr StickersListWidget::fillContextMenu( auto &set = sets[section]; Assert(index >= 0 && index < set.stickers.size()); - auto menu = base::make_unique_q( - this, - st::popupMenuWithIcons); + auto menu = base::make_unique_q(this, st().menu); const auto document = set.stickers[sticker->index].document; const auto send = [=](Api::SendOptions options) { @@ -1618,12 +1620,14 @@ base::unique_qptr StickersListWidget::fillContextMenu( : messageSentAnimationInfo(section, index, document), }); }; + const auto icons = &st().icons; SendMenu::FillSendMenu( menu, type, SendMenu::DefaultSilentCallback(send), SendMenu::DefaultScheduleCallback(this, type, send), - SendMenu::DefaultWhenOnlineCallback(send)); + SendMenu::DefaultWhenOnlineCallback(send), + icons); const auto show = _show; const auto toggleFavedSticker = [=] { @@ -1638,11 +1642,13 @@ base::unique_qptr StickersListWidget::fillContextMenu( ? tr::lng_faved_stickers_remove : tr::lng_faved_stickers_add)(tr::now), toggleFavedSticker, - isFaved ? &st::menuIconUnfave : &st::menuIconFave); + isFaved ? &icons->menuUnfave : &icons->menuFave); - menu->addAction(tr::lng_context_pack_info(tr::now), [=] { - showStickerSetBox(document); - }, &st::menuIconStickers); + if (_features.openStickerSets) { + menu->addAction(tr::lng_context_pack_info(tr::now), [=] { + showStickerSetBox(document); + }, &icons->menuStickerSet); + } if (const auto id = set.id; id == Data::Stickers::RecentSetId) { menu->addAction(tr::lng_recent_stickers_remove(tr::now), [=] { @@ -1650,7 +1656,7 @@ base::unique_qptr StickersListWidget::fillContextMenu( document, Data::FileOriginStickerSet(id, 0), false); - }, &st::menuIconDelete); + }, &icons->menuRecentRemove); } return menu; } @@ -1708,7 +1714,8 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) { return; } const auto document = set.stickers[sticker->index].document; - if (e->modifiers() & Qt::ControlModifier) { + if (_features.openStickerSets + && (e->modifiers() & Qt::ControlModifier)) { showStickerSetBox(document); } else { _chosen.fire({ @@ -1859,12 +1866,6 @@ void StickersListWidget::processPanelHideFinished() { if (_footer) { _footer->clearHeavyData(); } - // Preserve panel state through visibility toggles. - //// Reset to the recent stickers section. - //if (_section == Section::Featured && (!_footer || !_footer->hasOnlyFeaturedSets())) { - // setSection(Section::Stickers); - // validateSelectedIcon(ValidateIconAnimations::None); - //} } void StickersListWidget::setSection(Section section) { @@ -1994,9 +1995,6 @@ void StickersListWidget::refreshSettingsVisibility() { void StickersListWidget::refreshFooterIcons() { refreshIcons(ValidateIconAnimations::None); - if (_footer->hasOnlyFeaturedSets() && _section != Section::Featured) { - showStickerSet(Data::Stickers::FeaturedSetId); - } } void StickersListWidget::preloadImages() { @@ -2064,9 +2062,6 @@ void StickersListWidget::refreshRecent() { if (_section == Section::Stickers) { refreshRecentStickers(); } - if (_footer && _footer->hasOnlyFeaturedSets() && _section != Section::Featured) { - showStickerSet(Data::Stickers::FeaturedSetId); - } } auto StickersListWidget::collectRecentStickers() -> std::vector { @@ -2201,7 +2196,7 @@ void StickersListWidget::refreshFavedStickers() { } void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) { - if (!_megagroupSet || _isMasks) { + if (!_features.megagroupSet || !_megagroupSet || _isMasks) { return; } auto canEdit = _megagroupSet->canEditStickers(); @@ -2354,10 +2349,12 @@ void StickersListWidget::updateSelected() { newSelected = OverButton{ section }; } else if (featuredHasAddButton(section) && myrtlrect(featuredAddRect(info)).contains(p.x(), p.y())) { newSelected = OverButton{ section }; - } else if (!(sets[section].flags & SetFlag::Special)) { + } else if (_features.openStickerSets + && !(sets[section].flags & SetFlag::Special)) { newSelected = OverSet{ section }; - } else if (sets[section].id == Data::Stickers::MegagroupSetId - && (_megagroupSet->canEditStickers() || !sets[section].stickers.empty())) { + } else if ((sets[section].id == Data::Stickers::MegagroupSetId) + && (_megagroupSet->canEditStickers() + || !sets[section].stickers.empty())) { newSelected = OverSet{ section }; } } else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom && sx >= 0) { @@ -2624,10 +2621,12 @@ void StickersListWidget::removeMegagroupSet(bool locally) { close(); }), .cancelled = [](Fn &&close) { close(); }, + .labelStyle = &st().boxLabel, })); } void StickersListWidget::removeSet(uint64 setId) { + const auto &st = this->st().boxLabel; if (setId == Data::Stickers::MegagroupSetId) { const auto &sets = shownSets(); const auto i = ranges::find(sets, setId, &Set::id); @@ -2635,7 +2634,7 @@ void StickersListWidget::removeSet(uint64 setId) { const auto removeLocally = i->stickers.empty() || !_megagroupSet->canEditStickers(); removeMegagroupSet(removeLocally); - } else if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) { + } else if (auto box = MakeConfirmRemoveSetBox(&session(), st, setId)) { checkHideWithBox(std::move(box)); } } @@ -2660,6 +2659,7 @@ StickersListWidget::~StickersListWidget() = default; object_ptr MakeConfirmRemoveSetBox( not_null session, + const style::FlatLabel &st, uint64 setId) { const auto &sets = session->data().stickers().sets(); const auto it = sets.find(setId); @@ -2726,6 +2726,7 @@ object_ptr MakeConfirmRemoveSetBox( } }, .confirmText = tr::lng_stickers_remove_pack_confirm(), + .labelStyle = &st, }); } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index dc4e7dc44..6e2c2fa04 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "chat_helpers/compose/compose_features.h" #include "chat_helpers/tabbed_selector.h" #include "data/stickers/data_stickers.h" #include "ui/round_rect.h" @@ -50,6 +51,7 @@ enum class Notification; namespace style { struct EmojiPan; +struct FlatLabel; } // namespace style namespace ChatHelpers { @@ -70,7 +72,7 @@ struct StickersListDescriptor { StickersListMode mode = StickersListMode::Full; Fn paused; const style::EmojiPan *st = nullptr; - bool settingsHidden = false; + ComposeFeatures features; }; class StickersListWidget final : public TabbedSelector::Inner { @@ -352,6 +354,7 @@ private: const Mode _mode; const std::shared_ptr _show; + const ComposeFeatures _features; Ui::RoundRect _overBg; std::unique_ptr _search; MTP::Sender _api; @@ -375,7 +378,6 @@ private: Section _section = Section::Stickers; const bool _isMasks; - bool _settingsHidden = false; base::Timer _updateItemsTimer; base::Timer _updateSetsTimer; @@ -426,6 +428,7 @@ private: [[nodiscard]] object_ptr MakeConfirmRemoveSetBox( not_null session, + const style::FlatLabel &st, uint64 setId); } // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp index 5321e649e..e8ec060fb 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp @@ -240,7 +240,7 @@ void TabbedPanel::paintEvent(QPaintEvent *e) { hideFinished(); } else { if (!_cache.isNull()) _cache = QPixmap(); - Ui::Shadow::paint(p, innerRect(), width(), st::emojiPanAnimation.shadow); + Ui::Shadow::paint(p, innerRect(), width(), _selector->st().showAnimation.shadow); } } @@ -362,7 +362,11 @@ void TabbedPanel::startShowAnimation() { if (!_a_show.animating()) { auto image = grabForAnimation(); - _showAnimation = std::make_unique(st::emojiPanAnimation, _dropDown ? Ui::PanelAnimation::Origin::TopRight : Ui::PanelAnimation::Origin::BottomRight); + _showAnimation = std::make_unique( + _selector->st().showAnimation, + (_dropDown + ? Ui::PanelAnimation::Origin::TopRight + : Ui::PanelAnimation::Origin::BottomRight)); auto inner = rect().marginsRemoved(st::emojiPanMargins); _showAnimation->setFinalImage(std::move(image), QRect(inner.topLeft() * cIntRetinaFactor(), inner.size() * cIntRetinaFactor())); _showAnimation->setCornerMasks(Images::CornersMask(st::emojiPanRadius)); diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index 5131c9f9b..43b08c4a4 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -344,6 +344,7 @@ TabbedSelector::TabbedSelector( TabbedSelectorDescriptor &&descriptor) : RpWidget(parent) , _st(descriptor.st) +, _features(descriptor.features) , _show(std::move(descriptor.show)) , _level(descriptor.level) , _mode(descriptor.mode) @@ -377,7 +378,6 @@ TabbedSelector::TabbedSelector( : SelectorTab::Emoji) , _hasEmojiTab(ranges::contains(_tabs, SelectorTab::Emoji, &Tab::type)) , _hasStickersTab(ranges::contains(_tabs, SelectorTab::Stickers, &Tab::type)) -, _stickersSettingsHidden(descriptor.stickersSettingsHidden) , _hasGifsTab(ranges::contains(_tabs, SelectorTab::Gifs, &Tab::type)) , _hasMasksTab(ranges::contains(_tabs, SelectorTab::Masks, &Tab::type)) , _tabbed(_tabs.size() > 1) { @@ -487,6 +487,10 @@ TabbedSelector::TabbedSelector( TabbedSelector::~TabbedSelector() = default; +const style::EmojiPan &TabbedSelector::st() const { + return _st; +} + Main::Session &TabbedSelector::session() const { return _show->session(); } @@ -511,6 +515,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) { : EmojiMode::Full), .paused = paused, .st = &_st, + .features = _features, }); } case SelectorTab::Stickers: { @@ -521,7 +526,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) { .mode = StickersMode::Full, .paused = paused, .st = &_st, - .settingsHidden = _stickersSettingsHidden, + .features = _features, }); } case SelectorTab::Gifs: { @@ -540,6 +545,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) { .mode = StickersMode::Masks, .paused = paused, .st = &_st, + .features = _features, }); } } diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h index bcaa4fdee..d41aebb80 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "api/api_common.h" +#include "chat_helpers/compose/compose_features.h" #include "ui/rp_widget.h" #include "ui/effects/animations.h" #include "ui/effects/message_sending_animation_common.h" @@ -87,7 +88,7 @@ struct TabbedSelectorDescriptor { const style::EmojiPan &st; PauseReason level = {}; TabbedSelectorMode mode = TabbedSelectorMode::Full; - bool stickersSettingsHidden = false; + ComposeFeatures features; }; [[nodiscard]] std::unique_ptr MakeSearch( @@ -117,6 +118,7 @@ public: TabbedSelectorDescriptor &&descriptor); ~TabbedSelector(); + [[nodiscard]] const style::EmojiPan &st() const; [[nodiscard]] Main::Session &session() const; [[nodiscard]] PauseReason level() const; @@ -267,6 +269,7 @@ private: not_null masks() const; const style::EmojiPan &_st; + const ComposeFeatures _features; const std::shared_ptr _show; const PauseReason _level = {}; @@ -291,7 +294,6 @@ private: const bool _hasEmojiTab; const bool _hasStickersTab; - const bool _stickersSettingsHidden; const bool _hasGifsTab; const bool _hasMasksTab; const bool _tabbed; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 87da53703..ec4aa4d07 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1388,7 +1388,7 @@ AutocompleteQuery HistoryWidget::parseMentionHashtagBotCommandQuery() const { const auto result = (isChoosingTheme() || (_inlineBot && !_inlineLookingUpBot)) ? AutocompleteQuery() - : ParseMentionHashtagBotCommandQuery(_field); + : ParseMentionHashtagBotCommandQuery(_field, {}); if (result.query.isEmpty()) { return result; } else if (result.query[0] == '#' diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index a3fd8b3c8..1f4fb79b0 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -956,7 +956,7 @@ ComposeControls::ComposeControls( .st = _st.tabbed, .level = Window::GifPauseReason::TabbedPanel, .mode = ChatHelpers::TabbedSelector::Mode::Full, - .stickersSettingsHidden = !_features.stickersSettings, + .features = _features, })) , _selector(_regularWindow ? _regularWindow->tabbedSelector() @@ -982,7 +982,10 @@ ComposeControls::ComposeControls( _wrap.get(), st::historyBotCommandStart) : nullptr) -, _autocomplete(std::make_unique(parent, _show)) +, _autocomplete(std::make_unique( + parent, + _show, + &_st.tabbed)) , _header(std::make_unique(_wrap.get(), _show)) , _voiceRecordBar(std::make_unique( _wrap.get(), @@ -1389,7 +1392,7 @@ void ComposeControls::checkAutocomplete() { const auto peer = _history->peer; const auto autocomplete = _isInlineBot ? AutocompleteQuery() - : ParseMentionHashtagBotCommandQuery(_field); + : ParseMentionHashtagBotCommandQuery(_field, _features); if (!autocomplete.query.isEmpty()) { if (autocomplete.query[0] == '#' && cRecentWriteHashtags().isEmpty() @@ -1656,7 +1659,11 @@ void ComposeControls::initField() { _parent, _field, _session, - { .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow }); + { + .suggestCustomEmoji = true, + .allowCustomWithoutPremium = allow, + .st = &_st.suggestions, + }); _raiseEmojiSuggestions = [=] { suggestions->raise(); }; const auto rawTextEdit = _field->rawTextEdit().get(); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index d5749bfcb..223940671 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -7,10 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "base/required.h" #include "api/api_common.h" +#include "base/required.h" #include "base/unique_qptr.h" #include "base/timer.h" +#include "chat_helpers/compose/compose_features.h" #include "dialogs/dialogs_key.h" #include "history/view/controls/compose_controls_common.h" #include "ui/round_rect.h" @@ -93,16 +94,6 @@ enum class ComposeControlsMode { Scheduled, }; -struct ComposeControlsFeatures { - bool sendAs = true; - bool ttlInfo = true; - bool botCommandSend = true; - bool silentBroadcastToggle = true; - bool attachBotsMenu = true; - bool inlineBots = true; - bool stickersSettings = true; -}; - struct ComposeControlsDescriptor { const style::ComposeControls *stOverride = nullptr; std::shared_ptr show; @@ -111,7 +102,7 @@ struct ComposeControlsDescriptor { SendMenu::Type sendMenuType = {}; Window::SessionController *regularWindow = nullptr; rpl::producer stickerOrEmojiChosen; - ComposeControlsFeatures features; + ChatHelpers::ComposeFeatures features; }; class ComposeControls final { @@ -329,7 +320,7 @@ private: void changeFocusedControl(); const style::ComposeControls &_st; - const ComposeControlsFeatures _features; + const ChatHelpers::ComposeFeatures _features; const not_null _parent; const std::shared_ptr _show; const not_null _session; diff --git a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp index 6f9186882..3ce74ef55 100644 --- a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp +++ b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp @@ -321,7 +321,7 @@ void EmojiSelector::createSelector(Type type) { if (isEmoji) { st::userpicBuilderEmojiToggleStickersIcon.paintInCenter(p, r); } else { - st::emojiPeople.paintInCenter(p, r); + st::defaultEmojiPan.icons.people.paintInCenter(p, r); } }, toggleButton->lifetime()); } diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp index f800f192c..1b44b8fa2 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "inline_bots/inline_bot_result.h" #include "media/stories/media_stories_controller.h" #include "menu/menu_send.h" +#include "styles/style_chat_helpers.h" #include "styles/style_media_view.h" namespace Media::Stories { @@ -41,6 +42,12 @@ ReplyArea::ReplyArea(not_null controller) .silentBroadcastToggle = false, .attachBotsMenu = false, .inlineBots = false, + .megagroupSet = false, + .stickersSettings = false, + .openStickerSets = false, + .autocompleteHashtags = false, + .autocompleteMentions = false, + .autocompleteCommands = false, }, } )) { @@ -52,13 +59,27 @@ ReplyArea::~ReplyArea() { } void ReplyArea::initGeometry() { - _controller->layoutValue( - ) | rpl::start_with_next([=](const Layout &layout) { - _controls->resizeToWidth(layout.content.width()); - const auto position = layout.controlsBottomPosition - - QPoint(0, _controls->heightCurrent()); - _controls->move(position.x(), position.y()); - _controls->setAutocompleteBoundingRect(layout.autocompleteRect); + rpl::combine( + _controller->layoutValue(), + _controls->height() + ) | rpl::start_with_next([=](const Layout &layout, int height) { + const auto content = layout.content; + _controls->resizeToWidth(content.width()); + if (_controls->heightCurrent() == height) { + const auto position = layout.controlsBottomPosition + - QPoint(0, height); + _controls->move(position.x(), position.y()); + const auto &tabbed = st::storiesComposeControls.tabbed; + const auto upper = QRect( + content.x(), + content.y(), + content.width(), + (position.y() + + tabbed.autocompleteBottomSkip + - content.y())); + _controls->setAutocompleteBoundingRect( + layout.autocompleteRect.intersected(upper)); + } }, _lifetime); } diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 7e01278eb..aa9377f09 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -407,7 +407,7 @@ pipVolumeIcon2Over: icon {{ "player/player_volume_on", mediaviewPipControlsFgOve speedSliderDividerSize: size(2px, 8px); -storiesMaxSize: size(405px, 720px); +storiesMaxSize: size(540px, 960px); storiesMaxNameFontSize: 17px; storiesRadius: 8px; storiesControlSize: 64px; @@ -460,6 +460,53 @@ storiesAttach: IconButton(historyAttach) { } storiesRecordVoice: icon {{ "chat/input_record", storiesComposeGrayIcon }}; storiesRecordVoiceOver: icon {{ "chat/input_record", storiesComposeGrayIcon }}; +storiesRemoveSet: IconButton(stickerPanRemoveSet) { + icon: icon {{ "simple_close", storiesComposeGrayIcon }}; + iconOver: icon {{ "simple_close", storiesComposeGrayIcon }}; + ripple: RippleAnimation(defaultRippleAnimation) { + color: storiesComposeBgOver; + } +} +storiesMenu: Menu(defaultMenu) { + itemBg: groupCallMenuBg; + itemBgOver: groupCallMenuBgOver; + itemFg: groupCallMembersFg; + itemFgOver: groupCallMembersFg; + itemFgDisabled: groupCallMemberNotJoinedStatus; + itemFgShortcut: groupCallMemberNotJoinedStatus; + itemFgShortcutOver: groupCallMemberNotJoinedStatus; + itemFgShortcutDisabled: groupCallMemberNotJoinedStatus; + + separator: MenuSeparator(defaultMenuSeparator) { + fg: groupCallMenuBgOver; + } + arrow: icon {{ "menu/submenu_arrow", groupCallMemberNotJoinedStatus }}; + + ripple: RippleAnimation(defaultRippleAnimation) { + color: groupCallMenuBgRipple; + } +} +storiesMenuShadow: Shadow(defaultEmptyShadow) { + fallback: groupCallMenuBg; +} +storiesMenuAnimation: PanelAnimation(defaultPanelAnimation) { + fadeBg: groupCallMenuBg; + shadow: storiesMenuShadow; +} +storiesPopupMenu: PopupMenu(defaultPopupMenu) { + shadow: storiesMenuShadow; + menu: storiesMenu; + animation: storiesMenuAnimation; +} +storiesMenuWithIcons: Menu(storiesMenu) { + itemIconPosition: point(15px, 5px); + itemPadding: margins(54px, 8px, 17px, 8px); +} +storiesPopupMenuWithIcons: PopupMenu(storiesPopupMenu) { + scrollPadding: margins(0px, 5px, 0px, 5px); + menu: storiesMenuWithIcons; +} + storiesComposeControls: ComposeControls(defaultComposeControls) { bg: storiesComposeBg; radius: storiesRadius; @@ -469,6 +516,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { placeholderFg: storiesComposeGrayText; placeholderFgActive: storiesComposeGrayText; placeholderFgError: storiesComposeGrayText; + menu: storiesPopupMenu; } send: SendButton(historySend) { inner: IconButton(storiesAttach) { @@ -489,10 +537,30 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { lineFg: storiesComposeGrayIcon; lineFgOver: storiesComposeGrayIcon; } - tabbed: EmojiPan(defaultEmojiPan) { + suggestions: EmojiSuggestions(defaultEmojiSuggestions) { + dropdown: InnerDropdown(emojiSuggestionsDropdown) { + animation: PanelAnimation(defaultPanelAnimation) { + fadeBg: storiesComposeBg; + } + bg: storiesComposeBg; + } bg: storiesComposeBg; overBg: storiesComposeBgOver; - expandBg: storiesComposeGrayText; + textFg: storiesComposeWhiteText; + fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }}; + fadeRight: icon {{ "fade_horizontal", storiesComposeBg }}; + } + tabbed: EmojiPan(defaultEmojiPan) { + showAnimation: PanelAnimation(emojiPanAnimation) { + fadeBg: storiesComposeBg; + } + bg: storiesComposeBg; + headerFg: storiesComposeGrayText; + trendingHeaderFg: storiesComposeWhiteText; + trendingSubheaderFg: storiesComposeGrayText; + trendingUnreadFg: storiesComposeBlue; + trendingInstalled: icon {{ "chat/input_save", storiesComposeBlue }}; + overBg: storiesComposeBgOver; pathBg: storiesComposeBgRipple; pathFg: storiesComposeBgOver; textFg: storiesComposeWhiteText; @@ -500,6 +568,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { categoriesBgOver: storiesComposeBgOver; fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }}; fadeRight: icon {{ "fade_horizontal", storiesComposeBg }}; + menu: storiesPopupMenuWithIcons; tabs: SettingsSlider(emojiTabs) { barFgActive: storiesComposeBlue; labelFg: storiesComposeGrayText; @@ -536,5 +605,40 @@ storiesComposeControls: ComposeControls(defaultComposeControls) { ripple: emptyRippleAnimation; } } + removeSet: storiesRemoveSet; + boxLabel: FlatLabel(boxLabel) { + textFg: groupCallMembersFg; + } + icons: ComposeIcons { + settings: icon {{ "emoji/emoji_settings", storiesComposeGrayIcon }}; + + recent: icon {{ "emoji/emoji_recent", storiesComposeGrayIcon }}; + recentActive: icon {{ "emoji/emoji_recent", storiesComposeWhiteText }}; + people: icon {{ "emoji/emoji_smile", storiesComposeGrayIcon }}; + peopleActive: icon {{ "emoji/emoji_smile", storiesComposeWhiteText }}; + nature: icon {{ "emoji/emoji_nature", storiesComposeGrayIcon }}; + natureActive: icon {{ "emoji/emoji_nature", storiesComposeWhiteText }}; + food: icon {{ "emoji/emoji_food", storiesComposeGrayIcon }}; + foodActive: icon {{ "emoji/emoji_food", storiesComposeWhiteText }}; + activity: icon {{ "emoji/emoji_activities", storiesComposeGrayIcon }}; + activityActive: icon {{ "emoji/emoji_activities", storiesComposeWhiteText }}; + travel: icon {{ "emoji/emoji_travel", storiesComposeGrayIcon }}; + travelActive: icon {{ "emoji/emoji_travel", storiesComposeWhiteText }}; + objects: icon {{ "emoji/emoji_objects", storiesComposeGrayIcon }}; + objectsActive: icon {{ "emoji/emoji_objects", storiesComposeWhiteText }}; + symbols: icon {{ "emoji/emoji_love", storiesComposeGrayIcon }}; + symbolsActive: icon {{ "emoji/emoji_love", storiesComposeWhiteText }}; + + menuFave: icon {{ "menu/favorite", storiesComposeWhiteText }}; + menuUnfave: icon {{ "menu/unfavorite", storiesComposeWhiteText }}; + menuStickerSet: icon {{ "menu/stickers", storiesComposeWhiteText }}; + menuRecentRemove: icon {{ "menu/delete", storiesComposeWhiteText }}; + menuGifAdd: icon {{ "menu/gif", storiesComposeWhiteText }}; + menuGifRemove: icon {{ "menu/delete", storiesComposeWhiteText }}; + menuMute: icon {{ "menu/mute", storiesComposeWhiteText }}; + menuSchedule: icon {{ "menu/calendar", storiesComposeWhiteText }}; + menuWhenOnline: icon {{ "menu/send_when_online", storiesComposeWhiteText }}; + } + autocompleteBottomSkip: 10px; } } diff --git a/Telegram/SourceFiles/menu/menu_send.cpp b/Telegram/SourceFiles/menu/menu_send.cpp index 2d5ca3194..02ab8ed4b 100644 --- a/Telegram/SourceFiles/menu/menu_send.cpp +++ b/Telegram/SourceFiles/menu/menu_send.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history.h" #include "history/history_unread_things.h" #include "apiwrap.h" +#include "styles/style_chat_helpers.h" #include "styles/style_menu_icons.h" #include @@ -56,10 +57,14 @@ FillMenuResult FillSendMenu( Type type, Fn silent, Fn schedule, - Fn whenOnline) { + Fn whenOnline, + const style::ComposeIcons *iconsOverride) { if (!silent && !schedule) { return FillMenuResult::None; } + const auto &icons = iconsOverride + ? *iconsOverride + : st::defaultComposeIcons; const auto now = type; if (now == Type::Disabled || (!silent && now == Type::SilentOnly)) { @@ -70,7 +75,7 @@ FillMenuResult FillSendMenu( menu->addAction( tr::lng_send_silent_message(tr::now), silent, - &st::menuIconMute); + &icons.menuMute); } if (schedule && now != Type::SilentOnly) { menu->addAction( @@ -78,13 +83,13 @@ FillMenuResult FillSendMenu( ? tr::lng_reminder_message(tr::now) : tr::lng_schedule_message(tr::now)), schedule, - &st::menuIconSchedule); + &icons.menuSchedule); } if (whenOnline && now == Type::ScheduledToUser) { menu->addAction( tr::lng_scheduled_send_until_online(tr::now), whenOnline, - &st::menuIconWhenOnline); + &icons.menuWhenOnline); } return FillMenuResult::Success; } diff --git a/Telegram/SourceFiles/menu/menu_send.h b/Telegram/SourceFiles/menu/menu_send.h index 0676de49e..79edc3840 100644 --- a/Telegram/SourceFiles/menu/menu_send.h +++ b/Telegram/SourceFiles/menu/menu_send.h @@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +namespace style { +struct ComposeIcons; +} // namespace style + namespace Api { struct SendOptions; } // namespace Api @@ -47,7 +51,8 @@ FillMenuResult FillSendMenu( Type type, Fn silent, Fn schedule, - Fn whenOnline); + Fn whenOnline, + const style::ComposeIcons *iconsOverride = nullptr); void SetupMenuAndShortcuts( not_null button,