diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 2bcb2a3b06..cef13cf059 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4517,6 +4517,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "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."; +"lng_emoji_add_to_set" = "Add to Emoji Set"; +"lng_emoji_already_in_set" = "This Emoji is already in the Set."; +"lng_emoji_set_is_full" = "This Emoji Set is full."; +"lng_emoji_added" = "Emoji added."; "lng_stickers_pack_choose_emoji_title" = "Choose Emoji"; "lng_stickers_pack_choose_emoji_about" = "Pick an emoji that corresponds to this sticker."; "lng_stickers_pick_existing_title" = "Choose Sticker"; diff --git a/Telegram/SourceFiles/api/api_stickers_creator.cpp b/Telegram/SourceFiles/api/api_stickers_creator.cpp index d9d86d9301..78436916b6 100644 --- a/Telegram/SourceFiles/api/api_stickers_creator.cpp +++ b/Telegram/SourceFiles/api/api_stickers_creator.cpp @@ -92,19 +92,23 @@ void FeedSetIfFull( } template -void EnumerateOwnedStickerSets( +void EnumerateOwnedSets( not_null session, + Data::StickersType type, Callback &&callback) { const auto &stickers = session->data().stickers(); const auto &sets = stickers.sets(); - for (const auto setId : stickers.setsOrder()) { + const auto &order = (type == Data::StickersType::Emoji) + ? stickers.emojiSetsOrder() + : stickers.setsOrder(); + for (const auto setId : order) { const auto it = sets.find(setId); if (it == sets.end()) { continue; } const auto set = it->second.get(); if (!(set->flags & Data::StickersSetFlag::AmCreator) - || (set->type() != Data::StickersType::Stickers)) { + || (set->type() != type)) { continue; } using namespace Data; @@ -120,6 +124,81 @@ void EnumerateOwnedStickerSets( } } +void FillChooseOwnedSetMenu( + not_null menu, + std::shared_ptr show, + not_null document, + Data::StickersType type) { + const auto session = &show->session(); + const auto emoji = StickerEmojiOrDefault(document); + const auto isEmoji = (type == Data::StickersType::Emoji); + const auto maxCount = isEmoji + ? kEmojiInOwnedSetMax + : kStickersInOwnedSetMax; + const auto fullMessage = isEmoji + ? tr::lng_emoji_set_is_full + : tr::lng_stickers_set_is_full; + const auto addedMessage = isEmoji + ? tr::lng_emoji_added + : tr::lng_stickers_create_added; + const auto alreadyMessage = isEmoji + ? tr::lng_emoji_already_in_set + : tr::lng_stickers_already_in_set; + const auto failToast = [=](QString err) { + show->showToast(err.isEmpty() + ? tr::lng_attach_failed(tr::now) + : err); + }; + EnumerateOwnedSets(session, type, [&](not_null set) { + const auto identifier = set->identifier(); + const auto coverDocument = set->lookupThumbnailDocument(); + auto thumbnail = coverDocument + ? Ui::MakeDocumentThumbnail( + coverDocument, + Data::FileOriginStickerSet(set->id, set->accessHash)) + : nullptr; + const auto targetSetId = set->id; + const auto handler = crl::guard(session, [=] { + const auto &map = session->data().stickers().sets(); + const auto i = map.find(targetSetId); + if (i != map.end() && i->second->count >= maxCount) { + show->showToast(fullMessage(tr::now)); + return; + } + const auto oldCount = (i != map.end()) + ? i->second->count + : 0; + AddExistingStickerToSet( + session, + identifier, + document, + emoji, + crl::guard(session, [=](MTPmessages_StickerSet) { + const auto &map = session->data().stickers().sets(); + const auto i = map.find(targetSetId); + const auto newCount = (i != map.end()) + ? i->second->count + : oldCount; + show->showToast(newCount > oldCount + ? addedMessage(tr::now) + : alreadyMessage(tr::now)); + }), + crl::guard(session, failToast)); + }); + const auto rawAction = Ui::Menu::CreateAction( + menu.get(), + set->title, + handler); + auto item = base::make_unique_q( + menu->menu(), + menu->menu()->st(), + rawAction, + std::move(thumbnail), + st::menuIconStickerAdd.width()); + menu->addAction(std::move(item)); + }); +} + } // namespace void AddExistingStickerToSet( @@ -155,10 +234,25 @@ QString StickerEmojiOrDefault(not_null document) { bool HasOwnedStickerSets(not_null session) { auto found = false; - EnumerateOwnedStickerSets(session, [&](not_null) { - found = true; - return false; - }); + EnumerateOwnedSets( + session, + Data::StickersType::Stickers, + [&](not_null) { + found = true; + return false; + }); + return found; +} + +bool HasOwnedEmojiSets(not_null session) { + auto found = false; + EnumerateOwnedSets( + session, + Data::StickersType::Emoji, + [&](not_null) { + found = true; + return false; + }); return found; } @@ -166,62 +260,15 @@ void FillChooseStickerSetMenu( not_null menu, std::shared_ptr show, not_null document) { - const auto session = &show->session(); - const auto emoji = StickerEmojiOrDefault(document); - const auto failToast = [=](QString err) { - show->showToast(err.isEmpty() - ? tr::lng_attach_failed(tr::now) - : err); - }; - EnumerateOwnedStickerSets(session, [&](not_null set) { - const auto identifier = set->identifier(); - const auto coverDocument = set->lookupThumbnailDocument(); - auto thumbnail = coverDocument - ? Ui::MakeDocumentThumbnail( - coverDocument, - Data::FileOriginStickerSet(set->id, set->accessHash)) - : nullptr; - const auto targetSetId = set->id; - const auto handler = crl::guard(session, [=] { - const auto &map = session->data().stickers().sets(); - const auto i = map.find(targetSetId); - if (i != map.end() - && i->second->count >= kStickersInOwnedSetMax) { - show->showToast(tr::lng_stickers_set_is_full(tr::now)); - return; - } - const auto oldCount = (i != map.end()) - ? i->second->count - : 0; - AddExistingStickerToSet( - session, - identifier, - document, - emoji, - crl::guard(session, [=](MTPmessages_StickerSet) { - const auto &map = session->data().stickers().sets(); - const auto i = map.find(targetSetId); - const auto newCount = (i != map.end()) - ? i->second->count - : oldCount; - show->showToast(newCount > oldCount - ? tr::lng_stickers_create_added(tr::now) - : tr::lng_stickers_already_in_set(tr::now)); - }), - crl::guard(session, failToast)); - }); - const auto rawAction = Ui::Menu::CreateAction( - menu.get(), - set->title, - handler); - auto item = base::make_unique_q( - menu->menu(), - menu->menu()->st(), - rawAction, - std::move(thumbnail), - st::menuIconStickerAdd.width()); - menu->addAction(std::move(item)); - }); + using namespace Data; + FillChooseOwnedSetMenu(menu, show, document, StickersType::Stickers); +} + +void FillChooseEmojiSetMenu( + not_null menu, + std::shared_ptr show, + not_null document) { + FillChooseOwnedSetMenu(menu, show, document, Data::StickersType::Emoji); } void AddAddToStickerSetAction( @@ -242,6 +289,24 @@ void AddAddToStickerSetAction( }); } +void AddAddToEmojiSetAction( + const Ui::Menu::MenuCallback &addAction, + std::shared_ptr show, + not_null document) { + const auto session = &show->session(); + if (!HasOwnedEmojiSets(session)) { + return; + } + addAction({ + .text = tr::lng_emoji_add_to_set(tr::now), + .icon = &st::menuIconEmoji, + .fillSubmenu = [show, document](not_null submenu) { + FillChooseEmojiSetMenu(submenu, show, document); + }, + .submenuSt = &st::popupMenuWithIcons, + }); +} + void DeleteStickerSet( not_null session, const StickerSetIdentifier &set, diff --git a/Telegram/SourceFiles/api/api_stickers_creator.h b/Telegram/SourceFiles/api/api_stickers_creator.h index a97affca18..d537d1cb6e 100644 --- a/Telegram/SourceFiles/api/api_stickers_creator.h +++ b/Telegram/SourceFiles/api/api_stickers_creator.h @@ -31,6 +31,7 @@ struct MenuCallback; namespace Api { inline constexpr auto kStickersInOwnedSetMax = 120; +inline constexpr auto kEmojiInOwnedSetMax = 200; void AddExistingStickerToSet( not_null session, @@ -47,6 +48,7 @@ void DeleteStickerSet( Fn fail); [[nodiscard]] bool HasOwnedStickerSets(not_null session); +[[nodiscard]] bool HasOwnedEmojiSets(not_null session); [[nodiscard]] QString StickerEmojiOrDefault( not_null document); @@ -56,11 +58,21 @@ void FillChooseStickerSetMenu( std::shared_ptr show, not_null document); +void FillChooseEmojiSetMenu( + not_null menu, + std::shared_ptr show, + not_null document); + void AddAddToStickerSetAction( const Ui::Menu::MenuCallback &addAction, std::shared_ptr show, not_null document); +void AddAddToEmojiSetAction( + const Ui::Menu::MenuCallback &addAction, + std::shared_ptr show, + not_null document); + class StickerUpload final : public base::has_weak_ptr { public: StickerUpload( diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index eabf4b93d5..ed97954db8 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -1606,6 +1606,12 @@ void StickerSetBox::Inner::contextMenuEvent(QContextMenuEvent *e) { } }, &st::menuIconCopy); } + if (!amSetCreator()) { + Api::AddAddToEmojiSetAction( + Ui::Menu::CreateAddActionCallback(_menu.get()), + _show, + _pack[index]); + } } else if (details.type != SendMenu::Type::Disabled) { const auto document = _pack[index]; const auto send = crl::guard(this, [=](Api::SendOptions options) {