mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Add reaction selector widget.
This commit is contained in:
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "calls/group/calls_group_message_field.h"
|
||||
|
||||
#include "base/event_filter.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "calls/group/calls_group_messages.h"
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
@@ -18,6 +19,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/view/reactions/history_view_reactions_selector.h"
|
||||
#include "history/view/reactions/history_view_reactions_strip.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
@@ -39,8 +43,272 @@ namespace {
|
||||
constexpr auto kWarnLimit = 24;
|
||||
constexpr auto kErrorLimit = 99;
|
||||
|
||||
using Chosen = HistoryView::Reactions::ChosenReaction;
|
||||
|
||||
} // namespace
|
||||
|
||||
class ReactionPanel final {
|
||||
public:
|
||||
ReactionPanel(
|
||||
not_null<QWidget*> outer,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
rpl::producer<QRect> fieldGeometry);
|
||||
~ReactionPanel();
|
||||
|
||||
[[nodiscard]] rpl::producer<Chosen> chosen() const;
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
void raise();
|
||||
void hideIfCollapsed();
|
||||
void collapse();
|
||||
|
||||
private:
|
||||
struct Hiding;
|
||||
|
||||
void create();
|
||||
void updateShowState();
|
||||
void fadeOutSelector();
|
||||
void startAnimation();
|
||||
|
||||
const not_null<QWidget*> _outer;
|
||||
const std::shared_ptr<ChatHelpers::Show> _show;
|
||||
std::unique_ptr<Ui::RpWidget> _parent;
|
||||
std::unique_ptr<HistoryView::Reactions::Selector> _selector;
|
||||
std::vector<std::unique_ptr<Hiding>> _hiding;
|
||||
rpl::event_stream<Chosen> _chosen;
|
||||
Ui::Animations::Simple _showing;
|
||||
rpl::variable<float64> _shownValue;
|
||||
rpl::variable<QRect> _fieldGeometry;
|
||||
rpl::variable<bool> _expanded;
|
||||
rpl::variable<bool> _shown = false;
|
||||
|
||||
};
|
||||
|
||||
struct ReactionPanel::Hiding {
|
||||
explicit Hiding(not_null<QWidget*> parent) : widget(parent) {
|
||||
}
|
||||
|
||||
Ui::RpWidget widget;
|
||||
Ui::Animations::Simple animation;
|
||||
QImage frame;
|
||||
};
|
||||
|
||||
ReactionPanel::ReactionPanel(
|
||||
not_null<QWidget*> outer,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
rpl::producer<QRect> fieldGeometry)
|
||||
: _outer(outer)
|
||||
, _show(std::move(show))
|
||||
, _fieldGeometry(std::move(fieldGeometry)) {
|
||||
}
|
||||
|
||||
ReactionPanel::~ReactionPanel() = default;
|
||||
|
||||
auto ReactionPanel::chosen() const -> rpl::producer<Chosen> {
|
||||
return _chosen.events();
|
||||
}
|
||||
|
||||
void ReactionPanel::show() {
|
||||
if (_shown.current()) {
|
||||
return;
|
||||
}
|
||||
create();
|
||||
if (!_selector) {
|
||||
return;
|
||||
}
|
||||
const auto duration = st::defaultPanelAnimation.heightDuration
|
||||
* st::defaultPopupMenu.showDuration;
|
||||
_shown = true;
|
||||
_showing.start([=] { updateShowState(); }, 0., 1., duration);
|
||||
updateShowState();
|
||||
_parent->show();
|
||||
}
|
||||
|
||||
void ReactionPanel::hide() {
|
||||
if (!_selector) {
|
||||
return;
|
||||
}
|
||||
_selector->beforeDestroy();
|
||||
if (!anim::Disabled()) {
|
||||
fadeOutSelector();
|
||||
}
|
||||
_shown = false;
|
||||
_expanded = false;
|
||||
_showing.stop();
|
||||
_selector = nullptr;
|
||||
_parent = nullptr;
|
||||
}
|
||||
|
||||
void ReactionPanel::raise() {
|
||||
if (_parent) {
|
||||
_parent->raise();
|
||||
}
|
||||
}
|
||||
|
||||
void ReactionPanel::hideIfCollapsed() {
|
||||
if (!_expanded.current()) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
void ReactionPanel::collapse() {
|
||||
if (_expanded.current()) {
|
||||
hide();
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
void ReactionPanel::create() {
|
||||
auto reactions = Data::LookupPossibleReactions(&_show->session());
|
||||
if (reactions.recent.empty()) {
|
||||
return;
|
||||
}
|
||||
_parent = std::make_unique<Ui::RpWidget>(_outer);
|
||||
_parent->show();
|
||||
|
||||
_parent->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::MouseButtonPress) {
|
||||
const auto event = static_cast<QMouseEvent*>(e.get());
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (!_selector
|
||||
|| !_selector->geometry().contains(event->pos())) {
|
||||
collapse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, _parent->lifetime());
|
||||
|
||||
_selector = std::make_unique<HistoryView::Reactions::Selector>(
|
||||
_parent.get(),
|
||||
st::storiesReactionsPan,
|
||||
_show,
|
||||
std::move(reactions),
|
||||
TextWithEntities(),
|
||||
[=](bool fast) { hide(); },
|
||||
nullptr, // iconFactory
|
||||
nullptr, // paused
|
||||
true);
|
||||
|
||||
_selector->chosen(
|
||||
) | rpl::start_with_next([=](Chosen reaction) {
|
||||
if (reaction.id.custom() && !_show->session().premium()) {
|
||||
ShowPremiumPreviewBox(
|
||||
_show,
|
||||
PremiumFeature::AnimatedEmoji);
|
||||
} else {
|
||||
_chosen.fire(std::move(reaction));
|
||||
hide();
|
||||
}
|
||||
}, _selector->lifetime());
|
||||
|
||||
const auto desiredWidth = st::storiesReactionsWidth;
|
||||
const auto maxWidth = desiredWidth * 2;
|
||||
const auto width = _selector->countWidth(desiredWidth, maxWidth);
|
||||
const auto margins = _selector->marginsForShadow();
|
||||
const auto categoriesTop = _selector->extendTopForCategoriesAndAbout(
|
||||
width);
|
||||
const auto full = margins.left() + width + margins.right();
|
||||
|
||||
_shownValue = 0.;
|
||||
rpl::combine(
|
||||
_fieldGeometry.value(),
|
||||
_shownValue.value(),
|
||||
_expanded.value()
|
||||
) | rpl::start_with_next([=](QRect field, float64 shown, bool expanded) {
|
||||
const auto width = margins.left()
|
||||
+ _selector->countAppearedWidth(shown)
|
||||
+ margins.right();
|
||||
const auto available = field.y();
|
||||
const auto min = st::storiesReactionsBottomSkip
|
||||
+ st::reactStripHeight;
|
||||
const auto max = min
|
||||
+ margins.top()
|
||||
+ categoriesTop
|
||||
+ st::storiesReactionsAddedTop;
|
||||
const auto height = expanded ? std::min(available, max) : min;
|
||||
const auto top = field.y() - height;
|
||||
const auto shift = (width / 2);
|
||||
const auto right = (field.x() + field.width() / 2 + shift);
|
||||
_parent->setGeometry(QRect((right - width), top, full, height));
|
||||
const auto innerTop = height
|
||||
- st::storiesReactionsBottomSkip
|
||||
- st::reactStripHeight;
|
||||
const auto maxAdded = innerTop - margins.top() - categoriesTop;
|
||||
const auto added = std::min(maxAdded, st::storiesReactionsAddedTop);
|
||||
_selector->setSpecialExpandTopSkip(added);
|
||||
_selector->initGeometry(innerTop);
|
||||
}, _selector->lifetime());
|
||||
|
||||
_selector->willExpand(
|
||||
) | rpl::start_with_next([=] {
|
||||
_expanded = true;
|
||||
|
||||
const auto raw = _parent.get();
|
||||
base::install_event_filter(raw, qApp, [=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::MouseButtonPress) {
|
||||
const auto event = static_cast<QMouseEvent*>(e.get());
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (!_selector
|
||||
|| !_selector->geometry().contains(
|
||||
_parent->mapFromGlobal(event->globalPos()))) {
|
||||
collapse();
|
||||
}
|
||||
}
|
||||
}
|
||||
return base::EventFilterResult::Continue;
|
||||
});
|
||||
}, _selector->lifetime());
|
||||
|
||||
_selector->escapes() | rpl::start_with_next([=] {
|
||||
collapse();
|
||||
}, _selector->lifetime());
|
||||
}
|
||||
|
||||
void ReactionPanel::fadeOutSelector() {
|
||||
const auto geometry = Ui::MapFrom(
|
||||
_outer,
|
||||
_parent.get(),
|
||||
_selector->geometry());
|
||||
_hiding.push_back(std::make_unique<Hiding>(_outer));
|
||||
const auto raw = _hiding.back().get();
|
||||
raw->frame = Ui::GrabWidgetToImage(_selector.get());
|
||||
raw->widget.setGeometry(geometry);
|
||||
raw->widget.show();
|
||||
raw->widget.paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (const auto opacity = raw->animation.value(0.)) {
|
||||
auto p = QPainter(&raw->widget);
|
||||
p.setOpacity(opacity);
|
||||
p.drawImage(0, 0, raw->frame);
|
||||
}
|
||||
}, raw->widget.lifetime());
|
||||
Ui::PostponeCall(&raw->widget, [=] {
|
||||
raw->animation.start([=] {
|
||||
if (raw->animation.animating()) {
|
||||
raw->widget.update();
|
||||
} else {
|
||||
const auto i = ranges::find(
|
||||
_hiding,
|
||||
raw,
|
||||
&std::unique_ptr<Hiding>::get);
|
||||
if (i != end(_hiding)) {
|
||||
_hiding.erase(i);
|
||||
}
|
||||
}
|
||||
}, 1., 0., st::slideWrapDuration);
|
||||
});
|
||||
}
|
||||
|
||||
void ReactionPanel::updateShowState() {
|
||||
const auto progress = _showing.value(_shown.current() ? 1. : 0.);
|
||||
const auto opacity = 1.;
|
||||
const auto appearing = _showing.animating();
|
||||
const auto toggling = false;
|
||||
_shownValue = progress;
|
||||
_selector->updateShowState(progress, opacity, appearing, toggling);
|
||||
}
|
||||
|
||||
MessageField::MessageField(
|
||||
not_null<QWidget*> parent,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
@@ -70,11 +338,51 @@ void MessageField::createControls(PeerData *peer) {
|
||||
_field->setDocumentMargin(4.);
|
||||
_field->setAdditionalMargin(style::ConvertScale(4) - 4);
|
||||
|
||||
_reactionPanel = std::make_unique<ReactionPanel>(
|
||||
_parent,
|
||||
_show,
|
||||
_wrap->geometryValue());
|
||||
_fieldFocused = _field->focusedChanges();
|
||||
_fieldEmpty = _field->changes() | rpl::map([field = _field] {
|
||||
return field->getLastText().trimmed().isEmpty();
|
||||
});
|
||||
rpl::combine(
|
||||
_fieldFocused.value(),
|
||||
_fieldEmpty.value()
|
||||
) | rpl::start_with_next([=](bool focused, bool empty) {
|
||||
if (!focused) {
|
||||
_reactionPanel->hideIfCollapsed();
|
||||
} else if (empty) {
|
||||
_reactionPanel->show();
|
||||
} else {
|
||||
_reactionPanel->hide();
|
||||
}
|
||||
}, _field->lifetime());
|
||||
|
||||
_reactionPanel->chosen(
|
||||
) | rpl::start_with_next([=](Chosen reaction) {
|
||||
if (const auto customId = reaction.id.custom()) {
|
||||
const auto document = _show->session().data().document(customId);
|
||||
if (const auto sticker = document->sticker()) {
|
||||
if (const auto alt = sticker->alt; !alt.isEmpty()) {
|
||||
const auto length = int(alt.size());
|
||||
const auto data = Data::SerializeCustomEmojiId(customId);
|
||||
const auto tag = Ui::InputField::CustomEmojiLink(data);
|
||||
_submitted.fire({ alt, { { 0, length, tag } } });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_submitted.fire({ reaction.id.emoji() });
|
||||
}
|
||||
_reactionPanel->hide();
|
||||
}, _field->lifetime());
|
||||
|
||||
const auto show = _show;
|
||||
const auto allow = [=](not_null<DocumentData*> emoji) {
|
||||
return peer
|
||||
? Data::AllowEmojiWithoutPremium(peer, emoji)
|
||||
: show->session().premium();
|
||||
if (peer && Data::AllowEmojiWithoutPremium(peer, emoji)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
InitMessageFieldHandlers({
|
||||
.session = &show->session(),
|
||||
@@ -252,6 +560,8 @@ void MessageField::toggle(bool shown) {
|
||||
} else if (shown) {
|
||||
Assert(_width.current() > 0);
|
||||
Ui::SendPendingMoveResizeEvents(_wrap.get());
|
||||
} else if (Ui::InFocusChain(_field)) {
|
||||
_parent->setFocus();
|
||||
}
|
||||
_shown = shown;
|
||||
if (!anim::Disabled()) {
|
||||
@@ -291,6 +601,9 @@ void MessageField::raise() {
|
||||
if (_cache) {
|
||||
_cache->raise();
|
||||
}
|
||||
if (_reactionPanel) {
|
||||
_reactionPanel->raise();
|
||||
}
|
||||
if (_emojiPanel) {
|
||||
_emojiPanel->raise();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ class RpWidget;
|
||||
|
||||
namespace Calls::Group {
|
||||
|
||||
class ReactionPanel;
|
||||
|
||||
class MessageField final {
|
||||
public:
|
||||
MessageField(
|
||||
@@ -64,6 +66,9 @@ private:
|
||||
Ui::SendButton *_send = nullptr;
|
||||
Ui::EmojiButton *_emojiToggle = nullptr;
|
||||
std::unique_ptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
||||
std::unique_ptr<ReactionPanel> _reactionPanel;
|
||||
rpl::variable<bool> _fieldFocused;
|
||||
rpl::variable<bool> _fieldEmpty = true;
|
||||
|
||||
rpl::variable<int> _width;
|
||||
rpl::variable<int> _height;
|
||||
|
||||
@@ -82,7 +82,6 @@ private:
|
||||
style::complex_color _messageBg;
|
||||
Ui::RoundRect _messageBgRect;
|
||||
|
||||
|
||||
rpl::lifetime _effectsLifetime;
|
||||
|
||||
Ui::Animations::Simple _topFadeAnimation;
|
||||
|
||||
@@ -254,7 +254,7 @@ PossibleItemReactionsRef LookupPossibleReactions(
|
||||
}
|
||||
}
|
||||
if (allowed.paidEnabled
|
||||
&& !added.contains(Data::ReactionId::Paid())) {
|
||||
&& !added.contains(ReactionId::Paid())) {
|
||||
result.recent.push_back(reactions->lookupPaid());
|
||||
}
|
||||
} else {
|
||||
@@ -300,7 +300,7 @@ PossibleItemReactionsRef LookupPossibleReactions(
|
||||
}
|
||||
}
|
||||
if (!item->reactionsAreTags()) {
|
||||
const auto toFront = [&](Data::ReactionId id) {
|
||||
const auto toFront = [&](ReactionId id) {
|
||||
const auto i = ranges::find(result.recent, id, &Reaction::id);
|
||||
if (i != end(result.recent) && i != begin(result.recent)) {
|
||||
std::rotate(begin(result.recent), i, i + 1);
|
||||
@@ -308,12 +308,40 @@ PossibleItemReactionsRef LookupPossibleReactions(
|
||||
};
|
||||
toFront(reactions->favoriteId());
|
||||
if (paidInFront) {
|
||||
toFront(Data::ReactionId::Paid());
|
||||
toFront(ReactionId::Paid());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] PossibleItemReactionsRef LookupPossibleReactions(
|
||||
not_null<Main::Session*> session) {
|
||||
auto result = PossibleItemReactionsRef();
|
||||
const auto reactions = &session->data().reactions();
|
||||
const auto &full = reactions->list(Reactions::Type::Active);
|
||||
const auto &top = reactions->list(Reactions::Type::Top);
|
||||
const auto &recent = reactions->list(Reactions::Type::Recent);
|
||||
const auto premiumPossible = session->premiumPossible();
|
||||
auto added = base::flat_set<ReactionId>();
|
||||
result.recent.reserve(full.size());
|
||||
for (const auto &reaction : ranges::views::concat(top, recent, full)) {
|
||||
if (premiumPossible || !reaction.id.custom()) {
|
||||
if (added.emplace(reaction.id).second) {
|
||||
result.recent.push_back(&reaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.customAllowed = premiumPossible;
|
||||
const auto i = ranges::find(
|
||||
result.recent,
|
||||
reactions->favoriteId(),
|
||||
&Reaction::id);
|
||||
if (i != end(result.recent) && i != begin(result.recent)) {
|
||||
std::rotate(begin(result.recent), i, i + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PossibleItemReactions::PossibleItemReactions(
|
||||
const PossibleItemReactionsRef &other)
|
||||
: recent(other.recent | ranges::views::transform([](const auto &value) {
|
||||
@@ -574,8 +602,8 @@ DocumentData *Reactions::chooseGenericAnimation(
|
||||
const auto i = sticker
|
||||
? ranges::find(
|
||||
_available,
|
||||
::Data::ReactionId{ { sticker->alt } },
|
||||
&::Data::Reaction::id)
|
||||
ReactionId{ { sticker->alt } },
|
||||
&Reaction::id)
|
||||
: end(_available);
|
||||
if (i != end(_available) && i->aroundAnimation) {
|
||||
const auto view = i->aroundAnimation->createMediaView();
|
||||
|
||||
@@ -61,6 +61,8 @@ struct PossibleItemReactions {
|
||||
[[nodiscard]] PossibleItemReactionsRef LookupPossibleReactions(
|
||||
not_null<HistoryItem*> item,
|
||||
bool paidInFront = false);
|
||||
[[nodiscard]] PossibleItemReactionsRef LookupPossibleReactions(
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
struct MyTagInfo {
|
||||
ReactionId id;
|
||||
|
||||
@@ -36,7 +36,14 @@ StickerToast::StickerToast(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<QWidget*> parent,
|
||||
Fn<void()> destroy)
|
||||
: _controller(controller)
|
||||
: StickerToast(controller->uiShow(), parent, std::move(destroy)) {
|
||||
}
|
||||
|
||||
StickerToast::StickerToast(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<QWidget*> parent,
|
||||
Fn<void()> destroy)
|
||||
: _show(std::move(show))
|
||||
, _parent(parent)
|
||||
, _destroy(std::move(destroy)) {
|
||||
}
|
||||
@@ -104,7 +111,7 @@ void StickerToast::requestSet() {
|
||||
Expects(_for != nullptr);
|
||||
|
||||
if (const auto sticker = _for->sticker()) {
|
||||
const auto api = &_controller->session().api();
|
||||
const auto api = &_show->session().api();
|
||||
_setRequestId = api->request(MTPmessages_GetStickerSet(
|
||||
Data::InputStickerSet(sticker->set),
|
||||
MTP_int(0) // hash
|
||||
@@ -112,7 +119,7 @@ void StickerToast::requestSet() {
|
||||
_setRequestId = 0;
|
||||
result.match([&](const MTPDmessages_stickerSet &data) {
|
||||
data.vset().match([&](const MTPDstickerSet &data) {
|
||||
const auto owner = &_controller->session().data();
|
||||
const auto owner = &_show->session().data();
|
||||
showWithTitle(owner->stickers().getSetTitle(data));
|
||||
});
|
||||
}, [&](const MTPDmessages_stickerSetNotModified &) {
|
||||
@@ -125,7 +132,7 @@ void StickerToast::requestSet() {
|
||||
}
|
||||
|
||||
void StickerToast::cancelRequest() {
|
||||
_controller->session().api().request(base::take(_setRequestId)).cancel();
|
||||
_show->session().api().request(base::take(_setRequestId)).cancel();
|
||||
}
|
||||
|
||||
void StickerToast::showWithTitle(const QString &title) {
|
||||
@@ -219,29 +226,28 @@ void StickerToast::showWithTitle(const QString &title) {
|
||||
}
|
||||
button->setClickedCallback([=] {
|
||||
if (toSaved) {
|
||||
_controller->showPeerHistory(
|
||||
_controller->session().userPeerId(),
|
||||
Window::SectionShow::Way::Forward);
|
||||
if (const auto window = _show->resolveWindow()) {
|
||||
window->showPeerHistory(
|
||||
window->session().userPeerId(),
|
||||
Window::SectionShow::Way::Forward);
|
||||
}
|
||||
hideToast();
|
||||
return;
|
||||
} else if (_section == Section::TopicIcon) {
|
||||
Settings::ShowPremium(_controller, u"forum_topic_icon"_q);
|
||||
if (const auto window = _show->resolveWindow()) {
|
||||
Settings::ShowPremium(window, u"forum_topic_icon"_q);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto id = _for->sticker()->set.id;
|
||||
const auto id = _for->sticker()->set;
|
||||
const auto &sets = _for->owner().stickers().sets();
|
||||
const auto i = sets.find(id);
|
||||
const auto i = sets.find(id.id);
|
||||
if (isEmoji
|
||||
&& (i != end(sets))
|
||||
&& (i->second->flags & Data::StickersSetFlag::Installed)) {
|
||||
ShowPremiumPreviewBox(
|
||||
_controller,
|
||||
PremiumFeature::AnimatedEmoji);
|
||||
ShowPremiumPreviewBox(_show, PremiumFeature::AnimatedEmoji);
|
||||
} else {
|
||||
_controller->show(Box<StickerSetBox>(
|
||||
_controller->uiShow(),
|
||||
_for->sticker()->set,
|
||||
setType));
|
||||
_show->show(Box<StickerSetBox>(_show, id, setType));
|
||||
}
|
||||
hideToast();
|
||||
});
|
||||
|
||||
@@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Ui {
|
||||
class Show;
|
||||
class RpWidget;
|
||||
@@ -30,6 +34,10 @@ public:
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<QWidget*> parent,
|
||||
Fn<void()> destroy);
|
||||
StickerToast(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<QWidget*> parent,
|
||||
Fn<void()> destroy);
|
||||
~StickerToast();
|
||||
|
||||
enum class Section {
|
||||
@@ -50,7 +58,7 @@ private:
|
||||
void setupLottiePreview(not_null<Ui::RpWidget*> widget, int size);
|
||||
void clearHiddenHiding();
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const std::shared_ptr<ChatHelpers::Show> _show;
|
||||
const not_null<QWidget*> _parent;
|
||||
Section _section = {};
|
||||
style::Toast _st;
|
||||
|
||||
@@ -735,34 +735,6 @@ void WeatherView::cacheBackground() {
|
||||
return { QString() + QChar(10084) };
|
||||
}
|
||||
|
||||
[[nodiscard]] Data::PossibleItemReactionsRef LookupPossibleReactions(
|
||||
not_null<Main::Session*> session) {
|
||||
auto result = Data::PossibleItemReactionsRef();
|
||||
const auto reactions = &session->data().reactions();
|
||||
const auto &full = reactions->list(Data::Reactions::Type::Active);
|
||||
const auto &top = reactions->list(Data::Reactions::Type::Top);
|
||||
const auto &recent = reactions->list(Data::Reactions::Type::Recent);
|
||||
const auto premiumPossible = session->premiumPossible();
|
||||
auto added = base::flat_set<Data::ReactionId>();
|
||||
result.recent.reserve(full.size());
|
||||
for (const auto &reaction : ranges::views::concat(top, recent, full)) {
|
||||
if (premiumPossible || !reaction.id.custom()) {
|
||||
if (added.emplace(reaction.id).second) {
|
||||
result.recent.push_back(&reaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.customAllowed = premiumPossible;
|
||||
const auto i = ranges::find(
|
||||
result.recent,
|
||||
reactions->favoriteId(),
|
||||
&Data::Reaction::id);
|
||||
if (i != end(result.recent) && i != begin(result.recent)) {
|
||||
std::rotate(begin(result.recent), i, i + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HistoryView::Context ReactionView::elementContext() {
|
||||
return HistoryView::Context::ContactPreview;
|
||||
}
|
||||
@@ -907,7 +879,7 @@ void Reactions::Panel::attachToReactionButton(
|
||||
}
|
||||
|
||||
void Reactions::Panel::create() {
|
||||
auto reactions = LookupPossibleReactions(
|
||||
auto reactions = Data::LookupPossibleReactions(
|
||||
&_controller->uiShow()->session());
|
||||
if (reactions.recent.empty()) {
|
||||
return;
|
||||
@@ -1153,7 +1125,7 @@ auto Reactions::attachToMenu(
|
||||
desiredPosition,
|
||||
st::storiesReactionsPan,
|
||||
show,
|
||||
LookupPossibleReactions(&show->session()),
|
||||
Data::LookupPossibleReactions(&show->session()),
|
||||
TextWithEntities());
|
||||
if (!result) {
|
||||
return result.error();
|
||||
|
||||
Reference in New Issue
Block a user