mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Support reaction dropdown based on EmojiListWidget.
This commit is contained in:
parent
f72092a261
commit
c5fa4aae62
22 changed files with 529 additions and 160 deletions
|
@ -10,6 +10,25 @@ using "ui/basic.style";
|
|||
using "boxes/boxes.style";
|
||||
using "ui/widgets/widgets.style";
|
||||
|
||||
EmojiPan {
|
||||
margin: margins;
|
||||
padding: margins;
|
||||
desiredSize: pixels;
|
||||
verticalSizeSub: pixels;
|
||||
header: pixels;
|
||||
headerLeft: pixels;
|
||||
headerLockLeft: pixels;
|
||||
headerLockedLeft: pixels;
|
||||
headerTop: pixels;
|
||||
footer: pixels;
|
||||
iconSkip: pixels;
|
||||
iconWidth: pixels;
|
||||
iconArea: pixels;
|
||||
overBg: color;
|
||||
fadeLeft: icon;
|
||||
fadeRight: icon;
|
||||
}
|
||||
|
||||
switchPmButton: RoundButton(defaultBoxButton) {
|
||||
width: 320px;
|
||||
height: 34px;
|
||||
|
@ -147,23 +166,7 @@ emojiObjectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }};
|
|||
emojiSymbols: icon {{ "emoji/emoji_symbols", emojiIconFg }};
|
||||
emojiSymbolsActive: icon {{ "emoji/emoji_symbols", emojiSubIconFgActive }};
|
||||
|
||||
emojiFooterHeight: 46px;
|
||||
emojiCategorySkip: 4px;
|
||||
emojiCategory: IconButton {
|
||||
width: 42px;
|
||||
height: emojiFooterHeight;
|
||||
|
||||
iconPosition: point(-1px, 6px);
|
||||
}
|
||||
emojiCategoryRecent: IconButton(emojiCategory) { icon: emojiRecent; }
|
||||
emojiCategoryPeople: IconButton(emojiCategory) { icon: emojiPeople; }
|
||||
emojiCategoryNature: IconButton(emojiCategory) { icon: emojiNature; }
|
||||
emojiCategoryFood: IconButton(emojiCategory) { icon: emojiFood; }
|
||||
emojiCategoryActivity: IconButton(emojiCategory) { icon: emojiActivity; }
|
||||
emojiCategoryTravel: IconButton(emojiCategory) { icon: emojiTravel; }
|
||||
emojiCategoryObjects: IconButton(emojiCategory) { icon: emojiObjects; }
|
||||
emojiCategorySymbols: IconButton(emojiCategory) { icon: emojiSymbols; }
|
||||
|
||||
emojiCategoryIconTop: 6px;
|
||||
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
|
||||
fadeBg: emojiPanBg;
|
||||
}
|
||||
|
@ -176,21 +179,34 @@ emojiPanShowDuration: 200;
|
|||
emojiPanDuration: 200;
|
||||
emojiPanHover: windowBgOver;
|
||||
emojiPanSlideDuration: 200;
|
||||
emojiPanDesiredSize: 39px;
|
||||
emojiPanArea: size(34px, 32px);
|
||||
emojiPanLeft: 13px;
|
||||
emojiPanRight: 17px;
|
||||
emojiPanRadius: 8px;
|
||||
|
||||
defaultEmojiPan: EmojiPan {
|
||||
margin: margins(roundRadiusSmall, 0px, 14px, 0px);
|
||||
padding: margins(13px, 12px, 17px, 12px);
|
||||
desiredSize: 39px;
|
||||
verticalSizeSub: 2px;
|
||||
header: 40px;
|
||||
headerLeft: 23px;
|
||||
headerLockLeft: 17px;
|
||||
headerLockedLeft: 36px;
|
||||
headerTop: 12px;
|
||||
footer: 46px;
|
||||
iconSkip: 4px;
|
||||
iconWidth: 35px;
|
||||
iconArea: 32px;
|
||||
overBg: emojiPanHover;
|
||||
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }};
|
||||
fadeRight: icon {{ "fade_horizontal", emojiPanCategories }};
|
||||
}
|
||||
|
||||
inlineResultsMinHeight: 278px;
|
||||
inlineResultsMaxHeight: 640px;
|
||||
|
||||
emojiPanHeader: 40px;
|
||||
emojiPanHeaderFont: semiboldFont;
|
||||
emojiPanHeaderLeft: 23px;
|
||||
emojiPanHeaderLockLeft: 17px;
|
||||
emojiPanHeaderLockedLeft: 36px;
|
||||
emojiPanHeaderTop: 12px;
|
||||
emojiPanRemoveSkip: 10px;
|
||||
|
||||
emojiColorsPadding: 5px;
|
||||
|
@ -233,7 +249,6 @@ stickerPanDeleteOpacityFg: 0.8;
|
|||
stickerPanDeleteOpacityFgOver: 1.;
|
||||
stickerPanRemoveSet: hashtagClose;
|
||||
stickerIconWidth: 42px;
|
||||
stickerIconHeight: emojiFooterHeight;
|
||||
stickerIconPadding: 5px;
|
||||
stickerIconOpacity: 0.7;
|
||||
stickerIconSel: 2px;
|
||||
|
@ -242,9 +257,6 @@ stickerIconMove: 400;
|
|||
stickerPreviewDuration: 150;
|
||||
stickerPreviewMin: 0.1;
|
||||
|
||||
emojiIconWidth: 35px;
|
||||
emojiIconArea: 32px;
|
||||
|
||||
stickerGroupCategorySize: 28px;
|
||||
stickerGroupCategoryAbout: defaultTextStyle;
|
||||
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
|
||||
|
@ -315,9 +327,38 @@ stickersPremiumLock: icon{{ "emoji/premium_lock", premiumButtonFg }};
|
|||
reactStripExtend: margins(21px, 49px, 39px, 0px);
|
||||
reactStripHeight: 40px;
|
||||
reactStripSize: 32px;
|
||||
reactStripImage: 26px;
|
||||
reactStripSkip: 7px;
|
||||
reactStripBubble: icon{
|
||||
{ "chat/reactions_bubble_shadow", windowShadowFg },
|
||||
{ "chat/reactions_bubble", windowBg },
|
||||
};
|
||||
reactStripBubbleRight: 20px;
|
||||
reactPanelEmojiPan: EmojiPan(defaultEmojiPan) {
|
||||
margin: margins(reactStripSkip, 0px, reactStripSkip, 0px);
|
||||
padding: margins(reactStripSkip, 0px, reactStripSkip, reactStripSkip);
|
||||
desiredSize: reactStripSize;
|
||||
verticalSizeSub: 0px;
|
||||
headerLeft: 13px;
|
||||
headerLockLeft: 7px;
|
||||
headerLockedLeft: 26px;
|
||||
footer: 42px;
|
||||
iconSkip: 6px;
|
||||
iconWidth: 33px;
|
||||
iconArea: 30px;
|
||||
overBg: transparent;
|
||||
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", windowBg }};
|
||||
fadeRight: icon {{ "fade_horizontal", windowBg }};
|
||||
}
|
||||
reactPanelScroll: ScrollArea(defaultSolidScroll) {
|
||||
deltat: 3px;
|
||||
deltab: 3px;
|
||||
round: 1px;
|
||||
width: 7px;
|
||||
deltax: 2px;
|
||||
hiding: 0;
|
||||
}
|
||||
|
||||
emojiSuggestionsFadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }};
|
||||
emojiSuggestionsFadeRight: icon {{ "fade_horizontal", boxBg }};
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ using Core::RecentEmojiDocument;
|
|||
|
||||
} // namespace
|
||||
|
||||
class EmojiColorPicker : public Ui::RpWidget {
|
||||
class EmojiColorPicker final : public Ui::RpWidget {
|
||||
public:
|
||||
EmojiColorPicker(QWidget *parent);
|
||||
|
||||
|
@ -89,6 +89,7 @@ private:
|
|||
QSize _singleSize;
|
||||
QPoint _areaPosition;
|
||||
QPoint _innerPosition;
|
||||
Ui::RoundRect _overBg;
|
||||
|
||||
bool _hiding = false;
|
||||
QPixmap _cache;
|
||||
|
@ -110,7 +111,8 @@ struct EmojiListWidget::RecentOne {
|
|||
};
|
||||
|
||||
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
|
||||
: RpWidget(parent) {
|
||||
: RpWidget(parent)
|
||||
, _overBg(st::emojiPanRadius, st::emojiPanHover) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
|
@ -347,11 +349,7 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) {
|
|||
QPoint tl(w);
|
||||
if (rtl()) tl.setX(width() - tl.x() - st::emojiPanArea.width());
|
||||
|
||||
Ui::FillRoundRect(
|
||||
p,
|
||||
QRect(tl, st::emojiPanArea),
|
||||
st::emojiPanHover,
|
||||
Ui::EmojiHoverCorners);
|
||||
_overBg.paint(p, QRect(tl, st::emojiPanArea));
|
||||
}
|
||||
Ui::Emoji::Draw(
|
||||
p,
|
||||
|
@ -377,7 +375,11 @@ EmojiListWidget::EmojiListWidget(
|
|||
EmojiListWidget::EmojiListWidget(
|
||||
QWidget *parent,
|
||||
EmojiListDescriptor &&descriptor)
|
||||
: Inner(parent, descriptor.session, std::move(descriptor.paused))
|
||||
: Inner(
|
||||
parent,
|
||||
descriptor.st ? *descriptor.st : st::defaultEmojiPan,
|
||||
descriptor.session,
|
||||
std::move(descriptor.paused))
|
||||
, _controller(descriptor.controller)
|
||||
, _mode(descriptor.mode)
|
||||
, _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1)
|
||||
|
@ -386,6 +388,8 @@ EmojiListWidget::EmojiListWidget(
|
|||
: nullptr)
|
||||
, _localSetsManager(
|
||||
std::make_unique<LocalStickersManager>(&session()))
|
||||
, _customRecentFactory(std::move(descriptor.customRecentFactory))
|
||||
, _overBg(st::emojiPanRadius, st().overBg)
|
||||
, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg)
|
||||
, _picker(this)
|
||||
, _showPickerTimer([=] { showPicker(); }) {
|
||||
|
@ -433,6 +437,10 @@ EmojiListWidget::EmojiListWidget(
|
|||
initButton(_unlock, tr::lng_emoji_featured_unlock(tr::now), true);
|
||||
initButton(_restore, tr::lng_emoji_premium_restore(tr::now), true);
|
||||
}, lifetime());
|
||||
|
||||
if (!descriptor.customRecentList.empty()) {
|
||||
fillRecentFrom(descriptor.customRecentList);
|
||||
}
|
||||
}
|
||||
|
||||
EmojiListWidget::~EmojiListWidget() {
|
||||
|
@ -535,6 +543,7 @@ object_ptr<TabbedSelector::InnerFooter> EmojiListWidget::createFooter() {
|
|||
.session = &session(),
|
||||
.paused = pausedMethod(),
|
||||
.parent = this,
|
||||
.st = &st(),
|
||||
});
|
||||
_footer = result;
|
||||
|
||||
|
@ -557,7 +566,7 @@ bool EmojiListWidget::enumerateSections(Callback callback) const {
|
|||
? kCollapsedRows
|
||||
: (info.count + _columnCount - 1) / _columnCount;
|
||||
info.rowsTop = info.top
|
||||
+ (i == 0 ? st::emojiPanPadding : st::emojiPanHeader);
|
||||
+ (i == 0 ? st().padding.top() : st().header);
|
||||
info.rowsBottom = info.rowsTop
|
||||
+ (info.rowsCount * _singleSize.height())
|
||||
+ st::roundRadiusSmall;
|
||||
|
@ -637,18 +646,17 @@ void EmojiListWidget::setSingleSize(QSize size) {
|
|||
}
|
||||
|
||||
int EmojiListWidget::countDesiredHeight(int newWidth) {
|
||||
const auto left = st::emojiPanLeft;
|
||||
const auto right = st::emojiPanRight;
|
||||
const auto fullWidth = st::roundRadiusSmall
|
||||
const auto fullWidth = st().margin.left()
|
||||
+ newWidth
|
||||
+ st::emojiScroll.width;
|
||||
const auto innerWidth = fullWidth - left - right;
|
||||
_columnCount = std::max(innerWidth / st::emojiPanDesiredSize, 1);
|
||||
+ st().margin.right();
|
||||
const auto padding = st().padding;
|
||||
const auto innerWidth = fullWidth - padding.left() - padding.right();
|
||||
_columnCount = std::max(innerWidth / st().desiredSize, 1);
|
||||
const auto singleWidth = innerWidth / _columnCount;
|
||||
_rowsLeft = left
|
||||
_rowsLeft = padding.left()
|
||||
+ (innerWidth - _columnCount * singleWidth) / 2
|
||||
- st::roundRadiusSmall;
|
||||
setSingleSize({ singleWidth, singleWidth - 4 * st::lineWidth });
|
||||
- st().margin.left();
|
||||
setSingleSize({ singleWidth, singleWidth - 2 * st().verticalSizeSub });
|
||||
|
||||
auto visibleHeight = minimalHeight();
|
||||
auto minimalHeight = (visibleHeight - st::stickerPanPadding);
|
||||
|
@ -659,7 +667,13 @@ int EmojiListWidget::countDesiredHeight(int newWidth) {
|
|||
};
|
||||
const auto minimalLastHeight = minimalHeight;
|
||||
return qMax(minimalHeight, countResult(minimalLastHeight))
|
||||
+ st::emojiPanPadding;
|
||||
+ padding.bottom();
|
||||
}
|
||||
|
||||
int EmojiListWidget::defaultMinimalHeight() const {
|
||||
return (_mode != Mode::Full)
|
||||
? st::emojiPanArea.height()
|
||||
: Inner::defaultMinimalHeight();
|
||||
}
|
||||
|
||||
void EmojiListWidget::ensureLoaded(int section) {
|
||||
|
@ -688,6 +702,9 @@ void EmojiListWidget::ensureLoaded(int section) {
|
|||
}
|
||||
|
||||
void EmojiListWidget::fillRecent() {
|
||||
if (_mode != Mode::Full && _mode != Mode::EmojiStatus) {
|
||||
return; // #TODO emoji_status
|
||||
}
|
||||
_recent.clear();
|
||||
_recentCustomIds.clear();
|
||||
|
||||
|
@ -718,6 +735,21 @@ void EmojiListWidget::fillRecent() {
|
|||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::fillRecentFrom(const std::vector<DocumentId> &list) {
|
||||
Expects(_recent.empty());
|
||||
|
||||
const auto test = session().isTestMode();
|
||||
|
||||
_recent.reserve(list.size());
|
||||
for (const auto &id : list) {
|
||||
_recent.push_back({
|
||||
.custom = resolveCustomEmoji(id),
|
||||
.id = { RecentEmojiDocument{.id = id, .test = test } },
|
||||
});
|
||||
_recentCustomIds.emplace(id);
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
|
@ -752,7 +784,7 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
|||
? (selectedButton->section == info.section)
|
||||
: false;
|
||||
const auto widthForTitle = emojiRight()
|
||||
- (st::emojiPanHeaderLeft - st::roundRadiusSmall)
|
||||
- (st().headerLeft - st().margin.left())
|
||||
- paintButtonGetWidth(p, info, buttonSelected, r);
|
||||
if (info.section > 0 && r.top() < info.rowsTop) {
|
||||
p.setFont(st::emojiPanHeaderFont);
|
||||
|
@ -766,13 +798,13 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
|||
titleWidth = st::emojiPanHeaderFont->width(titleText);
|
||||
}
|
||||
const auto left = (info.premiumRequired
|
||||
? st::emojiPanHeaderLockedLeft
|
||||
: st::emojiPanHeaderLeft) - st::roundRadiusSmall;
|
||||
const auto top = info.top + st::emojiPanHeaderTop;
|
||||
? st().headerLockedLeft
|
||||
: st().headerLeft) - st().margin.left();
|
||||
const auto top = info.top + st().headerTop;
|
||||
if (info.premiumRequired) {
|
||||
st::emojiPremiumRequired.paint(
|
||||
p,
|
||||
st::emojiPanHeaderLockLeft - st::roundRadiusSmall,
|
||||
st().headerLockLeft - st().margin.left(),
|
||||
top,
|
||||
width());
|
||||
}
|
||||
|
@ -807,16 +839,12 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
|||
drawCollapsedBadge(p, w - _areaPosition, info.count);
|
||||
continue;
|
||||
}
|
||||
if (selected) {
|
||||
if (selected && st().overBg->c.alpha() > 0) {
|
||||
auto tl = w;
|
||||
if (rtl()) {
|
||||
tl.setX(width() - tl.x() - st::emojiPanArea.width());
|
||||
}
|
||||
Ui::FillRoundRect(
|
||||
p,
|
||||
QRect(tl, st::emojiPanArea),
|
||||
st::emojiPanHover,
|
||||
Ui::EmojiHoverCorners);
|
||||
_overBg.paint(p, QRect(tl, st::emojiPanArea));
|
||||
}
|
||||
if (info.section == int(Section::Recent)) {
|
||||
drawRecent(p, w, now, paused, index);
|
||||
|
@ -1070,10 +1098,13 @@ void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
|
|||
_premiumChosen.fire_copy(document);
|
||||
return;
|
||||
}
|
||||
Core::App().settings().incrementRecentEmoji({ RecentEmojiDocument{
|
||||
document->id,
|
||||
document->session().isTestMode(),
|
||||
} });
|
||||
auto &settings = Core::App().settings();
|
||||
if (_mode == Mode::Full) {
|
||||
settings.incrementRecentEmoji({ RecentEmojiDocument{
|
||||
document->id,
|
||||
document->session().isTestMode(),
|
||||
} });
|
||||
}
|
||||
_customChosen.fire({ .document = document });
|
||||
}
|
||||
|
||||
|
@ -1089,7 +1120,7 @@ void EmojiListWidget::showPicker() {
|
|||
|
||||
auto y = emojiRect(over->section, over->index).y();
|
||||
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
|
||||
if (y < st::emojiPanHeader) {
|
||||
if (y < st().header) {
|
||||
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
|
||||
}
|
||||
auto xmax = width() - _picker->width();
|
||||
|
@ -1124,11 +1155,14 @@ QRect EmojiListWidget::removeButtonRect(int index) const {
|
|||
}
|
||||
|
||||
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 buttonx = emojiRight() - st::emojiPanRemoveSkip - buttonw;
|
||||
const auto buttony = info.top + (st::emojiPanHeader - buttonh) / 2;
|
||||
const auto buttony = info.top + (st().header - buttonh) / 2;
|
||||
return QRect(buttonx, buttony, buttonw, buttonh);
|
||||
}
|
||||
|
||||
|
@ -1322,12 +1356,18 @@ void EmojiListWidget::processPanelHideFinished() {
|
|||
}
|
||||
|
||||
void EmojiListWidget::refreshRecent() {
|
||||
if (_mode != Mode::Full && _mode != Mode::EmojiStatus) {
|
||||
return; // #TODO emoji_status
|
||||
}
|
||||
clearSelection();
|
||||
fillRecent();
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
void EmojiListWidget::refreshCustom() {
|
||||
if (_mode == Mode::RecentReactions) {
|
||||
return;
|
||||
}
|
||||
auto old = base::take(_custom);
|
||||
const auto session = &this->session();
|
||||
const auto premiumPossible = session->premiumPossible();
|
||||
|
@ -1486,15 +1526,19 @@ not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
|
|||
if (i != end(_customEmoji)) {
|
||||
return i->second.emoji.get();
|
||||
}
|
||||
auto repaint = repaintCallback(documentId, RecentEmojiSectionSetId());
|
||||
auto custom = _customRecentFactory
|
||||
? _customRecentFactory(documentId, repaint)
|
||||
: nullptr;
|
||||
if (!custom) {
|
||||
custom = session().data().customEmojiManager().create(
|
||||
documentId,
|
||||
std::move(repaint),
|
||||
Data::CustomEmojiManager::SizeTag::Large);
|
||||
}
|
||||
return _customEmoji.emplace(
|
||||
documentId,
|
||||
CustomEmojiInstance{
|
||||
.emoji = session().data().customEmojiManager().create(
|
||||
documentId,
|
||||
repaintCallback(documentId, RecentEmojiSectionSetId()),
|
||||
Data::CustomEmojiManager::SizeTag::Large),
|
||||
.recentOnly = true,
|
||||
}
|
||||
CustomEmojiInstance{ .emoji = std::move(custom), .recentOnly = true }
|
||||
).first->second.emoji.get();
|
||||
}
|
||||
|
||||
|
@ -1503,7 +1547,7 @@ std::vector<StickerIcon> EmojiListWidget::fillIcons() {
|
|||
result.reserve(2 + _custom.size());
|
||||
|
||||
result.emplace_back(RecentEmojiSectionSetId());
|
||||
if (_mode == Mode::EmojiStatus) {
|
||||
if (_mode != Mode::Full) {
|
||||
} else if (_custom.empty()) {
|
||||
using Section = Ui::Emoji::Section;
|
||||
for (auto i = int(Section::People); i <= int(Section::Symbols); ++i) {
|
||||
|
@ -1534,7 +1578,9 @@ int EmojiListWidget::paintButtonGetWidth(
|
|||
auto &custom = _custom[info.section - _staticCount];
|
||||
if (hasRemoveButton(info.section)) {
|
||||
const auto remove = removeButtonRect(info);
|
||||
if (remove.intersects(clip)) {
|
||||
if (remove.isEmpty()) {
|
||||
return 0;
|
||||
} else if (remove.intersects(clip)) {
|
||||
if (custom.ripple) {
|
||||
custom.ripple->paint(
|
||||
p,
|
||||
|
@ -1603,7 +1649,7 @@ void EmojiListWidget::updateSelected() {
|
|||
if (hasButton(section)
|
||||
&& myrtlrect(buttonRect(section)).contains(p.x(), p.y())) {
|
||||
newSelected = OverButton{ section };
|
||||
} else if (section >= _staticCount) {
|
||||
} else if (section >= _staticCount && _mode == Mode::Full) {
|
||||
newSelected = OverSet{ section };
|
||||
}
|
||||
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
|
||||
|
|
|
@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/round_rect.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
namespace style {
|
||||
struct EmojiPan;
|
||||
} // namespace style
|
||||
|
||||
namespace Core {
|
||||
struct RecentEmojiId;
|
||||
} // namespace Core
|
||||
|
@ -56,7 +60,8 @@ class LocalStickersManager;
|
|||
enum class EmojiListMode {
|
||||
Full,
|
||||
EmojiStatus,
|
||||
Reactions,
|
||||
FullReactions,
|
||||
RecentReactions,
|
||||
};
|
||||
|
||||
struct EmojiListDescriptor {
|
||||
|
@ -64,6 +69,11 @@ struct EmojiListDescriptor {
|
|||
EmojiListMode mode = EmojiListMode::Full;
|
||||
Window::SessionController *controller = nullptr;
|
||||
Fn<bool()> paused;
|
||||
std::vector<DocumentId> customRecentList;
|
||||
Fn<std::unique_ptr<Ui::Text::CustomEmoji>(
|
||||
DocumentId,
|
||||
Fn<void()>)> customRecentFactory;
|
||||
const style::EmojiPan *st = nullptr;
|
||||
};
|
||||
|
||||
class EmojiListWidget
|
||||
|
@ -120,6 +130,7 @@ protected:
|
|||
void processHideFinished() override;
|
||||
void processPanelHideFinished() override;
|
||||
int countDesiredHeight(int newWidth) override;
|
||||
int defaultMinimalHeight() const override;
|
||||
|
||||
private:
|
||||
struct SectionInfo {
|
||||
|
@ -272,6 +283,7 @@ private:
|
|||
void repaintCustom(uint64 setId);
|
||||
|
||||
void fillRecent();
|
||||
void fillRecentFrom(const std::vector<DocumentId> &list);
|
||||
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
|
||||
not_null<DocumentData*> document,
|
||||
uint64 setId);
|
||||
|
@ -289,6 +301,9 @@ private:
|
|||
StickersListFooter *_footer = nullptr;
|
||||
std::unique_ptr<GradientPremiumStar> _premiumIcon;
|
||||
std::unique_ptr<LocalStickersManager> _localSetsManager;
|
||||
Fn<std::unique_ptr<Ui::Text::CustomEmoji>(
|
||||
DocumentId,
|
||||
Fn<void()>)> _customRecentFactory;
|
||||
|
||||
int _counts[kEmojiSectionCount];
|
||||
std::vector<RecentOne> _recent;
|
||||
|
@ -299,6 +314,7 @@ private:
|
|||
std::vector<CustomSet> _custom;
|
||||
base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji;
|
||||
bool _allowWithoutPremium = false;
|
||||
Ui::RoundRect _overBg;
|
||||
|
||||
int _rowsLeft = 0;
|
||||
int _columnCount = 1;
|
||||
|
|
|
@ -105,7 +105,8 @@ private:
|
|||
|
||||
};
|
||||
|
||||
GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent) : InnerFooter(parent)
|
||||
GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent)
|
||||
: InnerFooter(parent, st::defaultEmojiPan)
|
||||
, _pan(parent)
|
||||
, _field(this, st::gifsSearchField, tr::lng_gifs_search())
|
||||
, _cancel(this, st::gifsSearchCancel) {
|
||||
|
@ -170,7 +171,11 @@ GifsListWidget::GifsListWidget(
|
|||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Window::GifPauseReason level)
|
||||
: Inner(parent, &controller->session(), Window::PausedIn(controller, level))
|
||||
: Inner(
|
||||
parent,
|
||||
st::defaultEmojiPan,
|
||||
&controller->session(),
|
||||
Window::PausedIn(controller, level))
|
||||
, _controller(controller)
|
||||
, _api(&session().mtp())
|
||||
, _section(Section::Gifs)
|
||||
|
|
|
@ -181,7 +181,9 @@ void GradientPremiumStar::renderOnDemand() const {
|
|||
}
|
||||
|
||||
StickersListFooter::StickersListFooter(Descriptor &&descriptor)
|
||||
: InnerFooter(descriptor.parent)
|
||||
: InnerFooter(
|
||||
descriptor.parent,
|
||||
descriptor.st ? *descriptor.st : st::defaultEmojiPan)
|
||||
, _session(descriptor.session)
|
||||
, _paused(descriptor.paused)
|
||||
, _searchButtonVisible(descriptor.searchButtonVisible)
|
||||
|
@ -189,14 +191,14 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor)
|
|||
, _iconState([=] { update(); })
|
||||
, _subiconState([=] { update(); })
|
||||
, _selectionBg(st::roundRadiusLarge, st::windowBgRipple)
|
||||
, _subselectionBg(st::emojiIconArea / 2, st::windowBgRipple)
|
||||
, _subselectionBg(st().iconArea / 2, st::windowBgRipple)
|
||||
, _barSelection(descriptor.barSelection) {
|
||||
setMouseTracking(true);
|
||||
|
||||
_iconsLeft = st::emojiCategorySkip + (_searchButtonVisible
|
||||
_iconsLeft = st().iconSkip + (_searchButtonVisible
|
||||
? st::stickerIconWidth
|
||||
: 0);
|
||||
_iconsRight = st::emojiCategorySkip + (_settingsButtonVisible
|
||||
_iconsRight = st().iconSkip + (_settingsButtonVisible
|
||||
? st::stickerIconWidth
|
||||
: 0);
|
||||
|
||||
|
@ -552,7 +554,7 @@ void StickersListFooter::paintEvent(QPaintEvent *e) {
|
|||
_iconsLeft,
|
||||
_iconsTop,
|
||||
width() - _iconsLeft - _iconsRight,
|
||||
st::emojiFooterHeight);
|
||||
st().footer);
|
||||
if (rtl()) {
|
||||
clip.moveLeft(width() - _iconsLeft - clip.width());
|
||||
}
|
||||
|
@ -582,7 +584,7 @@ void StickersListFooter::paintSelectionBg(Painter &p) const {
|
|||
selx = width() - selx - selw;
|
||||
}
|
||||
const auto sely = _iconsTop;
|
||||
const auto area = st::emojiIconArea;
|
||||
const auto area = st().iconArea;
|
||||
const auto rect = QRect(
|
||||
QPoint(selx, sely) + _areaPosition,
|
||||
QSize(selw - 2 * _areaPosition.x(), area));
|
||||
|
@ -613,7 +615,7 @@ void StickersListFooter::paintSelectionBar(Painter &p) const {
|
|||
}
|
||||
p.fillRect(
|
||||
selx,
|
||||
_iconsTop + st::emojiFooterHeight - st::stickerIconPadding,
|
||||
_iconsTop + st().footer - st::stickerIconPadding,
|
||||
selw,
|
||||
st::stickerIconSel,
|
||||
st::stickerIconSelColor);
|
||||
|
@ -621,27 +623,27 @@ void StickersListFooter::paintSelectionBar(Painter &p) const {
|
|||
|
||||
void StickersListFooter::paintLeftRightFading(Painter &p) const {
|
||||
auto o_left = std::clamp(
|
||||
_iconState.x.current() / st::stickerIconLeft.width(),
|
||||
_iconState.x.current() / st().fadeLeft.width(),
|
||||
0.,
|
||||
1.);
|
||||
if (o_left > 0) {
|
||||
p.setOpacity(o_left);
|
||||
st::stickerIconLeft.fill(p, style::rtlrect(_iconsLeft, _iconsTop, st::stickerIconLeft.width(), st::emojiFooterHeight, width()));
|
||||
st().fadeLeft.fill(p, style::rtlrect(_iconsLeft, _iconsTop, st().fadeLeft.width(), st().footer, width()));
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
auto o_right = std::clamp(
|
||||
(_iconState.max - _iconState.x.current()) / st::stickerIconRight.width(),
|
||||
(_iconState.max - _iconState.x.current()) / st().fadeRight.width(),
|
||||
0.,
|
||||
1.);
|
||||
if (o_right > 0) {
|
||||
p.setOpacity(o_right);
|
||||
st::stickerIconRight.fill(
|
||||
st().fadeRight.fill(
|
||||
p,
|
||||
style::rtlrect(
|
||||
width() - _iconsRight - st::stickerIconRight.width(),
|
||||
width() - _iconsRight - st().fadeRight.width(),
|
||||
_iconsTop,
|
||||
st::stickerIconRight.width(),
|
||||
st::emojiFooterHeight, width()));
|
||||
st().fadeRight.width(),
|
||||
st().footer, width()));
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
}
|
||||
|
@ -880,19 +882,19 @@ void StickersListFooter::updateSelected() {
|
|||
&& x >= searchLeft
|
||||
&& x < searchLeft + _singleWidth
|
||||
&& y >= _iconsTop
|
||||
&& y < _iconsTop + st::emojiFooterHeight) {
|
||||
&& y < _iconsTop + st().footer) {
|
||||
newOver = SpecialOver::Search;
|
||||
} else if (_settingsButtonVisible
|
||||
&& x >= settingsLeft
|
||||
&& x < settingsLeft + _singleWidth
|
||||
&& y >= _iconsTop
|
||||
&& y < _iconsTop + st::emojiFooterHeight) {
|
||||
&& y < _iconsTop + st().footer) {
|
||||
if (!_icons.empty() && !hasOnlyFeaturedSets()) {
|
||||
newOver = SpecialOver::Settings;
|
||||
}
|
||||
} else if (!_icons.empty()) {
|
||||
if (y >= _iconsTop
|
||||
&& y < _iconsTop + st::emojiFooterHeight
|
||||
&& y < _iconsTop + st().footer
|
||||
&& x >= _iconsLeft
|
||||
&& x < width() - _iconsRight) {
|
||||
enumerateIcons([&](const IconInfo &info) {
|
||||
|
@ -994,11 +996,11 @@ void StickersListFooter::refreshIconsGeometry(
|
|||
&& _icons[1].setId == EmojiSectionSetId(EmojiSection::People)) {
|
||||
_singleWidth = (width() - _iconsLeft - _iconsRight) / _icons.size();
|
||||
} else {
|
||||
_singleWidth = st::emojiIconWidth;
|
||||
_singleWidth = st().iconWidth;
|
||||
}
|
||||
_areaPosition = QPoint(
|
||||
(_singleWidth - st::emojiIconArea) / 2,
|
||||
(st::emojiFooterHeight - st::emojiIconArea) / 2);
|
||||
(_singleWidth - st().iconArea) / 2,
|
||||
(st().footer - st().iconArea) / 2);
|
||||
refreshScrollableDimensions();
|
||||
refreshSubiconsGeometry();
|
||||
_iconState.selected = _subiconState.selected = -1;
|
||||
|
@ -1047,7 +1049,7 @@ void StickersListFooter::paintStickerSettingsIcon(Painter &p) const {
|
|||
p,
|
||||
settingsLeft
|
||||
+ (_singleWidth - st::stickersSettings.width()) / 2,
|
||||
_iconsTop + st::emojiCategory.iconPosition.y(),
|
||||
_iconsTop + st::emojiCategoryIconTop,
|
||||
width());
|
||||
}
|
||||
|
||||
|
@ -1056,7 +1058,7 @@ void StickersListFooter::paintSearchIcon(Painter &p) const {
|
|||
st::stickersSearch.paint(
|
||||
p,
|
||||
searchLeft + (_singleWidth - st::stickersSearch.width()) / 2,
|
||||
_iconsTop + st::emojiCategory.iconPosition.y(),
|
||||
_iconsTop + st::emojiCategoryIconTop,
|
||||
width());
|
||||
}
|
||||
|
||||
|
@ -1145,7 +1147,7 @@ void StickersListFooter::updateSetIcon(uint64 setId) {
|
|||
}
|
||||
|
||||
void StickersListFooter::updateSetIconAt(int left) {
|
||||
update(left, _iconsTop, _singleWidth, st::emojiFooterHeight);
|
||||
update(left, _iconsTop, _singleWidth, st().footer);
|
||||
}
|
||||
|
||||
void StickersListFooter::paintSetIcon(
|
||||
|
@ -1164,7 +1166,7 @@ void StickersListFooter::paintSetIcon(
|
|||
? icon.stickerMedia->thumbnail()
|
||||
: nullptr;
|
||||
const auto x = info.adjustedLeft + (_singleWidth - icon.pixw) / 2;
|
||||
const auto y = _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2;
|
||||
const auto y = _iconsTop + (st().footer - icon.pixh) / 2;
|
||||
if (icon.custom) {
|
||||
icon.custom->paint(p, x, y, now, st::emojiIconFg->c, paused);
|
||||
} else if (icon.lottie && icon.lottie->ready()) {
|
||||
|
@ -1177,7 +1179,7 @@ void StickersListFooter::paintSetIcon(
|
|||
p.drawImage(
|
||||
QRect(
|
||||
(info.adjustedLeft + (_singleWidth - size.width()) / 2),
|
||||
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
||||
_iconsTop + (st().footer - size.height()) / 2,
|
||||
size.width(),
|
||||
size.height()),
|
||||
frame);
|
||||
|
@ -1212,14 +1214,14 @@ void StickersListFooter::paintSetIcon(
|
|||
p,
|
||||
icon.megagroupUserpic,
|
||||
info.adjustedLeft + (_singleWidth - size) / 2,
|
||||
_iconsTop + (st::emojiFooterHeight - size) / 2,
|
||||
_iconsTop + (st().footer - size) / 2,
|
||||
width(),
|
||||
st::stickerGroupCategorySize);
|
||||
} else if (icon.setId == Data::Stickers::PremiumSetId) {
|
||||
const auto size = st::stickersPremium.size();
|
||||
p.drawImage(
|
||||
info.adjustedLeft + (_singleWidth - size.width()) / 2,
|
||||
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
||||
_iconsTop + (st().footer - size.height()) / 2,
|
||||
_premiumIcon.image());
|
||||
} else {
|
||||
using Section = Ui::Emoji::Section;
|
||||
|
@ -1252,7 +1254,7 @@ void StickersListFooter::paintSetIcon(
|
|||
icon->paint(
|
||||
p,
|
||||
left + (_singleWidth - icon->width()) / 2,
|
||||
_iconsTop + (st::emojiFooterHeight - icon->height()) / 2,
|
||||
_iconsTop + (st().footer - icon->height()) / 2,
|
||||
width());
|
||||
};
|
||||
if (_icons[info.index].setId == AllEmojiSectionSetId()
|
||||
|
@ -1263,7 +1265,7 @@ void StickersListFooter::paintSetIcon(
|
|||
left + skip,
|
||||
_iconsTop,
|
||||
info.width - 2 * skip,
|
||||
st::emojiFooterHeight,
|
||||
st().footer,
|
||||
Qt::IntersectClip);
|
||||
enumerateSubicons([&](const IconInfo &info) {
|
||||
if (info.visible) {
|
||||
|
|
|
@ -33,6 +33,10 @@ namespace Window {
|
|||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace style {
|
||||
struct EmojiPan;
|
||||
} // namespace style
|
||||
|
||||
namespace ChatHelpers {
|
||||
|
||||
enum class ValidateIconAnimations {
|
||||
|
@ -98,6 +102,7 @@ public:
|
|||
bool searchButtonVisible = false;
|
||||
bool settingsButtonVisible = false;
|
||||
bool barSelection = false;
|
||||
const style::EmojiPan *st = nullptr;
|
||||
};
|
||||
explicit StickersListFooter(Descriptor &&descriptor);
|
||||
|
||||
|
|
|
@ -164,7 +164,11 @@ StickersListWidget::StickersListWidget(
|
|||
not_null<Window::SessionController*> controller,
|
||||
Window::GifPauseReason level,
|
||||
bool masks)
|
||||
: Inner(parent, &controller->session(), Window::PausedIn(controller, level))
|
||||
: Inner(
|
||||
parent,
|
||||
st::defaultEmojiPan,
|
||||
&controller->session(),
|
||||
Window::PausedIn(controller, level))
|
||||
, _controller(controller)
|
||||
, _api(&session().mtp())
|
||||
, _localSetsManager(std::make_unique<LocalStickersManager>(&session()))
|
||||
|
@ -176,7 +180,7 @@ StickersListWidget::StickersListWidget(
|
|||
st::windowBgRipple,
|
||||
st::windowBgOver,
|
||||
[=] { update(); }))
|
||||
, _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st::emojiPanHeaderLeft)
|
||||
, _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st().headerLeft)
|
||||
, _addText(tr::lng_stickers_featured_add(tr::now).toUpper())
|
||||
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
|
||||
, _settings(this, tr::lng_stickers_you_have(tr::now))
|
||||
|
@ -411,7 +415,7 @@ bool StickersListWidget::enumerateSections(Callback callback) const {
|
|||
const auto titleSkip = set.externalLayout
|
||||
? st::stickersTrendingHeader
|
||||
: setHasTitle(set)
|
||||
? st::emojiPanHeader
|
||||
? st().header
|
||||
: st::stickerPanPadding;
|
||||
info.rowsTop = info.top + titleSkip;
|
||||
if (set.externalLayout) {
|
||||
|
@ -462,16 +466,16 @@ int StickersListWidget::countDesiredHeight(int newWidth) {
|
|||
if (newWidth <= st::stickerPanWidthMin) {
|
||||
return 0;
|
||||
}
|
||||
auto availableWidth = newWidth - (st::stickerPanPadding - st::roundRadiusSmall);
|
||||
auto availableWidth = newWidth - (st::stickerPanPadding - st().margin.left());
|
||||
auto columnCount = availableWidth / st::stickerPanWidthMin;
|
||||
auto singleWidth = availableWidth / columnCount;
|
||||
auto fullWidth = (st::roundRadiusSmall + newWidth + st::emojiScroll.width);
|
||||
auto fullWidth = (st().margin.left() + newWidth + st::emojiScroll.width);
|
||||
auto rowsRight = (fullWidth - columnCount * singleWidth) / 2;
|
||||
accumulate_max(rowsRight, st::emojiScroll.width);
|
||||
_rowsLeft = fullWidth
|
||||
- columnCount * singleWidth
|
||||
- rowsRight
|
||||
- st::roundRadiusSmall;
|
||||
- st().margin.left();
|
||||
_singleSize = QSize(singleWidth, singleWidth);
|
||||
setColumnCount(columnCount);
|
||||
|
||||
|
@ -831,7 +835,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
|||
? set.count
|
||||
: loadedCount;
|
||||
|
||||
auto widthForTitle = stickersRight() - (st::emojiPanHeaderLeft - st::roundRadiusSmall);
|
||||
auto widthForTitle = stickersRight() - (st().headerLeft - st().margin.left());
|
||||
if (featuredHasAddButton(info.section)) {
|
||||
auto add = featuredAddRect(info);
|
||||
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
|
||||
|
@ -867,7 +871,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
|||
}
|
||||
p.setFont(st::stickersTrendingHeaderFont);
|
||||
p.setPen(st::stickersTrendingHeaderFg);
|
||||
p.drawTextLeft(st::emojiPanHeaderLeft - st::roundRadiusSmall, 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) {
|
||||
p.setPen(Qt::NoPen);
|
||||
|
@ -875,14 +879,14 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
|||
|
||||
{
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawEllipse(style::rtlrect(st::emojiPanHeaderLeft - st::roundRadiusSmall + titleWidth + st::stickersFeaturedUnreadSkip, info.top + st::stickersTrendingHeaderTop + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
|
||||
p.drawEllipse(style::rtlrect(st().headerLeft - st().margin.left() + titleWidth + st::stickersFeaturedUnreadSkip, info.top + st::stickersTrendingHeaderTop + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
|
||||
}
|
||||
}
|
||||
|
||||
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.drawTextLeft(st::emojiPanHeaderLeft - st::roundRadiusSmall, 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()) {
|
||||
return true;
|
||||
|
@ -904,7 +908,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
|||
if (setHasTitle(set) && clip.top() < info.rowsTop) {
|
||||
auto titleText = set.title;
|
||||
auto titleWidth = st::stickersTrendingHeaderFont->width(titleText);
|
||||
auto widthForTitle = stickersRight() - (st::emojiPanHeaderLeft - st::roundRadiusSmall);
|
||||
auto widthForTitle = stickersRight() - (st().headerLeft - st().margin.left());
|
||||
if (hasRemoveButton(info.section)) {
|
||||
auto remove = removeButtonRect(info);
|
||||
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
|
||||
|
@ -924,7 +928,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
|||
}
|
||||
p.setFont(st::emojiPanHeaderFont);
|
||||
p.setPen(st::emojiPanHeaderFg);
|
||||
p.drawTextLeft(st::emojiPanHeaderLeft - st::roundRadiusSmall, info.top + st::emojiPanHeaderTop, width(), titleText, titleWidth);
|
||||
p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st().headerTop, width(), titleText, titleWidth);
|
||||
}
|
||||
if (clip.top() + clip.height() <= info.rowsTop) {
|
||||
return true;
|
||||
|
@ -1054,7 +1058,7 @@ void StickersListWidget::paintEmptySearchResults(Painter &p) {
|
|||
}
|
||||
|
||||
int StickersListWidget::megagroupSetInfoLeft() const {
|
||||
return st::emojiPanHeaderLeft - st::roundRadiusSmall;
|
||||
return st().headerLeft - st().margin.left();
|
||||
}
|
||||
|
||||
void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected) {
|
||||
|
@ -1440,7 +1444,7 @@ QRect StickersListWidget::removeButtonRect(const SectionInfo &info) const {
|
|||
auto buttonw = st::stickerPanRemoveSet.width;
|
||||
auto buttonh = st::stickerPanRemoveSet.height;
|
||||
auto buttonx = stickersRight() - buttonw;
|
||||
auto buttony = info.top + (st::emojiPanHeader - buttonh) / 2;
|
||||
auto buttony = info.top + (st().header - buttonh) / 2;
|
||||
return QRect(buttonx, buttony, buttonw, buttonh);
|
||||
}
|
||||
|
||||
|
@ -2322,7 +2326,7 @@ std::vector<StickerIcon> StickersListWidget::fillIcons() {
|
|||
Assert(set != nullptr);
|
||||
const auto s = _mySets[i].thumbnailDocument;
|
||||
const auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding;
|
||||
const auto availh = st::emojiFooterHeight - 2 * st::stickerIconPadding;
|
||||
const auto availh = st().footer - 2 * st::stickerIconPadding;
|
||||
const auto size = set->hasThumbnail()
|
||||
? QSize(
|
||||
set->thumbnailLocation().width(),
|
||||
|
|
|
@ -46,6 +46,10 @@ class ReaderPointer;
|
|||
enum class Notification;
|
||||
} // namespace Media::Clip
|
||||
|
||||
namespace style {
|
||||
struct EmojiPan;
|
||||
} // namespace style
|
||||
|
||||
namespace ChatHelpers {
|
||||
|
||||
struct StickerIcon;
|
||||
|
@ -320,8 +324,6 @@ private:
|
|||
void addSearchRow(not_null<Data::StickersSet*> set);
|
||||
|
||||
void showPreview();
|
||||
void validatePremiumLock(Set &set, int index, const QImage &frame);
|
||||
void validatePremiumStar();
|
||||
|
||||
Ui::MessageSendingAnimationFrom messageSentAnimationInfo(
|
||||
int section,
|
||||
|
|
|
@ -107,7 +107,7 @@ void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage
|
|||
_painterInnerBottom = _innerBottom / cIntRetinaFactor();
|
||||
_painterInnerWidth = _innerWidth / cIntRetinaFactor();
|
||||
_painterInnerHeight = _innerHeight / cIntRetinaFactor();
|
||||
_painterCategoriesTop = _painterInnerBottom - st::emojiFooterHeight;
|
||||
_painterCategoriesTop = _painterInnerBottom - st::defaultEmojiPan.footer;
|
||||
|
||||
_wasSectionIcons = wasSectionIcons;
|
||||
}
|
||||
|
@ -294,6 +294,7 @@ TabbedSelector::TabbedSelector(
|
|||
Window::GifPauseReason level,
|
||||
Mode mode)
|
||||
: RpWidget(parent)
|
||||
, _st(st::defaultEmojiPan)
|
||||
, _controller(controller)
|
||||
, _level(level)
|
||||
, _mode(mode)
|
||||
|
@ -605,7 +606,7 @@ void TabbedSelector::updateScrollGeometry(QSize oldSize) {
|
|||
}
|
||||
|
||||
void TabbedSelector::updateFooterGeometry() {
|
||||
_footerTop = _dropDown ? 0 : (height() - st::emojiFooterHeight);
|
||||
_footerTop = _dropDown ? 0 : (height() - _st.footer);
|
||||
for (auto &tab : _tabs) {
|
||||
tab.footer()->resizeToWidth(width());
|
||||
tab.footer()->moveToLeft(0, _footerTop);
|
||||
|
@ -684,7 +685,7 @@ void TabbedSelector::paintContent(Painter &p) {
|
|||
0,
|
||||
_footerTop - (_dropDown ? 0 : _roundRadius),
|
||||
width(),
|
||||
st::emojiFooterHeight + _roundRadius);
|
||||
_st.footer + _roundRadius);
|
||||
Ui::FillRoundRect(
|
||||
p,
|
||||
footerPart,
|
||||
|
@ -696,7 +697,7 @@ void TabbedSelector::paintContent(Painter &p) {
|
|||
if (_tabsSlider) {
|
||||
p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg);
|
||||
}
|
||||
p.fillRect(0, _footerTop, width(), st::emojiFooterHeight, footerBg);
|
||||
p.fillRect(0, _footerTop, width(), _st.footer, footerBg);
|
||||
}
|
||||
|
||||
auto sidesTop = marginTop();
|
||||
|
@ -719,18 +720,18 @@ void TabbedSelector::paintContent(Painter &p) {
|
|||
|
||||
int TabbedSelector::marginTop() const {
|
||||
return _dropDown
|
||||
? st::emojiFooterHeight
|
||||
? _st.footer
|
||||
: _tabsSlider
|
||||
? (_tabsSlider->height() - st::lineWidth)
|
||||
: _roundRadius;
|
||||
}
|
||||
|
||||
int TabbedSelector::scrollTop() const {
|
||||
return tabbed() ? marginTop() : _dropDown ? st::emojiFooterHeight : 0;
|
||||
return tabbed() ? marginTop() : _dropDown ? _st.footer : 0;
|
||||
}
|
||||
|
||||
int TabbedSelector::marginBottom() const {
|
||||
return _dropDown ? _roundRadius : st::emojiFooterHeight;
|
||||
return _dropDown ? _roundRadius : _st.footer;
|
||||
}
|
||||
|
||||
int TabbedSelector::scrollBottom() const {
|
||||
|
@ -1200,15 +1201,18 @@ TabbedSelector::Inner::Inner(
|
|||
Window::GifPauseReason level)
|
||||
: Inner(
|
||||
parent,
|
||||
st::defaultEmojiPan,
|
||||
&controller->session(),
|
||||
Window::PausedIn(controller, level)) {
|
||||
}
|
||||
|
||||
TabbedSelector::Inner::Inner(
|
||||
QWidget *parent,
|
||||
const style::EmojiPan &st,
|
||||
not_null<Main::Session*> session,
|
||||
Fn<bool()> paused)
|
||||
: RpWidget(parent)
|
||||
, _st(st)
|
||||
, _session(session)
|
||||
, _paused(paused) {
|
||||
}
|
||||
|
@ -1271,7 +1275,11 @@ int TabbedSelector::Inner::resizeGetHeight(int newWidth) {
|
|||
int TabbedSelector::Inner::minimalHeight() const {
|
||||
return (_minimalHeight > 0)
|
||||
? _minimalHeight
|
||||
: (st::emojiPanMaxHeight - st::emojiFooterHeight);
|
||||
: defaultMinimalHeight();
|
||||
}
|
||||
|
||||
int TabbedSelector::Inner::defaultMinimalHeight() const {
|
||||
return st::emojiPanMaxHeight - _st.footer;
|
||||
}
|
||||
|
||||
void TabbedSelector::Inner::hideFinished() {
|
||||
|
@ -1289,9 +1297,16 @@ void TabbedSelector::Inner::panelHideFinished() {
|
|||
}
|
||||
}
|
||||
|
||||
TabbedSelector::InnerFooter::InnerFooter(QWidget *parent)
|
||||
: RpWidget(parent) {
|
||||
resize(st::emojiPanWidth, st::emojiFooterHeight);
|
||||
TabbedSelector::InnerFooter::InnerFooter(
|
||||
QWidget *parent,
|
||||
const style::EmojiPan &st)
|
||||
: RpWidget(parent)
|
||||
, _st(st) {
|
||||
resize(st::emojiPanWidth, _st.footer);
|
||||
}
|
||||
|
||||
const style::EmojiPan &TabbedSelector::InnerFooter::st() const {
|
||||
return _st;
|
||||
}
|
||||
|
||||
} // namespace ChatHelpers
|
||||
|
|
|
@ -41,6 +41,10 @@ namespace SendMenu {
|
|||
enum class Type;
|
||||
} // namespace SendMenu
|
||||
|
||||
namespace style {
|
||||
struct EmojiPan;
|
||||
} // namespace style
|
||||
|
||||
namespace ChatHelpers {
|
||||
|
||||
enum class SelectorTab {
|
||||
|
@ -233,6 +237,7 @@ private:
|
|||
not_null<GifsListWidget*> gifs() const;
|
||||
not_null<StickersListWidget*> masks() const;
|
||||
|
||||
const style::EmojiPan &_st;
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const Window::GifPauseReason _level = {};
|
||||
|
||||
|
@ -278,12 +283,16 @@ public:
|
|||
Window::GifPauseReason level);
|
||||
Inner(
|
||||
QWidget *parent,
|
||||
const style::EmojiPan &st,
|
||||
not_null<Main::Session*> session,
|
||||
Fn<bool()> paused);
|
||||
|
||||
[[nodiscard]] Main::Session &session() const {
|
||||
return *_session;
|
||||
}
|
||||
[[nodiscard]] const style::EmojiPan &st() const {
|
||||
return _st;
|
||||
}
|
||||
[[nodiscard]] Fn<bool()> pausedMethod() const {
|
||||
return _paused;
|
||||
}
|
||||
|
@ -332,6 +341,7 @@ protected:
|
|||
int visibleTop,
|
||||
int visibleBottom) override;
|
||||
int minimalHeight() const;
|
||||
virtual int defaultMinimalHeight() const;
|
||||
int resizeGetHeight(int newWidth) override final;
|
||||
|
||||
virtual int countDesiredHeight(int newWidth) = 0;
|
||||
|
@ -347,6 +357,7 @@ protected:
|
|||
void checkHideWithBox(QPointer<Ui::BoxContent> box);
|
||||
|
||||
private:
|
||||
const style::EmojiPan &_st;
|
||||
const not_null<Main::Session*> _session;
|
||||
const Fn<bool()> _paused;
|
||||
|
||||
|
@ -364,7 +375,9 @@ private:
|
|||
|
||||
class TabbedSelector::InnerFooter : public Ui::RpWidget {
|
||||
public:
|
||||
InnerFooter(QWidget *parent);
|
||||
InnerFooter(QWidget *parent, const style::EmojiPan &st);
|
||||
|
||||
[[nodiscard]] const style::EmojiPan &st() const;
|
||||
|
||||
protected:
|
||||
virtual void processHideFinished() {
|
||||
|
@ -373,6 +386,9 @@ protected:
|
|||
}
|
||||
friend class Inner;
|
||||
|
||||
private:
|
||||
const style::EmojiPan &_st;
|
||||
|
||||
};
|
||||
|
||||
} // namespace ChatHelpers
|
||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/ui_utility.h"
|
||||
#include "apiwrap.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
|
@ -41,6 +42,7 @@ using SizeTag = CustomEmojiManager::SizeTag;
|
|||
case SizeTag::Normal: return LottieSize::EmojiInteraction;
|
||||
case SizeTag::Large: return LottieSize::EmojiInteractionReserved1;
|
||||
case SizeTag::Isolated: return LottieSize::EmojiInteractionReserved2;
|
||||
case SizeTag::ReactionFake: return LottieSize::EmojiInteractionReserved3;
|
||||
}
|
||||
Unexpected("SizeTag value in CustomEmojiManager-LottieSizeFromTag.");
|
||||
}
|
||||
|
@ -52,6 +54,8 @@ using SizeTag = CustomEmojiManager::SizeTag;
|
|||
case SizeTag::Isolated:
|
||||
return (st::largeEmojiSize + 2 * st::largeEmojiOutline)
|
||||
* style::DevicePixelRatio();
|
||||
case SizeTag::ReactionFake:
|
||||
return st::reactStripImage * style::DevicePixelRatio();
|
||||
}
|
||||
Unexpected("SizeTag value in CustomEmojiManager-SizeFromTag.");
|
||||
}
|
||||
|
@ -663,6 +667,9 @@ Session &CustomEmojiManager::owner() const {
|
|||
|
||||
int FrameSizeFromTag(SizeTag tag) {
|
||||
const auto emoji = EmojiSizeFromTag(tag);
|
||||
if (tag == SizeTag::ReactionFake) {
|
||||
return emoji;
|
||||
}
|
||||
const auto factor = style::DevicePixelRatio();
|
||||
return Ui::Text::AdjustCustomEmojiSize(emoji / factor) * factor;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
Normal,
|
||||
Large,
|
||||
Isolated,
|
||||
ReactionFake,
|
||||
|
||||
kCount,
|
||||
};
|
||||
|
|
|
@ -318,6 +318,7 @@ Manager::Manager(
|
|||
, _inner(QRect({}, st::reactionCornerSize))
|
||||
, _strip(
|
||||
_inner,
|
||||
st::reactionCornerImage,
|
||||
crl::guard(this, [=] { updateCurrentButton(); }),
|
||||
std::move(iconFactory))
|
||||
, _cachedRound(
|
||||
|
|
|
@ -7,13 +7,78 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "history/view/reactions/history_view_reactions_selector.h"
|
||||
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "history/history_item.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "main/main_session.h"
|
||||
#include "chat_helpers/emoji_list_widget.h"
|
||||
#include "chat_helpers/stickers_list_footer.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
namespace HistoryView::Reactions {
|
||||
namespace {
|
||||
|
||||
class ShiftedEmoji final : public Ui::Text::CustomEmoji {
|
||||
public:
|
||||
ShiftedEmoji(
|
||||
not_null<Data::CustomEmojiManager*> manager,
|
||||
DocumentId id,
|
||||
Fn<void()> repaint,
|
||||
QPoint shift);
|
||||
|
||||
QString entityData() override;
|
||||
void paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now,
|
||||
const QColor &preview,
|
||||
bool paused) override;
|
||||
void unload() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> _real;
|
||||
QPoint _shift;
|
||||
|
||||
};
|
||||
|
||||
ShiftedEmoji::ShiftedEmoji(
|
||||
not_null<Data::CustomEmojiManager*> manager,
|
||||
DocumentId id,
|
||||
Fn<void()> repaint,
|
||||
QPoint shift)
|
||||
: _real(manager->create(
|
||||
id,
|
||||
std::move(repaint),
|
||||
Data::CustomEmojiManager::SizeTag::ReactionFake))
|
||||
, _shift(shift) {
|
||||
}
|
||||
|
||||
QString ShiftedEmoji::entityData() {
|
||||
return _real->entityData();
|
||||
}
|
||||
|
||||
void ShiftedEmoji::paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now,
|
||||
const QColor &preview,
|
||||
bool paused) {
|
||||
_real->paint(p, x + _shift.x(), y + _shift.y(), now, preview, paused);
|
||||
}
|
||||
|
||||
void ShiftedEmoji::unload() {
|
||||
_real->unload();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Selector::Selector(
|
||||
not_null<QWidget*> parent,
|
||||
|
@ -29,6 +94,7 @@ Selector::Selector(
|
|||
st::reactStripHeight)
|
||||
, _strip(
|
||||
QRect(0, 0, st::reactStripSize, st::reactStripSize),
|
||||
st::reactStripImage,
|
||||
crl::guard(this, [=] { update(_inner); }),
|
||||
std::move(iconFactory))
|
||||
, _size(st::reactStripSize)
|
||||
|
@ -70,7 +136,7 @@ QMargins Selector::extentsForShadow() const {
|
|||
}
|
||||
|
||||
int Selector::extendTopForCategories() const {
|
||||
return _reactions.customAllowed ? st::emojiFooterHeight : 0;
|
||||
return _reactions.customAllowed ? st::reactPanelEmojiPan.footer : 0;
|
||||
}
|
||||
|
||||
int Selector::desiredHeight() const {
|
||||
|
@ -275,6 +341,10 @@ void Selector::finishExpand() {
|
|||
if (!fill.isEmpty()) {
|
||||
q.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
||||
}
|
||||
if (_footer) {
|
||||
_footer->show();
|
||||
}
|
||||
_scroll->show();
|
||||
}
|
||||
|
||||
void Selector::paintBubble(QPainter &p, int innerWidth) {
|
||||
|
@ -348,9 +418,8 @@ void Selector::mouseReleaseEvent(QMouseEvent *e) {
|
|||
_premiumPromoChosen.fire({});
|
||||
} else if (selected == Strip::AddedButton::Expand) {
|
||||
expand();
|
||||
} else {
|
||||
const auto id = std::get_if<Data::ReactionId>(&selected);
|
||||
if (id && !id->empty()) {
|
||||
} else if (const auto id = std::get_if<Data::ReactionId>(&selected)) {
|
||||
if (!id->empty()) {
|
||||
_chosen.fire({ .id = *id });
|
||||
}
|
||||
}
|
||||
|
@ -360,13 +429,23 @@ void Selector::expand() {
|
|||
const auto parent = parentWidget()->geometry();
|
||||
const auto additionalBottom = parent.height() - y() - height();
|
||||
const auto additional = _specialExpandTopSkip + additionalBottom;
|
||||
if (additionalBottom < 0 || additional <= 0) {
|
||||
const auto strong = _parentController.get();
|
||||
if (additionalBottom < 0 || additional <= 0 || !strong) {
|
||||
return;
|
||||
}
|
||||
if (additionalBottom > 0) {
|
||||
} else if (additionalBottom > 0) {
|
||||
resize(width(), height() + additionalBottom);
|
||||
raise();
|
||||
}
|
||||
|
||||
createList(strong);
|
||||
cacheExpandIcon();
|
||||
|
||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
||||
_expanded = true;
|
||||
_expanding.start([=] { update(); }, 0., 1., st::slideDuration);
|
||||
}
|
||||
|
||||
void Selector::cacheExpandIcon() {
|
||||
_expandIconCache = _cachedRound.PrepareImage({ _size, _size });
|
||||
_expandIconCache.fill(Qt::transparent);
|
||||
auto q = QPainter(&_expandIconCache);
|
||||
|
@ -378,9 +457,130 @@ void Selector::expand() {
|
|||
QRect(-(count - 1) * _size, 0, count * _size, _size),
|
||||
1.,
|
||||
false);
|
||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
||||
_expanded = true;
|
||||
_expanding.start([=] { update(); }, 0., 1., st::slideDuration);
|
||||
}
|
||||
|
||||
void Selector::createList(not_null<Window::SessionController*> controller) {
|
||||
using namespace ChatHelpers;
|
||||
auto recent = std::vector<DocumentId>();
|
||||
auto defaultReactionIds = base::flat_map<DocumentId, QString>();
|
||||
recent.reserve(_reactions.recent.size());
|
||||
for (const auto &reaction : _reactions.recent) {
|
||||
if (const auto id = reaction->id.custom()) {
|
||||
recent.push_back(id);
|
||||
} else {
|
||||
recent.push_back(reaction->selectAnimation->id);
|
||||
defaultReactionIds.emplace(recent.back(), reaction->id.emoji());
|
||||
}
|
||||
};
|
||||
const auto manager = &controller->session().data().customEmojiManager();
|
||||
const auto shift = [&] {
|
||||
// See EmojiListWidget custom emoji position resolving.
|
||||
const auto area = st::emojiPanArea;
|
||||
const auto areaPosition = QPoint(
|
||||
(_size - area.width()) / 2,
|
||||
(_size - area.height()) / 2);
|
||||
const auto esize = Ui::Emoji::GetSizeLarge() / style::DevicePixelRatio();
|
||||
const auto innerPosition = QPoint(
|
||||
(area.width() - esize) / 2,
|
||||
(area.height() - esize) / 2);
|
||||
const auto customSize = Ui::Text::AdjustCustomEmojiSize(esize);
|
||||
const auto customSkip = (esize - customSize) / 2;
|
||||
const auto customPosition = QPoint(customSkip, customSkip);
|
||||
return QPoint(
|
||||
(_size - st::reactStripImage) / 2,
|
||||
(_size - st::reactStripImage) / 2
|
||||
) - areaPosition - innerPosition - customPosition;
|
||||
}();
|
||||
auto factory = [=](DocumentId id, Fn<void()> repaint) {
|
||||
return defaultReactionIds.contains(id)
|
||||
? std::make_unique<ShiftedEmoji>(
|
||||
manager,
|
||||
id,
|
||||
std::move(repaint),
|
||||
shift)
|
||||
: nullptr;
|
||||
};
|
||||
_scroll = Ui::CreateChild<Ui::ScrollArea>(this, st::reactPanelScroll);
|
||||
_scroll->hide();
|
||||
|
||||
const auto st = lifetime().make_state<style::EmojiPan>(
|
||||
st::reactPanelEmojiPan);
|
||||
st->padding.setTop(_skipy);
|
||||
_list = _scroll->setOwnedWidget(
|
||||
object_ptr<EmojiListWidget>(_scroll, EmojiListDescriptor{
|
||||
.session = &controller->session(),
|
||||
.mode = (_reactions.customAllowed
|
||||
? EmojiListMode::FullReactions
|
||||
: EmojiListMode::RecentReactions),
|
||||
.controller = controller,
|
||||
.paused = [] { return false; },
|
||||
.customRecentList = std::move(recent),
|
||||
.customRecentFactory = std::move(factory),
|
||||
.st = st,
|
||||
})
|
||||
).data();
|
||||
|
||||
_list->customChosen(
|
||||
) | rpl::start_with_next([=](const TabbedSelector::FileChosen &chosen) {
|
||||
const auto id = DocumentId{ chosen.document->id };
|
||||
const auto i = defaultReactionIds.find(id);
|
||||
if (i != end(defaultReactionIds)) {
|
||||
_chosen.fire({ .id = { i->second } });
|
||||
} else {
|
||||
_chosen.fire({ .id = { id } });
|
||||
}
|
||||
}, _list->lifetime());
|
||||
|
||||
const auto inner = rect().marginsRemoved(extentsForShadow());
|
||||
const auto footer = _reactions.customAllowed
|
||||
? _list->createFooter().data()
|
||||
: nullptr;
|
||||
if ((_footer = static_cast<StickersListFooter*>(footer))) {
|
||||
_footer->setParent(this);
|
||||
_footer->hide();
|
||||
_footer->setGeometry(
|
||||
inner.x(),
|
||||
inner.y(),
|
||||
inner.width(),
|
||||
_footer->height());
|
||||
const auto shadow = Ui::CreateChild<Ui::PlainShadow>(this);
|
||||
_footer->geometryValue() | rpl::start_with_next([=](QRect geometry) {
|
||||
shadow->setGeometry(
|
||||
geometry.x(),
|
||||
geometry.y() + geometry.height(),
|
||||
geometry.width(),
|
||||
st::lineWidth);
|
||||
}, shadow->lifetime());
|
||||
shadow->show();
|
||||
}
|
||||
const auto geometry = inner.marginsRemoved(
|
||||
st::reactPanelEmojiPan.margin);
|
||||
_list->move(0, 0);
|
||||
_list->refreshEmoji();
|
||||
_list->resizeToWidth(geometry.width());
|
||||
_list->show();
|
||||
|
||||
const auto updateVisibleTopBottom = [=] {
|
||||
const auto scrollTop = _scroll->scrollTop();
|
||||
const auto scrollBottom = scrollTop + _scroll->height();
|
||||
_list->setVisibleTopBottom(scrollTop, scrollBottom);
|
||||
};
|
||||
_scroll->scrollTopChanges(
|
||||
) | rpl::start_with_next(updateVisibleTopBottom, _list->lifetime());
|
||||
|
||||
_list->scrollToRequests(
|
||||
) | rpl::start_with_next([=](int y) {
|
||||
_scroll->scrollToY(y);
|
||||
}, _list->lifetime());
|
||||
|
||||
_scroll->setGeometry(inner.marginsRemoved({
|
||||
st::reactPanelEmojiPan.margin.left(),
|
||||
_footer ? _footer->height() : 0,
|
||||
0,
|
||||
0,
|
||||
}));
|
||||
|
||||
updateVisibleTopBottom();
|
||||
}
|
||||
|
||||
bool AdjustMenuGeometryForSelector(
|
||||
|
|
|
@ -20,6 +20,8 @@ struct ReactionId;
|
|||
|
||||
namespace ChatHelpers {
|
||||
class TabbedPanel;
|
||||
class EmojiListWidget;
|
||||
class StickersListFooter;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Window {
|
||||
|
@ -28,6 +30,7 @@ class SessionController;
|
|||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
class ScrollArea;
|
||||
} // namespace Ui
|
||||
|
||||
namespace HistoryView::Reactions {
|
||||
|
@ -78,12 +81,14 @@ private:
|
|||
void paintExpanded(QPainter &p);
|
||||
void paintBubble(QPainter &p, int innerWidth);
|
||||
void paintBackgroundToBuffer();
|
||||
void finishExpand();
|
||||
|
||||
[[nodiscard]] int lookupSelectedIndex(QPoint position) const;
|
||||
void setSelected(int index);
|
||||
|
||||
void expand();
|
||||
void cacheExpandIcon();
|
||||
void createList(not_null<Window::SessionController*> controller);
|
||||
void finishExpand();
|
||||
|
||||
const base::weak_ptr<Window::SessionController> _parentController;
|
||||
const Data::PossibleItemReactions _reactions;
|
||||
|
@ -93,6 +98,10 @@ private:
|
|||
rpl::event_stream<ChosenReaction> _chosen;
|
||||
rpl::event_stream<> _premiumPromoChosen;
|
||||
|
||||
Ui::ScrollArea *_scroll = nullptr;
|
||||
ChatHelpers::EmojiListWidget *_list = nullptr;
|
||||
ChatHelpers::StickersListFooter *_footer = nullptr;
|
||||
|
||||
QImage _paintBuffer;
|
||||
Ui::Animations::Simple _expanding;
|
||||
float64 _appearProgress = 0.;
|
||||
|
|
|
@ -45,11 +45,12 @@ constexpr auto kHoverScale = 1.24;
|
|||
|
||||
Strip::Strip(
|
||||
QRect inner,
|
||||
int size,
|
||||
Fn<void()> update,
|
||||
IconFactory iconFactory)
|
||||
: _iconFactory(std::move(iconFactory))
|
||||
, _inner(inner)
|
||||
, _finalSize(st::reactionCornerImage)
|
||||
, _finalSize(size)
|
||||
, _update(std::move(update)) {
|
||||
}
|
||||
|
||||
|
@ -98,8 +99,7 @@ void Strip::paint(
|
|||
const auto animationRect = clip.marginsRemoved({ 0, skip, 0, skip });
|
||||
|
||||
PainterHighQualityEnabler hq(p);
|
||||
const auto finalSize = st::reactionCornerImage;
|
||||
const auto hoveredSize = int(base::SafeRound(finalSize * kHoverScale));
|
||||
const auto hoveredSize = int(base::SafeRound(_finalSize * kHoverScale));
|
||||
const auto basicTargetForScale = [&](int size, float64 scale) {
|
||||
const auto remove = size * (1. - scale) / 2.;
|
||||
return QRectF(QRect(
|
||||
|
@ -109,7 +109,7 @@ void Strip::paint(
|
|||
size
|
||||
)).marginsRemoved({ remove, remove, remove, remove });
|
||||
};
|
||||
const auto basicTarget = basicTargetForScale(finalSize, scale);
|
||||
const auto basicTarget = basicTargetForScale(_finalSize, scale);
|
||||
const auto countTarget = [&](const ReactionIcons &icon) {
|
||||
const auto selectScale = icon.selectedScale.value(
|
||||
icon.selected ? kHoverScale : 1.);
|
||||
|
@ -118,7 +118,7 @@ void Strip::paint(
|
|||
}
|
||||
const auto finalScale = scale * selectScale;
|
||||
return (finalScale <= 1.)
|
||||
? basicTargetForScale(finalSize, finalScale)
|
||||
? basicTargetForScale(_finalSize, finalScale)
|
||||
: basicTargetForScale(hoveredSize, finalScale / kHoverScale);
|
||||
};
|
||||
for (auto &icon : _icons) {
|
||||
|
@ -288,7 +288,7 @@ auto Strip::selected() const -> std::variant<AddedButton, ReactionId> {
|
|||
}
|
||||
|
||||
int Strip::computeOverSize() const {
|
||||
return int(base::SafeRound(st::reactionCornerImage * kHoverScale));
|
||||
return int(base::SafeRound(_finalSize * kHoverScale));
|
||||
}
|
||||
|
||||
void Strip::clearAppearAnimations(bool mainAppeared) {
|
||||
|
|
|
@ -43,7 +43,7 @@ class Strip final {
|
|||
public:
|
||||
using ReactionId = Data::ReactionId;
|
||||
|
||||
Strip(QRect inner, Fn<void()> update, IconFactory iconFactory);
|
||||
Strip(QRect inner, int size, Fn<void()> update, IconFactory iconFactory);
|
||||
|
||||
enum class AddedButton : uchar {
|
||||
None,
|
||||
|
|
|
@ -1183,7 +1183,7 @@ void Contact::initDimensions() {
|
|||
}
|
||||
|
||||
void Contact::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
|
||||
int32 left = st::defaultEmojiPan.headerLeft - st::inlineResultsLeft;
|
||||
|
||||
left = st::inlineFileSize + st::inlineThumbSkip;
|
||||
prepareThumbnail(st::inlineFileSize, st::inlineFileSize);
|
||||
|
@ -1272,7 +1272,7 @@ Article::Article(
|
|||
|
||||
void Article::initDimensions() {
|
||||
_maxw = st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft;
|
||||
int32 textWidth = _maxw - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : (st::emojiPanHeaderLeft - st::inlineResultsLeft));
|
||||
int32 textWidth = _maxw - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : (st::defaultEmojiPan.headerLeft - st::inlineResultsLeft));
|
||||
TextParseOptions titleOpts = { 0, textWidth, 2 * st::semiboldFont->height, Qt::LayoutDirectionAuto };
|
||||
_title.setText(st::semiboldTextStyle, TextUtilities::SingleLine(_result->getLayoutTitle()), titleOpts);
|
||||
int32 titleHeight = qMin(_title.countHeight(textWidth), 2 * st::semiboldFont->height);
|
||||
|
@ -1294,7 +1294,7 @@ int32 Article::resizeGetHeight(int32 width) {
|
|||
if (_url) {
|
||||
_urlText = getResultUrl();
|
||||
_urlWidth = st::normalFont->width(_urlText);
|
||||
int32 textWidth = _width - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : (st::emojiPanHeaderLeft - st::inlineResultsLeft));
|
||||
int32 textWidth = _width - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : (st::defaultEmojiPan.headerLeft - st::inlineResultsLeft));
|
||||
if (_urlWidth > textWidth) {
|
||||
_urlText = st::normalFont->elided(_urlText, textWidth);
|
||||
_urlWidth = st::normalFont->width(_urlText);
|
||||
|
@ -1305,7 +1305,7 @@ int32 Article::resizeGetHeight(int32 width) {
|
|||
}
|
||||
|
||||
void Article::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
|
||||
int32 left = st::defaultEmojiPan.headerLeft - st::inlineResultsLeft;
|
||||
if (_withThumb) {
|
||||
left = st::inlineThumbSize + st::inlineThumbSkip;
|
||||
prepareThumbnail(st::inlineThumbSize, st::inlineThumbSize);
|
||||
|
@ -1470,7 +1470,7 @@ void Game::setPosition(int32 position) {
|
|||
}
|
||||
|
||||
void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
|
||||
int32 left = st::defaultEmojiPan.headerLeft - st::inlineResultsLeft;
|
||||
|
||||
left = st::inlineThumbSize + st::inlineThumbSkip;
|
||||
auto rthumb = style::rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width);
|
||||
|
|
|
@ -80,7 +80,6 @@ void CreatePaletteCorners() {
|
|||
PrepareCorners(OverviewVideoSelectedCorners, st::overviewVideoStatusRadius, st::msgDateImgBgSelected);
|
||||
PrepareCorners(ForwardCorners, st::historyMessageRadius, st::historyForwardChooseBg);
|
||||
PrepareCorners(MediaviewSaveCorners, st::mediaviewControllerRadius, st::mediaviewSaveMsgBg);
|
||||
PrepareCorners(EmojiHoverCorners, st::emojiPanRadius, st::emojiPanHover);
|
||||
PrepareCorners(StickerHoverCorners, st::roundRadiusSmall, st::emojiPanHover);
|
||||
PrepareCorners(BotKeyboardCorners, st::roundRadiusSmall, st::botKbBg);
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ enum CachedRoundCorners : int {
|
|||
OverviewVideoSelectedCorners,
|
||||
ForwardCorners,
|
||||
MediaviewSaveCorners,
|
||||
EmojiHoverCorners,
|
||||
StickerHoverCorners,
|
||||
BotKeyboardCorners,
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ notifySendReply: IconButton {
|
|||
iconOver: historySendIconOver;
|
||||
iconPosition: point(6px, 6px);
|
||||
}
|
||||
notifyFadeRight: icon {{ "fade_horizontal", notificationBg }};
|
||||
|
||||
titleUnreadCounterTop: 6px;
|
||||
titleUnreadCounterRight: 35px;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a1ec2c9ade2b050bd307ecf669a2ae5019d70df4
|
||||
Subproject commit 8162619cb17456f31d1be378a7ed72dc928e0831
|
Loading…
Add table
Reference in a new issue