diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp index 2f1338cfb..4e2a5ce59 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_reactions.cpp @@ -282,6 +282,9 @@ void SetupOnlyCustomEmojiField( const auto offset = size(); if (unifiedId) { result.text.append('@'); + } else if (id.paid()) { + result.text.append(QChar(0x2B50)); + unifiedId = reactions->lookupPaid()->selectAnimation->id; } else { result.text.append(id.emoji()); const auto i = ranges::find(all, id, &Data::Reaction::id); @@ -312,6 +315,7 @@ struct ReactionsSelectorArgs { rpl::producer title; std::vector list; std::vector selected; + rpl::producer paid; Fn, bool)> callback; rpl::producer stateValue; int customAllowed = 0; @@ -341,13 +345,18 @@ object_ptr AddReactionsSelector( std::unique_ptr unifiedFactoryOwner; UnifiedFactoryOwner::RecentFactory factory; base::flat_set allowed; + std::vector reactions; rpl::lifetime focusLifetime; }; + const auto paid = reactions->lookupPaid(); + auto normal = reactions->list(Data::Reactions::Type::Active); + normal.push_back(*paid); const auto state = raw->lifetime().make_state(); state->unifiedFactoryOwner = std::make_unique( session, - reactions->list(Data::Reactions::Type::Active)); + normal); state->factory = state->unifiedFactoryOwner->factory(); + state->reactions = std::move(args.selected); const auto customEmojiPaused = [controller = args.controller] { return controller->isGifPausedAtLeastFor(PauseReason::Layer); @@ -396,9 +405,32 @@ object_ptr AddReactionsSelector( state->allowed = std::move(allowed); raw->rawTextEdit()->update(); } + state->reactions = reactions; callback(std::move(reactions), hardLimitHit); }, isCustom, args.customHardLimit); - raw->setTextWithTags(ComposeEmojiList(reactions, args.selected)); + const auto applyFromState = [=] { + raw->setTextWithTags(ComposeEmojiList(reactions, state->reactions)); + }; + + applyFromState(); + std::move( + args.paid + ) | rpl::start_with_next([=](bool paid) { + const auto id = Data::ReactionId::Paid(); + if (paid && !ranges::contains(state->reactions, id)) { + state->reactions.insert(begin(state->reactions), id); + applyFromState(); + } else if (!paid && ranges::contains(state->reactions, id)) { + state->reactions.erase( + ranges::remove(state->reactions, id), + end(state->reactions)); + applyFromState(); + } + }, raw->lifetime()); + + const auto toggle = Ui::CreateChild( + parent.get(), + st::manageGroupReactions); using SelectorState = ReactionsSelectorState; std::move( @@ -444,10 +476,6 @@ object_ptr AddReactionsSelector( } }, raw->lifetime()); - const auto toggle = Ui::CreateChild( - parent.get(), - st::manageGroupReactions); - const auto panel = Ui::CreateChild( args.outer.get(), args.controller, @@ -458,8 +486,11 @@ object_ptr AddReactionsSelector( (args.all ? TabbedSelector::Mode::FullReactions : TabbedSelector::Mode::RecentReactions))); - panel->selector()->provideRecentEmoji( - state->unifiedFactoryOwner->unifiedIdsList()); + auto panelList = state->unifiedFactoryOwner->unifiedIdsList(); + panelList.erase( + ranges::remove(panelList, paid->selectAnimation->id), + end(panelList)); + panel->selector()->provideRecentEmoji(panelList); panel->setDesiredHeightValues( 1., st::emojiPanMinHeight / 2, @@ -608,12 +639,12 @@ void EditAllowedReactionsBox( rpl::variable selectorState; std::vector selected; rpl::variable customCount; - bool paidEnabled = false; + rpl::variable paidEnabled; }; const auto allowed = args.allowed; const auto optionInitial = (allowed.type != AllowedReactionsType::Some) ? Option::All - : allowed.some.empty() + : (allowed.some.empty() && !allowed.paidEnabled) ? Option::None : Option::Some; const auto state = box->lifetime().make_state(State{ @@ -704,13 +735,19 @@ void EditAllowedReactionsBox( | ranges::views::transform(&Data::Reaction::id) | ranges::to_vector) : allowed.some; + if (allowed.paidEnabled) { + selected.insert(begin(selected), Data::ReactionId::Paid()); + } const auto changed = [=]( - std::vector chosen, - bool hardLimitHit) { + std::vector chosen, + bool hardLimitHit) { state->selected = std::move(chosen); state->customCount = ranges::count_if( state->selected, &Data::ReactionId::custom); + state->paidEnabled = ranges::contains( + state->selected, + Data::ReactionId::Paid()); if (hardLimitHit) { box->uiShow()->showToast( tr::lng_manage_peer_reactions_limit(tr::now)); @@ -729,6 +766,7 @@ void EditAllowedReactionsBox( .title = tr::lng_manage_peer_reactions_available_ph(), .list = all, .selected = state->selected, + .paid = state->paidEnabled.value(), .callback = changed, .stateValue = state->selectorState.value(), .customAllowed = args.allowedCustomReactions, @@ -737,7 +775,7 @@ void EditAllowedReactionsBox( }), st::boxRowPadding); box->setFocusCallback([=] { - if (!wrap || state->option.current() == Option::Some) { + if (state->option.current() == Option::Some) { state->selectorState.force_assign(SelectorState::Active); } }); @@ -855,7 +893,7 @@ void EditAllowedReactionsBox( inner, tr::lng_manage_peer_reactions_paid(), st::manageGroupNoIconButton.button)); - paid->toggleOn(rpl::single(allowed.paidEnabled)); + paid->toggleOn(state->paidEnabled.value()); paid->toggledValue( ) | rpl::start_with_next([=](bool value) { state->paidEnabled = value; @@ -882,7 +920,7 @@ void EditAllowedReactionsBox( result.some = state->selected; } if (!isGroup && enabled->toggled()) { - result.paidEnabled = state->paidEnabled; + result.paidEnabled = state->paidEnabled.current(); } auto some = result.some; auto simple = all | ranges::views::transform( diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index 1457eaddc..abfb39f35 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -214,20 +214,21 @@ PossibleItemReactionsRef LookupPossibleReactions( result.tags = true; } else if (limited) { result.recent.reserve((allowed.paidEnabled ? 1 : 0) + all.size()); - if (allowed.paidEnabled) { - result.recent.push_back(reactions->lookupPaid()); - } add([&](const Reaction &reaction) { return ranges::contains(all, reaction.id, &MessageReaction::id); }); for (const auto &reaction : all) { const auto id = reaction.id; - if (!added.contains(id)) { + if (added.emplace(id).second) { if (const auto temp = reactions->lookupTemporary(id)) { result.recent.push_back(temp); } } } + if (allowed.paidEnabled + && !added.contains(Data::ReactionId::Paid())) { + result.recent.push_back(reactions->lookupPaid()); + } } else { result.recent.reserve((allowed.paidEnabled ? 1 : 0) + ((allowed.type == AllowedReactionsType::Some)