Implement improved allowed reactions editing.

This commit is contained in:
John Preston 2022-08-30 13:21:58 +04:00
parent 021e275336
commit 5e81c65ea6
9 changed files with 291 additions and 163 deletions

View file

@ -1195,13 +1195,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_permissions" = "Permissions"; "lng_manage_peer_permissions" = "Permissions";
"lng_manage_peer_invite_links" = "Invite links"; "lng_manage_peer_invite_links" = "Invite links";
"lng_manage_peer_reactions" = "Reactions"; "lng_manage_peer_reactions" = "Reactions";
"lng_manage_peer_reactions_on" = "All";
"lng_manage_peer_reactions_off" = "Off"; "lng_manage_peer_reactions_off" = "Off";
"lng_manage_peer_requests" = "Member Requests"; "lng_manage_peer_requests" = "Member Requests";
"lng_manage_peer_requests_channel" = "Subscriber Requests"; "lng_manage_peer_requests_channel" = "Subscriber Requests";
"lng_manage_peer_reactions_enable" = "Enable Reactions"; "lng_manage_peer_reactions_all" = "All reactions";
"lng_manage_peer_reactions_about" = "Allow members to react to group messages."; "lng_manage_peer_reactions_all_about" = "Members of the group can use any emoji as reactions to messages.";
"lng_manage_peer_reactions_about_channel" = "Allow subscribers to react to channel posts."; "lng_manage_peer_reactions_all_about_channel" = "Subscribers of this channel can use any emoji as reactions to messages.";
"lng_manage_peer_reactions_some" = "Some reactions";
"lng_manage_peer_reactions_some_about" = "You can select emoji that will allow members of your group to react to messages.";
"lng_manage_peer_reactions_some_about_channel" = "You can select emoji that will allow subscribers of this channel to react to messages.";
"lng_manage_peer_reactions_none" = "No reactions";
"lng_manage_peer_reactions_none_about" = "Members of the group can't add any reactions to messages.";
"lng_manage_peer_reactions_none_about_channel" = "Subscribers of this channel can't add any reactions to messages.";
"lng_manage_peer_reactions_some_title" = "Only allow these reactions";
"lng_manage_peer_reactions_available" = "Available reactions"; "lng_manage_peer_reactions_available" = "Available reactions";
"lng_manage_peer_group_type" = "Group type"; "lng_manage_peer_group_type" = "Group type";

View file

