mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Allow choosing emoji color for all emoji.
This commit is contained in:
parent
ecaf3340f6
commit
ed9028e1c4
12 changed files with 327 additions and 116 deletions
BIN
Telegram/Resources/icons/emoji/emoji_skin.png
Normal file
BIN
Telegram/Resources/icons/emoji/emoji_skin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 412 B |
BIN
Telegram/Resources/icons/emoji/emoji_skin@2x.png
Normal file
BIN
Telegram/Resources/icons/emoji/emoji_skin@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 698 B |
BIN
Telegram/Resources/icons/emoji/emoji_skin@3x.png
Normal file
BIN
Telegram/Resources/icons/emoji/emoji_skin@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 952 B |
|
@ -1807,6 +1807,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_emoji_set_active" = "Current set";
|
||||
"lng_emoji_set_download" = "Download {size}";
|
||||
"lng_emoji_set_loading" = "{percent}, {progress}";
|
||||
"lng_emoji_color_all" = "Choose color for all emoji";
|
||||
|
||||
"lng_recent_stickers" = "Frequently used";
|
||||
"lng_faved_stickers_add" = "Add to Favorites";
|
||||
|
|
|
@ -118,6 +118,8 @@ EmojiPan {
|
|||
tabs: SettingsSlider;
|
||||
search: TabbedSearch;
|
||||
searchMargin: margins;
|
||||
colorAll: IconButton;
|
||||
colorAllLabel: FlatLabel;
|
||||
removeSet: IconButton;
|
||||
boxLabel: FlatLabel;
|
||||
icons: ComposeIcons;
|
||||
|
@ -448,6 +450,7 @@ inlineResultsMaxHeight: 640px;
|
|||
emojiPanHeaderFont: semiboldFont;
|
||||
emojiPanRemoveSkip: 10px;
|
||||
emojiPanRemoveTop: 10px;
|
||||
emojiPanColorAllSkip: 9px;
|
||||
|
||||
emojiColorsPadding: 5px;
|
||||
emojiColorsSep: 1px;
|
||||
|
@ -490,6 +493,25 @@ stickerIconMove: 400;
|
|||
stickerPreviewDuration: 150;
|
||||
stickerPreviewMin: 0.1;
|
||||
|
||||
emojiPanColorAll: IconButton(stickerPanRemoveSet) {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
rippleAreaSize: 24px;
|
||||
icon: icon {{ "emoji/emoji_skin", smallCloseIconFg }};
|
||||
iconOver: icon {{ "emoji/emoji_skin", smallCloseIconFgOver }};
|
||||
}
|
||||
emojiPanColorAllLabel: FlatLabel(defaultFlatLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
align: align(top);
|
||||
minWidth: 40px;
|
||||
style: TextStyle(defaultTextStyle) {
|
||||
font: font(12px);
|
||||
linkFont: font(12px);
|
||||
linkFontOver: font(12px);
|
||||
}
|
||||
}
|
||||
emojiPanColorAllPadding: margins(10px, 6px, 10px, -1px);
|
||||
|
||||
stickerGroupCategorySize: 28px;
|
||||
stickerGroupCategoryAbout: defaultTextStyle;
|
||||
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
|
||||
|
@ -626,6 +648,8 @@ defaultEmojiPan: EmojiPan {
|
|||
tabs: emojiTabs;
|
||||
search: defaultTabbedSearch;
|
||||
searchMargin: margins(1px, 11px, 2px, 5px);
|
||||
colorAll: emojiPanColorAll;
|
||||
colorAllLabel: emojiPanColorAllLabel;
|
||||
removeSet: stickerPanRemoveSet;
|
||||
boxLabel: boxLabel;
|
||||
icons: defaultComposeIcons;
|
||||
|
|
|
@ -672,17 +672,9 @@ std::vector<Result> EmojiKeywords::PrioritizeRecent(
|
|||
}
|
||||
|
||||
std::vector<Result> EmojiKeywords::ApplyVariants(std::vector<Result> list) {
|
||||
auto &settings = Core::App().settings();
|
||||
for (auto &item : list) {
|
||||
item.emoji = [&] {
|
||||
const auto result = item.emoji;
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
const auto i = result->hasVariants()
|
||||
? variants.find(result->nonColoredId())
|
||||
: end(variants);
|
||||
return (i != end(variants))
|
||||
? result->variant(i->second)
|
||||
: result;
|
||||
}();
|
||||
item.emoji = settings.lookupEmojiVariant(item.emoji);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ class EmojiColorPicker final : public Ui::RpWidget {
|
|||
public:
|
||||
EmojiColorPicker(QWidget *parent, const style::EmojiPan &st);
|
||||
|
||||
void showEmoji(EmojiPtr emoji);
|
||||
void showEmoji(EmojiPtr emoji, bool allLabel = false);
|
||||
|
||||
void clearSelection();
|
||||
void handleMouseMove(QPoint globalPos);
|
||||
|
@ -79,8 +79,10 @@ protected:
|
|||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
void createAllLabel();
|
||||
void animationCallback();
|
||||
void updateSize();
|
||||
[[nodiscard]] int topColorAllSkip() const;
|
||||
|
||||
void drawVariant(QPainter &p, int variant);
|
||||
|
||||
|
@ -106,6 +108,8 @@ private:
|
|||
QPixmap _cache;
|
||||
Ui::Animations::Simple _a_opacity;
|
||||
|
||||
std::unique_ptr<Ui::FlatLabel> _allLabel;
|
||||
|
||||
rpl::event_stream<EmojiChosen> _chosen;
|
||||
rpl::event_stream<> _hidden;
|
||||
|
||||
|
@ -131,10 +135,15 @@ EmojiColorPicker::EmojiColorPicker(
|
|||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void EmojiColorPicker::showEmoji(EmojiPtr emoji) {
|
||||
void EmojiColorPicker::showEmoji(EmojiPtr emoji, bool allLabel) {
|
||||
if (!emoji || !emoji->hasVariants()) {
|
||||
return;
|
||||
}
|
||||
if (!allLabel) {
|
||||
_allLabel = nullptr;
|
||||
} else if (!_allLabel) {
|
||||
createAllLabel();
|
||||
}
|
||||
_ignoreShow = false;
|
||||
|
||||
_variants.resize(emoji->variantsCount() + 1);
|
||||
|
@ -144,10 +153,21 @@ void EmojiColorPicker::showEmoji(EmojiPtr emoji) {
|
|||
|
||||
updateSize();
|
||||
|
||||
if (!_cache.isNull()) _cache = QPixmap();
|
||||
if (!_cache.isNull()) {
|
||||
_cache = QPixmap();
|
||||
}
|
||||
showAnimated();
|
||||
}
|
||||
|
||||
void EmojiColorPicker::createAllLabel() {
|
||||
_allLabel = std::make_unique<Ui::FlatLabel>(
|
||||
this,
|
||||
tr::lng_emoji_color_all(),
|
||||
_st.colorAllLabel);
|
||||
_allLabel->show();
|
||||
_allLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
}
|
||||
|
||||
void EmojiColorPicker::updateSize() {
|
||||
auto width = st::emojiPanMargins.left()
|
||||
+ _singleSize.width() * _variants.size()
|
||||
|
@ -158,6 +178,17 @@ void EmojiColorPicker::updateSize() {
|
|||
+ 2 * st::emojiColorsPadding
|
||||
+ _singleSize.height()
|
||||
+ st::emojiPanMargins.bottom();
|
||||
if (_allLabel) {
|
||||
_allLabel->resizeToWidth(width
|
||||
- st::emojiPanMargins.left()
|
||||
- st::emojiPanMargins.right()
|
||||
- st::emojiPanColorAllPadding.left()
|
||||
- st::emojiPanColorAllPadding.right());
|
||||
_allLabel->move(
|
||||
st::emojiPanMargins.left() + st::emojiPanColorAllPadding.left(),
|
||||
st::emojiPanMargins.top() + st::emojiPanColorAllPadding.top());
|
||||
height += topColorAllSkip();
|
||||
}
|
||||
resize(width, height);
|
||||
update();
|
||||
updateSelected();
|
||||
|
@ -186,11 +217,15 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
|
|||
Ui::Shadow::paint(p, inner, width(), _st.showAnimation.shadow);
|
||||
_backgroundRect.paint(p, inner);
|
||||
|
||||
const auto skip = topColorAllSkip();
|
||||
auto x = st::emojiPanMargins.left() + 2 * st::emojiColorsPadding + _singleSize.width();
|
||||
if (rtl()) x = width() - x - st::emojiColorsSep;
|
||||
p.fillRect(x, st::emojiPanMargins.top() + st::emojiColorsPadding, st::emojiColorsSep, inner.height() - st::emojiColorsPadding * 2, st::emojiColorsSepColor);
|
||||
p.fillRect(x, st::emojiPanMargins.top() + skip + st::emojiColorsPadding, st::emojiColorsSep, inner.height() - st::emojiColorsPadding * 2 - skip, st::emojiColorsSepColor);
|
||||
|
||||
if (_variants.isEmpty()) return;
|
||||
if (_variants.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
p.translate(0, skip);
|
||||
for (auto i = 0, count = int(_variants.size()); i != count; ++i) {
|
||||
drawVariant(p, i);
|
||||
}
|
||||
|
@ -248,6 +283,9 @@ void EmojiColorPicker::animationCallback() {
|
|||
update();
|
||||
if (!_a_opacity.animating()) {
|
||||
_cache = QPixmap();
|
||||
if (_allLabel) {
|
||||
_allLabel->show();
|
||||
}
|
||||
if (_hiding) {
|
||||
hide();
|
||||
_hidden.fire({});
|
||||
|
@ -276,10 +314,16 @@ rpl::producer<> EmojiColorPicker::hidden() const {
|
|||
|
||||
void EmojiColorPicker::hideAnimated() {
|
||||
if (_cache.isNull()) {
|
||||
if (_allLabel) {
|
||||
_allLabel->show();
|
||||
}
|
||||
_cache = Ui::GrabWidget(this);
|
||||
clearSelection();
|
||||
}
|
||||
_hiding = true;
|
||||
if (_allLabel) {
|
||||
_allLabel->hide();
|
||||
}
|
||||
_a_opacity.start([this] { animationCallback(); }, 1., 0., st::emojiPanDuration);
|
||||
}
|
||||
|
||||
|
@ -291,10 +335,16 @@ void EmojiColorPicker::showAnimated() {
|
|||
}
|
||||
_hiding = false;
|
||||
if (_cache.isNull()) {
|
||||
if (_allLabel) {
|
||||
_allLabel->show();
|
||||
}
|
||||
_cache = Ui::GrabWidget(this);
|
||||
clearSelection();
|
||||
}
|
||||
show();
|
||||
if (_allLabel) {
|
||||
_allLabel->hide();
|
||||
}
|
||||
_a_opacity.start([this] { animationCallback(); }, 0., 1., st::emojiPanDuration);
|
||||
}
|
||||
|
||||
|
@ -304,10 +354,18 @@ void EmojiColorPicker::clearSelection() {
|
|||
_lastMousePos = mapToGlobal(QPoint(-10, -10));
|
||||
}
|
||||
|
||||
int EmojiColorPicker::topColorAllSkip() const {
|
||||
return _allLabel
|
||||
? (st::emojiPanColorAllPadding.top()
|
||||
+ _allLabel->height()
|
||||
+ st::emojiPanColorAllPadding.bottom())
|
||||
: 0;
|
||||
}
|
||||
|
||||
void EmojiColorPicker::updateSelected() {
|
||||
auto newSelected = -1;
|
||||
auto p = mapFromGlobal(_lastMousePos);
|
||||
auto sx = rtl() ? (width() - p.x()) : p.x(), y = p.y() - st::emojiPanMargins.top() - st::emojiColorsPadding;
|
||||
auto sx = rtl() ? (width() - p.x()) : p.x(), y = p.y() - st::emojiPanMargins.top() - topColorAllSkip() - st::emojiColorsPadding;
|
||||
if (y >= 0 && y < _singleSize.height()) {
|
||||
auto x = sx - st::emojiPanMargins.left() - st::emojiColorsPadding;
|
||||
if (x >= 0 && x < _singleSize.width()) {
|
||||
|
@ -327,7 +385,8 @@ void EmojiColorPicker::setSelected(int newSelected) {
|
|||
if (_selected == newSelected) {
|
||||
return;
|
||||
}
|
||||
auto updateSelectedRect = [this] {
|
||||
const auto skip = topColorAllSkip();
|
||||
const auto updateSelectedRect = [&] {
|
||||
if (_selected < 0) return;
|
||||
auto addedSkip = (_selected > 0)
|
||||
? (2 * st::emojiColorsPadding + st::emojiColorsSep)
|
||||
|
@ -338,7 +397,7 @@ void EmojiColorPicker::setSelected(int newSelected) {
|
|||
+ addedSkip;
|
||||
rtlupdate(
|
||||
left,
|
||||
st::emojiPanMargins.top() + st::emojiColorsPadding,
|
||||
st::emojiPanMargins.top() + st::emojiColorsPadding + skip,
|
||||
_singleSize.width(),
|
||||
_singleSize.height());
|
||||
};
|
||||
|
@ -851,6 +910,31 @@ void EmojiListWidget::setSingleSize(QSize size) {
|
|||
_picker->setSingleSize(_singleSize);
|
||||
}
|
||||
|
||||
void EmojiListWidget::setColorAllForceRippled(bool force) {
|
||||
_colorAllRippleForced = force;
|
||||
if (_colorAllRippleForced) {
|
||||
_colorAllRippleForcedLifetime = style::PaletteChanged(
|
||||
) | rpl::filter([=] {
|
||||
return _colorAllRipple != nullptr;
|
||||
}) | rpl::start_with_next([=] {
|
||||
_colorAllRipple->forceRepaint();
|
||||
});
|
||||
if (!_colorAllRipple) {
|
||||
_colorAllRipple = createButtonRipple(int(Section::People));
|
||||
}
|
||||
if (_colorAllRipple->empty()) {
|
||||
_colorAllRipple->addFading();
|
||||
} else {
|
||||
_colorAllRipple->lastUnstop();
|
||||
}
|
||||
} else {
|
||||
if (_colorAllRipple) {
|
||||
_colorAllRipple->lastStop();
|
||||
}
|
||||
_colorAllRippleForcedLifetime.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
int EmojiListWidget::countDesiredHeight(int newWidth) {
|
||||
const auto fullWidth = st().margin.left()
|
||||
+ newWidth
|
||||
|
@ -897,14 +981,9 @@ void EmojiListWidget::ensureLoaded(int section) {
|
|||
_emoji[section] = Ui::Emoji::GetSection(static_cast<Section>(section));
|
||||
_counts[section] = _emoji[section].size();
|
||||
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
const auto &settings = Core::App().settings();
|
||||
for (auto &emoji : _emoji[section]) {
|
||||
if (emoji->hasVariants()) {
|
||||
const auto j = variants.find(emoji->nonColoredId());
|
||||
if (j != end(variants)) {
|
||||
emoji = emoji->variant(j->second);
|
||||
}
|
||||
}
|
||||
emoji = settings.lookupEmojiVariant(emoji);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1366,8 +1445,7 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
|||
if (emoji && emoji->hasVariants()) {
|
||||
_pickerSelected = _selected;
|
||||
setCursor(style::cur_default);
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
if (!variants.contains(emoji->nonColoredId())) {
|
||||
if (!Core::App().settings().hasChosenEmojiVariant(emoji)) {
|
||||
showPicker();
|
||||
} else {
|
||||
_showPickerTimer.callOnce(500);
|
||||
|
@ -1385,12 +1463,11 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
|||
return _picker->handleMouseRelease(QCursor::pos());
|
||||
} else if (const auto over = std::get_if<OverEmoji>(&_pickerSelected)) {
|
||||
const auto emoji = lookupOverEmoji(over);
|
||||
if (emoji && emoji->hasVariants()) {
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
if (variants.contains(emoji->nonColoredId())) {
|
||||
_picker->hideAnimated();
|
||||
_pickerSelected = v::null;
|
||||
}
|
||||
if (emoji
|
||||
&& emoji->hasVariants()
|
||||
&& Core::App().settings().hasChosenEmojiVariant(emoji)) {
|
||||
_picker->hideAnimated();
|
||||
_pickerSelected = v::null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1429,11 +1506,15 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
|||
&& set->section < _staticCount + _custom.size());
|
||||
displaySet(_custom[set->section - _staticCount].id);
|
||||
} else if (auto button = std::get_if<OverButton>(&pressed)) {
|
||||
Assert(button->section >= _staticCount
|
||||
&& button->section < _staticCount + _custom.size());
|
||||
const auto id = _custom[button->section - _staticCount].id;
|
||||
Assert(hasButton(button->section));
|
||||
const auto id = hasColorButton(button->section)
|
||||
? 0
|
||||
: _custom[button->section - _staticCount].id;
|
||||
const auto usage = ChatHelpers::WindowUsage::PremiumPromo;
|
||||
if (hasRemoveButton(button->section)) {
|
||||
if (hasColorButton(button->section)) {
|
||||
_pickerSelected = pressed;
|
||||
showPicker();
|
||||
} else if (hasRemoveButton(button->section)) {
|
||||
removeSet(id);
|
||||
} else if (hasAddButton(button->section)) {
|
||||
_localSetsManager->install(id);
|
||||
|
@ -1496,23 +1577,35 @@ void EmojiListWidget::showPicker() {
|
|||
if (v::is_null(_pickerSelected)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||
const auto emoji = lookupOverEmoji(over);
|
||||
if (emoji && emoji->hasVariants()) {
|
||||
_picker->showEmoji(emoji);
|
||||
|
||||
auto y = emojiRect(over->section, over->index).y();
|
||||
const auto showAt = [&](float64 xCoef, int y, int height) {
|
||||
y -= _picker->height() - st::emojiPanRadius + getVisibleTop();
|
||||
if (y < st().header) {
|
||||
y += _picker->height() - st::emojiPanRadius + _singleSize.height() - st::emojiPanRadius;
|
||||
y += _picker->height() + height;
|
||||
}
|
||||
auto xmax = width() - _picker->width();
|
||||
auto coef = float64(over->index % _columnCount) / float64(_columnCount - 1);
|
||||
if (rtl()) coef = 1. - coef;
|
||||
_picker->move(qRound(xmax * coef), y);
|
||||
if (rtl()) xCoef = 1. - xCoef;
|
||||
_picker->move(qRound(xmax * xCoef), y);
|
||||
|
||||
disableScroll(true);
|
||||
};
|
||||
if (const auto button = std::get_if<OverButton>(&_pickerSelected)) {
|
||||
const auto hand = QString::fromUtf8("\xF0\x9F\x91\x8B");
|
||||
const auto emoji = Ui::Emoji::Find(hand);
|
||||
Assert(emoji != nullptr && emoji->hasVariants());
|
||||
_picker->showEmoji(emoji, true);
|
||||
setColorAllForceRippled(true);
|
||||
const auto rect = buttonRect(button->section);
|
||||
showAt(1., rect.y(), rect.height() - 2 * st::emojiPanRadius);
|
||||
} else if (const auto over = std::get_if<OverEmoji>(&_pickerSelected)) {
|
||||
const auto emoji = lookupOverEmoji(over);
|
||||
if (emoji && emoji->hasVariants()) {
|
||||
_picker->showEmoji(emoji);
|
||||
|
||||
const auto coef = float64(over->index % _columnCount)
|
||||
/ float64(_columnCount - 1);
|
||||
const auto h = _singleSize.height() - 2 * st::emojiPanRadius;
|
||||
showAt(coef, emojiRect(over->section, over->index).y(), h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1520,11 +1613,34 @@ void EmojiListWidget::pickerHidden() {
|
|||
_pickerSelected = v::null;
|
||||
update();
|
||||
disableScroll(false);
|
||||
setColorAllForceRippled(false);
|
||||
|
||||
_lastMousePos = QCursor::pos();
|
||||
updateSelected();
|
||||
}
|
||||
|
||||
bool EmojiListWidget::hasColorButton(int index) const {
|
||||
return (_staticCount > int(Section::People))
|
||||
&& (index == int(Section::People));
|
||||
}
|
||||
|
||||
QRect EmojiListWidget::colorButtonRect(int index) const {
|
||||
return colorButtonRect(sectionInfo(index));
|
||||
}
|
||||
|
||||
QRect EmojiListWidget::colorButtonRect(const SectionInfo &info) const {
|
||||
if (_mode != Mode::Full) {
|
||||
return QRect();
|
||||
}
|
||||
const auto &colorSt = st().colorAll;
|
||||
const auto buttonw = colorSt.rippleAreaPosition.x()
|
||||
+ colorSt.rippleAreaSize;
|
||||
const auto buttonh = colorSt.height;
|
||||
const auto buttonx = emojiRight() - st::emojiPanColorAllSkip - buttonw;
|
||||
const auto buttony = info.top + st::emojiPanRemoveTop;
|
||||
return QRect(buttonx, buttony, buttonw, buttonh);
|
||||
}
|
||||
|
||||
bool EmojiListWidget::hasRemoveButton(int index) const {
|
||||
if (index < _staticCount
|
||||
|| index >= _staticCount + _custom.size()) {
|
||||
|
@ -1581,15 +1697,18 @@ QRect EmojiListWidget::unlockButtonRect(int index) const {
|
|||
}
|
||||
|
||||
bool EmojiListWidget::hasButton(int index) const {
|
||||
if (index < _staticCount
|
||||
|| index >= _staticCount + _custom.size()) {
|
||||
return false;
|
||||
if (hasColorButton(index)
|
||||
|| (index >= _staticCount
|
||||
&& index < _staticCount + _custom.size())) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
QRect EmojiListWidget::buttonRect(int index) const {
|
||||
return hasRemoveButton(index)
|
||||
return hasColorButton(index)
|
||||
? colorButtonRect(index)
|
||||
: hasRemoveButton(index)
|
||||
? removeButtonRect(index)
|
||||
: hasAddButton(index)
|
||||
? addButtonRect(index)
|
||||
|
@ -1637,19 +1756,33 @@ QRect EmojiListWidget::emojiRect(int section, int index) const {
|
|||
}
|
||||
|
||||
void EmojiListWidget::colorChosen(EmojiChosen data) {
|
||||
Expects(data.emoji != nullptr && data.emoji->hasVariants());
|
||||
|
||||
const auto emoji = data.emoji;
|
||||
if (emoji->hasVariants()) {
|
||||
Core::App().settings().saveEmojiVariant(emoji);
|
||||
auto &settings = Core::App().settings();
|
||||
if (const auto button = std::get_if<OverButton>(&_pickerSelected)) {
|
||||
settings.saveAllEmojiVariants(emoji);
|
||||
for (auto section = int(Section::People)
|
||||
; section < _staticCount
|
||||
; ++section) {
|
||||
for (auto &emoji : _emoji[section]) {
|
||||
emoji = settings.lookupEmojiVariant(emoji);
|
||||
}
|
||||
}
|
||||
update();
|
||||
} else {
|
||||
settings.saveEmojiVariant(emoji);
|
||||
|
||||
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||
if (over
|
||||
&& over->section > int(Section::Recent)
|
||||
&& over->section < _staticCount
|
||||
&& over->index < _emoji[over->section].size()) {
|
||||
_emoji[over->section][over->index] = emoji;
|
||||
rtlupdate(emojiRect(over->section, over->index));
|
||||
}
|
||||
selectEmoji(data);
|
||||
}
|
||||
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||
if (over
|
||||
&& over->section > int(Section::Recent)
|
||||
&& over->section < _staticCount
|
||||
&& over->index < _emoji[over->section].size()) {
|
||||
_emoji[over->section][over->index] = emoji;
|
||||
rtlupdate(emojiRect(over->section, over->index));
|
||||
}
|
||||
selectEmoji(data);
|
||||
_picker->hideAnimated();
|
||||
}
|
||||
|
||||
|
@ -1967,47 +2100,54 @@ int EmojiListWidget::paintButtonGetWidth(
|
|||
const SectionInfo &info,
|
||||
bool selected,
|
||||
QRect clip) const {
|
||||
if (info.section < _staticCount
|
||||
|| info.section >= _staticCount + _custom.size()) {
|
||||
if (!hasButton(info.section)) {
|
||||
return 0;
|
||||
}
|
||||
auto &custom = _custom[info.section - _staticCount];
|
||||
if (hasRemoveButton(info.section)) {
|
||||
const auto remove = removeButtonRect(info);
|
||||
if (remove.isEmpty()) {
|
||||
auto &ripple = (info.section >= _staticCount)
|
||||
? _custom[info.section - _staticCount].ripple
|
||||
: _colorAllRipple;
|
||||
const auto colorAll = hasColorButton(info.section);
|
||||
if (colorAll || hasRemoveButton(info.section)) {
|
||||
const auto rect = colorAll
|
||||
? colorButtonRect(info)
|
||||
: removeButtonRect(info);
|
||||
if (rect.isEmpty()) {
|
||||
return 0;
|
||||
} else if (remove.intersects(clip)) {
|
||||
const auto &removeSt = st().removeSet;
|
||||
if (custom.ripple) {
|
||||
custom.ripple->paint(
|
||||
} else if (rect.intersects(clip)) {
|
||||
const auto &bst = colorAll ? st().colorAll : st().removeSet;
|
||||
if (colorAll && _colorAllRippleForced) {
|
||||
selected = true;
|
||||
}
|
||||
if (ripple) {
|
||||
ripple->paint(
|
||||
p,
|
||||
remove.x() + removeSt.rippleAreaPosition.x(),
|
||||
remove.y() + removeSt.rippleAreaPosition.y(),
|
||||
rect.x() + bst.rippleAreaPosition.x(),
|
||||
rect.y() + bst.rippleAreaPosition.y(),
|
||||
width());
|
||||
if (custom.ripple->empty()) {
|
||||
custom.ripple.reset();
|
||||
if (ripple->empty()) {
|
||||
ripple.reset();
|
||||
}
|
||||
}
|
||||
const auto &icon = selected ? removeSt.iconOver : removeSt.icon;
|
||||
const auto &icon = selected ? bst.iconOver : bst.icon;
|
||||
icon.paint(
|
||||
p,
|
||||
(remove.topLeft()
|
||||
(rect.topLeft()
|
||||
+ QPoint(
|
||||
remove.width() - icon.width(),
|
||||
remove.height() - icon.height()) / 2),
|
||||
rect.width() - icon.width(),
|
||||
rect.height() - icon.height()) / 2),
|
||||
width());
|
||||
}
|
||||
return emojiRight() - remove.x();
|
||||
return emojiRight() - rect.x();
|
||||
}
|
||||
const auto canAdd = hasAddButton(info.section);
|
||||
const auto &button = rightButton(info.section);
|
||||
const auto rect = buttonRect(info, button);
|
||||
p.drawImage(rect.topLeft(), selected ? button.backOver : button.back);
|
||||
if (custom.ripple) {
|
||||
const auto ripple = QColor(0, 0, 0, 36);
|
||||
custom.ripple->paint(p, rect.x(), rect.y(), width(), &ripple);
|
||||
if (custom.ripple->empty()) {
|
||||
custom.ripple.reset();
|
||||
if (ripple) {
|
||||
const auto color = QColor(0, 0, 0, 36);
|
||||
ripple->paint(p, rect.x(), rect.y(), width(), &color);
|
||||
if (ripple->empty()) {
|
||||
ripple.reset();
|
||||
}
|
||||
}
|
||||
p.setPen(!canAdd
|
||||
|
@ -2108,22 +2248,28 @@ void EmojiListWidget::setSelected(OverState newSelected) {
|
|||
|
||||
void EmojiListWidget::setPressed(OverState newPressed) {
|
||||
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||
Assert(button->section >= _staticCount
|
||||
&& button->section < _staticCount + _custom.size());
|
||||
auto &set = _custom[button->section - _staticCount];
|
||||
if (set.ripple) {
|
||||
set.ripple->lastStop();
|
||||
Assert(hasColorButton(button->section)
|
||||
|| (button->section >= _staticCount
|
||||
&& button->section < _staticCount + _custom.size()));
|
||||
auto &ripple = (button->section >= _staticCount)
|
||||
? _custom[button->section - _staticCount].ripple
|
||||
: _colorAllRipple;
|
||||
if (ripple) {
|
||||
ripple->lastStop();
|
||||
}
|
||||
}
|
||||
_pressed = newPressed;
|
||||
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||
Assert(button->section >= _staticCount
|
||||
&& button->section < _staticCount + _custom.size());
|
||||
auto &set = _custom[button->section - _staticCount];
|
||||
if (!set.ripple) {
|
||||
set.ripple = createButtonRipple(button->section);
|
||||
Assert(hasColorButton(button->section)
|
||||
|| (button->section >= _staticCount
|
||||
&& button->section < _staticCount + _custom.size()));
|
||||
auto &ripple = (button->section >= _staticCount)
|
||||
? _custom[button->section - _staticCount].ripple
|
||||
: _colorAllRipple;
|
||||
if (!ripple) {
|
||||
ripple = createButtonRipple(button->section);
|
||||
}
|
||||
set.ripple->add(mapFromGlobal(QCursor::pos()) - buttonRippleTopLeft(button->section));
|
||||
ripple->add(mapFromGlobal(QCursor::pos()) - buttonRippleTopLeft(button->section));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2167,16 +2313,18 @@ void EmojiListWidget::initButton(
|
|||
|
||||
std::unique_ptr<Ui::RippleAnimation> EmojiListWidget::createButtonRipple(
|
||||
int section) {
|
||||
Expects(section >= _staticCount
|
||||
&& section < _staticCount + _custom.size());
|
||||
Expects(hasButton(section));
|
||||
|
||||
const auto colorAll = hasColorButton(section);
|
||||
const auto remove = hasRemoveButton(section);
|
||||
const auto &removeSt = st().removeSet;
|
||||
const auto &st = remove ? removeSt.ripple : st::emojiPanButton.ripple;
|
||||
auto mask = remove
|
||||
const auto &staticSt = colorAll ? st().colorAll : st().removeSet;
|
||||
const auto &st = (colorAll || remove)
|
||||
? staticSt.ripple
|
||||
: st::emojiPanButton.ripple;
|
||||
auto mask = (colorAll || remove)
|
||||
? Ui::RippleAnimation::EllipseMask(QSize(
|
||||
removeSt.rippleAreaSize,
|
||||
removeSt.rippleAreaSize))
|
||||
staticSt.rippleAreaSize,
|
||||
staticSt.rippleAreaSize))
|
||||
: rightButton(section).rippleMask;
|
||||
return std::make_unique<Ui::RippleAnimation>(
|
||||
st,
|
||||
|
@ -2185,11 +2333,12 @@ std::unique_ptr<Ui::RippleAnimation> EmojiListWidget::createButtonRipple(
|
|||
}
|
||||
|
||||
QPoint EmojiListWidget::buttonRippleTopLeft(int section) const {
|
||||
Expects(section >= _staticCount
|
||||
&& section < _staticCount + _custom.size());
|
||||
Expects(hasButton(section));
|
||||
|
||||
return myrtlrect(buttonRect(section)).topLeft()
|
||||
+ (hasRemoveButton(section)
|
||||
+ (hasColorButton(section)
|
||||
? st().colorAll.rippleAreaPosition
|
||||
: hasRemoveButton(section)
|
||||
? st().removeSet.rippleAreaPosition
|
||||
: QPoint());
|
||||
}
|
||||
|
|
|
@ -247,6 +247,7 @@ private:
|
|||
[[nodiscard]] SectionInfo sectionInfoByOffset(int yOffset) const;
|
||||
[[nodiscard]] int sectionsCount() const;
|
||||
void setSingleSize(QSize size);
|
||||
void setColorAllForceRippled(bool force);
|
||||
|
||||
void showPicker();
|
||||
void pickerHidden();
|
||||
|
@ -297,6 +298,9 @@ private:
|
|||
int set,
|
||||
int index);
|
||||
void validateEmojiPaintContext(const ExpandingContext &context);
|
||||
[[nodiscard]] bool hasColorButton(int index) const;
|
||||
[[nodiscard]] QRect colorButtonRect(int index) const;
|
||||
[[nodiscard]] QRect colorButtonRect(const SectionInfo &info) const;
|
||||
[[nodiscard]] bool hasRemoveButton(int index) const;
|
||||
[[nodiscard]] QRect removeButtonRect(int index) const;
|
||||
[[nodiscard]] QRect removeButtonRect(const SectionInfo &info) const;
|
||||
|
@ -378,6 +382,10 @@ private:
|
|||
Ui::RoundRect _overBg;
|
||||
QImage _searchExpandCache;
|
||||
|
||||
mutable std::unique_ptr<Ui::RippleAnimation> _colorAllRipple;
|
||||
bool _colorAllRippleForced = false;
|
||||
rpl::lifetime _colorAllRippleForcedLifetime;
|
||||
|
||||
std::vector<QString> _nextSearchQuery;
|
||||
std::vector<QString> _searchQuery;
|
||||
base::flat_set<EmojiPtr> _searchEmoji;
|
||||
|
|
|
@ -1076,11 +1076,40 @@ void Settings::setLegacyRecentEmojiPreload(
|
|||
}
|
||||
}
|
||||
|
||||
EmojiPtr Settings::lookupEmojiVariant(EmojiPtr emoji) const {
|
||||
if (emoji->hasVariants()) {
|
||||
const auto i = _emojiVariants.find(emoji->nonColoredId());
|
||||
if (i != end(_emojiVariants)) {
|
||||
return emoji->variant(i->second);
|
||||
}
|
||||
const auto j = _emojiVariants.find(QString());
|
||||
if (j != end(_emojiVariants)) {
|
||||
return emoji->variant(j->second);
|
||||
}
|
||||
}
|
||||
return emoji;
|
||||
}
|
||||
|
||||
bool Settings::hasChosenEmojiVariant(EmojiPtr emoji) const {
|
||||
return _emojiVariants.contains(QString())
|
||||
|| _emojiVariants.contains(emoji->nonColoredId());
|
||||
}
|
||||
|
||||
void Settings::saveEmojiVariant(EmojiPtr emoji) {
|
||||
Expects(emoji->hasVariants());
|
||||
|
||||
_emojiVariants[emoji->nonColoredId()] = emoji->variantIndex(emoji);
|
||||
_saveDelayed.fire({});
|
||||
}
|
||||
|
||||
void Settings::saveAllEmojiVariants(EmojiPtr emoji) {
|
||||
Expects(emoji->hasVariants());
|
||||
|
||||
_emojiVariants.clear();
|
||||
_emojiVariants[QString()] = emoji->variantIndex(emoji);
|
||||
_saveDelayed.fire({});
|
||||
}
|
||||
|
||||
void Settings::setLegacyEmojiVariants(QMap<QString, int> data) {
|
||||
if (!_emojiVariants.empty() || data.isEmpty()) {
|
||||
return;
|
||||
|
|
|
@ -668,7 +668,10 @@ public:
|
|||
[[nodiscard]] const base::flat_map<QString, uint8> &emojiVariants() const {
|
||||
return _emojiVariants;
|
||||
}
|
||||
[[nodiscard]] EmojiPtr lookupEmojiVariant(EmojiPtr emoji) const;
|
||||
[[nodiscard]] bool hasChosenEmojiVariant(EmojiPtr emoji) const;
|
||||
void saveEmojiVariant(EmojiPtr emoji);
|
||||
void saveAllEmojiVariants(EmojiPtr emoji);
|
||||
void setLegacyEmojiVariants(QMap<QString, int> data);
|
||||
|
||||
[[nodiscard]] bool disableOpenGL() const {
|
||||
|
|
|
@ -282,15 +282,10 @@ rpl::producer<> UiIntegration::forcePopupMenuHideRequests() {
|
|||
|
||||
const Ui::Emoji::One *UiIntegration::defaultEmojiVariant(
|
||||
const Ui::Emoji::One *emoji) {
|
||||
if (!emoji || !emoji->hasVariants()) {
|
||||
if (!emoji) {
|
||||
return emoji;
|
||||
}
|
||||
const auto nonColored = emoji->nonColoredId();
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
const auto i = variants.find(nonColored);
|
||||
const auto result = (i != end(variants))
|
||||
? emoji->variant(i->second)
|
||||
: emoji;
|
||||
const auto result = Core::App().settings().lookupEmojiVariant(emoji);
|
||||
Core::App().settings().incrementRecentEmoji({ result });
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -479,6 +479,14 @@ storiesRemoveSet: IconButton(stickerPanRemoveSet) {
|
|||
iconOver: icon {{ "simple_close", storiesComposeGrayIcon }};
|
||||
ripple: storiesComposeRippleLight;
|
||||
}
|
||||
storiesColorAll: IconButton(emojiPanColorAll) {
|
||||
icon: icon {{ "emoji/emoji_skin", storiesComposeGrayIcon }};
|
||||
iconOver: icon {{ "emoji/emoji_skin", storiesComposeGrayIcon }};
|
||||
ripple: storiesComposeRippleLight;
|
||||
}
|
||||
storiesColorAllLabel: FlatLabel(emojiPanColorAllLabel) {
|
||||
textFg: storiesComposeGrayText;
|
||||
}
|
||||
storiesMenuSeparator: mediaviewMenuSeparator;
|
||||
storiesMenu: Menu(defaultMenu) {
|
||||
itemBg: groupCallMenuBg;
|
||||
|
@ -588,6 +596,8 @@ storiesEmojiPan: EmojiPan(defaultEmojiPan) {
|
|||
rippleBgActive: storiesComposeBgOver;
|
||||
}
|
||||
search: storiesEmojiTabbedSearch;
|
||||
colorAll: storiesColorAll;
|
||||
colorAllLabel: storiesColorAllLabel;
|
||||
removeSet: storiesRemoveSet;
|
||||
boxLabel: storiesBoxLabel;
|
||||
icons: ComposeIcons {
|
||||
|
|
Loading…
Add table
Reference in a new issue