Finish improved stories reply area theming.

This commit is contained in:
John Preston 2023-05-17 15:51:04 +04:00
parent 75d2b5994f
commit a02876562a
38 changed files with 638 additions and 349 deletions

View File

@ -348,6 +348,7 @@ PRIVATE
calls/calls_video_bubble.h calls/calls_video_bubble.h
calls/calls_video_incoming.cpp calls/calls_video_incoming.cpp
calls/calls_video_incoming.h calls/calls_video_incoming.h
chat_helpers/compose/compose_features.h
chat_helpers/compose/compose_show.cpp chat_helpers/compose/compose_show.cpp
chat_helpers/compose/compose_show.h chat_helpers/compose/compose_show.h
chat_helpers/bot_command.cpp chat_helpers/bot_command.cpp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -606,6 +606,7 @@ void StickerSetBox::updateButtons() {
const auto session = &_show->session(); const auto session = &_show->session();
auto box = ChatHelpers::MakeConfirmRemoveSetBox( auto box = ChatHelpers::MakeConfirmRemoveSetBox(
session, session,
st::boxLabel,
_inner->setId()); _inner->setId());
if (box) { if (box) {
_show->showBox(std::move(box)); _show->showBox(std::move(box));

View File

@ -63,7 +63,7 @@ ShowButton::ShowButton(not_null<Ui::RpWidget*> parent)
_button.sizeValue( _button.sizeValue(
) | rpl::start_with_next([=](const QSize &s) { ) | rpl::start_with_next([=](const QSize &s) {
resize( resize(
s.width() + st::emojiSuggestionsFadeRight.width(), s.width() + st::defaultEmojiSuggestions.fadeRight.width(),
s.height()); s.height());
_button.moveToRight(0, 0); _button.moveToRight(0, 0);
}, lifetime()); }, lifetime());
@ -74,7 +74,7 @@ void ShowButton::paintEvent(QPaintEvent *e) {
auto p = QPainter(this); auto p = QPainter(this);
const auto clip = e->rect(); 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()); const auto fade = QRect(0, 0, icon.width(), height());
if (fade.intersects(clip)) { if (fade.intersects(clip)) {
icon.fill(p, fade); icon.fill(p, fade);

View File

@ -10,6 +10,7 @@ using "ui/basic.style";
using "boxes/boxes.style"; using "boxes/boxes.style";
using "ui/layers/layers.style"; using "ui/layers/layers.style";
using "ui/widgets/widgets.style"; using "ui/widgets/widgets.style";
using "ui/menu_icons.style";
GroupCallUserpics { GroupCallUserpics {
size: pixels; size: pixels;
@ -36,9 +37,50 @@ TabbedSearch {
height: pixels; 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 { EmojiPan {
margin: margins; margin: margins;
padding: margins; padding: margins;
showAnimation: PanelAnimation;
desiredSize: pixels; desiredSize: pixels;
verticalSizeSub: pixels; verticalSizeSub: pixels;
header: pixels; header: pixels;
@ -51,8 +93,12 @@ EmojiPan {
iconWidth: pixels; iconWidth: pixels;
iconArea: pixels; iconArea: pixels;
bg: color; bg: color;
headerFg: color;
trendingHeaderFg: color;
trendingSubheaderFg: color;
trendingUnreadFg: color;
trendingInstalled: icon;
overBg: color; overBg: color;
expandBg: color;
pathBg: color; pathBg: color;
pathFg: color; pathFg: color;
textFg: color; textFg: color;
@ -60,9 +106,14 @@ EmojiPan {
categoriesBgOver: color; categoriesBgOver: color;
fadeLeft: icon; fadeLeft: icon;
fadeRight: icon; fadeRight: icon;
menu: PopupMenu;
tabs: SettingsSlider; tabs: SettingsSlider;
search: TabbedSearch; search: TabbedSearch;
searchMargin: margins; searchMargin: margins;
removeSet: IconButton;
boxLabel: FlatLabel;
icons: ComposeIcons;
autocompleteBottomSkip: pixels;
} }
MessageBar { MessageBar {
@ -96,6 +147,7 @@ ComposeControls {
send: SendButton; send: SendButton;
attach: IconButton; attach: IconButton;
emoji: EmojiButton; emoji: EmojiButton;
suggestions: EmojiSuggestions;
tabbed: EmojiPan; tabbed: EmojiPan;
} }
@ -191,12 +243,6 @@ stickersScroll: ScrollArea(boxScroll) {
stickersRowDisabledOpacity: 0.4; stickersRowDisabledOpacity: 0.4;
stickersRowDuration: 200; 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 }}; emojiStatusDefault: icon {{ "emoji/stickers_premium", emojiIconFg }};
filtersRemove: IconButton(stickersRemove) { filtersRemove: IconButton(stickersRemove) {
@ -210,22 +256,6 @@ emojiTabs: SettingsSlider(defaultTabsSlider) {
barTop: 40px; barTop: 40px;
labelTop: 12px; 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; emojiCategoryIconTop: 6px;
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) { emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
@ -297,40 +327,6 @@ defaultTabbedSearch: TabbedSearch {
groupSkip: 2px; groupSkip: 2px;
height: 33px; 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; inlineResultsMinHeight: 278px;
inlineResultsMaxHeight: 640px; inlineResultsMaxHeight: 640px;
@ -394,6 +390,81 @@ stickersToast: Toast(defaultToast) {
stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }}; stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }};
emojiEmpty: icon {{ "emoji_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) { inlineBotsScroll: ScrollArea(defaultSolidScroll) {
deltat: stickerPanPadding; deltat: stickerPanPadding;
deltab: stickerPanPadding; deltab: stickerPanPadding;
@ -410,6 +481,15 @@ emojiSuggestionsScrolledWidth: 240px;
emojiSuggestionsPadding: margins(emojiColorsPadding, 0px, emojiColorsPadding, 0px); emojiSuggestionsPadding: margins(emojiColorsPadding, 0px, emojiColorsPadding, 0px);
emojiSuggestionsFadeAfter: 20px; 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; mentionHeight: 40px;
mentionPadding: margins(8px, 5px, 8px, 5px); mentionPadding: margins(8px, 5px, 8px, 5px);
mentionTop: 11px; mentionTop: 11px;
@ -479,9 +559,6 @@ reactPanelScroll: ScrollArea(emojiScroll) {
deltab: 7px; deltab: 7px;
} }
emojiSuggestionsFadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }};
emojiSuggestionsFadeRight: icon {{ "fade_horizontal", boxBg }};
choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }}; choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }};
choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }}; choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }};
choosePeerCreateIconLeft: 25px; choosePeerCreateIconLeft: 25px;
@ -857,5 +934,6 @@ defaultComposeControls: ComposeControls {
send: historySend; send: historySend;
attach: historyAttach; attach: historyAttach;
emoji: historyAttachEmoji; emoji: historyAttachEmoji;
suggestions: defaultEmojiSuggestions;
tabbed: defaultEmojiPan; tabbed: defaultEmojiPan;
} }

View File

@ -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

View File

@ -99,6 +99,7 @@ private:
QSize _singleSize; QSize _singleSize;
QPoint _areaPosition; QPoint _areaPosition;
QPoint _innerPosition; QPoint _innerPosition;
Ui::RoundRect _backgroundRect;
Ui::RoundRect _overBg; Ui::RoundRect _overBg;
bool _hiding = false; bool _hiding = false;
@ -125,6 +126,7 @@ EmojiColorPicker::EmojiColorPicker(
const style::EmojiPan &st) const style::EmojiPan &st)
: RpWidget(parent) : RpWidget(parent)
, _st(st) , _st(st)
, _backgroundRect(st::emojiPanRadius, _st.bg)
, _overBg(st::emojiPanRadius, _st.overBg) { , _overBg(st::emojiPanRadius, _st.overBg) {
setMouseTracking(true); setMouseTracking(true);
} }
@ -181,8 +183,8 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
p.drawPixmap(0, 0, _cache); p.drawPixmap(0, 0, _cache);
return; return;
} }
Ui::Shadow::paint(p, inner, width(), st::emojiPanAnimation.shadow); Ui::Shadow::paint(p, inner, width(), _st.showAnimation.shadow);
Ui::FillRoundRect(p, inner, st::boxBg, Ui::BoxCorners); _backgroundRect.paint(p, inner);
auto x = st::emojiPanMargins.left() + 2 * st::emojiColorsPadding + _singleSize.width(); auto x = st::emojiPanMargins.left() + 2 * st::emojiColorsPadding + _singleSize.width();
if (rtl()) x = width() - x - st::emojiColorsSep; if (rtl()) x = width() - x - st::emojiColorsSep;
@ -393,6 +395,7 @@ EmojiListWidget::EmojiListWidget(
descriptor.show, descriptor.show,
std::move(descriptor.paused)) std::move(descriptor.paused))
, _show(std::move(descriptor.show)) , _show(std::move(descriptor.show))
, _features(descriptor.features)
, _mode(descriptor.mode) , _mode(descriptor.mode)
, _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1) , _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1)
, _premiumIcon(_mode == Mode::EmojiStatus , _premiumIcon(_mode == Mode::EmojiStatus
@ -402,7 +405,7 @@ EmojiListWidget::EmojiListWidget(
std::make_unique<LocalStickersManager>(&session())) std::make_unique<LocalStickersManager>(&session()))
, _customRecentFactory(std::move(descriptor.customRecentFactory)) , _customRecentFactory(std::move(descriptor.customRecentFactory))
, _overBg(st::emojiPanRadius, st().overBg) , _overBg(st::emojiPanRadius, st().overBg)
, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg) , _collapsedBg(st::emojiPanExpand.height / 2, st().headerFg)
, _picker(this, st()) , _picker(this, st())
, _showPickerTimer([=] { showPicker(); }) { , _showPickerTimer([=] { showPicker(); }) {
setMouseTracking(true); setMouseTracking(true);
@ -1072,7 +1075,7 @@ void EmojiListWidget::paint(
- paintButtonGetWidth(p, info, buttonSelected, clip); - paintButtonGetWidth(p, info, buttonSelected, clip);
if (info.section > 0 && clip.top() < info.rowsTop) { if (info.section > 0 && clip.top() < info.rowsTop) {
p.setFont(st::emojiPanHeaderFont); p.setFont(st::emojiPanHeaderFont);
p.setPen(st::emojiPanHeaderFg); p.setPen(st().headerFg);
auto titleText = (info.section < _staticCount) auto titleText = (info.section < _staticCount)
? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now) ? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now)
: _custom[info.section - _staticCount].title; : _custom[info.section - _staticCount].title;
@ -1091,7 +1094,7 @@ void EmojiListWidget::paint(
} }
const auto textBaseline = top + st::emojiPanHeaderFont->ascent; const auto textBaseline = top + st::emojiPanHeaderFont->ascent;
p.setFont(st::emojiPanHeaderFont); p.setFont(st::emojiPanHeaderFont);
p.setPen(st::emojiPanHeaderFg); p.setPen(st().headerFg);
p.drawText(titleLeft, textBaseline, titleText); p.drawText(titleLeft, textBaseline, titleText);
} }
if (clip.top() + clip.height() > info.rowsTop) { if (clip.top() + clip.height() > info.rowsTop) {
@ -1459,7 +1462,8 @@ void EmojiListWidget::displaySet(uint64 setId) {
} }
void EmojiListWidget::removeSet(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)); checkHideWithBox(std::move(box));
} }
} }
@ -1532,9 +1536,10 @@ QRect EmojiListWidget::removeButtonRect(const SectionInfo &info) const {
if (_mode != Mode::Full) { if (_mode != Mode::Full) {
return QRect(); return QRect();
} }
const auto buttonw = st::stickerPanRemoveSet.rippleAreaPosition.x() const auto &removeSt = st().removeSet;
+ st::stickerPanRemoveSet.rippleAreaSize; const auto buttonw = removeSt.rippleAreaPosition.x()
const auto buttonh = st::stickerPanRemoveSet.height; + removeSt.rippleAreaSize;
const auto buttonh = removeSt.height;
const auto buttonx = emojiRight() - st::emojiPanRemoveSkip - buttonw; const auto buttonx = emojiRight() - st::emojiPanRemoveSkip - buttonw;
const auto buttony = info.top + st::emojiPanRemoveTop; const auto buttony = info.top + st::emojiPanRemoveTop;
return QRect(buttonx, buttony, buttonw, buttonh); return QRect(buttonx, buttony, buttonw, buttonh);
@ -1966,19 +1971,18 @@ int EmojiListWidget::paintButtonGetWidth(
if (remove.isEmpty()) { if (remove.isEmpty()) {
return 0; return 0;
} else if (remove.intersects(clip)) { } else if (remove.intersects(clip)) {
const auto &removeSt = st().removeSet;
if (custom.ripple) { if (custom.ripple) {
custom.ripple->paint( custom.ripple->paint(
p, p,
remove.x() + st::stickerPanRemoveSet.rippleAreaPosition.x(), remove.x() + removeSt.rippleAreaPosition.x(),
remove.y() + st::stickerPanRemoveSet.rippleAreaPosition.y(), remove.y() + removeSt.rippleAreaPosition.y(),
width()); width());
if (custom.ripple->empty()) { if (custom.ripple->empty()) {
custom.ripple.reset(); custom.ripple.reset();
} }
} }
const auto &icon = selected const auto &icon = selected ? removeSt.iconOver : removeSt.icon;
? st::stickerPanRemoveSet.iconOver
: st::stickerPanRemoveSet.icon;
icon.paint( icon.paint(
p, p,
(remove.topLeft() (remove.topLeft()
@ -2045,7 +2049,9 @@ void EmojiListWidget::updateSelected() {
if (hasButton(section) if (hasButton(section)
&& myrtlrect(buttonRect(section)).contains(p.x(), p.y())) { && myrtlrect(buttonRect(section)).contains(p.x(), p.y())) {
newSelected = OverButton{ section }; newSelected = OverButton{ section };
} else if (section >= _staticCount && _mode == Mode::Full) { } else if (_features.openStickerSets
&& section >= _staticCount
&& _mode == Mode::Full) {
newSelected = OverSet{ section }; newSelected = OverSet{ section };
} }
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) { } else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
@ -2159,13 +2165,12 @@ std::unique_ptr<Ui::RippleAnimation> EmojiListWidget::createButtonRipple(
&& section < _staticCount + _custom.size()); && section < _staticCount + _custom.size());
const auto remove = hasRemoveButton(section); const auto remove = hasRemoveButton(section);
const auto &st = remove const auto &removeSt = st().removeSet;
? st::stickerPanRemoveSet.ripple const auto &st = remove ? removeSt.ripple : st::emojiPanButton.ripple;
: st::emojiPanButton.ripple;
auto mask = remove auto mask = remove
? Ui::RippleAnimation::EllipseMask(QSize( ? Ui::RippleAnimation::EllipseMask(QSize(
st::stickerPanRemoveSet.rippleAreaSize, removeSt.rippleAreaSize,
st::stickerPanRemoveSet.rippleAreaSize)) removeSt.rippleAreaSize))
: rightButton(section).rippleMask; : rightButton(section).rippleMask;
return std::make_unique<Ui::RippleAnimation>( return std::make_unique<Ui::RippleAnimation>(
st, st,
@ -2179,7 +2184,7 @@ QPoint EmojiListWidget::buttonRippleTopLeft(int section) const {
return myrtlrect(buttonRect(section)).topLeft() return myrtlrect(buttonRect(section)).topLeft()
+ (hasRemoveButton(section) + (hasRemoveButton(section)
? st::stickerPanRemoveSet.rippleAreaPosition ? st().removeSet.rippleAreaPosition
: QPoint()); : QPoint());
} }

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "chat_helpers/compose/compose_features.h"
#include "chat_helpers/tabbed_selector.h" #include "chat_helpers/tabbed_selector.h"
#include "ui/widgets/tooltip.h" #include "ui/widgets/tooltip.h"
#include "ui/round_rect.h" #include "ui/round_rect.h"
@ -84,6 +85,7 @@ struct EmojiListDescriptor {
DocumentId, DocumentId,
Fn<void()>)> customRecentFactory; Fn<void()>)> customRecentFactory;
const style::EmojiPan *st = nullptr; const style::EmojiPan *st = nullptr;
ComposeFeatures features;
}; };
class EmojiListWidget final class EmojiListWidget final
@ -345,6 +347,7 @@ private:
void applyNextSearchQuery(); void applyNextSearchQuery();
const std::shared_ptr<Show> _show; const std::shared_ptr<Show> _show;
const ComposeFeatures _features;
Mode _mode = Mode::Full; Mode _mode = Mode::Full;
std::unique_ptr<Ui::TabbedSearch> _search; std::unique_ptr<Ui::TabbedSearch> _search;
const int _staticCount = 0; const int _staticCount = 0;

View File

@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "ui/cached_round_corners.h" #include "ui/cached_round_corners.h"
#include "ui/round_rect.h"
#include "platform/platform_specific.h" #include "platform/platform_specific.h"
#include "core/application.h" #include "core/application.h"
#include "base/event_filter.h" #include "base/event_filter.h"
@ -41,15 +42,133 @@ constexpr auto kAnimationDuration = crl::time(120);
} // namespace } // namespace
class SuggestionsWidget final : public Ui::RpWidget {
public:
SuggestionsWidget(
QWidget *parent,
const style::EmojiSuggestions &st,
not_null<Main::Session*> session,
bool suggestCustomEmoji,
Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium);
~SuggestionsWidget();
void showWithQuery(SuggestionsQuery query, bool force = false);
void selectFirstResult();
bool handleKeyEvent(int key);
[[nodiscard]] rpl::producer<bool> toggleAnimated() const;
struct Chosen {
QString emoji;
QString customData;
};
[[nodiscard]] rpl::producer<Chosen> triggered() const;
private:
struct Row {
Row(not_null<EmojiPtr> emoji, const QString &replacement);
Ui::Text::CustomEmoji *custom = nullptr;
DocumentData *document = nullptr;
not_null<EmojiPtr> emoji;
QString replacement;
};
struct Custom {
not_null<DocumentData*> document;
not_null<EmojiPtr> 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<QWheelEvent*> e);
void paintFadings(QPainter &p) const;
[[nodiscard]] std::vector<Row> getRowsByQuery(const QString &text) const;
[[nodiscard]] base::flat_multi_map<int, Custom> lookupCustom(
const std::vector<Row> &rows) const;
[[nodiscard]] std::vector<Row> appendCustom(
std::vector<Row> rows);
[[nodiscard]] std::vector<Row> appendCustom(
std::vector<Row> rows,
const base::flat_multi_map<int, Custom> &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<Ui::Text::CustomEmoji*> resolveCustomEmoji(
not_null<DocumentData*> document);
void customEmojiRepaint();
const style::EmojiSuggestions &_st;
const not_null<Main::Session*> _session;
SuggestionsQuery _query;
std::vector<Row> _rows;
bool _suggestCustomEmoji = false;
Fn<bool(not_null<DocumentData*>)> _allowCustomWithoutPremium;
Ui::RoundRect _overRect;
base::flat_map<
not_null<DocumentData*>,
std::unique_ptr<Ui::Text::CustomEmoji>> _customEmoji;
bool _repaintScheduled = false;
std::optional<QPoint> _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<bool> _toggleAnimated;
rpl::event_stream<Chosen> _triggered;
};
SuggestionsWidget::SuggestionsWidget( SuggestionsWidget::SuggestionsWidget(
QWidget *parent, QWidget *parent,
const style::EmojiSuggestions &st,
not_null<Main::Session*> session, not_null<Main::Session*> session,
bool suggestCustomEmoji, bool suggestCustomEmoji,
Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium) Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium)
: RpWidget(parent) : RpWidget(parent)
, _st(st)
, _session(session) , _session(session)
, _suggestCustomEmoji(suggestCustomEmoji) , _suggestCustomEmoji(suggestCustomEmoji)
, _allowCustomWithoutPremium(std::move(allowCustomWithoutPremium)) , _allowCustomWithoutPremium(std::move(allowCustomWithoutPremium))
, _overRect(st::roundRadiusSmall, _st.overBg)
, _oneWidth(st::emojiSuggestionSize) , _oneWidth(st::emojiSuggestionSize)
, _padding(st::emojiSuggestionsPadding) { , _padding(st::emojiSuggestionsPadding) {
resize( resize(
@ -284,7 +403,7 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
_repaintScheduled = false; _repaintScheduled = false;
const auto clip = e->rect(); const auto clip = e->rect();
p.fillRect(clip, st::boxBg); p.fillRect(clip, _st.bg);
const auto shift = innerShift(); const auto shift = innerShift();
p.translate(-shift); p.translate(-shift);
@ -298,15 +417,13 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
? _pressed ? _pressed
: _selectedAnimation.value(_selected); : _selectedAnimation.value(_selected);
if (selected > -1.) { if (selected > -1.) {
Ui::FillRoundRect( _overRect.paint(
p, p,
QRect(selected * _oneWidth, 0, _oneWidth, _oneWidth), QRect(selected * _oneWidth, 0, _oneWidth, _oneWidth));
st::emojiPanHover,
Ui::StickerHoverCorners);
} }
auto context = Ui::CustomEmoji::Context{ auto context = Ui::CustomEmoji::Context{
.textColor = st::windowFg->c, .textColor = _st.textFg->c,
.now = crl::now(), .now = crl::now(),
}; };
for (auto i = from; i != till; ++i) { for (auto i = from; i != till; ++i) {
@ -338,9 +455,9 @@ void SuggestionsWidget::paintFadings(QPainter &p) const {
const auto rect = myrtlrect( const auto rect = myrtlrect(
shift.x(), shift.x(),
0, 0,
st::emojiSuggestionsFadeLeft.width(), _st.fadeLeft.width(),
height()); height());
st::emojiSuggestionsFadeLeft.fill(p, rect); _st.fadeLeft.fill(p, rect);
p.setOpacity(1.); p.setOpacity(1.);
} }
const auto o_right = std::clamp( const auto o_right = std::clamp(
@ -350,11 +467,11 @@ void SuggestionsWidget::paintFadings(QPainter &p) const {
if (o_right > 0.) { if (o_right > 0.) {
p.setOpacity(o_right); p.setOpacity(o_right);
const auto rect = myrtlrect( const auto rect = myrtlrect(
shift.x() + width() - st::emojiSuggestionsFadeRight.width(), shift.x() + width() - _st.fadeRight.width(),
0, 0,
st::emojiSuggestionsFadeRight.width(), _st.fadeRight.width(),
height()); height());
st::emojiSuggestionsFadeRight.fill(p, rect); _st.fadeRight.fill(p, rect);
p.setOpacity(1.); p.setOpacity(1.);
} }
} }
@ -601,17 +718,17 @@ SuggestionsController::SuggestionsController(
not_null<QTextEdit*> field, not_null<QTextEdit*> field,
not_null<Main::Session*> session, not_null<Main::Session*> session,
const Options &options) const Options &options)
: _field(field) : _st(options.st ? *options.st : st::defaultEmojiSuggestions)
, _field(field)
, _session(session) , _session(session)
, _showExactTimer([=] { showWithQuery(getEmojiQuery()); }) , _showExactTimer([=] { showWithQuery(getEmojiQuery()); })
, _options(options) { , _options(options) {
_container = base::make_unique_q<InnerDropdown>( _container = base::make_unique_q<InnerDropdown>(outer, _st.dropdown);
outer,
st::emojiSuggestionsDropdown);
_container->setAutoHiding(false); _container->setAutoHiding(false);
_suggestions = _container->setOwnedWidget( _suggestions = _container->setOwnedWidget(
object_ptr<Ui::Emoji::SuggestionsWidget>( object_ptr<Ui::Emoji::SuggestionsWidget>(
_container, _container,
_st,
session, session,
_options.suggestCustomEmoji, _options.suggestCustomEmoji,
_options.allowCustomWithoutPremium)); _options.allowCustomWithoutPremium));
@ -910,7 +1027,7 @@ void SuggestionsController::updateGeometry() {
auto boundingRect = _container->parentWidget()->rect(); auto boundingRect = _container->parentWidget()->rect();
auto origin = rtl() ? PanelAnimation::Origin::BottomRight : PanelAnimation::Origin::BottomLeft; auto origin = rtl() ? PanelAnimation::Origin::BottomRight : PanelAnimation::Origin::BottomLeft;
auto point = rtl() ? (aroundRect.topLeft() + QPoint(aroundRect.width(), 0)) : aroundRect.topLeft(); 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; 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()); point -= rtl() ? QPoint(_container->width() - padding.right() - shift, _container->height()) : QPoint(padding.left() + shift, _container->height());
if (rtl()) { if (rtl()) {

View File

@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QTextEdit> #include <QtWidgets/QTextEdit>
namespace style {
struct EmojiSuggestions;
} // namespace style
namespace Main { namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
@ -29,125 +33,17 @@ class CustomEmoji;
namespace Ui::Emoji { namespace Ui::Emoji {
class SuggestionsWidget;
using SuggestionsQuery = std::variant<QString, EmojiPtr>; using SuggestionsQuery = std::variant<QString, EmojiPtr>;
class SuggestionsWidget final : public Ui::RpWidget {
public:
SuggestionsWidget(
QWidget *parent,
not_null<Main::Session*> session,
bool suggestCustomEmoji,
Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium);
~SuggestionsWidget();
void showWithQuery(SuggestionsQuery query, bool force = false);
void selectFirstResult();
bool handleKeyEvent(int key);
[[nodiscard]] rpl::producer<bool> toggleAnimated() const;
struct Chosen {
QString emoji;
QString customData;
};
[[nodiscard]] rpl::producer<Chosen> triggered() const;
private:
struct Row {
Row(not_null<EmojiPtr> emoji, const QString &replacement);
Ui::Text::CustomEmoji *custom = nullptr;
DocumentData *document = nullptr;
not_null<EmojiPtr> emoji;
QString replacement;
};
struct Custom {
not_null<DocumentData*> document;
not_null<EmojiPtr> 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<QWheelEvent*> e);
void paintFadings(QPainter &p) const;
[[nodiscard]] std::vector<Row> getRowsByQuery(const QString &text) const;
[[nodiscard]] base::flat_multi_map<int, Custom> lookupCustom(
const std::vector<Row> &rows) const;
[[nodiscard]] std::vector<Row> appendCustom(
std::vector<Row> rows);
[[nodiscard]] std::vector<Row> appendCustom(
std::vector<Row> rows,
const base::flat_multi_map<int, Custom> &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<Ui::Text::CustomEmoji*> resolveCustomEmoji(
not_null<DocumentData*> document);
void customEmojiRepaint();
const not_null<Main::Session*> _session;
SuggestionsQuery _query;
std::vector<Row> _rows;
bool _suggestCustomEmoji = false;
Fn<bool(not_null<DocumentData*>)> _allowCustomWithoutPremium;
base::flat_map<
not_null<DocumentData*>,
std::unique_ptr<Ui::Text::CustomEmoji>> _customEmoji;
bool _repaintScheduled = false;
std::optional<QPoint> _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<bool> _toggleAnimated;
rpl::event_stream<Chosen> _triggered;
};
class SuggestionsController { class SuggestionsController {
public: public:
struct Options { struct Options {
bool suggestExactFirstWord = true; bool suggestExactFirstWord = true;
bool suggestCustomEmoji = false; bool suggestCustomEmoji = false;
Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium; Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium;
const style::EmojiSuggestions *st = nullptr;
}; };
SuggestionsController( SuggestionsController(
@ -189,6 +85,7 @@ private:
bool fieldFilter(not_null<QEvent*> event); bool fieldFilter(not_null<QEvent*> event);
bool outerFilter(not_null<QEvent*> event); bool outerFilter(not_null<QEvent*> event);
const style::EmojiSuggestions &_st;
bool _shown = false; bool _shown = false;
bool _forceHidden = false; bool _forceHidden = false;
int _queryStartPosition = 0; int _queryStartPosition = 0;

View File

@ -685,6 +685,7 @@ void FieldAutocomplete::recount(bool resetScroll) {
} else if (!_brows.empty()) { } else if (!_brows.empty()) {
h = _brows.size() * st::mentionHeight; h = _brows.size() * st::mentionHeight;
} }
h += _st.autocompleteBottomSkip;
if (_inner->width() != _boundings.width() || _inner->height() != h) { if (_inner->width() != _boundings.width() || _inner->height() != h) {
_inner->resize(_boundings.width(), h); _inner->resize(_boundings.width(), h);
@ -1375,8 +1376,10 @@ void FieldAutocomplete::Inner::setSel(int sel, bool scroll) {
int32 row = _sel / _stickersPerRow; int32 row = _sel / _stickersPerRow;
const auto padding = st::stickerPanPadding; const auto padding = st::stickerPanPadding;
_scrollToRequested.fire({ _scrollToRequested.fire({
padding + row * st::stickerPanSize.height(), (row ? padding : 0) + row * st::stickerPanSize.height(),
padding + (row + 1) * st::stickerPanSize.height() }); (padding
+ (row + 1) * st::stickerPanSize.height()
+ _st.autocompleteBottomSkip) });
} }
} }
} }

View File

@ -57,7 +57,8 @@ constexpr auto kMinAfterScrollDelay = crl::time(33);
void AddGifAction( void AddGifAction(
Fn<void(QString, Fn<void()> &&, const style::icon*)> callback, Fn<void(QString, Fn<void()> &&, const style::icon*)> callback,
std::shared_ptr<Show> show, std::shared_ptr<Show> show,
not_null<DocumentData*> document) { not_null<DocumentData*> document,
const style::ComposeIcons *iconsOverride) {
if (!document->isGifv()) { if (!document->isGifv()) {
return; return;
} }
@ -67,6 +68,9 @@ void AddGifAction(
const auto text = (saved const auto text = (saved
? tr::lng_context_delete_gif ? tr::lng_context_delete_gif
: tr::lng_context_save_gif)(tr::now); : tr::lng_context_save_gif)(tr::now);
const auto &icons = iconsOverride
? *iconsOverride
: st::defaultComposeIcons;
callback(text, [=] { callback(text, [=] {
Api::ToggleSavedGif( Api::ToggleSavedGif(
show, show,
@ -80,7 +84,7 @@ void AddGifAction(
document->session().local().writeSavedGifs(); document->session().local().writeSavedGifs();
} }
data.stickers().notifySavedGifsUpdated(); data.stickers().notifySavedGifsUpdated();
}, saved ? &st::menuIconDelete : &st::menuIconGif); }, saved ? &icons.menuGifRemove : &icons.menuGifAdd);
} }
GifsListWidget::GifsListWidget( GifsListWidget::GifsListWidget(
@ -380,18 +384,18 @@ base::unique_qptr<Ui::PopupMenu> GifsListWidget::fillContextMenu(
return nullptr; return nullptr;
} }
auto menu = base::make_unique_q<Ui::PopupMenu>( auto menu = base::make_unique_q<Ui::PopupMenu>(this, st().menu);
this,
st::popupMenuWithIcons);
const auto send = [=, selected = _selected](Api::SendOptions options) { const auto send = [=, selected = _selected](Api::SendOptions options) {
selectInlineResult(selected, options, true); selectInlineResult(selected, options, true);
}; };
const auto icons = &st().icons;
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
menu, menu,
type, type,
SendMenu::DefaultSilentCallback(send), SendMenu::DefaultSilentCallback(send),
SendMenu::DefaultScheduleCallback(this, type, send), SendMenu::DefaultScheduleCallback(this, type, send),
SendMenu::DefaultWhenOnlineCallback(send)); SendMenu::DefaultWhenOnlineCallback(send),
icons);
if (const auto item = _mosaic.maybeItemAt(_selected)) { if (const auto item = _mosaic.maybeItemAt(_selected)) {
const auto document = item->getDocument() const auto document = item->getDocument()
@ -404,7 +408,7 @@ base::unique_qptr<Ui::PopupMenu> GifsListWidget::fillContextMenu(
const style::icon *icon) { const style::icon *icon) {
menu->addAction(text, std::move(done), icon); menu->addAction(text, std::move(done), icon);
}; };
AddGifAction(std::move(callback), _show, document); AddGifAction(std::move(callback), _show, document, icons);
} }
} }
return menu; return menu;

View File

@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QTimer> #include <QtCore/QTimer>
namespace style {
struct ComposeIcons;
} // namespace style
namespace Api { namespace Api {
struct SendOptions; struct SendOptions;
} // namespace Api } // namespace Api
@ -48,7 +52,8 @@ namespace ChatHelpers {
void AddGifAction( void AddGifAction(
Fn<void(QString, Fn<void()> &&, const style::icon*)> callback, Fn<void(QString, Fn<void()> &&, const style::icon*)> callback,
std::shared_ptr<Show> show, std::shared_ptr<Show> show,
not_null<DocumentData*> document); not_null<DocumentData*> document,
const style::ComposeIcons *iconsOverride = nullptr);
class StickersListFooter; class StickersListFooter;
struct StickerIcon; struct StickerIcon;

View File

@ -498,7 +498,8 @@ InlineBotQuery ParseInlineBotQuery(
} }
AutocompleteQuery ParseMentionHashtagBotCommandQuery( AutocompleteQuery ParseMentionHashtagBotCommandQuery(
not_null<const Ui::InputField*> field) { not_null<const Ui::InputField*> field,
ChatHelpers::ComposeFeatures features) {
auto result = AutocompleteQuery(); auto result = AutocompleteQuery();
const auto cursor = field->textCursor(); const auto cursor = field->textCursor();
@ -530,6 +531,9 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery(
const auto text = fragment.text(); const auto text = fragment.text();
for (auto i = position - fragmentPosition; i != 0; --i) { for (auto i = position - fragmentPosition; i != 0; --i) {
if (text[i - 1] == '@') { 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] == '_'))) { if ((position - fragmentPosition - i < 1 || text[i].isLetter()) && (i < 2 || !(text[i - 2].isLetterOrNumber() || text[i - 2] == '_'))) {
result.fromStart = (i == 1) && (fragmentPosition == 0); result.fromStart = (i == 1) && (fragmentPosition == 0);
result.query = text.mid(i - 1, position - fragmentPosition - i + 1); result.query = text.mid(i - 1, position - fragmentPosition - i + 1);
@ -540,12 +544,18 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery(
} }
return result; return result;
} else if (text[i - 1] == '#') { } else if (text[i - 1] == '#') {
if (!features.autocompleteHashtags) {
return {};
}
if (i < 2 || !(text[i - 2].isLetterOrNumber() || text[i - 2] == '_')) { if (i < 2 || !(text[i - 2].isLetterOrNumber() || text[i - 2] == '_')) {
result.fromStart = (i == 1) && (fragmentPosition == 0); result.fromStart = (i == 1) && (fragmentPosition == 0);
result.query = text.mid(i - 1, position - fragmentPosition - i + 1); result.query = text.mid(i - 1, position - fragmentPosition - i + 1);
} }
return result; return result;
} else if (text[i - 1] == '/') { } else if (text[i - 1] == '/') {
if (!features.autocompleteCommands) {
return {};
}
if (i < 2 && !fragmentPosition) { if (i < 2 && !fragmentPosition) {
result.fromStart = (i == 1) && (fragmentPosition == 0); result.fromStart = (i == 1) && (fragmentPosition == 0);
result.query = text.mid(i - 1, position - fragmentPosition - i + 1); result.query = text.mid(i - 1, position - fragmentPosition - i + 1);

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "base/timer.h" #include "base/timer.h"
#include "base/qt_connection.h" #include "base/qt_connection.h"
#include "chat_helpers/compose/compose_features.h"
#ifndef TDESKTOP_DISABLE_SPELLCHECK #ifndef TDESKTOP_DISABLE_SPELLCHECK
#include "boxes/dictionaries_manager.h" #include "boxes/dictionaries_manager.h"
@ -90,7 +91,8 @@ struct AutocompleteQuery {
bool fromStart = false; bool fromStart = false;
}; };
AutocompleteQuery ParseMentionHashtagBotCommandQuery( AutocompleteQuery ParseMentionHashtagBotCommandQuery(
not_null<const Ui::InputField*> field); not_null<const Ui::InputField*> field,
ChatHelpers::ComposeFeatures features);
class MessageLinksParser : private QObject { class MessageLinksParser : private QObject {
public: public:

View File

@ -292,7 +292,7 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor)
descriptor.st ? *descriptor.st : st::defaultEmojiPan) descriptor.st ? *descriptor.st : st::defaultEmojiPan)
, _session(descriptor.session) , _session(descriptor.session)
, _paused(descriptor.paused) , _paused(descriptor.paused)
, _settingsButtonVisible(descriptor.settingsButtonVisible) , _features(descriptor.features)
, _iconState([=] { update(); }) , _iconState([=] { update(); })
, _subiconState([=] { update(); }) , _subiconState([=] { update(); })
, _selectionBg(st::emojiPanRadius, st().categoriesBgOver) , _selectionBg(st::emojiPanRadius, st().categoriesBgOver)
@ -300,7 +300,7 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor)
setMouseTracking(true); setMouseTracking(true);
_iconsLeft = st().iconSkip _iconsLeft = st().iconSkip
+ (_settingsButtonVisible ? st().iconWidth : 0); + (_features.stickersSettings ? st().iconWidth : 0);
_iconsRight = st().iconSkip; _iconsRight = st().iconSkip;
_session->downloaderTaskFinished( _session->downloaderTaskFinished(
@ -618,7 +618,7 @@ void StickersListFooter::paint(
return; return;
} }
if (_settingsButtonVisible && !hasOnlyFeaturedSets()) { if (_features.stickersSettings) {
paintStickerSettingsIcon(p); paintStickerSettingsIcon(p);
} }
@ -1012,12 +1012,12 @@ void StickersListFooter::updateSelected() {
if (rtl()) x = width() - x; if (rtl()) x = width() - x;
const auto settingsLeft = _iconsLeft - _singleWidth; const auto settingsLeft = _iconsLeft - _singleWidth;
auto newOver = OverState(SpecialOver::None); auto newOver = OverState(SpecialOver::None);
if (_settingsButtonVisible if (_features.stickersSettings
&& x >= settingsLeft && x >= settingsLeft
&& x < settingsLeft + _singleWidth && x < settingsLeft + _singleWidth
&& y >= _iconsTop && y >= _iconsTop
&& y < _iconsTop + st().footer) { && y < _iconsTop + st().footer) {
if (!_icons.empty() && !hasOnlyFeaturedSets()) { if (!_icons.empty()) {
newOver = SpecialOver::Settings; newOver = SpecialOver::Settings;
} }
} else if (!_icons.empty()) { } else if (!_icons.empty()) {
@ -1161,17 +1161,11 @@ void StickersListFooter::refreshSubiconsGeometry() {
updateEmojiWidthCallback(); updateEmojiWidthCallback();
} }
bool StickersListFooter::hasOnlyFeaturedSets() const {
return (_icons.size() == 1)
&& (_icons[0].setId == Data::Stickers::FeaturedSetId);
}
void StickersListFooter::paintStickerSettingsIcon(QPainter &p) const { void StickersListFooter::paintStickerSettingsIcon(QPainter &p) const {
const auto settingsLeft = _iconsLeft - _singleWidth; const auto settingsLeft = _iconsLeft - _singleWidth;
st::stickersSettings.paint( st().icons.settings.paint(
p, p,
settingsLeft (settingsLeft + (_singleWidth - st().icons.settings.width()) / 2),
+ (_singleWidth - st::stickersSettings.width()) / 2,
_iconsTop + st::emojiCategoryIconTop, _iconsTop + st::emojiCategoryIconTop,
width()); width());
} }
@ -1411,22 +1405,22 @@ void StickersListFooter::paintSetIconToCache(
using Section = Ui::Emoji::Section; using Section = Ui::Emoji::Section;
const auto sectionIcon = [&](Section section, bool active) { const auto sectionIcon = [&](Section section, bool active) {
const auto icons = std::array{ const auto icons = std::array{
&st::emojiRecent, &st().icons.recent,
&st::emojiRecentActive, &st().icons.recentActive,
&st::emojiPeople, &st().icons.people,
&st::emojiPeopleActive, &st().icons.peopleActive,
&st::emojiNature, &st().icons.nature,
&st::emojiNatureActive, &st().icons.natureActive,
&st::emojiFood, &st().icons.food,
&st::emojiFoodActive, &st().icons.foodActive,
&st::emojiActivity, &st().icons.activity,
&st::emojiActivityActive, &st().icons.activityActive,
&st::emojiTravel, &st().icons.travel,
&st::emojiTravelActive, &st().icons.travelActive,
&st::emojiObjects, &st().icons.objects,
&st::emojiObjectsActive, &st().icons.objectsActive,
&st::emojiSymbols, &st().icons.symbols,
&st::emojiSymbolsActive, &st().icons.symbolsActive,
}; };
const auto index = int(section) * 2 + (active ? 1 : 0); const auto index = int(section) * 2 + (active ? 1 : 0);
@ -1464,15 +1458,8 @@ void StickersListFooter::paintSetIconToCache(
} else { } else {
paintOne(0, [&] { paintOne(0, [&] {
const auto selected = (info.index == _iconState.selected); const auto selected = (info.index == _iconState.selected);
if (icon.setId == Data::Stickers::FeaturedSetId) { if (icon.setId == AllEmojiSectionSetId()) {
const auto &stickers = _session->data().stickers(); return &st().icons.people;
return stickers.featuredSetsUnreadCount()
? &st::stickersTrendingUnread
: &st::stickersTrending;
//} else if (setId == Stickers::FavedSetId) {
// return &st::stickersFaved;
} else if (icon.setId == AllEmojiSectionSetId()) {
return &st::emojiPeople;
} else if (const auto section = SetIdEmojiSection(icon.setId)) { } else if (const auto section = SetIdEmojiSection(icon.setId)) {
return sectionIcon(*section, selected); return sectionIcon(*section, selected);
} }

View File

@ -7,8 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "media/clip/media_clip_reader.h" #include "chat_helpers/compose/compose_features.h"
#include "chat_helpers/tabbed_selector.h" #include "chat_helpers/tabbed_selector.h"
#include "media/clip/media_clip_reader.h"
#include "mtproto/sender.h" #include "mtproto/sender.h"
#include "ui/dpr/dpr_image.h" #include "ui/dpr/dpr_image.h"
#include "ui/round_rect.h" #include "ui/round_rect.h"
@ -116,8 +117,8 @@ public:
not_null<Main::Session*> session; not_null<Main::Session*> session;
Fn<bool()> paused; Fn<bool()> paused;
not_null<RpWidget*> parent; not_null<RpWidget*> parent;
bool settingsButtonVisible = false;
const style::EmojiPan *st = nullptr; const style::EmojiPan *st = nullptr;
ComposeFeatures features;
}; };
explicit StickersListFooter(Descriptor &&descriptor); explicit StickersListFooter(Descriptor &&descriptor);
@ -130,7 +131,6 @@ public:
uint64 activeSetId, uint64 activeSetId,
Fn<std::shared_ptr<Lottie::FrameRenderer>()> renderer, Fn<std::shared_ptr<Lottie::FrameRenderer>()> renderer,
ValidateIconAnimations animations); ValidateIconAnimations animations);
[[nodiscard]] bool hasOnlyFeaturedSets() const;
void leaveToChildEvent(QEvent *e, QWidget *child) override; void leaveToChildEvent(QEvent *e, QWidget *child) override;
@ -270,7 +270,7 @@ private:
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
const Fn<bool()> _paused; const Fn<bool()> _paused;
const bool _settingsButtonVisible = false; const ComposeFeatures _features;
static constexpr auto kVisibleIconsCount = 8; static constexpr auto kVisibleIconsCount = 8;

View File

@ -184,12 +184,12 @@ StickersListWidget::StickersListWidget(
descriptor.paused) descriptor.paused)
, _mode(descriptor.mode) , _mode(descriptor.mode)
, _show(std::move(descriptor.show)) , _show(std::move(descriptor.show))
, _features(descriptor.features)
, _overBg(st::roundRadiusSmall, st().overBg) , _overBg(st::roundRadiusSmall, st().overBg)
, _api(&session().mtp()) , _api(&session().mtp())
, _localSetsManager(std::make_unique<LocalStickersManager>(&session())) , _localSetsManager(std::make_unique<LocalStickersManager>(&session()))
, _section(Section::Stickers) , _section(Section::Stickers)
, _isMasks(_mode == Mode::Masks) , _isMasks(_mode == Mode::Masks)
, _settingsHidden(descriptor.settingsHidden)
, _updateItemsTimer([=] { updateItems(); }) , _updateItemsTimer([=] { updateItems(); })
, _updateSetsTimer([=] { updateSets(); }) , _updateSetsTimer([=] { updateSets(); })
, _trendingAddBgOver( , _trendingAddBgOver(
@ -286,8 +286,8 @@ object_ptr<TabbedSelector::InnerFooter> StickersListWidget::createFooter() {
.session = &session(), .session = &session(),
.paused = footerPaused, .paused = footerPaused,
.parent = this, .parent = this,
.settingsButtonVisible = !_settingsHidden,
.st = &st(), .st = &st(),
.features = _features,
}); });
_footer = result; _footer = result;
@ -298,7 +298,7 @@ object_ptr<TabbedSelector::InnerFooter> StickersListWidget::createFooter() {
_footer->openSettingsRequests( _footer->openSettingsRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
const auto onlyFeatured = _footer->hasOnlyFeaturedSets(); const auto onlyFeatured = !_isMasks && _mySets.empty();
_show->showBox(Box<StickersBox>( _show->showBox(Box<StickersBox>(
_show, _show,
(onlyFeatured (onlyFeatured
@ -908,7 +908,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
auto add = featuredAddRect(info); auto add = featuredAddRect(info);
int checkx = add.left() + (add.width() - st::stickersFeaturedInstalled.width()) / 2; int checkx = add.left() + (add.width() - st::stickersFeaturedInstalled.width()) / 2;
int checky = add.top() + (add.height() - st::stickersFeaturedInstalled.height()) / 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) { if (set.flags & SetFlag::Unread) {
widthForTitle -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip; widthForTitle -= st::stickersFeaturedUnreadSize + st::stickersFeaturedUnreadSkip;
@ -921,12 +921,12 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
titleWidth = st::stickersTrendingHeaderFont->width(titleText); titleWidth = st::stickersTrendingHeaderFont->width(titleText);
} }
p.setFont(st::stickersTrendingHeaderFont); 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); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st::stickersTrendingHeaderTop, width(), titleText, titleWidth);
if (set.flags & SetFlag::Unread) { if (set.flags & SetFlag::Unread) {
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(st::stickersFeaturedUnreadBg); p.setBrush(st().trendingUnreadFg);
{ {
PainterHighQualityEnabler hq(p); 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); auto statusText = (count > 0) ? tr::lng_stickers_count(tr::now, lt_count, count) : tr::lng_contacts_loading(tr::now);
p.setFont(st::stickersTrendingSubheaderFont); 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); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st::stickersTrendingSubheaderTop, width(), statusText);
if (info.rowsTop >= clip.y() + clip.height()) { if (info.rowsTop >= clip.y() + clip.height()) {
@ -963,13 +963,14 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
if (hasRemoveButton(info.section)) { if (hasRemoveButton(info.section)) {
auto remove = removeButtonRect(info); auto remove = removeButtonRect(info);
auto selected = selectedButton ? (selectedButton->section == info.section) : false; auto selected = selectedButton ? (selectedButton->section == info.section) : false;
const auto &removeSt = st().removeSet;
if (set.ripple) { 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()) { if (set.ripple->empty()) {
set.ripple.reset(); set.ripple.reset();
} }
} }
const auto &icon = selected ? st::stickerPanRemoveSet.iconOver : st::stickerPanRemoveSet.icon; const auto &icon = selected ? removeSt.iconOver : removeSt.icon;
icon.paint( icon.paint(
p, p,
remove.x() + (remove.width() - icon.width()) / 2, remove.x() + (remove.width() - icon.width()) / 2,
@ -983,7 +984,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
titleWidth = st::stickersTrendingHeaderFont->width(titleText); titleWidth = st::stickersTrendingHeaderFont->width(titleText);
} }
p.setFont(st::emojiPanHeaderFont); 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); p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st().headerTop, width(), titleText, titleWidth);
} }
if (clip.top() + clip.height() <= info.rowsTop) { if (clip.top() + clip.height() <= info.rowsTop) {
@ -1108,7 +1109,7 @@ int StickersListWidget::megagroupSetInfoLeft() const {
} }
void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected) { void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected) {
p.setPen(st::emojiPanHeaderFg); p.setPen(st().headerFg);
auto infoLeft = megagroupSetInfoLeft(); auto infoLeft = megagroupSetInfoLeft();
_megagroupSetAbout.drawLeft(p, infoLeft, y, width() - infoLeft, width()); _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 { QRect StickersListWidget::removeButtonRect(const SectionInfo &info) const {
auto buttonw = st::stickerPanRemoveSet.width; const auto &removeSt = st().removeSet;
auto buttonh = st::stickerPanRemoveSet.height; auto buttonw = removeSt.width;
auto buttonh = removeSt.height;
auto buttonx = stickersRight() - buttonw; auto buttonx = stickersRight() - buttonw;
auto buttony = info.top + (st().header - buttonh) / 2; auto buttony = info.top + (st().header - buttonh) / 2;
return QRect(buttonx, buttony, buttonw, buttonh); return QRect(buttonx, buttony, buttonw, buttonh);
@ -1561,10 +1563,11 @@ std::unique_ptr<Ui::RippleAnimation> StickersListWidget::createButtonRipple(int
std::move(mask), std::move(mask),
[this, section] { rtlupdate(featuredAddRect(section)); }); [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); auto mask = Ui::RippleAnimation::EllipseMask(maskSize);
return std::make_unique<Ui::RippleAnimation>( return std::make_unique<Ui::RippleAnimation>(
st::stickerPanRemoveSet.ripple, removeSt.ripple,
std::move(mask), std::move(mask),
[this, section] { rtlupdate(removeButtonRect(section)); }); [this, section] { rtlupdate(removeButtonRect(section)); });
} }
@ -1575,7 +1578,8 @@ QPoint StickersListWidget::buttonRippleTopLeft(int section) const {
if (shownSets()[section].externalLayout) { if (shownSets()[section].externalLayout) {
return myrtlrect(featuredAddRect(section)).topLeft(); 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<DocumentData*> document) { void StickersListWidget::showStickerSetBox(not_null<DocumentData*> document) {
@ -1604,9 +1608,7 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
auto &set = sets[section]; auto &set = sets[section];
Assert(index >= 0 && index < set.stickers.size()); Assert(index >= 0 && index < set.stickers.size());
auto menu = base::make_unique_q<Ui::PopupMenu>( auto menu = base::make_unique_q<Ui::PopupMenu>(this, st().menu);
this,
st::popupMenuWithIcons);
const auto document = set.stickers[sticker->index].document; const auto document = set.stickers[sticker->index].document;
const auto send = [=](Api::SendOptions options) { const auto send = [=](Api::SendOptions options) {
@ -1618,12 +1620,14 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
: messageSentAnimationInfo(section, index, document), : messageSentAnimationInfo(section, index, document),
}); });
}; };
const auto icons = &st().icons;
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
menu, menu,
type, type,
SendMenu::DefaultSilentCallback(send), SendMenu::DefaultSilentCallback(send),
SendMenu::DefaultScheduleCallback(this, type, send), SendMenu::DefaultScheduleCallback(this, type, send),
SendMenu::DefaultWhenOnlineCallback(send)); SendMenu::DefaultWhenOnlineCallback(send),
icons);
const auto show = _show; const auto show = _show;
const auto toggleFavedSticker = [=] { const auto toggleFavedSticker = [=] {
@ -1638,11 +1642,13 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
? tr::lng_faved_stickers_remove ? tr::lng_faved_stickers_remove
: tr::lng_faved_stickers_add)(tr::now), : tr::lng_faved_stickers_add)(tr::now),
toggleFavedSticker, toggleFavedSticker,
isFaved ? &st::menuIconUnfave : &st::menuIconFave); isFaved ? &icons->menuUnfave : &icons->menuFave);
menu->addAction(tr::lng_context_pack_info(tr::now), [=] { if (_features.openStickerSets) {
showStickerSetBox(document); menu->addAction(tr::lng_context_pack_info(tr::now), [=] {
}, &st::menuIconStickers); showStickerSetBox(document);
}, &icons->menuStickerSet);
}
if (const auto id = set.id; id == Data::Stickers::RecentSetId) { if (const auto id = set.id; id == Data::Stickers::RecentSetId) {
menu->addAction(tr::lng_recent_stickers_remove(tr::now), [=] { menu->addAction(tr::lng_recent_stickers_remove(tr::now), [=] {
@ -1650,7 +1656,7 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
document, document,
Data::FileOriginStickerSet(id, 0), Data::FileOriginStickerSet(id, 0),
false); false);
}, &st::menuIconDelete); }, &icons->menuRecentRemove);
} }
return menu; return menu;
} }
@ -1708,7 +1714,8 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
return; return;
} }
const auto document = set.stickers[sticker->index].document; const auto document = set.stickers[sticker->index].document;
if (e->modifiers() & Qt::ControlModifier) { if (_features.openStickerSets
&& (e->modifiers() & Qt::ControlModifier)) {
showStickerSetBox(document); showStickerSetBox(document);
} else { } else {
_chosen.fire({ _chosen.fire({
@ -1859,12 +1866,6 @@ void StickersListWidget::processPanelHideFinished() {
if (_footer) { if (_footer) {
_footer->clearHeavyData(); _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) { void StickersListWidget::setSection(Section section) {
@ -1994,9 +1995,6 @@ void StickersListWidget::refreshSettingsVisibility() {
void StickersListWidget::refreshFooterIcons() { void StickersListWidget::refreshFooterIcons() {
refreshIcons(ValidateIconAnimations::None); refreshIcons(ValidateIconAnimations::None);
if (_footer->hasOnlyFeaturedSets() && _section != Section::Featured) {
showStickerSet(Data::Stickers::FeaturedSetId);
}
} }
void StickersListWidget::preloadImages() { void StickersListWidget::preloadImages() {
@ -2064,9 +2062,6 @@ void StickersListWidget::refreshRecent() {
if (_section == Section::Stickers) { if (_section == Section::Stickers) {
refreshRecentStickers(); refreshRecentStickers();
} }
if (_footer && _footer->hasOnlyFeaturedSets() && _section != Section::Featured) {
showStickerSet(Data::Stickers::FeaturedSetId);
}
} }
auto StickersListWidget::collectRecentStickers() -> std::vector<Sticker> { auto StickersListWidget::collectRecentStickers() -> std::vector<Sticker> {
@ -2201,7 +2196,7 @@ void StickersListWidget::refreshFavedStickers() {
} }
void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) { void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) {
if (!_megagroupSet || _isMasks) { if (!_features.megagroupSet || !_megagroupSet || _isMasks) {
return; return;
} }
auto canEdit = _megagroupSet->canEditStickers(); auto canEdit = _megagroupSet->canEditStickers();
@ -2354,10 +2349,12 @@ void StickersListWidget::updateSelected() {
newSelected = OverButton{ section }; newSelected = OverButton{ section };
} else if (featuredHasAddButton(section) && myrtlrect(featuredAddRect(info)).contains(p.x(), p.y())) { } else if (featuredHasAddButton(section) && myrtlrect(featuredAddRect(info)).contains(p.x(), p.y())) {
newSelected = OverButton{ section }; newSelected = OverButton{ section };
} else if (!(sets[section].flags & SetFlag::Special)) { } else if (_features.openStickerSets
&& !(sets[section].flags & SetFlag::Special)) {
newSelected = OverSet{ section }; newSelected = OverSet{ section };
} else if (sets[section].id == Data::Stickers::MegagroupSetId } else if ((sets[section].id == Data::Stickers::MegagroupSetId)
&& (_megagroupSet->canEditStickers() || !sets[section].stickers.empty())) { && (_megagroupSet->canEditStickers()
|| !sets[section].stickers.empty())) {
newSelected = OverSet{ section }; newSelected = OverSet{ section };
} }
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom && sx >= 0) { } else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom && sx >= 0) {
@ -2624,10 +2621,12 @@ void StickersListWidget::removeMegagroupSet(bool locally) {
close(); close();
}), }),
.cancelled = [](Fn<void()> &&close) { close(); }, .cancelled = [](Fn<void()> &&close) { close(); },
.labelStyle = &st().boxLabel,
})); }));
} }
void StickersListWidget::removeSet(uint64 setId) { void StickersListWidget::removeSet(uint64 setId) {
const auto &st = this->st().boxLabel;
if (setId == Data::Stickers::MegagroupSetId) { if (setId == Data::Stickers::MegagroupSetId) {
const auto &sets = shownSets(); const auto &sets = shownSets();
const auto i = ranges::find(sets, setId, &Set::id); const auto i = ranges::find(sets, setId, &Set::id);
@ -2635,7 +2634,7 @@ void StickersListWidget::removeSet(uint64 setId) {
const auto removeLocally = i->stickers.empty() const auto removeLocally = i->stickers.empty()
|| !_megagroupSet->canEditStickers(); || !_megagroupSet->canEditStickers();
removeMegagroupSet(removeLocally); removeMegagroupSet(removeLocally);
} else if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) { } else if (auto box = MakeConfirmRemoveSetBox(&session(), st, setId)) {
checkHideWithBox(std::move(box)); checkHideWithBox(std::move(box));
} }
} }
@ -2660,6 +2659,7 @@ StickersListWidget::~StickersListWidget() = default;
object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox( object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const style::FlatLabel &st,
uint64 setId) { uint64 setId) {
const auto &sets = session->data().stickers().sets(); const auto &sets = session->data().stickers().sets();
const auto it = sets.find(setId); const auto it = sets.find(setId);
@ -2726,6 +2726,7 @@ object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox(
} }
}, },
.confirmText = tr::lng_stickers_remove_pack_confirm(), .confirmText = tr::lng_stickers_remove_pack_confirm(),
.labelStyle = &st,
}); });
} }

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "chat_helpers/compose/compose_features.h"
#include "chat_helpers/tabbed_selector.h" #include "chat_helpers/tabbed_selector.h"
#include "data/stickers/data_stickers.h" #include "data/stickers/data_stickers.h"
#include "ui/round_rect.h" #include "ui/round_rect.h"
@ -50,6 +51,7 @@ enum class Notification;
namespace style { namespace style {
struct EmojiPan; struct EmojiPan;
struct FlatLabel;
} // namespace style } // namespace style
namespace ChatHelpers { namespace ChatHelpers {
@ -70,7 +72,7 @@ struct StickersListDescriptor {
StickersListMode mode = StickersListMode::Full; StickersListMode mode = StickersListMode::Full;
Fn<bool()> paused; Fn<bool()> paused;
const style::EmojiPan *st = nullptr; const style::EmojiPan *st = nullptr;
bool settingsHidden = false; ComposeFeatures features;
}; };
class StickersListWidget final : public TabbedSelector::Inner { class StickersListWidget final : public TabbedSelector::Inner {
@ -352,6 +354,7 @@ private:
const Mode _mode; const Mode _mode;
const std::shared_ptr<Show> _show; const std::shared_ptr<Show> _show;
const ComposeFeatures _features;
Ui::RoundRect _overBg; Ui::RoundRect _overBg;
std::unique_ptr<Ui::TabbedSearch> _search; std::unique_ptr<Ui::TabbedSearch> _search;
MTP::Sender _api; MTP::Sender _api;
@ -375,7 +378,6 @@ private:
Section _section = Section::Stickers; Section _section = Section::Stickers;
const bool _isMasks; const bool _isMasks;
bool _settingsHidden = false;
base::Timer _updateItemsTimer; base::Timer _updateItemsTimer;
base::Timer _updateSetsTimer; base::Timer _updateSetsTimer;
@ -426,6 +428,7 @@ private:
[[nodiscard]] object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox( [[nodiscard]] object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const style::FlatLabel &st,
uint64 setId); uint64 setId);
} // namespace ChatHelpers } // namespace ChatHelpers

View File

@ -240,7 +240,7 @@ void TabbedPanel::paintEvent(QPaintEvent *e) {
hideFinished(); hideFinished();
} else { } else {
if (!_cache.isNull()) _cache = QPixmap(); 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()) { if (!_a_show.animating()) {
auto image = grabForAnimation(); auto image = grabForAnimation();
_showAnimation = std::make_unique<Ui::PanelAnimation>(st::emojiPanAnimation, _dropDown ? Ui::PanelAnimation::Origin::TopRight : Ui::PanelAnimation::Origin::BottomRight); _showAnimation = std::make_unique<Ui::PanelAnimation>(
_selector->st().showAnimation,
(_dropDown
? Ui::PanelAnimation::Origin::TopRight
: Ui::PanelAnimation::Origin::BottomRight));
auto inner = rect().marginsRemoved(st::emojiPanMargins); auto inner = rect().marginsRemoved(st::emojiPanMargins);
_showAnimation->setFinalImage(std::move(image), QRect(inner.topLeft() * cIntRetinaFactor(), inner.size() * cIntRetinaFactor())); _showAnimation->setFinalImage(std::move(image), QRect(inner.topLeft() * cIntRetinaFactor(), inner.size() * cIntRetinaFactor()));
_showAnimation->setCornerMasks(Images::CornersMask(st::emojiPanRadius)); _showAnimation->setCornerMasks(Images::CornersMask(st::emojiPanRadius));

View File

@ -344,6 +344,7 @@ TabbedSelector::TabbedSelector(
TabbedSelectorDescriptor &&descriptor) TabbedSelectorDescriptor &&descriptor)
: RpWidget(parent) : RpWidget(parent)
, _st(descriptor.st) , _st(descriptor.st)
, _features(descriptor.features)
, _show(std::move(descriptor.show)) , _show(std::move(descriptor.show))
, _level(descriptor.level) , _level(descriptor.level)
, _mode(descriptor.mode) , _mode(descriptor.mode)
@ -377,7 +378,6 @@ TabbedSelector::TabbedSelector(
: SelectorTab::Emoji) : SelectorTab::Emoji)
, _hasEmojiTab(ranges::contains(_tabs, SelectorTab::Emoji, &Tab::type)) , _hasEmojiTab(ranges::contains(_tabs, SelectorTab::Emoji, &Tab::type))
, _hasStickersTab(ranges::contains(_tabs, SelectorTab::Stickers, &Tab::type)) , _hasStickersTab(ranges::contains(_tabs, SelectorTab::Stickers, &Tab::type))
, _stickersSettingsHidden(descriptor.stickersSettingsHidden)
, _hasGifsTab(ranges::contains(_tabs, SelectorTab::Gifs, &Tab::type)) , _hasGifsTab(ranges::contains(_tabs, SelectorTab::Gifs, &Tab::type))
, _hasMasksTab(ranges::contains(_tabs, SelectorTab::Masks, &Tab::type)) , _hasMasksTab(ranges::contains(_tabs, SelectorTab::Masks, &Tab::type))
, _tabbed(_tabs.size() > 1) { , _tabbed(_tabs.size() > 1) {
@ -487,6 +487,10 @@ TabbedSelector::TabbedSelector(
TabbedSelector::~TabbedSelector() = default; TabbedSelector::~TabbedSelector() = default;
const style::EmojiPan &TabbedSelector::st() const {
return _st;
}
Main::Session &TabbedSelector::session() const { Main::Session &TabbedSelector::session() const {
return _show->session(); return _show->session();
} }
@ -511,6 +515,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) {
: EmojiMode::Full), : EmojiMode::Full),
.paused = paused, .paused = paused,
.st = &_st, .st = &_st,
.features = _features,
}); });
} }
case SelectorTab::Stickers: { case SelectorTab::Stickers: {
@ -521,7 +526,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) {
.mode = StickersMode::Full, .mode = StickersMode::Full,
.paused = paused, .paused = paused,
.st = &_st, .st = &_st,
.settingsHidden = _stickersSettingsHidden, .features = _features,
}); });
} }
case SelectorTab::Gifs: { case SelectorTab::Gifs: {
@ -540,6 +545,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) {
.mode = StickersMode::Masks, .mode = StickersMode::Masks,
.paused = paused, .paused = paused,
.st = &_st, .st = &_st,
.features = _features,
}); });
} }
} }

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "api/api_common.h" #include "api/api_common.h"
#include "chat_helpers/compose/compose_features.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/effects/message_sending_animation_common.h" #include "ui/effects/message_sending_animation_common.h"
@ -87,7 +88,7 @@ struct TabbedSelectorDescriptor {
const style::EmojiPan &st; const style::EmojiPan &st;
PauseReason level = {}; PauseReason level = {};
TabbedSelectorMode mode = TabbedSelectorMode::Full; TabbedSelectorMode mode = TabbedSelectorMode::Full;
bool stickersSettingsHidden = false; ComposeFeatures features;
}; };
[[nodiscard]] std::unique_ptr<Ui::TabbedSearch> MakeSearch( [[nodiscard]] std::unique_ptr<Ui::TabbedSearch> MakeSearch(
@ -117,6 +118,7 @@ public:
TabbedSelectorDescriptor &&descriptor); TabbedSelectorDescriptor &&descriptor);
~TabbedSelector(); ~TabbedSelector();
[[nodiscard]] const style::EmojiPan &st() const;
[[nodiscard]] Main::Session &session() const; [[nodiscard]] Main::Session &session() const;
[[nodiscard]] PauseReason level() const; [[nodiscard]] PauseReason level() const;
@ -267,6 +269,7 @@ private:
not_null<StickersListWidget*> masks() const; not_null<StickersListWidget*> masks() const;
const style::EmojiPan &_st; const style::EmojiPan &_st;
const ComposeFeatures _features;
const std::shared_ptr<Show> _show; const std::shared_ptr<Show> _show;
const PauseReason _level = {}; const PauseReason _level = {};
@ -291,7 +294,6 @@ private:
const bool _hasEmojiTab; const bool _hasEmojiTab;
const bool _hasStickersTab; const bool _hasStickersTab;
const bool _stickersSettingsHidden;
const bool _hasGifsTab; const bool _hasGifsTab;
const bool _hasMasksTab; const bool _hasMasksTab;
const bool _tabbed; const bool _tabbed;

