From bb3fc17489708956865f779efe6013adaf2397f5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 5 Aug 2024 11:53:42 +0200 Subject: [PATCH] Allow enabling paid reactions. --- .../{art => animations/dice}/bball_idle.tgs | Bin .../{art => animations/dice}/dart_idle.tgs | Bin .../{art => animations/dice}/dice_idle.tgs | Bin .../{art => animations/dice}/fball_idle.tgs | Bin .../{art => animations/dice}/slot_0_idle.tgs | Bin .../{art => animations/dice}/slot_1_idle.tgs | Bin .../{art => animations/dice}/slot_2_idle.tgs | Bin .../{art => animations/dice}/slot_back.tgs | Bin .../{art => animations/dice}/slot_pull.tgs | Bin .../{art => animations/dice}/winners.tgs | Bin .../animations/star_reaction/appear.tgs | Bin 0 -> 6538 bytes .../animations/star_reaction/effect.tgs | Bin 0 -> 8420 bytes .../animations/star_reaction/select.tgs | Bin 0 -> 4699 bytes Telegram/Resources/langs/lang.strings | 4 + .../Resources/qrc/telegram/animations.qrc | 15 ++++ Telegram/Resources/qrc/telegram/telegram.qrc | 10 --- .../boxes/peers/edit_peer_reactions.cpp | 42 +++++++-- .../chat_helpers/stickers_dice_pack.cpp | 37 ++------ .../chat_helpers/stickers_dice_pack.h | 1 - .../chat_helpers/stickers_lottie.cpp | 32 +++++++ .../chat_helpers/stickers_lottie.h | 4 + Telegram/SourceFiles/data/data_channel.cpp | 11 ++- Telegram/SourceFiles/data/data_chat.cpp | 4 +- .../data/data_message_reactions.cpp | 81 ++++++++++++++++-- .../SourceFiles/data/data_message_reactions.h | 4 + Telegram/SourceFiles/data/data_peer.cpp | 28 +++--- Telegram/SourceFiles/data/data_peer.h | 17 ++-- .../history/history_inner_widget.cpp | 10 +++ Telegram/SourceFiles/history/history_item.cpp | 11 ++- Telegram/SourceFiles/history/history_item.h | 1 + .../history/view/history_view_message.cpp | 7 +- .../view/reactions/history_view_reactions.cpp | 4 + .../ui/effects/reaction_fly_animation.cpp | 5 ++ 33 files changed, 248 insertions(+), 80 deletions(-) rename Telegram/Resources/{art => animations/dice}/bball_idle.tgs (100%) rename Telegram/Resources/{art => animations/dice}/dart_idle.tgs (100%) rename Telegram/Resources/{art => animations/dice}/dice_idle.tgs (100%) rename Telegram/Resources/{art => animations/dice}/fball_idle.tgs (100%) rename Telegram/Resources/{art => animations/dice}/slot_0_idle.tgs (100%) rename Telegram/Resources/{art => animations/dice}/slot_1_idle.tgs (100%) rename Telegram/Resources/{art => animations/dice}/slot_2_idle.tgs (100%) rename Telegram/Resources/{art => animations/dice}/slot_back.tgs (100%) rename Telegram/Resources/{art => animations/dice}/slot_pull.tgs (100%) rename Telegram/Resources/{art => animations/dice}/winners.tgs (100%) create mode 100644 Telegram/Resources/animations/star_reaction/appear.tgs create mode 100644 Telegram/Resources/animations/star_reaction/effect.tgs create mode 100644 Telegram/Resources/animations/star_reaction/select.tgs diff --git a/Telegram/Resources/art/bball_idle.tgs b/Telegram/Resources/animations/dice/bball_idle.tgs similarity index 100% rename from Telegram/Resources/art/bball_idle.tgs rename to Telegram/Resources/animations/dice/bball_idle.tgs diff --git a/Telegram/Resources/art/dart_idle.tgs b/Telegram/Resources/animations/dice/dart_idle.tgs similarity index 100% rename from Telegram/Resources/art/dart_idle.tgs rename to Telegram/Resources/animations/dice/dart_idle.tgs diff --git a/Telegram/Resources/art/dice_idle.tgs b/Telegram/Resources/animations/dice/dice_idle.tgs similarity index 100% rename from Telegram/Resources/art/dice_idle.tgs rename to Telegram/Resources/animations/dice/dice_idle.tgs diff --git a/Telegram/Resources/art/fball_idle.tgs b/Telegram/Resources/animations/dice/fball_idle.tgs similarity index 100% rename from Telegram/Resources/art/fball_idle.tgs rename to Telegram/Resources/animations/dice/fball_idle.tgs diff --git a/Telegram/Resources/art/slot_0_idle.tgs b/Telegram/Resources/animations/dice/slot_0_idle.tgs similarity index 100% rename from Telegram/Resources/art/slot_0_idle.tgs rename to Telegram/Resources/animations/dice/slot_0_idle.tgs diff --git a/Telegram/Resources/art/slot_1_idle.tgs b/Telegram/Resources/animations/dice/slot_1_idle.tgs similarity index 100% rename from Telegram/Resources/art/slot_1_idle.tgs rename to Telegram/Resources/animations/dice/slot_1_idle.tgs diff --git a/Telegram/Resources/art/slot_2_idle.tgs b/Telegram/Resources/animations/dice/slot_2_idle.tgs similarity index 100% rename from Telegram/Resources/art/slot_2_idle.tgs rename to Telegram/Resources/animations/dice/slot_2_idle.tgs diff --git a/Telegram/Resources/art/slot_back.tgs b/Telegram/Resources/animations/dice/slot_back.tgs similarity index 100% rename from Telegram/Resources/art/slot_back.tgs rename to Telegram/Resources/animations/dice/slot_back.tgs diff --git a/Telegram/Resources/art/slot_pull.tgs b/Telegram/Resources/animations/dice/slot_pull.tgs similarity index 100% rename from Telegram/Resources/art/slot_pull.tgs rename to Telegram/Resources/animations/dice/slot_pull.tgs diff --git a/Telegram/Resources/art/winners.tgs b/Telegram/Resources/animations/dice/winners.tgs similarity index 100% rename from Telegram/Resources/art/winners.tgs rename to Telegram/Resources/animations/dice/winners.tgs diff --git a/Telegram/Resources/animations/star_reaction/appear.tgs b/Telegram/Resources/animations/star_reaction/appear.tgs new file mode 100644 index 0000000000000000000000000000000000000000..e47d5492eb8b5b27037efe0f3a6fdb4c95997761 GIT binary patch literal 6538 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 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/animations/star_reaction/select.tgs b/Telegram/Resources/animations/star_reaction/select.tgs new file mode 100644 index 0000000000000000000000000000000000000000..cf8fc6758006c33e9a700cc66ffcbe00050ed4e9 GIT binary patch literal 4699 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 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 1b6ab0ea1..f45253adf 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1550,6 +1550,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_manage_peer_reactions_max_slider#other" = "{count} reactions per post"; "lng_manage_peer_reactions_max_about" = "Limit the number of different reactions that can be added to a post, including already published ones."; +"lng_manage_peer_reactions_paid" = "Enable Paid Reactions"; +"lng_manage_peer_reactions_paid_about" = "Switch this on to let your subscribers set paid reactions with Telegram Stars, which you will be able to withdraw later as TON. {link}"; +"lng_manage_peer_reactions_paid_link" = "Learn more >"; + "lng_manage_peer_antispam" = "Aggressive Anti-Spam"; "lng_manage_peer_antispam_about" = "Telegram will filter more spam but may occasionally affect ordinary messages. You can report False Positives in Recent Actions."; "lng_manage_peer_antispam_not_enough#one" = "Aggressive filtering can be enabled only in groups with more than **{count} member**."; diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc index 0d6663d8f..18a9e0734 100644 --- a/Telegram/Resources/qrc/telegram/animations.qrc +++ b/Telegram/Resources/qrc/telegram/animations.qrc @@ -28,5 +28,20 @@ ../../animations/collectible_phone.tgs ../../animations/search.tgs ../../animations/noresults.tgs + + ../../animations/dice/dice_idle.tgs + ../../animations/dice/dart_idle.tgs + ../../animations/dice/bball_idle.tgs + ../../animations/dice/fball_idle.tgs + ../../animations/dice/slot_0_idle.tgs + ../../animations/dice/slot_1_idle.tgs + ../../animations/dice/slot_2_idle.tgs + ../../animations/dice/slot_back.tgs + ../../animations/dice/slot_pull.tgs + ../../animations/dice/winners.tgs + + ../../animations/star_reaction/appear.tgs + ../../animations/star_reaction/effect.tgs + ../../animations/star_reaction/select.tgs diff --git a/Telegram/Resources/qrc/telegram/telegram.qrc b/Telegram/Resources/qrc/telegram/telegram.qrc index ae6edc957..e83243d33 100644 --- a/Telegram/Resources/qrc/telegram/telegram.qrc +++ b/Telegram/Resources/qrc/telegram/telegram.qrc @@ -7,16 +7,6 @@ ../../art/logo_256.png ../../art/logo_256_no_margin.png ../../art/themeimage.jpg - ../../art/dice_idle.tgs - ../../art/dart_idle.tgs - ../../art/bball_idle.tgs - ../../art/fball_idle.tgs - ../../art/slot_0_idle.tgs - ../../art/slot_1_idle.tgs - ../../art/slot_2_idle.tgs - ../../art/slot_back.tgs - ../../art/slot_pull.tgs - ../../art/winners.tgs ../../day-blue.tdesktop-theme ../../night.tdesktop-theme ../../night-green.tdesktop-theme diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp index 226e30af2..2f1338cfb 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp @@ -608,6 +608,7 @@ void EditAllowedReactionsBox( rpl::variable selectorState; std::vector selected; rpl::variable customCount; + bool paidEnabled = false; }; const auto allowed = args.allowed; const auto optionInitial = (allowed.type != AllowedReactionsType::Some) @@ -617,6 +618,7 @@ void EditAllowedReactionsBox( : Option::Some; const auto state = box->lifetime().make_state(State{ .option = optionInitial, + .paidEnabled = allowed.paidEnabled, }); const auto container = box->verticalLayout(); @@ -847,6 +849,29 @@ void EditAllowedReactionsBox( ) | rpl::map(rpl::mappers::_1 == SelectorState::Active))); Ui::AddDividerText(inner, tr::lng_manage_peer_reactions_max_about()); + + Ui::AddSkip(inner); + const auto paid = inner->add(object_ptr( + inner, + tr::lng_manage_peer_reactions_paid(), + st::manageGroupNoIconButton.button)); + paid->toggleOn(rpl::single(allowed.paidEnabled)); + paid->toggledValue( + ) | rpl::start_with_next([=](bool value) { + state->paidEnabled = value; + }, paid->lifetime()); + Ui::AddSkip(inner); + + Ui::AddDividerText( + inner, + tr::lng_manage_peer_reactions_paid_about( + lt_link, + tr::lng_manage_peer_reactions_paid_link([=](QString text) { + return Ui::Text::Link( + text, + u"https://telegram.org/tos/stars"_q); + }), + Ui::Text::WithEntities)); } const auto collect = [=] { auto result = AllowedReactions(); @@ -856,6 +881,9 @@ void EditAllowedReactionsBox( : (enabled->toggled())) { result.some = state->selected; } + if (!isGroup && enabled->toggled()) { + result.paidEnabled = state->paidEnabled; + } auto some = result.some; auto simple = all | ranges::views::transform( &Data::Reaction::id @@ -907,16 +935,20 @@ void SaveAllowedReactions( : allowed.some.empty() ? MTP_chatReactionsNone() : MTP_chatReactionsSome(MTP_vector(ids)); + const auto editPaidEnabled = peer->isBroadcast(); + const auto paidEnabled = editPaidEnabled && allowed.paidEnabled; + const auto maxCount = allowed.maxCount; peer->session().api().request(MTPmessages_SetChatAvailableReactions( - allowed.maxCount ? MTP_flags(Flag::f_reactions_limit) : MTP_flags(0), + MTP_flags(Flag() + | (maxCount ? Flag::f_reactions_limit : Flag()) + | (editPaidEnabled ? Flag::f_paid_enabled : Flag())), peer->input, updated, - MTP_int(allowed.maxCount), - MTPbool() // paid_enabled + MTP_int(maxCount), + MTP_bool(paidEnabled) )).done([=](const MTPUpdates &result) { peer->session().api().applyUpdates(result); - auto parsed = Data::Parse(updated); - parsed.maxCount = allowed.maxCount; + auto parsed = Data::Parse(updated, maxCount, paidEnabled); if (const auto chat = peer->asChat()) { chat->setAllowedReactions(parsed); } else if (const auto channel = peer->asChannel()) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp index 69aaddee1..8941f35aa 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp @@ -8,11 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/stickers_dice_pack.h" #include "main/main_session.h" +#include "chat_helpers/stickers_lottie.h" #include "data/data_session.h" #include "data/data_document.h" -#include "ui/chat/attach/attach_prepare.h" -#include "ui/image/image_location_factory.h" -#include "storage/localimageloader.h" #include "base/unixtime.h" #include "apiwrap.h" @@ -104,6 +102,11 @@ void DicePack::tryGenerateLocalZero() { return; } + const auto generateLocal = [&](int index, const QString &name) { + _map.emplace( + index, + ChatHelpers::GenerateLocalTgsSticker(_session, name)); + }; if (_emoji == DicePacks::kDiceString) { generateLocal(0, u"dice_idle"_q); } else if (_emoji == DicePacks::kDartString) { @@ -123,32 +126,8 @@ void DicePack::tryGenerateLocalZero() { } } -void DicePack::generateLocal(int index, const QString &name) { - const auto path = u":/gui/art/"_q + name + u".tgs"_q; - auto task = FileLoadTask( - _session, - path, - QByteArray(), - nullptr, - SendMediaType::File, - FileLoadTo(0, {}, {}, 0), - {}, - false); - task.process({ .generateGoodThumbnail = false }); - const auto result = task.peekResult(); - Assert(result != nullptr); - const auto document = _session->data().processDocument( - result->document, - Images::FromImageInMemory(result->thumb, "WEBP", result->thumbbytes)); - document->setLocation(Core::FileLocation(path)); - - _map.emplace(index, document); - - Ensures(document->sticker()); - Ensures(document->sticker()->isLottie()); -} - -DicePacks::DicePacks(not_null session) : _session(session) { +DicePacks::DicePacks(not_null session) +: _session(session) { } DocumentData *DicePacks::lookup(const QString &emoji, int value) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h index 3a1c49f46..cb5210c35 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h @@ -26,7 +26,6 @@ private: void load(); void applySet(const MTPDmessages_stickerSet &data); void tryGenerateLocalZero(); - void generateLocal(int index, const QString &name); const not_null _session; QString _emoji; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp b/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp index 5e2aceb7a..314a99a8a 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp @@ -15,9 +15,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_file_origin.h" #include "storage/cache/storage_cache_database.h" +#include "storage/localimageloader.h" #include "history/view/media/history_view_media_common.h" #include "media/clip/media_clip_reader.h" +#include "ui/chat/attach/attach_prepare.h" #include "ui/effects/path_shift_gradient.h" +#include "ui/image/image_location_factory.h" #include "ui/painter.h" #include "main/main_session.h" @@ -312,4 +315,33 @@ QSize ComputeStickerSize(not_null document, QSize box) { return HistoryView::NonEmptySize(request.size(dimensions, 8) / ratio); } +not_null GenerateLocalTgsSticker( + not_null session, + const QString &name) { + const auto path = u":/animations/"_q + name + u".tgs"_q; + auto task = FileLoadTask( + session, + path, + QByteArray(), + nullptr, + SendMediaType::File, + FileLoadTo(0, {}, {}, 0), + {}, + false); + task.process({ .generateGoodThumbnail = false }); + const auto result = task.peekResult(); + Assert(result != nullptr); + const auto document = session->data().processDocument( + result->document, + Images::FromImageInMemory( + result->thumb, + "WEBP", + result->thumbbytes)); + document->setLocation(Core::FileLocation(path)); + + Ensures(document->sticker()); + Ensures(document->sticker()->isLottie()); + return document; +} + } // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/stickers_lottie.h b/Telegram/SourceFiles/chat_helpers/stickers_lottie.h index 7bd24ac8f..e659329dd 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_lottie.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_lottie.h @@ -130,4 +130,8 @@ bool PaintStickerThumbnailPath( not_null document, QSize box); +[[nodiscard]] not_null GenerateLocalTgsSticker( + not_null session, + const QString &name); + } // namespace ChatHelpers diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 6162024fd..28c1a1b38 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -1220,11 +1220,16 @@ void ApplyChannelUpdate( const auto reactionsLimit = update.vreactions_limit().value_or_empty(); if (const auto allowed = update.vavailable_reactions()) { - auto parsed = Data::Parse(*allowed); - parsed.maxCount = reactionsLimit; + auto parsed = Data::Parse( + *allowed, + reactionsLimit, + update.is_paid_reactions_available()); channel->setAllowedReactions(std::move(parsed)); } else { - channel->setAllowedReactions({ .maxCount = reactionsLimit }); + channel->setAllowedReactions({ + .maxCount = reactionsLimit, + .paidEnabled = update.is_paid_reactions_available(), + }); } channel->owner().stories().apply(channel, update.vstories()); channel->fullUpdated(); diff --git a/Telegram/SourceFiles/data/data_chat.cpp b/Telegram/SourceFiles/data/data_chat.cpp index 76aa1f714..b5f5bcf66 100644 --- a/Telegram/SourceFiles/data/data_chat.cpp +++ b/Telegram/SourceFiles/data/data_chat.cpp @@ -486,8 +486,8 @@ void ApplyChatUpdate(not_null chat, const MTPDchatFull &update) { chat->setTranslationDisabled(update.is_translations_disabled()); const auto reactionsLimit = update.vreactions_limit().value_or_empty(); if (const auto allowed = update.vavailable_reactions()) { - auto parsed = Data::Parse(*allowed); - parsed.maxCount = reactionsLimit; + const auto paidEnabled = false; + auto parsed = Data::Parse(*allowed, reactionsLimit, paidEnabled); chat->setAllowedReactions(std::move(parsed)); } else { chat->setAllowedReactions({ .maxCount = reactionsLimit }); diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index 2b42a740d..c2b92de24 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_message_reactions.h" +#include "chat_helpers/stickers_lottie.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_item_components.h" @@ -29,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/mtproto_config.h" #include "base/timer_rpl.h" #include "base/call_delayed.h" +#include "base/unixtime.h" #include "apiwrap.h" #include "styles/style_chat.h" @@ -204,9 +206,13 @@ PossibleItemReactionsRef LookupPossibleReactions( } } else { const auto &allowed = PeerAllowedReactions(peer); - result.recent.reserve((allowed.type == AllowedReactionsType::Some) - ? allowed.some.size() - : full.size()); + result.recent.reserve((allowed.paidEnabled ? 1 : 0) + + ((allowed.type == AllowedReactionsType::Some) + ? allowed.some.size() + : full.size())); + if (allowed.paidEnabled) { + result.recent.push_back(reactions->lookupPaid()); + } add([&](const Reaction &reaction) { const auto id = reaction.id; if (id.custom() && !premiumPossible) { @@ -569,7 +575,7 @@ rpl::producer<> Reactions::effectsUpdates() const { } void Reactions::preloadReactionImageFor(const ReactionId &emoji) { - if (!emoji.emoji().isEmpty()) { + if (emoji.paid() || !emoji.emoji().isEmpty()) { preloadImageFor(emoji); } } @@ -586,6 +592,10 @@ void Reactions::preloadImageFor(const ReactionId &id) { } auto &set = _images.emplace(id).first->second; set.effect = (id.custom() != 0); + if (id.paid()) { + loadImage(set, lookupPaid()->selectAnimation, true); + return; + } auto &list = set.effect ? _effects : _available; const auto i = ranges::find(list, id, &Reaction::id); const auto document = (i == end(list)) @@ -1356,7 +1366,10 @@ void Reactions::send(not_null item, bool addToRecent) { MTP_flags(flags), item->history()->peer->input, MTP_int(id.msg), - MTP_vector(chosen | ranges::views::transform( + MTP_vector(chosen | ranges::views::filter([]( + const ReactionId &id) { + return !id.paid(); + }) | ranges::views::transform( ReactionToMTP ) | ranges::to>()) )).done([=](const MTPUpdates &result) { @@ -1367,6 +1380,21 @@ void Reactions::send(not_null item, bool addToRecent) { }).send(); } +void Reactions::sendPaid(not_null item, int count) { + const auto id = item->fullId(); + const auto randomId = base::unixtime::mtproto_msg_id(); + auto &api = _owner->session().api(); + api.request(MTPmessages_SendPaidReaction( + item->history()->peer->input, + MTP_int(id.msg), + MTP_int(count), + MTP_long(randomId) + )).done([=](const MTPUpdates &result) { + _owner->session().api().applyUpdates(result); + }).fail([=](const MTP::Error &error) { + }).send(); +} + void Reactions::poll(not_null item, crl::time now) { // Group them by one second. const auto last = item->lastReactionsRefreshTime(); @@ -1403,7 +1431,9 @@ void Reactions::clearTemporary() { } Reaction *Reactions::lookupTemporary(const ReactionId &id) { - if (const auto emoji = id.emoji(); !emoji.isEmpty()) { + if (id.paid()) { + return lookupPaid(); + } else if (const auto emoji = id.emoji(); !emoji.isEmpty()) { const auto i = ranges::find(_available, id, &Reaction::id); return (i != end(_available)) ? &*i : nullptr; } else if (const auto customId = id.custom()) { @@ -1424,6 +1454,26 @@ Reaction *Reactions::lookupTemporary(const ReactionId &id) { return nullptr; } +not_null Reactions::lookupPaid() { + if (!_paid) { + const auto generate = [&](const QString &name) { + const auto session = &_owner->session(); + return ChatHelpers::GenerateLocalTgsSticker(session, name); + }; + const auto select = generate(u"star_reaction_select"_q); + _paid.emplace(Reaction{ + .id = ReactionId::Paid(), + .title = u"Telegram Star"_q, + .appearAnimation = generate(u"star_reaction_appear"_q), + .selectAnimation = select, + .centerIcon = select, + //.aroundAnimation = generate(u"star_reaction_effect"_q), + .active = true, + }); + } + return &*_paid; +} + rpl::producer> Reactions::myTagsValue( SavedSublist *sublist) { refreshMyTags(sublist); @@ -1529,6 +1579,25 @@ MessageReactions::MessageReactions(not_null item) : _item(item) { } +void MessageReactions::addPaid(int count) { + Expects(_item->history()->peer->isBroadcast()); + + const auto id = Data::ReactionId::Paid(); + const auto history = _item->history(); + const auto peer = history->peer; + const auto i = ranges::find(_list, id, &MessageReaction::id); + if (i != end(_list)) { + i->my = true; + i->count += count; + std::rotate(i, i + 1, end(_list)); + } else { + _list.push_back({ .id = id, .count = count, .my = true }); + } + auto &owner = history->owner(); + owner.reactions().sendPaid(_item, count); + owner.notifyItemDataChange(_item); +} + void MessageReactions::add(const ReactionId &id, bool addToRecent) { Expects(!id.empty()); diff --git a/Telegram/SourceFiles/data/data_message_reactions.h b/Telegram/SourceFiles/data/data_message_reactions.h index 793fcc198..fff6fcf04 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.h +++ b/Telegram/SourceFiles/data/data_message_reactions.h @@ -129,6 +129,7 @@ public: void preloadAnimationsFor(const ReactionId &emoji); void send(not_null item, bool addToRecent); + void sendPaid(not_null item, int count); [[nodiscard]] bool sending(not_null item) const; void poll(not_null item, crl::time now); @@ -137,6 +138,7 @@ public: void clearTemporary(); [[nodiscard]] Reaction *lookupTemporary(const ReactionId &id); + [[nodiscard]] not_null lookupPaid(); [[nodiscard]] rpl::producer> myTagsValue( SavedSublist *sublist = nullptr); @@ -275,6 +277,7 @@ private: // So we use std::map instead of base::flat_map here. // Otherwise we could use flat_map>. std::map _temporary; + std::optional _paid; base::Timer _topRefreshTimer; mtpRequestId _topRequestId = 0; @@ -333,6 +336,7 @@ public: explicit MessageReactions(not_null item); void add(const ReactionId &id, bool addToRecent); + void addPaid(int count); void remove(const ReactionId &id); bool change( const QVector &list, diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 064f8d91b..265e9f0a9 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -95,28 +95,22 @@ bool ApplyBotMenuButton( return changed; } -bool operator<( - const AllowedReactions &a, - const AllowedReactions &b) { - return (a.type < b.type) || ((a.type == b.type) && (a.some < b.some)); -} - -bool operator==( - const AllowedReactions &a, - const AllowedReactions &b) { - return (a.type == b.type) - && (a.some == b.some) - && (a.maxCount == b.maxCount); -} - -AllowedReactions Parse(const MTPChatReactions &value) { +AllowedReactions Parse( + const MTPChatReactions &value, + int maxCount, + bool paidEnabled) { return value.match([&](const MTPDchatReactionsNone &) { - return AllowedReactions(); + return AllowedReactions{ + .maxCount = maxCount, + .paidEnabled = paidEnabled, + }; }, [&](const MTPDchatReactionsAll &data) { return AllowedReactions{ + .maxCount = maxCount, .type = (data.is_allow_custom() ? AllowedReactionsType::All : AllowedReactionsType::Default), + .paidEnabled = paidEnabled, }; }, [&](const MTPDchatReactionsSome &data) { return AllowedReactions{ @@ -125,7 +119,9 @@ AllowedReactions Parse(const MTPChatReactions &value) { ) | ranges::views::transform( ReactionFromMTP ) | ranges::to_vector, + .maxCount = maxCount, .type = AllowedReactionsType::Some, + .paidEnabled = paidEnabled, }; }); } diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 563f5a068..b884f679a 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -101,7 +101,7 @@ bool ApplyBotMenuButton( not_null info, const MTPBotMenuButton *button); -enum class AllowedReactionsType { +enum class AllowedReactionsType : uchar { All, Default, Some, @@ -109,14 +109,19 @@ enum class AllowedReactionsType { struct AllowedReactions { std::vector some; - AllowedReactionsType type = AllowedReactionsType::Some; int maxCount = 0; + AllowedReactionsType type = AllowedReactionsType::Some; + bool paidEnabled = false; + + friend inline bool operator==( + const AllowedReactions &, + const AllowedReactions &) = default; }; -bool operator<(const AllowedReactions &a, const AllowedReactions &b); -bool operator==(const AllowedReactions &a, const AllowedReactions &b); - -[[nodiscard]] AllowedReactions Parse(const MTPChatReactions &value); +[[nodiscard]] AllowedReactions Parse( + const MTPChatReactions &value, + int maxCount, + bool paidEnabled); [[nodiscard]] PeerData *PeerFromInputMTP( not_null owner, const MTPInputPeer &input); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 7838dda79..5a8e833a2 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/reaction_fly_animation.h" #include "ui/text/text_options.h" #include "ui/text/text_isolated_emoji.h" +#include "ui/boxes/confirm_box.h" #include "ui/boxes/edit_factcheck_box.h" #include "ui/boxes/report_box.h" #include "ui/layers/generic_box.h" @@ -488,6 +489,15 @@ void HistoryInner::reactionChosen(const ChosenReaction &reaction) { const auto item = session().data().message(reaction.context); if (!item) { return; + } else if (reaction.id.paid()) { + _controller->show(Ui::MakeConfirmBox({ + .text = u"Send 10-stars reaction?"_q, + .confirmed = [=](Fn close) { + item->addPaidReaction(10, HistoryItem::ReactionSource::Selector); + close(); + }, + })); + return; } else if (Window::ShowReactPremiumError( _controller, item, diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index a38b9b33f..e40947033 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -2514,6 +2514,16 @@ bool HistoryItem::canReact() const { return true; } +void HistoryItem::addPaidReaction(int count, ReactionSource source) { + Expects(_history->peer->isBroadcast()); + + if (!_reactions) { + _reactions = std::make_unique(this); + } + _reactions->addPaid(count); + _history->owner().notifyItemDataChange(this); +} + void HistoryItem::toggleReaction( const Data::ReactionId &reaction, ReactionSource source) { @@ -2530,7 +2540,6 @@ void HistoryItem::toggleReaction( if (_reactions->empty()) { _reactions = nullptr; _flags &= ~MessageFlag::CanViewReactions; - _history->owner().notifyItemDataChange(this); } } else { _reactions->add(reaction, (source == ReactionSource::Selector)); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index e4ed45cf9..9e852c77e 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -443,6 +443,7 @@ public: void toggleReaction( const Data::ReactionId &reaction, ReactionSource source); + void addPaidReaction(int count, ReactionSource source); void updateReactionsUnknown(); [[nodiscard]] auto reactions() const -> const std::vector &; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index e1d67952e..14597582d 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -3306,7 +3306,12 @@ void Message::refreshReactions() { ClickContext context) { if (const auto strong = weak.get()) { const auto item = strong->data(); - if (item->reactionsAreTags()) { + if (id.paid()) { + item->addPaidReaction( + 1, + HistoryItem::ReactionSource::Existing); + return; + } else if (item->reactionsAreTags()) { if (item->history()->session().premium()) { const auto tag = Data::SearchTagToQuery(id); HashtagClickHandler(tag).onClick(context); diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index 3a79d50b7..7dcf5929b 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -144,6 +144,10 @@ void InlineList::layoutButtons() { return true; } else if (acount < bcount) { return false; + } else if (b->id.paid()) { + return false; + } else if (a->id.paid()) { + return true; } return ranges::find(list, a->id, &::Data::Reaction::id) < ranges::find(list, b->id, &::Data::Reaction::id); diff --git a/Telegram/SourceFiles/ui/effects/reaction_fly_animation.cpp b/Telegram/SourceFiles/ui/effects/reaction_fly_animation.cpp index 395e38fae..e26c8c9d1 100644 --- a/Telegram/SourceFiles/ui/effects/reaction_fly_animation.cpp +++ b/Telegram/SourceFiles/ui/effects/reaction_fly_animation.cpp @@ -86,6 +86,11 @@ ReactionFlyAnimation::ReactionFlyAnimation( _customSize = esize; _centerSizeMultiplier = _customSize / float64(size); aroundAnimation = owner->chooseGenericAnimation(document); + } else if (args.id.paid()) { + const auto fake = owner->lookupPaid(); + centerIcon = fake->centerIcon; + aroundAnimation = fake->aroundAnimation; + _centerSizeMultiplier = 1.;// fake->centerIcon ? 1. : 0.5; } else { const auto i = ranges::find(list, args.id, &::Data::Reaction::id); if (i == end(list)/* || !i->centerIcon*/) {