@ -988,22 +988,31 @@ void Controller::fillManageSection() {
if (canEditReactions()) { if (canEditReactions()) {
const auto session = &_peer->session(); const auto session = &_peer->session();
auto reactionsCount = Info::Profile::MigratedOrMeValue( auto allowedReactions = Info::Profile::MigratedOrMeValue(
_peer _peer
) | rpl::map( ) | rpl::map([=](not_null<PeerData*> peer) {
Info::Profile::AllowedReactionsCountValue return peer->session().changes().peerFlagsValue(
) | rpl::flatten_latest(); peer,
auto fullCount = Info::Profile::FullReactionsCountValue(session); Data::PeerUpdate::Flag::Reactions
) | rpl::map([=] {
return Data::PeerAllowedReactions(peer);
});
}) | rpl::flatten_latest();
auto label = rpl::combine( auto label = rpl::combine(
std::move(reactionsCount), std::move(allowedReactions),
std::move(fullCount) Info::Profile::FullReactionsCountValue(session)
) | rpl::map([=](int allowed, int total) { ) | rpl::map([=](const Data::AllowedReactions &allowed, int total) {
return allowed const auto some = int(allowed.some.size());
? QString::number(allowed) + " / " + QString::number(total) return (allowed.type != Data::AllowedReactionsType::Some)
? tr::lng_manage_peer_reactions_on(tr::now)
: some
? (QString::number(some)
+ " / "
+ QString::number(std::max(some, total)))
: tr::lng_manage_peer_reactions_off(tr::now); : tr::lng_manage_peer_reactions_off(tr::now);
}); });
const auto done = [=](const std::vector<QString> &chosen, bool all) { const auto done = [=](const Data::AllowedReactions &chosen) {
SaveAllowedReactions(_peer, chosen, all); SaveAllowedReactions(_peer, chosen);
}; };
AddButtonWithCount( AddButtonWithCount(
_controls.buttonsLayout, _controls.buttonsLayout,
@ -1012,6 +1021,7 @@ void Controller::fillManageSection() {
[=] { [=] {
_navigation->parentController()->show(Box( _navigation->parentController()->show(Box(
EditAllowedReactionsBox, EditAllowedReactionsBox,
_navigation,
!_peer->isBroadcast(), !_peer->isBroadcast(),
session->data().reactions().list( session->data().reactions().list(
Data::Reactions::Type::Active), Data::Reactions::Type::Active),

View file

@ -18,34 +18,57 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/wrap/slide_wrap.h"
#include "settings/settings_common.h" #include "settings/settings_common.h"
#include "window/window_session_controller.h"
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "styles/style_info.h" #include "styles/style_info.h"
void EditAllowedReactionsBox( void EditAllowedReactionsBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Window::SessionNavigation*> navigation,
bool isGroup, bool isGroup,
const std::vector<Data::Reaction> &list, const std::vector<Data::Reaction> &list,
const Data::AllowedReactions &allowed, const Data::AllowedReactions &allowed,
Fn<void(const std::vector<QString> &, bool all)> callback) { Fn<void(const Data::AllowedReactions &)> callback) {
using namespace Data;
using namespace rpl::mappers;
const auto iconHeight = st::editPeerReactionsPreview; const auto iconHeight = st::editPeerReactionsPreview;
box->setTitle(tr::lng_manage_peer_reactions()); box->setTitle(tr::lng_manage_peer_reactions());
enum class Option {
All,
Some,
None,
};
struct State { struct State {
base::flat_map<QString, not_null<Ui::SettingsButton*>> toggles; base::flat_map<ReactionId, not_null<Ui::SettingsButton*>> toggles;
rpl::variable<bool> anyToggled; rpl::variable<Option> option;
rpl::event_stream<bool> forceToggleAll;
}; };
const auto state = box->lifetime().make_state<State>(State{ const auto state = box->lifetime().make_state<State>(State{
.anyToggled = (allowed.type != Data::AllowedReactionsType::Some), .option = (allowed.type != AllowedReactionsType::Some
? Option::All
: allowed.some.empty()
? Option::None
: Option::Some),
}); });
const auto collect = [=] { const auto collect = [=] {
auto result = std::vector<QString>(); auto result = AllowedReactions{
result.reserve(state->toggles.size()); .type = (state->option.current() != Option::All
for (const auto &[emoji, button] : state->toggles) { ? AllowedReactionsType::Some
if (button->toggled()) { : isGroup
result.push_back(emoji); ? AllowedReactionsType::All
: AllowedReactionsType::Default),
};
if (state->option.current() == Option::Some) {
result.some.reserve(state->toggles.size());
for (const auto &[id, button] : state->toggles) {
if (button->toggled()) {
result.some.push_back(id);
}
} }
} }
return result; return result;
@ -53,52 +76,64 @@ void EditAllowedReactionsBox(
const auto container = box->verticalLayout(); const auto container = box->verticalLayout();
const auto enabled = Settings::AddButton( const auto group = std::make_shared<Ui::RadioenumGroup<Option>>(
container, state->option.current());
tr::lng_manage_peer_reactions_enable(), group->setChangedCallback([=](Option value) {
st::manageGroupButton.button); state->option = value;
if (!list.empty()) { });
AddReactionAnimatedIcon( const auto addOption = [&](Option option, const QString &text) {
enabled, container->add(
enabled->sizeValue( object_ptr<Ui::Radioenum<Option>>(
) | rpl::map([=](const QSize &size) { container,
return QPoint( group,
st::manageGroupButton.iconPosition.x(), option,
(size.height() - iconHeight) / 2); text,
}), st::settingsSendType),
iconHeight, st::settingsSendTypePadding);
list.front(), };
rpl::never<>(), addOption(Option::All, tr::lng_manage_peer_reactions_all(tr::now));
rpl::never<>(), addOption(Option::Some, tr::lng_manage_peer_reactions_some(tr::now));
&enabled->lifetime()); addOption(Option::None, tr::lng_manage_peer_reactions_none(tr::now));
}
enabled->toggleOn(state->anyToggled.value());
enabled->toggledChanges(
) | rpl::filter([=](bool value) {
return (value != state->anyToggled.current());
}) | rpl::start_to_stream(state->forceToggleAll, enabled->lifetime());
const auto about = [isGroup](Option option) {
switch (option) {
case Option::All: return isGroup
? tr::lng_manage_peer_reactions_all_about()
: tr::lng_manage_peer_reactions_all_about_channel();
case Option::Some: return isGroup
? tr::lng_manage_peer_reactions_some_about()
: tr::lng_manage_peer_reactions_some_about_channel();
case Option::None: return isGroup
? tr::lng_manage_peer_reactions_none_about()
: tr::lng_manage_peer_reactions_none_about_channel();
}
Unexpected("Option value in EditAllowedReactionsBox.");
};
Settings::AddSkip(container); Settings::AddSkip(container);
Settings::AddDividerText( Settings::AddDividerText(
container, container,
(isGroup state->option.value() | rpl::map(about) | rpl::flatten_latest());
? tr::lng_manage_peer_reactions_about
: tr::lng_manage_peer_reactions_about_channel)());
Settings::AddSkip(container); const auto wrap = container->add(
Settings::AddSubsectionTitle( object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
tr::lng_manage_peer_reactions_available());
const auto active = [&](const Data::Reaction &entry) {
return ranges::contains(allowed.some, entry.id);
};
const auto add = [&](const Data::Reaction &entry) {
if (entry.id.emoji().isEmpty()) {
return;
}
const auto button = Settings::AddButton(
container, container,
object_ptr<Ui::VerticalLayout>(container)));
wrap->toggleOn(state->option.value() | rpl::map(_1 == Option::Some));
wrap->finishAnimating();
const auto reactions = wrap->entity();
Settings::AddSkip(reactions);
Settings::AddSubsectionTitle(
reactions,
tr::lng_manage_peer_reactions_some_title());
const auto active = [&](const ReactionId &id) {
return (allowed.type != AllowedReactionsType::Some)
|| ranges::contains(allowed.some, id);
};
const auto add = [&](const Reaction &entry) {
const auto button = Settings::AddButton(
reactions,
rpl::single(entry.title), rpl::single(entry.title),
st::manageGroupButton.button); st::manageGroupButton.button);
AddReactionAnimatedIcon( AddReactionAnimatedIcon(
@ -117,29 +152,41 @@ void EditAllowedReactionsBox(
}) | rpl::to_empty, }) | rpl::to_empty,
rpl::never<>(), rpl::never<>(),
&button->lifetime()); &button->lifetime());
state->toggles.emplace(entry.id.emoji(), button); state->toggles.emplace(entry.id, button);
button->toggleOn(rpl::single( button->toggleOn(rpl::single(active(entry.id)));
active(entry)
) | rpl::then(
state->forceToggleAll.events()
));
button->toggledChanges(
) | rpl::start_with_next([=](bool toggled) {
if (toggled) {
state->anyToggled = true;
} else if (collect().empty()) {
state->anyToggled = false;
}
}, button->lifetime());
}; };
for (const auto &entry : list) { for (const auto &entry : list) {
add(entry); add(entry);
} }
for (const auto &id : allowed.some) {
if (const auto customId = id.custom()) {
// Some possible forward compatibility.
const auto button = Settings::AddButton(
reactions,
rpl::single(u"Custom reaction"_q),
st::manageGroupButton.button);
AddReactionCustomIcon(
button,
button->sizeValue(
) | rpl::map([=](const QSize &size) {
return QPoint(
st::editPeerReactionsIconLeft,
(size.height() - iconHeight) / 2);
}),
iconHeight,
navigation->parentController(),
customId,
rpl::never<>(),
&button->lifetime());
state->toggles.emplace(id, button);
button->toggleOn(rpl::single(true));
}
}
box->addButton(tr::lng_settings_save(), [=] { box->addButton(tr::lng_settings_save(), [=] {
const auto ids = collect(); const auto result = collect();
box->closeBox(); box->closeBox();
callback(ids, false); callback(result);
}); });
box->addButton(tr::lng_cancel(), [=] { box->addButton(tr::lng_cancel(), [=] {
box->closeBox(); box->closeBox();
@ -148,16 +195,18 @@ void EditAllowedReactionsBox(
void SaveAllowedReactions( void SaveAllowedReactions(
not_null<PeerData*> peer, not_null<PeerData*> peer,
const std::vector<QString> &allowed, const Data::AllowedReactions &allowed) {
bool all) { auto ids = allowed.some | ranges::views::transform(
auto ids = allowed | ranges::views::transform([=](QString value) { Data::ReactionToMTP
return MTP_reactionEmoji(MTP_string(value)); ) | ranges::to<QVector<MTPReaction>>;
}) | ranges::to<QVector<MTPReaction>>;
const auto updated = all using Type = Data::AllowedReactionsType;
? MTP_chatReactionsAll(MTP_flags(peer->isBroadcast() const auto updated = (allowed.type != Type::Some)
? MTP_chatReactionsAll(MTP_flags((allowed.type == Type::Default)
? MTPDchatReactionsAll::Flag(0) ? MTPDchatReactionsAll::Flag(0)
: MTPDchatReactionsAll::Flag::f_allow_custom)) : MTPDchatReactionsAll::Flag::f_allow_custom))
: allowed.some.empty()
? MTP_chatReactionsNone()
: MTP_chatReactionsSome(MTP_vector<MTPReaction>(ids)); : MTP_chatReactionsSome(MTP_vector<MTPReaction>(ids));
peer->session().api().request(MTPmessages_SetChatAvailableReactions( peer->session().api().request(MTPmessages_SetChatAvailableReactions(
peer->input, peer->input,

View file

@ -18,14 +18,18 @@ namespace Ui {
class GenericBox; class GenericBox;
} // namespace Ui } // namespace Ui
namespace Window {
class SessionNavigation;
} // namespace Window
void EditAllowedReactionsBox( void EditAllowedReactionsBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Window::SessionNavigation*> navigation,
bool isGroup, bool isGroup,
const std::vector<Data::Reaction> &list, const std::vector<Data::Reaction> &list,
const Data::AllowedReactions &allowed, const Data::AllowedReactions &allowed,
Fn<void(const std::vector<QString> &, bool all)> callback); Fn<void(const Data::AllowedReactions &)> callback);
void SaveAllowedReactions( void SaveAllowedReactions(
not_null<PeerData*> peer, not_null<PeerData*> peer,
const std::vector<QString> &allowed, const Data::AllowedReactions &allowed);
bool all);

View file

@ -251,6 +251,73 @@ void AddMessage(
}, widget->lifetime()); }, widget->lifetime());
} }
not_null<Ui::RpWidget*> AddReactionIconWrap(
not_null<Ui::RpWidget*> parent,
rpl::producer<QPoint> iconPositionValue,
int iconSize,
Fn<void(not_null<QWidget*>, QPainter&)> paintCallback,
rpl::producer<> &&destroys,
not_null<rpl::lifetime*> stateLifetime) {
struct State {
base::unique_qptr<Ui::RpWidget> widget;
Ui::Animations::Simple finalAnimation;
};
const auto state = stateLifetime->make_state<State>();
state->widget = base::make_unique_q<Ui::RpWidget>(parent);
const auto widget = state->widget.get();
widget->resize(iconSize, iconSize);
widget->setAttribute(Qt::WA_TransparentForMouseEvents);
std::move(
iconPositionValue
) | rpl::start_with_next([=](const QPoint &point) {
widget->moveToLeft(point.x(), point.y());
}, widget->lifetime());
const auto update = crl::guard(widget, [=] { widget->update(); });
widget->paintRequest(
) | rpl::start_with_next([=] {
auto p = QPainter(widget);
if (state->finalAnimation.animating()) {
const auto progress = 1. - state->finalAnimation.value(0.);
const auto size = widget->size();
const auto scaledSize = size * progress;
const auto scaledCenter = QPoint(
(size.width() - scaledSize.width()) / 2.,
(size.height() - scaledSize.height()) / 2.);
p.setOpacity(progress);
p.translate(scaledCenter);
p.scale(progress, progress);
}
paintCallback(widget, p);
}, widget->lifetime());
std::move(
destroys
) | rpl::take(1) | rpl::start_with_next([=, from = 0., to = 1.] {
state->finalAnimation.start(
[=](float64 value) {
update();
if (value == to) {
stateLifetime->destroy();
}
},
from,
to,
st::defaultPopupMenu.showDuration);
}, widget->lifetime());
widget->raise();
widget->show();
return widget;
}
} // namespace } // namespace
void AddReactionAnimatedIcon( void AddReactionAnimatedIcon(
@ -270,14 +337,8 @@ void AddReactionAnimatedIcon(
Entry select; Entry select;
bool appearAnimated = false; bool appearAnimated = false;
rpl::lifetime loadingLifetime; rpl::lifetime loadingLifetime;
base::unique_qptr<Ui::RpWidget> widget;
Ui::Animations::Simple finalAnimation;
}; };
const auto state = stateLifetime->make_state<State>(); const auto state = stateLifetime->make_state<State>();
state->widget = base::make_unique_q<Ui::RpWidget>(parent);
state->appear.media = reaction.appearAnimation->createMediaView(); state->appear.media = reaction.appearAnimation->createMediaView();
state->select.media = reaction.selectAnimation->createMediaView(); state->select.media = reaction.selectAnimation->createMediaView();
@ -303,34 +364,7 @@ void AddReactionAnimatedIcon(
} }
}, state->loadingLifetime); }, state->loadingLifetime);
const auto widget = state->widget.get(); const auto paintCallback = [=](not_null<QWidget*> widget, QPainter &p) {
widget->resize(iconSize, iconSize);
widget->setAttribute(Qt::WA_TransparentForMouseEvents);
std::move(
iconPositionValue
) | rpl::start_with_next([=](const QPoint &point) {
widget->moveToLeft(point.x(), point.y());
}, widget->lifetime());
const auto update = crl::guard(widget, [=] { widget->update(); });
widget->paintRequest(
) | rpl::start_with_next([=] {
Painter p(widget);
if (state->finalAnimation.animating()) {
const auto progress = 1. - state->finalAnimation.value(0.);
const auto size = widget->size();
const auto scaledSize = size * progress;
const auto scaledCenter = QPoint(
(size.width() - scaledSize.width()) / 2.,
(size.height() - scaledSize.height()) / 2.);
p.setOpacity(progress);
p.translate(scaledCenter);
p.scale(progress, progress);
}
const auto paintFrame = [&](not_null<Ui::AnimatedIcon*> animation) { const auto paintFrame = [&](not_null<Ui::AnimatedIcon*> animation) {
const auto frame = animation->frame(); const auto frame = animation->frame();
p.drawImage( p.drawImage(
@ -345,41 +379,72 @@ void AddReactionAnimatedIcon(
const auto appear = state->appear.icon.get(); const auto appear = state->appear.icon.get();
if (appear && !state->appearAnimated) { if (appear && !state->appearAnimated) {
state->appearAnimated = true; state->appearAnimated = true;
appear->animate(update); appear->animate(crl::guard(widget, [=] { widget->update(); }));
} }
if (appear && appear->animating()) { if (appear && appear->animating()) {
paintFrame(appear); paintFrame(appear);
} else if (const auto select = state->select.icon.get()) { } else if (const auto select = state->select.icon.get()) {
paintFrame(select); paintFrame(select);
} }
}, widget->lifetime());
};
const auto widget = AddReactionIconWrap(
parent,
std::move(iconPositionValue),
iconSize,
paintCallback,
std::move(destroys),
stateLifetime);
std::move( std::move(
selects selects
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
const auto select = state->select.icon.get(); const auto select = state->select.icon.get();
if (select && !select->animating()) { if (select && !select->animating()) {
select->animate(update); select->animate(crl::guard(widget, [=] { widget->update(); }));
} }
}, widget->lifetime()); }, widget->lifetime());
}
std::move( void AddReactionCustomIcon(
destroys not_null<Ui::RpWidget*> parent,
) | rpl::take(1) | rpl::start_with_next([=, from = 0., to = 1.] { rpl::producer<QPoint> iconPositionValue,
state->finalAnimation.start( int iconSize,
[=](float64 value) { not_null<Window::SessionController*> controller,
update(); DocumentId customId,
if (value == to) { rpl::producer<> &&destroys,
stateLifetime->destroy(); not_null<rpl::lifetime*> stateLifetime) {
} struct State {
}, std::unique_ptr<Ui::Text::CustomEmoji> custom;
from, Fn<void()> repaint;
to, };
st::defaultPopupMenu.showDuration); const auto state = stateLifetime->make_state<State>();
}, widget->lifetime()); static constexpr auto tag = Data::CustomEmojiManager::SizeTag::Large;
state->custom = controller->session().data().customEmojiManager().create(
customId,
[=] { state->repaint(); },
tag);
widget->raise(); const auto paintCallback = [=](not_null<QWidget*> widget, QPainter &p) {
widget->show(); const auto ratio = style::DevicePixelRatio();
const auto size = Data::FrameSizeFromTag(tag) / ratio;
state->custom->paint(p, {
.preview = st::windowBgRipple->c,
.now = crl::now(),
.position = QPoint(
(widget->width() - size) / 2,
(widget->height() - size) / 2),
.paused = controller->isGifPausedAtLeastFor(
Window::GifPauseReason::Layer),
});
};
const auto widget = AddReactionIconWrap(
parent,
std::move(iconPositionValue),
iconSize,
paintCallback,
std::move(destroys),
stateLifetime);
} }
void ReactionsSettingsBox( void ReactionsSettingsBox(

View file

@ -28,6 +28,14 @@ void AddReactionAnimatedIcon(
rpl::producer<> &&selects, rpl::producer<> &&selects,
rpl::producer<> &&destroys, rpl::producer<> &&destroys,
not_null<rpl::lifetime*> stateLifetime); not_null<rpl::lifetime*> stateLifetime);
void AddReactionCustomIcon(
not_null<Ui::RpWidget*> parent,
rpl::producer<QPoint> iconPositionValue,
int iconSize,
not_null<Window::SessionController*> controller,
DocumentId customId,
rpl::producer<> &&destroys,
not_null<rpl::lifetime*> stateLifetime);
void ReactionsSettingsBox( void ReactionsSettingsBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,

View file

@ -140,6 +140,9 @@ PossibleItemReactionsRef LookupPossibleReactions(
if ((allowed.type == AllowedReactionsType::Some) if ((allowed.type == AllowedReactionsType::Some)
&& !ranges::contains(allowed.some, id)) { && !ranges::contains(allowed.some, id)) {
return false; return false;
} else if (id.custom()
&& allowed.type == AllowedReactionsType::Default) {
return false;
} else if (reaction.premium } else if (reaction.premium
&& !session->premium() && !session->premium()
&& !ranges::contains(all, id, &MessageReaction::id)) { && !ranges::contains(all, id, &MessageReaction::id)) {

View file

@ -455,23 +455,6 @@ rpl::producer<int> FullReactionsCountValue(
}) | rpl::distinct_until_changed(); }) | rpl::distinct_until_changed();
} }
rpl::producer<int> AllowedReactionsCountValue(not_null<PeerData*> peer) {
if (peer->isUser()) {
return FullReactionsCountValue(&peer->session());
}
return rpl::combine(
FullReactionsCountValue(&peer->session()),
peer->session().changes().peerFlagsValue(
peer,
UpdateFlag::Reactions)
) | rpl::map([=](int full, const auto&) {
const auto &allowed = Data::PeerAllowedReactions(peer);
return (allowed.type == Data::AllowedReactionsType::Some)
? int(allowed.some.size())
: full;
});
}
template <typename Flag, typename Peer> template <typename Flag, typename Peer>
rpl::producer<Badge> BadgeValueFromFlags(Peer peer) { rpl::producer<Badge> BadgeValueFromFlags(Peer peer) {
return rpl::combine( return rpl::combine(

View file

@ -89,8 +89,6 @@ rpl::producer<not_null<PeerData*>> MigratedOrMeValue(
not_null<PeerData*> peer); not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<int> FullReactionsCountValue( [[nodiscard]] rpl::producer<int> FullReactionsCountValue(
not_null<Main::Session*> peer); not_null<Main::Session*> peer);
[[nodiscard]] rpl::producer<int> AllowedReactionsCountValue(
not_null<PeerData*> peer);
enum class Badge; enum class Badge;
[[nodiscard]] rpl::producer<Badge> BadgeValue(not_null<PeerData*> peer); [[nodiscard]] rpl::producer<Badge> BadgeValue(not_null<PeerData*> peer);