Finish improved stories reply area theming.

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

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

View File

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

View File

@ -10,6 +10,7 @@ using "ui/basic.style";
using "boxes/boxes.style";
using "ui/layers/layers.style";
using "ui/widgets/widgets.style";
using "ui/menu_icons.style";
GroupCallUserpics {
size: pixels;
@ -36,9 +37,50 @@ TabbedSearch {
height: pixels;
}
ComposeIcons {
settings: icon;
recent: icon;
recentActive: icon;
people: icon;
peopleActive: icon;
nature: icon;
natureActive: icon;
food: icon;
foodActive: icon;
activity: icon;
activityActive: icon;
travel: icon;
travelActive: icon;
objects: icon;
objectsActive: icon;
symbols: icon;
symbolsActive: icon;
menuFave: icon;
menuUnfave: icon;
menuStickerSet: icon;
menuRecentRemove: icon;
menuGifAdd: icon;
menuGifRemove: icon;
menuMute: icon;
menuSchedule: icon;
menuWhenOnline: icon;
}
EmojiSuggestions {
dropdown: InnerDropdown;
bg: color;
overBg: color;
textFg: color;
fadeLeft: icon;
fadeRight: icon;
}
EmojiPan {
margin: margins;
padding: margins;
showAnimation: PanelAnimation;
desiredSize: pixels;
verticalSizeSub: pixels;
header: pixels;
@ -51,8 +93,12 @@ EmojiPan {
iconWidth: pixels;
iconArea: pixels;
bg: color;
headerFg: color;
trendingHeaderFg: color;
trendingSubheaderFg: color;
trendingUnreadFg: color;
trendingInstalled: icon;
overBg: color;
expandBg: color;
pathBg: color;
pathFg: color;
textFg: color;
@ -60,9 +106,14 @@ EmojiPan {
categoriesBgOver: color;
fadeLeft: icon;
fadeRight: icon;
menu: PopupMenu;
tabs: SettingsSlider;
search: TabbedSearch;
searchMargin: margins;
removeSet: IconButton;
boxLabel: FlatLabel;
icons: ComposeIcons;
autocompleteBottomSkip: pixels;
}
MessageBar {
@ -96,6 +147,7 @@ ComposeControls {
send: SendButton;
attach: IconButton;
emoji: EmojiButton;
suggestions: EmojiSuggestions;
tabbed: EmojiPan;
}
@ -191,12 +243,6 @@ stickersScroll: ScrollArea(boxScroll) {
stickersRowDisabledOpacity: 0.4;
stickersRowDuration: 200;
stickersSettings: icon {{ "emoji/emoji_settings", emojiIconFg }};
stickersTrending: icon {{ "emoji/stickers_add", emojiIconFg }};
stickersTrendingUnread: icon {
{ "emoji/stickers_add_unread", emojiIconFg },
{ "emoji/stickers_add_dot", dialogsUnreadBg }
};
emojiStatusDefault: icon {{ "emoji/stickers_premium", emojiIconFg }};
filtersRemove: IconButton(stickersRemove) {
@ -210,22 +256,6 @@ emojiTabs: SettingsSlider(defaultTabsSlider) {
barTop: 40px;
labelTop: 12px;
}
emojiRecent: icon {{ "emoji/emoji_recent", emojiIconFg }};
emojiRecentActive: icon {{ "emoji/emoji_recent", emojiSubIconFgActive }};
emojiPeople: icon {{ "emoji/emoji_smile", emojiIconFg }};
emojiPeopleActive: icon {{ "emoji/emoji_smile", emojiSubIconFgActive }};
emojiNature: icon {{ "emoji/emoji_nature", emojiIconFg }};
emojiNatureActive: icon {{ "emoji/emoji_nature", emojiSubIconFgActive }};
emojiFood: icon {{ "emoji/emoji_food", emojiIconFg }};
emojiFoodActive: icon {{ "emoji/emoji_food", emojiSubIconFgActive }};
emojiActivity: icon {{ "emoji/emoji_activities", emojiIconFg }};
emojiActivityActive: icon {{ "emoji/emoji_activities", emojiSubIconFgActive }};
emojiTravel: icon {{ "emoji/emoji_travel", emojiIconFg }};
emojiTravelActive: icon {{ "emoji/emoji_travel", emojiSubIconFgActive }};
emojiObjects: icon {{ "emoji/emoji_objects", emojiIconFg }};
emojiObjectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }};
emojiSymbols: icon {{ "emoji/emoji_love", emojiIconFg }};
emojiSymbolsActive: icon {{ "emoji/emoji_love", emojiSubIconFgActive }};
emojiCategoryIconTop: 6px;
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
@ -297,40 +327,6 @@ defaultTabbedSearch: TabbedSearch {
groupSkip: 2px;
height: 33px;
}
defaultEmojiPan: EmojiPan {
margin: margins(7px, 0px, 7px, 0px);
padding: margins(7px, 0px, 4px, 7px);
desiredSize: 37px;
verticalSizeSub: 1px;
header: 33px;
headerLeft: 14px;
headerLockLeft: 7px;
headerLockedLeft: 26px;
headerTop: 10px;
footer: 36px;
iconSkip: 3px;
iconWidth: 30px;
iconArea: 28px;
bg: emojiPanBg;
overBg: emojiPanHover;
expandBg: emojiPanHeaderFg;
pathBg: windowBgRipple;
pathFg: windowBgOver;
textFg: windowFg;
categoriesBg: emojiPanCategories;
categoriesBgOver: windowBgRipple;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }};
fadeRight: icon {{ "fade_horizontal", emojiPanCategories }};
tabs: emojiTabs;
search: defaultTabbedSearch;
searchMargin: margins(1px, 11px, 2px, 5px);
}
statusEmojiPan: EmojiPan(defaultEmojiPan) {
categoriesBg: windowBg;
categoriesBgOver: windowBgOver;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", windowBg }};
fadeRight: icon {{ "fade_horizontal", windowBg }};
}
inlineResultsMinHeight: 278px;
inlineResultsMaxHeight: 640px;
@ -394,6 +390,81 @@ stickersToast: Toast(defaultToast) {
stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }};
emojiEmpty: icon {{ "emoji_empty", windowSubTextFg }};
defaultComposeIcons: ComposeIcons {
settings: icon {{ "emoji/emoji_settings", emojiIconFg }};
recent: icon {{ "emoji/emoji_recent", emojiIconFg }};
recentActive: icon {{ "emoji/emoji_recent", emojiSubIconFgActive }};
people: icon {{ "emoji/emoji_smile", emojiIconFg }};
peopleActive: icon {{ "emoji/emoji_smile", emojiSubIconFgActive }};
nature: icon {{ "emoji/emoji_nature", emojiIconFg }};
natureActive: icon {{ "emoji/emoji_nature", emojiSubIconFgActive }};
food: icon {{ "emoji/emoji_food", emojiIconFg }};
foodActive: icon {{ "emoji/emoji_food", emojiSubIconFgActive }};
activity: icon {{ "emoji/emoji_activities", emojiIconFg }};
activityActive: icon {{ "emoji/emoji_activities", emojiSubIconFgActive }};
travel: icon {{ "emoji/emoji_travel", emojiIconFg }};
travelActive: icon {{ "emoji/emoji_travel", emojiSubIconFgActive }};
objects: icon {{ "emoji/emoji_objects", emojiIconFg }};
objectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }};
symbols: icon {{ "emoji/emoji_love", emojiIconFg }};
symbolsActive: icon {{ "emoji/emoji_love", emojiSubIconFgActive }};
menuFave: menuIconFave;
menuUnfave: menuIconUnfave;
menuStickerSet: menuIconStickers;
menuRecentRemove: menuIconDelete;
menuGifAdd: menuIconGif;
menuGifRemove: menuIconDelete;
menuMute: menuIconMute;
menuSchedule: menuIconSchedule;
menuWhenOnline: menuIconWhenOnline;
}
defaultEmojiPan: EmojiPan {
margin: margins(7px, 0px, 7px, 0px);
padding: margins(7px, 0px, 4px, 7px);
showAnimation: emojiPanAnimation;
desiredSize: 37px;
verticalSizeSub: 1px;
header: 33px;
headerLeft: 14px;
headerLockLeft: 7px;
headerLockedLeft: 26px;
headerTop: 10px;
footer: 36px;
iconSkip: 3px;
iconWidth: 30px;
iconArea: 28px;
bg: emojiPanBg;
headerFg: emojiPanHeaderFg;
trendingHeaderFg: stickersTrendingHeaderFg;
trendingSubheaderFg: stickersTrendingSubheaderFg;
trendingUnreadFg: stickersFeaturedUnreadBg;
trendingInstalled: stickersFeaturedInstalled;
overBg: emojiPanHover;
pathBg: windowBgRipple;
pathFg: windowBgOver;
textFg: windowFg;
categoriesBg: emojiPanCategories;
categoriesBgOver: windowBgRipple;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }};
fadeRight: icon {{ "fade_horizontal", emojiPanCategories }};
menu: popupMenuWithIcons;
tabs: emojiTabs;
search: defaultTabbedSearch;
searchMargin: margins(1px, 11px, 2px, 5px);
removeSet: stickerPanRemoveSet;
boxLabel: boxLabel;
icons: defaultComposeIcons;
autocompleteBottomSkip: 0px;
}
statusEmojiPan: EmojiPan(defaultEmojiPan) {
categoriesBg: windowBg;
categoriesBgOver: windowBgOver;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", windowBg }};
fadeRight: icon {{ "fade_horizontal", windowBg }};
}
inlineBotsScroll: ScrollArea(defaultSolidScroll) {
deltat: stickerPanPadding;
deltab: stickerPanPadding;
@ -410,6 +481,15 @@ emojiSuggestionsScrolledWidth: 240px;
emojiSuggestionsPadding: margins(emojiColorsPadding, 0px, emojiColorsPadding, 0px);
emojiSuggestionsFadeAfter: 20px;
defaultEmojiSuggestions: EmojiSuggestions {
dropdown: emojiSuggestionsDropdown;
bg: menuBg;
overBg: emojiPanHover;
textFg: windowFg;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }};
fadeRight: icon {{ "fade_horizontal", boxBg }};
}
mentionHeight: 40px;
mentionPadding: margins(8px, 5px, 8px, 5px);
mentionTop: 11px;
@ -479,9 +559,6 @@ reactPanelScroll: ScrollArea(emojiScroll) {
deltab: 7px;
}
emojiSuggestionsFadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }};
emojiSuggestionsFadeRight: icon {{ "fade_horizontal", boxBg }};
choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }};
choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }};
choosePeerCreateIconLeft: 25px;
@ -857,5 +934,6 @@ defaultComposeControls: ComposeControls {
send: historySend;
attach: historyAttach;
emoji: historyAttachEmoji;
suggestions: defaultEmojiSuggestions;
tabbed: defaultEmojiPan;
}

