mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 07:37:11 +02:00
Implement improved allowed reactions editing.
This commit is contained in:
parent
021e275336
commit
5e81c65ea6
9 changed files with 291 additions and 163 deletions
|
@ -1195,13 +1195,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_manage_peer_permissions" = "Permissions";
|
||||
"lng_manage_peer_invite_links" = "Invite links";
|
||||
"lng_manage_peer_reactions" = "Reactions";
|
||||
"lng_manage_peer_reactions_on" = "All";
|
||||
"lng_manage_peer_reactions_off" = "Off";
|
||||
"lng_manage_peer_requests" = "Member Requests";
|
||||
"lng_manage_peer_requests_channel" = "Subscriber Requests";
|
||||
|
||||
"lng_manage_peer_reactions_enable" = "Enable Reactions";
|
||||
"lng_manage_peer_reactions_about" = "Allow members to react to group messages.";
|
||||
"lng_manage_peer_reactions_about_channel" = "Allow subscribers to react to channel posts.";
|
||||
"lng_manage_peer_reactions_all" = "All reactions";
|
||||
"lng_manage_peer_reactions_all_about" = "Members of the group can use any emoji as reactions to messages.";
|
||||
"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_group_type" = "Group type";
|
||||
|
|
|
@ -988,22 +988,31 @@ void Controller::fillManageSection() {
|
|||
|
||||
if (canEditReactions()) {
|
||||
const auto session = &_peer->session();
|
||||
auto reactionsCount = Info::Profile::MigratedOrMeValue(
|
||||
auto allowedReactions = Info::Profile::MigratedOrMeValue(
|
||||
_peer
|
||||
) | rpl::map(
|
||||
Info::Profile::AllowedReactionsCountValue
|
||||
) | rpl::flatten_latest();
|
||||
auto fullCount = Info::Profile::FullReactionsCountValue(session);
|
||||
) | rpl::map([=](not_null<PeerData*> peer) {
|
||||
return peer->session().changes().peerFlagsValue(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::Reactions
|
||||
) | rpl::map([=] {
|
||||
return Data::PeerAllowedReactions(peer);
|
||||
});
|
||||
}) | rpl::flatten_latest();
|
||||
auto label = rpl::combine(
|
||||
std::move(reactionsCount),
|
||||
std::move(fullCount)
|
||||
) | rpl::map([=](int allowed, int total) {
|
||||
return allowed
|
||||
? QString::number(allowed) + " / " + QString::number(total)
|
||||
std::move(allowedReactions),
|
||||
Info::Profile::FullReactionsCountValue(session)
|
||||
) | rpl::map([=](const Data::AllowedReactions &allowed, int total) {
|
||||
const auto some = int(allowed.some.size());
|
||||
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);
|
||||
});
|
||||
const auto done = [=](const std::vector<QString> &chosen, bool all) {
|
||||
SaveAllowedReactions(_peer, chosen, all);
|
||||
const auto done = [=](const Data::AllowedReactions &chosen) {
|
||||
SaveAllowedReactions(_peer, chosen);
|
||||
};
|
||||
AddButtonWithCount(
|
||||
_controls.buttonsLayout,
|
||||
|
@ -1012,6 +1021,7 @@ void Controller::fillManageSection() {
|
|||
[=] {
|
||||
_navigation->parentController()->show(Box(
|
||||
EditAllowedReactionsBox,
|
||||
_navigation,
|
||||
!_peer->isBroadcast(),
|
||||
session->data().reactions().list(
|
||||
Data::Reactions::Type::Active),
|
||||
|
|
|
@ -18,34 +18,57 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
void EditAllowedReactionsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
bool isGroup,
|
||||
const std::vector<Data::Reaction> &list,
|
||||
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;
|
||||
box->setTitle(tr::lng_manage_peer_reactions());
|
||||
|
||||
enum class Option {
|
||||
All,
|
||||
Some,
|
||||
None,
|
||||
};
|
||||
struct State {
|
||||
base::flat_map<QString, not_null<Ui::SettingsButton*>> toggles;
|
||||
rpl::variable<bool> anyToggled;
|
||||
rpl::event_stream<bool> forceToggleAll;
|
||||
base::flat_map<ReactionId, not_null<Ui::SettingsButton*>> toggles;
|
||||
rpl::variable<Option> option;
|
||||
};
|
||||
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 = [=] {
|
||||
auto result = std::vector<QString>();
|
||||
result.reserve(state->toggles.size());
|
||||
for (const auto &[emoji, button] : state->toggles) {
|
||||
if (button->toggled()) {
|
||||
result.push_back(emoji);
|
||||
auto result = AllowedReactions{
|
||||
.type = (state->option.current() != Option::All
|
||||
? AllowedReactionsType::Some
|
||||
: isGroup
|
||||
? 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;
|
||||
|
@ -53,52 +76,64 @@ void EditAllowedReactionsBox(
|
|||
|
||||
const auto container = box->verticalLayout();
|
||||
|
||||
const auto enabled = Settings::AddButton(
|
||||
container,
|
||||
tr::lng_manage_peer_reactions_enable(),
|
||||
st::manageGroupButton.button);
|
||||
if (!list.empty()) {
|
||||
AddReactionAnimatedIcon(
|
||||
enabled,
|
||||
enabled->sizeValue(
|
||||
) | rpl::map([=](const QSize &size) {
|
||||
return QPoint(
|
||||
st::manageGroupButton.iconPosition.x(),
|
||||
(size.height() - iconHeight) / 2);
|
||||
}),
|
||||
iconHeight,
|
||||
list.front(),
|
||||
rpl::never<>(),
|
||||
rpl::never<>(),
|
||||
&enabled->lifetime());
|
||||
}
|
||||
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 group = std::make_shared<Ui::RadioenumGroup<Option>>(
|
||||
state->option.current());
|
||||
group->setChangedCallback([=](Option value) {
|
||||
state->option = value;
|
||||
});
|
||||
const auto addOption = [&](Option option, const QString &text) {
|
||||
container->add(
|
||||
object_ptr<Ui::Radioenum<Option>>(
|
||||
container,
|
||||
group,
|
||||
option,
|
||||
text,
|
||||
st::settingsSendType),
|
||||
st::settingsSendTypePadding);
|
||||
};
|
||||
addOption(Option::All, tr::lng_manage_peer_reactions_all(tr::now));
|
||||
addOption(Option::Some, tr::lng_manage_peer_reactions_some(tr::now));
|
||||
addOption(Option::None, tr::lng_manage_peer_reactions_none(tr::now));
|
||||
|
||||
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::AddDividerText(
|
||||
container,
|
||||
(isGroup
|
||||
? tr::lng_manage_peer_reactions_about
|
||||
: tr::lng_manage_peer_reactions_about_channel)());
|
||||
state->option.value() | rpl::map(about) | rpl::flatten_latest());
|
||||
|
||||
Settings::AddSkip(container);
|
||||
Settings::AddSubsectionTitle(
|
||||
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(
|
||||
const auto wrap = container->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
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),
|
||||
st::manageGroupButton.button);
|
||||
AddReactionAnimatedIcon(
|
||||
|
@ -117,29 +152,41 @@ void EditAllowedReactionsBox(
|
|||
}) | rpl::to_empty,
|
||||
rpl::never<>(),
|
||||
&button->lifetime());
|
||||
state->toggles.emplace(entry.id.emoji(), button);
|
||||
button->toggleOn(rpl::single(
|
||||
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());
|
||||
state->toggles.emplace(entry.id, button);
|
||||
button->toggleOn(rpl::single(active(entry.id)));
|
||||
};
|
||||
for (const auto &entry : list) {
|
||||
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(), [=] {
|
||||
const auto ids = collect();
|
||||
const auto result = collect();
|
||||
box->closeBox();
|
||||
callback(ids, false);
|
||||
callback(result);
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] {
|
||||
box->closeBox();
|
||||
|
@ -148,16 +195,18 @@ void EditAllowedReactionsBox(
|
|||
|
||||
void SaveAllowedReactions(
|
||||
not_null<PeerData*> peer,
|
||||
const std::vector<QString> &allowed,
|
||||
bool all) {
|
||||
auto ids = allowed | ranges::views::transform([=](QString value) {
|
||||
return MTP_reactionEmoji(MTP_string(value));
|
||||
}) | ranges::to<QVector<MTPReaction>>;
|
||||
const Data::AllowedReactions &allowed) {
|
||||
auto ids = allowed.some | ranges::views::transform(
|
||||
Data::ReactionToMTP
|
||||
) | ranges::to<QVector<MTPReaction>>;
|
||||
|
||||
const auto updated = all
|
||||
? MTP_chatReactionsAll(MTP_flags(peer->isBroadcast()
|
||||
using Type = Data::AllowedReactionsType;
|
||||
const auto updated = (allowed.type != Type::Some)
|
||||
? MTP_chatReactionsAll(MTP_flags((allowed.type == Type::Default)
|
||||
? MTPDchatReactionsAll::Flag(0)
|
||||
: MTPDchatReactionsAll::Flag::f_allow_custom))
|
||||
: allowed.some.empty()
|
||||
? MTP_chatReactionsNone()
|
||||
: MTP_chatReactionsSome(MTP_vector<MTPReaction>(ids));
|
||||
peer->session().api().request(MTPmessages_SetChatAvailableReactions(
|
||||
peer->input,
|
||||
|
|
|
@ -18,14 +18,18 @@ namespace Ui {
|
|||
class GenericBox;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
class SessionNavigation;
|
||||
} // namespace Window
|
||||
|
||||
void EditAllowedReactionsBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
bool isGroup,
|
||||
const std::vector<Data::Reaction> &list,
|
||||
const Data::AllowedReactions &allowed,
|
||||
Fn<void(const std::vector<QString> &, bool all)> callback);
|
||||
Fn<void(const Data::AllowedReactions &)> callback);
|
||||
|
||||
void SaveAllowedReactions(
|
||||
not_null<PeerData*> peer,
|
||||
const std::vector<QString> &allowed,
|
||||
bool all);
|
||||
const Data::AllowedReactions &allowed);
|
||||
|
|
|
@ -251,6 +251,73 @@ void AddMessage(
|
|||
}, 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
|
||||
|
||||
void AddReactionAnimatedIcon(
|
||||
|
@ -270,14 +337,8 @@ void AddReactionAnimatedIcon(
|
|||
Entry select;
|
||||
bool appearAnimated = false;
|
||||
rpl::lifetime loadingLifetime;
|
||||
|
||||
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);
|
||||
|
||||
state->appear.media = reaction.appearAnimation->createMediaView();
|
||||
state->select.media = reaction.selectAnimation->createMediaView();
|
||||
|
@ -303,34 +364,7 @@ void AddReactionAnimatedIcon(
|
|||
}
|
||||
}, state->loadingLifetime);
|
||||
|
||||
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([=] {
|
||||
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 paintCallback = [=](not_null<QWidget*> widget, QPainter &p) {
|
||||
const auto paintFrame = [&](not_null<Ui::AnimatedIcon*> animation) {
|
||||
const auto frame = animation->frame();
|
||||
p.drawImage(
|
||||
|
@ -345,41 +379,72 @@ void AddReactionAnimatedIcon(
|
|||
const auto appear = state->appear.icon.get();
|
||||
if (appear && !state->appearAnimated) {
|
||||
state->appearAnimated = true;
|
||||
appear->animate(update);
|
||||
appear->animate(crl::guard(widget, [=] { widget->update(); }));
|
||||
}
|
||||
if (appear && appear->animating()) {
|
||||
paintFrame(appear);
|
||||
} else if (const auto select = state->select.icon.get()) {
|
||||
paintFrame(select);
|
||||
}
|
||||
}, widget->lifetime());
|
||||
|
||||
};
|
||||
const auto widget = AddReactionIconWrap(
|
||||
parent,
|
||||
std::move(iconPositionValue),
|
||||
iconSize,
|
||||
paintCallback,
|
||||
std::move(destroys),
|
||||
stateLifetime);
|
||||
|
||||
std::move(
|
||||
selects
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto select = state->select.icon.get();
|
||||
if (select && !select->animating()) {
|
||||
select->animate(update);
|
||||
select->animate(crl::guard(widget, [=] { widget->update(); }));
|
||||
}
|
||||
}, 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());
|
||||
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) {
|
||||
struct State {
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> custom;
|
||||
Fn<void()> repaint;
|
||||
};
|
||||
const auto state = stateLifetime->make_state<State>();
|
||||
static constexpr auto tag = Data::CustomEmojiManager::SizeTag::Large;
|
||||
state->custom = controller->session().data().customEmojiManager().create(
|
||||
customId,
|
||||
[=] { state->repaint(); },
|
||||
tag);
|
||||
|
||||
widget->raise();
|
||||
widget->show();
|
||||
const auto paintCallback = [=](not_null<QWidget*> widget, QPainter &p) {
|
||||
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(
|
||||
|
|
|
@ -28,6 +28,14 @@ void AddReactionAnimatedIcon(
|
|||
rpl::producer<> &&selects,
|
||||
rpl::producer<> &&destroys,
|
||||
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(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
|
|
|
@ -140,6 +140,9 @@ PossibleItemReactionsRef LookupPossibleReactions(
|
|||
if ((allowed.type == AllowedReactionsType::Some)
|
||||
&& !ranges::contains(allowed.some, id)) {
|
||||
return false;
|
||||
} else if (id.custom()
|
||||
&& allowed.type == AllowedReactionsType::Default) {
|
||||
return false;
|
||||
} else if (reaction.premium
|
||||
&& !session->premium()
|
||||
&& !ranges::contains(all, id, &MessageReaction::id)) {
|
||||
|
|
|
@ -455,23 +455,6 @@ rpl::producer<int> FullReactionsCountValue(
|
|||
}) | 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>
|
||||
rpl::producer<Badge> BadgeValueFromFlags(Peer peer) {
|
||||
return rpl::combine(
|
||||
|
|
|
@ -89,8 +89,6 @@ rpl::producer<not_null<PeerData*>> MigratedOrMeValue(
|
|||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] rpl::producer<int> FullReactionsCountValue(
|
||||
not_null<Main::Session*> peer);
|
||||
[[nodiscard]] rpl::producer<int> AllowedReactionsCountValue(
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
enum class Badge;
|
||||
[[nodiscard]] rpl::producer<Badge> BadgeValue(not_null<PeerData*> peer);
|
||||
|
|
Loading…
Add table
Reference in a new issue