Finish improved stories reply area theming.
|
@ -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
|
||||||
|
|
Before Width: | Height: | Size: 470 B |
Before Width: | Height: | Size: 899 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 312 B |
Before Width: | Height: | Size: 494 B |
Before Width: | Height: | Size: 527 B |
Before Width: | Height: | Size: 1007 B |
Before Width: | Height: | Size: 1.4 KiB |
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
27
Telegram/SourceFiles/chat_helpers/compose/compose_features.h
Normal 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
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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] == '#'
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|