Added adapting existing sticker into custom emoji.

This commit is contained in:
23rd
2026-06-24 12:08:57 +03:00
parent 103c256d10
commit 9895e5bb89
4 changed files with 128 additions and 0 deletions

View File

@@ -4603,6 +4603,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"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_emoji_adapt_sticker" = "Adapt from a Sticker";
"lng_emoji_adapt_no_video" = "Video stickers are not supported yet.";
"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.";

View File

@@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/compose/compose_show.h"
#include "chat_helpers/emoji_picker_overlay.h"
#include "core/file_utilities.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "editor/editor_layer_widget.h"
#include "editor/photo_editor.h"
#include "editor/photo_editor_common.h"
@@ -242,6 +244,35 @@ void OpenPhotoEditorForImage(
return bytes;
}
void LoadStickerImage(
std::shared_ptr<ChatHelpers::Show> show,
not_null<DocumentData*> document,
Fn<void(QImage)> done) {
struct State {
std::shared_ptr<Data::DocumentMedia> media;
rpl::lifetime lifetime;
};
const auto state = std::make_shared<State>();
state->media = document->createMediaView();
state->media->checkStickerLarge();
const auto finish = [=] {
const auto large = state->media->getStickerLarge();
auto image = large ? large->original() : QImage();
state->lifetime.destroy();
done(std::move(image));
};
if (state->media->loaded()) {
finish();
return;
}
show->session().downloaderTaskFinished(
) | rpl::filter([=] {
return state->media->loaded();
}) | rpl::on_next([=] {
finish();
}, state->lifetime);
}
} // namespace
namespace Api {
@@ -487,4 +518,54 @@ void OpenCreateEmojiFlow(
std::move(done));
}
bool AdaptStickerToEmoji(
std::shared_ptr<ChatHelpers::Show> show,
StickerSetIdentifier set,
not_null<DocumentData*> document,
Fn<void(MTPmessages_StickerSet)> done) {
const auto sticker = document->sticker();
if (!sticker || sticker->isWebm()) {
show->showToast(tr::lng_emoji_adapt_no_video(tr::now));
return false;
}
if (sticker->isLottie()) {
const auto emoji = StickerEmojiOrDefault(document);
AddExistingStickerToSet(
&show->session(),
set,
document,
emoji,
[=](MTPmessages_StickerSet result) {
show->showToast(tr::lng_emoji_added(tr::now));
if (done) {
done(result);
}
},
[=](QString err) {
show->showToast(err.isEmpty()
? tr::lng_attach_failed(tr::now)
: err);
});
return true;
}
LoadStickerImage(
show,
document,
[=, set = std::move(set), done = std::move(done)](
QImage image) mutable {
if (image.isNull()) {
show->showToast(
tr::lng_stickers_create_open_failed(tr::now));
return;
}
RunImageEditorAndCreate(
show,
std::move(set),
std::move(image),
Data::StickersType::Emoji,
std::move(done));
});
return true;
}
} // namespace Api

View File

@@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/stickers/data_stickers.h"
class DocumentData;
namespace ChatHelpers {
class Show;
} // namespace ChatHelpers
@@ -29,4 +31,10 @@ void OpenCreateEmojiFlow(
StickerSetIdentifier set,
Fn<void(MTPmessages_StickerSet)> done = nullptr);
[[nodiscard]] bool AdaptStickerToEmoji(
std::shared_ptr<ChatHelpers::Show> show,
StickerSetIdentifier set,
not_null<DocumentData*> document,
Fn<void(MTPmessages_StickerSet)> done = nullptr);
} // namespace Api

View File

@@ -404,6 +404,7 @@ private:
void startCreateNewStickerFlow();
void startAddExistingEmojiFlow();
void startCreateNewEmojiFlow();
void startAdaptStickerToEmojiFlow();
[[nodiscard]] ChatHelpers::TabbedPanel *createPickerPanel(
ChatHelpers::TabbedSelector::Mode mode,
uint64 excludeSetId);
@@ -2533,6 +2534,10 @@ void StickerSetBox::Inner::showAddMenu(QPoint globalPos) {
tr::lng_emoji_add_existing(tr::now),
crl::guard(this, [=] { startAddExistingEmojiFlow(); }),
&st::menuIconEmoji);
_menu->addAction(
tr::lng_emoji_adapt_sticker(tr::now),
crl::guard(this, [=] { startAdaptStickerToEmojiFlow(); }),
&st::menuIconStickerAdd);
} else {
_menu->addAction(
tr::lng_stickers_create_new(tr::now),
@@ -2722,4 +2727,36 @@ void StickerSetBox::Inner::startCreateNewEmojiFlow() {
Api::OpenCreateEmojiFlow(_show, identifier, onDone);
}
void StickerSetBox::Inner::startAdaptStickerToEmojiFlow() {
if (!hasAddCell()) {
return;
}
const auto panel = createPickerPanel(
ChatHelpers::TabbedSelector::Mode::StickersOnly,
0);
if (!panel) {
return;
}
const auto identifier = StickerSetIdentifier{
.id = _setId,
.accessHash = _setAccessHash,
.shortName = _setShortName,
};
const auto show = _show;
panel->selector()->fileChosen(
) | rpl::on_next([=, this](const ChatHelpers::FileChosen &chosen) {
const auto accepted = Api::AdaptStickerToEmoji(
show,
identifier,
chosen.document,
crl::guard(this, [=, this](MTPmessages_StickerSet result) {
applySet(result);
}));
if (accepted && _pickerPanel) {
_pickerPanel->hideAnimated();
}
}, panel->lifetime());
panel->showAnimated();
}
StickerSetBox::Inner::~Inner() = default;