View File

@ -1388,7 +1388,7 @@ AutocompleteQuery HistoryWidget::parseMentionHashtagBotCommandQuery() const {
const auto result = (isChoosingTheme() const auto result = (isChoosingTheme()
|| (_inlineBot && !_inlineLookingUpBot)) || (_inlineBot && !_inlineLookingUpBot))
? AutocompleteQuery() ? AutocompleteQuery()
: ParseMentionHashtagBotCommandQuery(_field); : ParseMentionHashtagBotCommandQuery(_field, {});
if (result.query.isEmpty()) { if (result.query.isEmpty()) {
return result; return result;
} else if (result.query[0] == '#' } else if (result.query[0] == '#'

View File

@ -956,7 +956,7 @@ ComposeControls::ComposeControls(
.st = _st.tabbed, .st = _st.tabbed,
.level = Window::GifPauseReason::TabbedPanel, .level = Window::GifPauseReason::TabbedPanel,
.mode = ChatHelpers::TabbedSelector::Mode::Full, .mode = ChatHelpers::TabbedSelector::Mode::Full,
.stickersSettingsHidden = !_features.stickersSettings, .features = _features,
})) }))
, _selector(_regularWindow , _selector(_regularWindow
? _regularWindow->tabbedSelector() ? _regularWindow->tabbedSelector()
@ -982,7 +982,10 @@ ComposeControls::ComposeControls(
_wrap.get(), _wrap.get(),
st::historyBotCommandStart) st::historyBotCommandStart)
: nullptr) : nullptr)
, _autocomplete(std::make_unique<FieldAutocomplete>(parent, _show)) , _autocomplete(std::make_unique<FieldAutocomplete>(
parent,
_show,
&_st.tabbed))
, _header(std::make_unique<FieldHeader>(_wrap.get(), _show)) , _header(std::make_unique<FieldHeader>(_wrap.get(), _show))
, _voiceRecordBar(std::make_unique<VoiceRecordBar>( , _voiceRecordBar(std::make_unique<VoiceRecordBar>(
_wrap.get(), _wrap.get(),
@ -1389,7 +1392,7 @@ void ComposeControls::checkAutocomplete() {
const auto peer = _history->peer; const auto peer = _history->peer;
const auto autocomplete = _isInlineBot const auto autocomplete = _isInlineBot
? AutocompleteQuery() ? AutocompleteQuery()
: ParseMentionHashtagBotCommandQuery(_field); : ParseMentionHashtagBotCommandQuery(_field, _features);
if (!autocomplete.query.isEmpty()) { if (!autocomplete.query.isEmpty()) {
if (autocomplete.query[0] == '#' if (autocomplete.query[0] == '#'
&& cRecentWriteHashtags().isEmpty() && cRecentWriteHashtags().isEmpty()
@ -1656,7 +1659,11 @@ void ComposeControls::initField() {
_parent, _parent,
_field, _field,
_session, _session,
{ .suggestCustomEmoji = true, .allowCustomWithoutPremium = allow }); {
.suggestCustomEmoji = true,
.allowCustomWithoutPremium = allow,
.st = &_st.suggestions,
});
_raiseEmojiSuggestions = [=] { suggestions->raise(); }; _raiseEmojiSuggestions = [=] { suggestions->raise(); };
const auto rawTextEdit = _field->rawTextEdit().get(); const auto rawTextEdit = _field->rawTextEdit().get();

View File

@ -7,10 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/required.h"
#include "api/api_common.h" #include "api/api_common.h"
#include "base/required.h"
#include "base/unique_qptr.h" #include "base/unique_qptr.h"
#include "base/timer.h" #include "base/timer.h"
#include "chat_helpers/compose/compose_features.h"
#include "dialogs/dialogs_key.h" #include "dialogs/dialogs_key.h"
#include "history/view/controls/compose_controls_common.h" #include "history/view/controls/compose_controls_common.h"
#include "ui/round_rect.h" #include "ui/round_rect.h"
@ -93,16 +94,6 @@ enum class ComposeControlsMode {
Scheduled, 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 { struct ComposeControlsDescriptor {
const style::ComposeControls *stOverride = nullptr; const style::ComposeControls *stOverride = nullptr;
std::shared_ptr<ChatHelpers::Show> show; std::shared_ptr<ChatHelpers::Show> show;
@ -111,7 +102,7 @@ struct ComposeControlsDescriptor {
SendMenu::Type sendMenuType = {}; SendMenu::Type sendMenuType = {};
Window::SessionController *regularWindow = nullptr; Window::SessionController *regularWindow = nullptr;
rpl::producer<ChatHelpers::FileChosen> stickerOrEmojiChosen; rpl::producer<ChatHelpers::FileChosen> stickerOrEmojiChosen;
ComposeControlsFeatures features; ChatHelpers::ComposeFeatures features;
}; };
class ComposeControls final { class ComposeControls final {
@ -329,7 +320,7 @@ private:
void changeFocusedControl(); void changeFocusedControl();
const style::ComposeControls &_st; const style::ComposeControls &_st;
const ComposeControlsFeatures _features; const ChatHelpers::ComposeFeatures _features;
const not_null<QWidget*> _parent; const not_null<QWidget*> _parent;
const std::shared_ptr<ChatHelpers::Show> _show; const std::shared_ptr<ChatHelpers::Show> _show;
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;

View File

@ -321,7 +321,7 @@ void EmojiSelector::createSelector(Type type) {
if (isEmoji) { if (isEmoji) {
st::userpicBuilderEmojiToggleStickersIcon.paintInCenter(p, r); st::userpicBuilderEmojiToggleStickersIcon.paintInCenter(p, r);
} else { } else {
st::emojiPeople.paintInCenter(p, r); st::defaultEmojiPan.icons.people.paintInCenter(p, r);
} }
}, toggleButton->lifetime()); }, toggleButton->lifetime());
} }

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "inline_bots/inline_bot_result.h" #include "inline_bots/inline_bot_result.h"
#include "media/stories/media_stories_controller.h" #include "media/stories/media_stories_controller.h"
#include "menu/menu_send.h" #include "menu/menu_send.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_media_view.h" #include "styles/style_media_view.h"
namespace Media::Stories { namespace Media::Stories {
@ -41,6 +42,12 @@ ReplyArea::ReplyArea(not_null<Controller*> controller)
.silentBroadcastToggle = false, .silentBroadcastToggle = false,
.attachBotsMenu = false, .attachBotsMenu = false,
.inlineBots = false, .inlineBots = false,
.megagroupSet = false,
.stickersSettings = false,
.openStickerSets = false,
.autocompleteHashtags = false,
.autocompleteMentions = false,
.autocompleteCommands = false,
}, },
} }
)) { )) {
@ -52,13 +59,27 @@ ReplyArea::~ReplyArea() {
} }
void ReplyArea::initGeometry() { void ReplyArea::initGeometry() {
_controller->layoutValue( rpl::combine(
) | rpl::start_with_next([=](const Layout &layout) { _controller->layoutValue(),
_controls->resizeToWidth(layout.content.width()); _controls->height()
const auto position = layout.controlsBottomPosition ) | rpl::start_with_next([=](const Layout &layout, int height) {
- QPoint(0, _controls->heightCurrent()); const auto content = layout.content;
_controls->move(position.x(), position.y()); _controls->resizeToWidth(content.width());
_controls->setAutocompleteBoundingRect(layout.autocompleteRect); 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); }, _lifetime);
} }

View File

@ -407,7 +407,7 @@ pipVolumeIcon2Over: icon {{ "player/player_volume_on", mediaviewPipControlsFgOve
speedSliderDividerSize: size(2px, 8px); speedSliderDividerSize: size(2px, 8px);
storiesMaxSize: size(405px, 720px); storiesMaxSize: size(540px, 960px);
storiesMaxNameFontSize: 17px; storiesMaxNameFontSize: 17px;
storiesRadius: 8px; storiesRadius: 8px;
storiesControlSize: 64px; storiesControlSize: 64px;
@ -460,6 +460,53 @@ storiesAttach: IconButton(historyAttach) {
} }
storiesRecordVoice: icon {{ "chat/input_record", storiesComposeGrayIcon }}; storiesRecordVoice: icon {{ "chat/input_record", storiesComposeGrayIcon }};
storiesRecordVoiceOver: 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) { storiesComposeControls: ComposeControls(defaultComposeControls) {
bg: storiesComposeBg; bg: storiesComposeBg;
radius: storiesRadius; radius: storiesRadius;
@ -469,6 +516,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
placeholderFg: storiesComposeGrayText; placeholderFg: storiesComposeGrayText;
placeholderFgActive: storiesComposeGrayText; placeholderFgActive: storiesComposeGrayText;
placeholderFgError: storiesComposeGrayText; placeholderFgError: storiesComposeGrayText;
menu: storiesPopupMenu;
} }
send: SendButton(historySend) { send: SendButton(historySend) {
inner: IconButton(storiesAttach) { inner: IconButton(storiesAttach) {
@ -489,10 +537,30 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
lineFg: storiesComposeGrayIcon; lineFg: storiesComposeGrayIcon;
lineFgOver: storiesComposeGrayIcon; lineFgOver: storiesComposeGrayIcon;
} }
tabbed: EmojiPan(defaultEmojiPan) { suggestions: EmojiSuggestions(defaultEmojiSuggestions) {
dropdown: InnerDropdown(emojiSuggestionsDropdown) {
animation: PanelAnimation(defaultPanelAnimation) {
fadeBg: storiesComposeBg;
}
bg: storiesComposeBg;
}
bg: storiesComposeBg; bg: storiesComposeBg;
overBg: storiesComposeBgOver; 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; pathBg: storiesComposeBgRipple;
pathFg: storiesComposeBgOver; pathFg: storiesComposeBgOver;
textFg: storiesComposeWhiteText; textFg: storiesComposeWhiteText;
@ -500,6 +568,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
categoriesBgOver: storiesComposeBgOver; categoriesBgOver: storiesComposeBgOver;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }}; fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }};
fadeRight: icon {{ "fade_horizontal", storiesComposeBg }}; fadeRight: icon {{ "fade_horizontal", storiesComposeBg }};
menu: storiesPopupMenuWithIcons;
tabs: SettingsSlider(emojiTabs) { tabs: SettingsSlider(emojiTabs) {
barFgActive: storiesComposeBlue; barFgActive: storiesComposeBlue;
labelFg: storiesComposeGrayText; labelFg: storiesComposeGrayText;
@ -536,5 +605,40 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
ripple: emptyRippleAnimation; 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;
} }
} }

View File

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h" #include "history/history.h"
#include "history/history_unread_things.h" #include "history/history_unread_things.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_menu_icons.h" #include "styles/style_menu_icons.h"
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
@ -56,10 +57,14 @@ FillMenuResult FillSendMenu(
Type type, Type type,
Fn<void()> silent, Fn<void()> silent,
Fn<void()> schedule, Fn<void()> schedule,
Fn<void()> whenOnline) { Fn<void()> whenOnline,
const style::ComposeIcons *iconsOverride) {
if (!silent && !schedule) { if (!silent && !schedule) {
return FillMenuResult::None; return FillMenuResult::None;
} }
const auto &icons = iconsOverride
? *iconsOverride
: st::defaultComposeIcons;
const auto now = type; const auto now = type;
if (now == Type::Disabled if (now == Type::Disabled
|| (!silent && now == Type::SilentOnly)) { || (!silent && now == Type::SilentOnly)) {
@ -70,7 +75,7 @@ FillMenuResult FillSendMenu(
menu->addAction( menu->addAction(
tr::lng_send_silent_message(tr::now), tr::lng_send_silent_message(tr::now),
silent, silent,
&st::menuIconMute); &icons.menuMute);
} }
if (schedule && now != Type::SilentOnly) { if (schedule && now != Type::SilentOnly) {
menu->addAction( menu->addAction(
@ -78,13 +83,13 @@ FillMenuResult FillSendMenu(
? tr::lng_reminder_message(tr::now) ? tr::lng_reminder_message(tr::now)
: tr::lng_schedule_message(tr::now)), : tr::lng_schedule_message(tr::now)),
schedule, schedule,
&st::menuIconSchedule); &icons.menuSchedule);
} }
if (whenOnline && now == Type::ScheduledToUser) { if (whenOnline && now == Type::ScheduledToUser) {
menu->addAction( menu->addAction(
tr::lng_scheduled_send_until_online(tr::now), tr::lng_scheduled_send_until_online(tr::now),
whenOnline, whenOnline,
&st::menuIconWhenOnline); &icons.menuWhenOnline);
} }
return FillMenuResult::Success; return FillMenuResult::Success;
} }

View File

@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
namespace style {
struct ComposeIcons;
} // namespace style
namespace Api { namespace Api {
struct SendOptions; struct SendOptions;
} // namespace Api } // namespace Api
@ -47,7 +51,8 @@ FillMenuResult FillSendMenu(
Type type, Type type,
Fn<void()> silent, Fn<void()> silent,
Fn<void()> schedule, Fn<void()> schedule,
Fn<void()> whenOnline); Fn<void()> whenOnline,
const style::ComposeIcons *iconsOverride = nullptr);
void SetupMenuAndShortcuts( void SetupMenuAndShortcuts(
not_null<Ui::RpWidget*> button, not_null<Ui::RpWidget*> button,