Added new-emoji button with menu to emoji set boxes.

This commit is contained in:
23rd
2026-06-24 12:01:35 +03:00
parent 6241d23fc6
commit 103c256d10
7 changed files with 161 additions and 55 deletions
+2
View File
@@ -4601,6 +4601,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stickers_create_new" = "Create a New Sticker";
"lng_stickers_add_existing" = "Add an Existing Sticker";
"lng_emoji_create_new" = "Create a New Emoji";
"lng_emoji_add_existing" = "Add an Existing Emoji";
"lng_stickers_add_to_set" = "Add to Sticker Set";
"lng_stickers_already_in_set" = "This Sticker is already in the Set.";
"lng_stickers_set_is_full" = "This Sticker Set is full.";
+151 -55
View File
@@ -402,6 +402,11 @@ private:
void showAddMenu(QPoint globalPos);
void startAddExistingStickerFlow();
void startCreateNewStickerFlow();
void startAddExistingEmojiFlow();
void startCreateNewEmojiFlow();
[[nodiscard]] ChatHelpers::TabbedPanel *createPickerPanel(
ChatHelpers::TabbedSelector::Mode mode,
uint64 excludeSetId);
void installDone(const MTPmessages_StickerSetInstallResult &result);
@@ -2426,11 +2431,16 @@ void StickerSetBox::Inner::repaintItems(crl::time now) {
}
bool StickerSetBox::Inner::hasAddCell() const {
return _loaded
&& _amSetCreator
&& (setType() == Data::StickersType::Stickers)
&& !_pack.isEmpty()
&& (_pack.size() < Api::kStickersInOwnedSetMax);
if (!_loaded || !_amSetCreator || _pack.isEmpty()) {
return false;
}
const auto type = setType();
if (type == Data::StickersType::Emoji) {
return (_pack.size() < Api::kEmojiInOwnedSetMax);
} else if (type == Data::StickersType::Stickers) {
return (_pack.size() < Api::kStickersInOwnedSetMax);
}
return false;
}
int StickerSetBox::Inner::totalCellsCount() const {
@@ -2470,11 +2480,15 @@ void StickerSetBox::Inner::paintAddCell(QPainter &p) const {
ltrRect.height())
: ltrRect;
const auto center = rect::center(rect);
const auto bgRadius = isEmojiSet()
? st::emojiSetAddCellBgRadius
: st::stickersAddCellBgRadius;
const auto plusSize = isEmojiSet()
? st::emojiSetAddCellPlusSize
: st::stickersAddCellPlusSize;
const auto inner = QRect(
center - QPoint(
st::stickersAddCellBgRadius,
st::stickersAddCellBgRadius),
Size(st::stickersAddCellBgRadius * 2));
center - QPoint(bgRadius, bgRadius),
Size(bgRadius * 2));
auto hq = PainterHighQualityEnabler(p);
const auto base = st::windowSubTextFg->c;
@@ -2485,7 +2499,7 @@ void StickerSetBox::Inner::paintAddCell(QPainter &p) const {
p.setBrush(anim::with_alpha(base, bgAlpha));
p.drawEllipse(inner);
const auto plusHalf = st::stickersAddCellPlusSize / 2;
const auto plusHalf = plusSize / 2;
const auto thickness = st::stickersAddCellPlusThickness;
const auto plusH = QRectF(
center.x() - plusHalf,
@@ -2510,14 +2524,25 @@ void StickerSetBox::Inner::showAddMenu(QPoint globalPos) {
_menu = base::make_unique_q<Ui::PopupMenu>(
this,
st::popupMenuWithIcons);
_menu->addAction(
tr::lng_stickers_create_new(tr::now),
crl::guard(this, [=] { startCreateNewStickerFlow(); }),
&st::menuIconStickerCreate);
_menu->addAction(
tr::lng_stickers_add_existing(tr::now),
crl::guard(this, [=] { startAddExistingStickerFlow(); }),
&st::menuIconStickerAdd);
if (setType() == Data::StickersType::Emoji) {
_menu->addAction(
tr::lng_emoji_create_new(tr::now),
crl::guard(this, [=] { startCreateNewEmojiFlow(); }),
&st::menuIconStickerCreate);
_menu->addAction(
tr::lng_emoji_add_existing(tr::now),
crl::guard(this, [=] { startAddExistingEmojiFlow(); }),
&st::menuIconEmoji);
} else {
_menu->addAction(
tr::lng_stickers_create_new(tr::now),
crl::guard(this, [=] { startCreateNewStickerFlow(); }),
&st::menuIconStickerCreate);
_menu->addAction(
tr::lng_stickers_add_existing(tr::now),
crl::guard(this, [=] { startAddExistingStickerFlow(); }),
&st::menuIconStickerAdd);
}
_menu->popup(globalPos);
}
@@ -2525,19 +2550,13 @@ void StickerSetBox::Inner::setOuterContainer(QPointer<QWidget> container) {
_outerContainer = std::move(container);
}
void StickerSetBox::Inner::startAddExistingStickerFlow() {
if (!hasAddCell() || !_outerContainer) {
return;
ChatHelpers::TabbedPanel *StickerSetBox::Inner::createPickerPanel(
ChatHelpers::TabbedSelector::Mode mode,
uint64 excludeSetId) {
if (!_outerContainer) {
return nullptr;
}
const auto container = _outerContainer.data();
const auto identifier = StickerSetIdentifier{
.id = _setId,
.accessHash = _setAccessHash,
.shortName = _setShortName,
};
const auto session = _session;
const auto show = _show;
using Selector = ChatHelpers::TabbedSelector;
_pickerPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
container,
@@ -2548,8 +2567,8 @@ void StickerSetBox::Inner::startAddExistingStickerFlow() {
.show = _show,
.st = st::defaultComposeControls.tabbed,
.level = Window::GifPauseReason::Layer,
.mode = Selector::Mode::StickersOnly,
.excludeStickerSetId = _setId,
.mode = mode,
.excludeStickerSetId = excludeSetId,
}),
});
const auto panel = _pickerPanel.get();
@@ -2561,30 +2580,6 @@ void StickerSetBox::Inner::startAddExistingStickerFlow() {
panel->setShowAnimationOrigin(Ui::PanelAnimation::Origin::TopLeft);
panel->hide();
panel->selector()->fileChosen(
) | rpl::on_next([=, this](const ChatHelpers::FileChosen &chosen) {
const auto document = chosen.document;
if (_pickerPanel) {
_pickerPanel->hideAnimated();
}
const auto emoji = Api::StickerEmojiOrDefault(document);
Api::AddExistingStickerToSet(
session,
identifier,
document,
emoji,
crl::guard(this, [=, this](MTPmessages_StickerSet result) {
applySet(result);
show->showToast(
tr::lng_stickers_create_added(tr::now));
}),
crl::guard(this, [=](QString err) {
show->showToast(err.isEmpty()
? tr::lng_attach_failed(tr::now)
: err);
}));
}, panel->lifetime());
const auto reposition = [=] {
const auto size = container->size();
const auto margins = st::emojiPanMargins;
@@ -2607,6 +2602,91 @@ void StickerSetBox::Inner::startAddExistingStickerFlow() {
return base::EventFilterResult::Continue;
});
reposition();
return panel;
}
void StickerSetBox::Inner::startAddExistingStickerFlow() {
if (!hasAddCell()) {
return;
}
const auto panel = createPickerPanel(
ChatHelpers::TabbedSelector::Mode::StickersOnly,
_setId);
if (!panel) {
return;
}
const auto identifier = StickerSetIdentifier{
.id = _setId,
.accessHash = _setAccessHash,
.shortName = _setShortName,
};
const auto session = _session;
const auto show = _show;
panel->selector()->fileChosen(
) | rpl::on_next([=, this](const ChatHelpers::FileChosen &chosen) {
const auto document = chosen.document;
if (_pickerPanel) {
_pickerPanel->hideAnimated();
}
const auto emoji = Api::StickerEmojiOrDefault(document);
Api::AddExistingStickerToSet(
session,
identifier,
document,
emoji,
crl::guard(this, [=, this](MTPmessages_StickerSet result) {
applySet(result);
show->showToast(
tr::lng_stickers_create_added(tr::now));
}),
crl::guard(this, [=](QString err) {
show->showToast(err.isEmpty()
? tr::lng_attach_failed(tr::now)
: err);
}));
}, panel->lifetime());
panel->showAnimated();
}
void StickerSetBox::Inner::startAddExistingEmojiFlow() {
if (!hasAddCell()) {
return;
}
const auto panel = createPickerPanel(
ChatHelpers::TabbedSelector::Mode::CustomEmojiOnly,
0);
if (!panel) {
return;
}
const auto identifier = StickerSetIdentifier{
.id = _setId,
.accessHash = _setAccessHash,
.shortName = _setShortName,
};
const auto session = _session;
const auto show = _show;
panel->selector()->customEmojiChosen(
) | rpl::on_next([=, this](const ChatHelpers::FileChosen &chosen) {
const auto document = chosen.document;
if (_pickerPanel) {
_pickerPanel->hideAnimated();
}
const auto emoji = Api::StickerEmojiOrDefault(document);
Api::AddExistingStickerToSet(
session,
identifier,
document,
emoji,
crl::guard(this, [=, this](MTPmessages_StickerSet result) {
applySet(result);
show->showToast(tr::lng_emoji_added(tr::now));
}),
crl::guard(this, [=](QString err) {
show->showToast(err.isEmpty()
? tr::lng_attach_failed(tr::now)
: err);
}));
}, panel->lifetime());
panel->showAnimated();
}
@@ -2626,4 +2706,20 @@ void StickerSetBox::Inner::startCreateNewStickerFlow() {
Api::OpenCreateStickerFlow(_show, identifier, onDone);
}
void StickerSetBox::Inner::startCreateNewEmojiFlow() {
if (!hasAddCell()) {
return;
}
const auto identifier = StickerSetIdentifier{
.id = _setId,
.accessHash = _setAccessHash,
.shortName = _setShortName,
};
const auto onDone = crl::guard(this, [=, this](
MTPmessages_StickerSet result) {
applySet(result);
});
Api::OpenCreateEmojiFlow(_show, identifier, onDone);
}
StickerSetBox::Inner::~Inner() = default;
@@ -444,6 +444,8 @@ stickersRowDuration: 200;
stickersAddCellPlusSize: 22px;
stickersAddCellPlusThickness: 2px;
stickersAddCellBgRadius: 28px;
emojiSetAddCellPlusSize: 13px;
emojiSetAddCellBgRadius: 16px;
stickersEmojiPickerExpandedRadius: 20px;
stickersEmojiPickerBg: emojiPanBg;
@@ -519,6 +519,7 @@ EmojiListWidget::EmojiListWidget(
if (_mode != Mode::RecentReactions
&& _mode != Mode::BackgroundEmoji
&& _mode != Mode::ChannelStatus
&& _mode != Mode::CustomOnly
&& !_onlyUnicodeEmoji) {
setupSearch();
}
@@ -2896,6 +2897,7 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
switch (_mode) {
case Mode::Full:
case Mode::UserpicBuilder:
case Mode::CustomOnly:
Settings::ShowPremium(resolved, u"animated_emoji"_q);
break;
case Mode::FullReactions:
@@ -85,6 +85,7 @@ enum class EmojiListMode {
BackgroundEmoji,
PeerTitle,
MessageEffects,
CustomOnly,
};
[[nodiscard]] std::vector<EmojiStatusId> DocumentListToRecent(
@@ -625,6 +625,8 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) {
? EmojiMode::FullReactions
: _mode == Mode::RecentReactions
? EmojiMode::RecentReactions
: _mode == Mode::CustomEmojiOnly
? EmojiMode::CustomOnly
: _mode == Mode::PeerTitle
? EmojiMode::PeerTitle
: EmojiMode::Full),
@@ -83,6 +83,7 @@ using InlineChosen = InlineBots::ResultSelected;
enum class TabbedSelectorMode {
Full,
EmojiOnly,
CustomEmojiOnly,
StickersOnly,
MediaEditor,
EmojiStatus,