View File

@ -0,0 +1,27 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace ChatHelpers {
struct ComposeFeatures {
bool sendAs = true;
bool ttlInfo = true;
bool botCommandSend = true;
bool silentBroadcastToggle = true;
bool attachBotsMenu = true;
bool inlineBots = true;
bool megagroupSet = true;
bool stickersSettings = true;
bool openStickerSets = true;
bool autocompleteHashtags = true;
bool autocompleteMentions = true;
bool autocompleteCommands = true;
};
} // namespace ChatHelpers

View File

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

View File

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

View File

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

View File

@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QTextEdit>
namespace style {
struct EmojiSuggestions;
} // namespace style
namespace Main {
class Session;
} // namespace Main
@ -29,125 +33,17 @@ class CustomEmoji;
namespace Ui::Emoji {
class SuggestionsWidget;
using SuggestionsQuery = std::variant<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 {
public:
struct Options {
bool suggestExactFirstWord = true;
bool suggestCustomEmoji = false;
Fn<bool(not_null<DocumentData*>)> allowCustomWithoutPremium;
const style::EmojiSuggestions *st = nullptr;
};
SuggestionsController(
@ -189,6 +85,7 @@ private:
bool fieldFilter(not_null<QEvent*> event);
bool outerFilter(not_null<QEvent*> event);
const style::EmojiSuggestions &_st;
bool _shown = false;
bool _forceHidden = false;
int _queryStartPosition = 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -240,7 +240,7 @@ void TabbedPanel::paintEvent(QPaintEvent *e) {
hideFinished();
} else {
if (!_cache.isNull()) _cache = QPixmap();
Ui::Shadow::paint(p, innerRect(), width(), st::emojiPanAnimation.shadow);
Ui::Shadow::paint(p, innerRect(), width(), _selector->st().showAnimation.shadow);
}
}
@ -362,7 +362,11 @@ void TabbedPanel::startShowAnimation() {
if (!_a_show.animating()) {
auto image = grabForAnimation();
_showAnimation = std::make_unique<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);
_showAnimation->setFinalImage(std::move(image), QRect(inner.topLeft() * cIntRetinaFactor(), inner.size() * cIntRetinaFactor()));
_showAnimation->setCornerMasks(Images::CornersMask(st::emojiPanRadius));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -407,7 +407,7 @@ pipVolumeIcon2Over: icon {{ "player/player_volume_on", mediaviewPipControlsFgOve
speedSliderDividerSize: size(2px, 8px);
storiesMaxSize: size(405px, 720px);
storiesMaxSize: size(540px, 960px);
storiesMaxNameFontSize: 17px;
storiesRadius: 8px;
storiesControlSize: 64px;
@ -460,6 +460,53 @@ storiesAttach: IconButton(historyAttach) {
}
storiesRecordVoice: icon {{ "chat/input_record", storiesComposeGrayIcon }};
storiesRecordVoiceOver: icon {{ "chat/input_record", storiesComposeGrayIcon }};
storiesRemoveSet: IconButton(stickerPanRemoveSet) {
icon: icon {{ "simple_close", storiesComposeGrayIcon }};
iconOver: icon {{ "simple_close", storiesComposeGrayIcon }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: storiesComposeBgOver;
}
}
storiesMenu: Menu(defaultMenu) {
itemBg: groupCallMenuBg;
itemBgOver: groupCallMenuBgOver;
itemFg: groupCallMembersFg;
itemFgOver: groupCallMembersFg;
itemFgDisabled: groupCallMemberNotJoinedStatus;
itemFgShortcut: groupCallMemberNotJoinedStatus;
itemFgShortcutOver: groupCallMemberNotJoinedStatus;
itemFgShortcutDisabled: groupCallMemberNotJoinedStatus;
separator: MenuSeparator(defaultMenuSeparator) {
fg: groupCallMenuBgOver;
}
arrow: icon {{ "menu/submenu_arrow", groupCallMemberNotJoinedStatus }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: groupCallMenuBgRipple;
}
}
storiesMenuShadow: Shadow(defaultEmptyShadow) {
fallback: groupCallMenuBg;
}
storiesMenuAnimation: PanelAnimation(defaultPanelAnimation) {
fadeBg: groupCallMenuBg;
shadow: storiesMenuShadow;
}
storiesPopupMenu: PopupMenu(defaultPopupMenu) {
shadow: storiesMenuShadow;
menu: storiesMenu;
animation: storiesMenuAnimation;
}
storiesMenuWithIcons: Menu(storiesMenu) {
itemIconPosition: point(15px, 5px);
itemPadding: margins(54px, 8px, 17px, 8px);
}
storiesPopupMenuWithIcons: PopupMenu(storiesPopupMenu) {
scrollPadding: margins(0px, 5px, 0px, 5px);
menu: storiesMenuWithIcons;
}
storiesComposeControls: ComposeControls(defaultComposeControls) {
bg: storiesComposeBg;
radius: storiesRadius;
@ -469,6 +516,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
placeholderFg: storiesComposeGrayText;
placeholderFgActive: storiesComposeGrayText;
placeholderFgError: storiesComposeGrayText;
menu: storiesPopupMenu;
}
send: SendButton(historySend) {
inner: IconButton(storiesAttach) {
@ -489,10 +537,30 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
lineFg: storiesComposeGrayIcon;
lineFgOver: storiesComposeGrayIcon;
}
tabbed: EmojiPan(defaultEmojiPan) {
suggestions: EmojiSuggestions(defaultEmojiSuggestions) {
dropdown: InnerDropdown(emojiSuggestionsDropdown) {
animation: PanelAnimation(defaultPanelAnimation) {
fadeBg: storiesComposeBg;
}
bg: storiesComposeBg;
}
bg: storiesComposeBg;
overBg: storiesComposeBgOver;
expandBg: storiesComposeGrayText;
textFg: storiesComposeWhiteText;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }};
fadeRight: icon {{ "fade_horizontal", storiesComposeBg }};
}
tabbed: EmojiPan(defaultEmojiPan) {
showAnimation: PanelAnimation(emojiPanAnimation) {
fadeBg: storiesComposeBg;
}
bg: storiesComposeBg;
headerFg: storiesComposeGrayText;
trendingHeaderFg: storiesComposeWhiteText;
trendingSubheaderFg: storiesComposeGrayText;
trendingUnreadFg: storiesComposeBlue;
trendingInstalled: icon {{ "chat/input_save", storiesComposeBlue }};
overBg: storiesComposeBgOver;
pathBg: storiesComposeBgRipple;
pathFg: storiesComposeBgOver;
textFg: storiesComposeWhiteText;
@ -500,6 +568,7 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
categoriesBgOver: storiesComposeBgOver;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", storiesComposeBg }};
fadeRight: icon {{ "fade_horizontal", storiesComposeBg }};
menu: storiesPopupMenuWithIcons;
tabs: SettingsSlider(emojiTabs) {
barFgActive: storiesComposeBlue;
labelFg: storiesComposeGrayText;
@ -536,5 +605,40 @@ storiesComposeControls: ComposeControls(defaultComposeControls) {
ripple: emptyRippleAnimation;
}
}
removeSet: storiesRemoveSet;
boxLabel: FlatLabel(boxLabel) {
textFg: groupCallMembersFg;
}
icons: ComposeIcons {
settings: icon {{ "emoji/emoji_settings", storiesComposeGrayIcon }};
recent: icon {{ "emoji/emoji_recent", storiesComposeGrayIcon }};
recentActive: icon {{ "emoji/emoji_recent", storiesComposeWhiteText }};
people: icon {{ "emoji/emoji_smile", storiesComposeGrayIcon }};
peopleActive: icon {{ "emoji/emoji_smile", storiesComposeWhiteText }};
nature: icon {{ "emoji/emoji_nature", storiesComposeGrayIcon }};
natureActive: icon {{ "emoji/emoji_nature", storiesComposeWhiteText }};
food: icon {{ "emoji/emoji_food", storiesComposeGrayIcon }};
foodActive: icon {{ "emoji/emoji_food", storiesComposeWhiteText }};
activity: icon {{ "emoji/emoji_activities", storiesComposeGrayIcon }};
activityActive: icon {{ "emoji/emoji_activities", storiesComposeWhiteText }};
travel: icon {{ "emoji/emoji_travel", storiesComposeGrayIcon }};
travelActive: icon {{ "emoji/emoji_travel", storiesComposeWhiteText }};
objects: icon {{ "emoji/emoji_objects", storiesComposeGrayIcon }};
objectsActive: icon {{ "emoji/emoji_objects", storiesComposeWhiteText }};
symbols: icon {{ "emoji/emoji_love", storiesComposeGrayIcon }};
symbolsActive: icon {{ "emoji/emoji_love", storiesComposeWhiteText }};
menuFave: icon {{ "menu/favorite", storiesComposeWhiteText }};
menuUnfave: icon {{ "menu/unfavorite", storiesComposeWhiteText }};
menuStickerSet: icon {{ "menu/stickers", storiesComposeWhiteText }};
menuRecentRemove: icon {{ "menu/delete", storiesComposeWhiteText }};
menuGifAdd: icon {{ "menu/gif", storiesComposeWhiteText }};
menuGifRemove: icon {{ "menu/delete", storiesComposeWhiteText }};
menuMute: icon {{ "menu/mute", storiesComposeWhiteText }};
menuSchedule: icon {{ "menu/calendar", storiesComposeWhiteText }};
menuWhenOnline: icon {{ "menu/send_when_online", storiesComposeWhiteText }};
}
autocompleteBottomSkip: 10px;
}
}

View File

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

View File

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