mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Show premium emoji tooltip on paste.
This commit is contained in:
parent
4ca6af33d4
commit
5ce8ed80bf
19 changed files with 225 additions and 49 deletions
|
@ -226,6 +226,7 @@ void ShareBox::prepareCommentField() {
|
|||
_show,
|
||||
field,
|
||||
nullptr,
|
||||
nullptr,
|
||||
_descriptor.stLabel);
|
||||
}
|
||||
field->setSubmitSettings(Core::App().settings().sendSubmitWay());
|
||||
|
|
|
@ -474,7 +474,7 @@ void EmojiListWidget::repaintLater(
|
|||
DocumentId documentId,
|
||||
uint64 setId,
|
||||
Ui::CustomEmoji::RepaintRequest request) {
|
||||
if (_instances.empty()) {
|
||||
if (_instances.empty() || !request.when) {
|
||||
return;
|
||||
}
|
||||
auto &repaint = _repaints[request.duration];
|
||||
|
|
|
@ -54,23 +54,29 @@ constexpr auto kParseLinksTimeout = crl::time(1000);
|
|||
// ignore tags for different users.
|
||||
class FieldTagMimeProcessor final {
|
||||
public:
|
||||
explicit FieldTagMimeProcessor(not_null<Main::Session*> _session);
|
||||
FieldTagMimeProcessor(
|
||||
not_null<Main::Session*> _session,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted);
|
||||
|
||||
QString operator()(QStringView mimeTag);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
const Fn<void(not_null<DocumentData*>)> _unavailableEmojiPasted;
|
||||
|
||||
};
|
||||
|
||||
FieldTagMimeProcessor::FieldTagMimeProcessor(
|
||||
not_null<Main::Session*> session)
|
||||
: _session(session) {
|
||||
not_null<Main::Session*> session,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted)
|
||||
: _session(session)
|
||||
, _unavailableEmojiPasted(unavailableEmojiPasted) {
|
||||
}
|
||||
|
||||
QString FieldTagMimeProcessor::operator()(QStringView mimeTag) {
|
||||
const auto id = _session->userId().bare;
|
||||
auto all = TextUtilities::SplitTags(mimeTag);
|
||||
auto premiumSkipped = (DocumentData*)nullptr;
|
||||
for (auto i = all.begin(); i != all.end();) {
|
||||
const auto tag = *i;
|
||||
if (TextUtilities::IsMentionLink(tag)
|
||||
|
@ -86,7 +92,8 @@ QString FieldTagMimeProcessor::operator()(QStringView mimeTag) {
|
|||
}
|
||||
if (!_session->premium()) {
|
||||
const auto document = _session->data().document(emoji.id);
|
||||
if (document->isPremiumSticker()) {
|
||||
if (document->isPremiumEmoji()) {
|
||||
premiumSkipped = document;
|
||||
i = all.erase(i);
|
||||
continue;
|
||||
}
|
||||
|
@ -94,6 +101,11 @@ QString FieldTagMimeProcessor::operator()(QStringView mimeTag) {
|
|||
}
|
||||
++i;
|
||||
}
|
||||
if (premiumSkipped
|
||||
&& _session->premiumPossible()
|
||||
&& _unavailableEmojiPasted) {
|
||||
_unavailableEmojiPasted(premiumSkipped);
|
||||
}
|
||||
return TextUtilities::JoinTag(all);
|
||||
}
|
||||
|
||||
|
@ -301,8 +313,10 @@ void InitMessageFieldHandlers(
|
|||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<Ui::InputField*> field,
|
||||
Fn<bool()> customEmojiPaused,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted,
|
||||
const style::InputField *fieldStyle) {
|
||||
field->setTagMimeProcessor(FieldTagMimeProcessor(session));
|
||||
field->setTagMimeProcessor(
|
||||
FieldTagMimeProcessor(session, unavailableEmojiPasted));
|
||||
field->setCustomEmojiFactory([=](QStringView data, Fn<void()> update) {
|
||||
return session->data().customEmojiManager().create(
|
||||
data,
|
||||
|
@ -322,12 +336,14 @@ void InitMessageFieldHandlers(
|
|||
void InitMessageFieldHandlers(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::InputField*> field,
|
||||
Window::GifPauseReason pauseReasonLevel) {
|
||||
Window::GifPauseReason pauseReasonLevel,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted) {
|
||||
InitMessageFieldHandlers(
|
||||
&controller->session(),
|
||||
std::make_shared<Window::Show>(controller),
|
||||
field,
|
||||
[=] { return controller->isGifPausedAtLeastFor(pauseReasonLevel); });
|
||||
[=] { return controller->isGifPausedAtLeastFor(pauseReasonLevel); },
|
||||
unavailableEmojiPasted);
|
||||
}
|
||||
|
||||
void InitMessageFieldGeometry(not_null<Ui::InputField*> field) {
|
||||
|
@ -341,8 +357,13 @@ void InitMessageFieldGeometry(not_null<Ui::InputField*> field) {
|
|||
|
||||
void InitMessageField(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::InputField*> field) {
|
||||
InitMessageFieldHandlers(controller, field, Window::GifPauseReason::Any);
|
||||
not_null<Ui::InputField*> field,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted) {
|
||||
InitMessageFieldHandlers(
|
||||
controller,
|
||||
field,
|
||||
Window::GifPauseReason::Any,
|
||||
unavailableEmojiPasted);
|
||||
InitMessageFieldGeometry(field);
|
||||
field->customTab(true);
|
||||
}
|
||||
|
|
|
@ -49,14 +49,17 @@ void InitMessageFieldHandlers(
|
|||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<Ui::InputField*> field,
|
||||
Fn<bool()> customEmojiPaused,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted = nullptr,
|
||||
const style::InputField *fieldStyle = nullptr);
|
||||
void InitMessageFieldHandlers(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::InputField*> field,
|
||||
Window::GifPauseReason pauseReasonLevel);
|
||||
Window::GifPauseReason pauseReasonLevel,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted = nullptr);
|
||||
void InitMessageField(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::InputField*> field);
|
||||
not_null<Ui::InputField*> field,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted);
|
||||
|
||||
void InitSpellchecker(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
|
|
|
@ -394,7 +394,10 @@ HistoryWidget::HistoryWidget(
|
|||
return _history ? _history->peer.get() : nullptr;
|
||||
});
|
||||
|
||||
InitMessageField(controller, _field);
|
||||
InitMessageField(controller, _field, [=](
|
||||
not_null<DocumentData*> document) {
|
||||
showPremiumToast(document);
|
||||
});
|
||||
|
||||
_keyboard->sendCommandRequests(
|
||||
) | rpl::start_with_next([=](Bot::SendCommandRequest r) {
|
||||
|
@ -6732,17 +6735,21 @@ void HistoryWidget::showPremiumStickerTooltip(
|
|||
not_null<const HistoryView::Element*> view) {
|
||||
if (const auto media = view->data()->media()) {
|
||||
if (const auto document = media->document()) {
|
||||
if (!_stickerToast) {
|
||||
_stickerToast = std::make_unique<HistoryView::StickerToast>(
|
||||
controller(),
|
||||
_scroll.data(),
|
||||
[=] { _stickerToast = nullptr; });
|
||||
}
|
||||
_stickerToast->showFor(document);
|
||||
showPremiumToast(document);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::showPremiumToast(not_null<DocumentData*> document) {
|
||||
if (!_stickerToast) {
|
||||
_stickerToast = std::make_unique<HistoryView::StickerToast>(
|
||||
controller(),
|
||||
_scroll.data(),
|
||||
[=] { _stickerToast = nullptr; });
|
||||
}
|
||||
_stickerToast->showFor(document);
|
||||
}
|
||||
|
||||
void HistoryWidget::setFieldText(
|
||||
const TextWithTags &textWithTags,
|
||||
TextUpdateEvents events,
|
||||
|
|
|
@ -265,6 +265,7 @@ public:
|
|||
Fn<void()> hiddenCallback);
|
||||
void showPremiumStickerTooltip(
|
||||
not_null<const HistoryView::Element*> view);
|
||||
void showPremiumToast(not_null<DocumentData*> document);
|
||||
|
||||
// Tabbed selector management.
|
||||
bool pushTabbedSelectorToThirdSection(
|
||||
|
|
|
@ -811,6 +811,7 @@ MessageToEdit FieldHeader::queryToEdit() {
|
|||
ComposeControls::ComposeControls(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> window,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted,
|
||||
Mode mode,
|
||||
SendMenu::Type sendMenuType)
|
||||
: _parent(parent)
|
||||
|
@ -847,6 +848,7 @@ ComposeControls::ComposeControls(
|
|||
_send,
|
||||
st::historySendSize.height()))
|
||||
, _sendMenuType(sendMenuType)
|
||||
, _unavailableEmojiPasted(unavailableEmojiPasted)
|
||||
, _saveDraftTimer([=] { saveDraft(); }) {
|
||||
init();
|
||||
}
|
||||
|
@ -1420,7 +1422,7 @@ void ComposeControls::initField() {
|
|||
Ui::Connect(_field, &Ui::InputField::resized, [=] { updateHeight(); });
|
||||
//Ui::Connect(_field, &Ui::InputField::focused, [=] { fieldFocused(); });
|
||||
Ui::Connect(_field, &Ui::InputField::changed, [=] { fieldChanged(); });
|
||||
InitMessageField(_window, _field);
|
||||
InitMessageField(_window, _field, _unavailableEmojiPasted);
|
||||
initAutocomplete();
|
||||
const auto suggestions = Ui::Emoji::SuggestionsController::Init(
|
||||
_parent,
|
||||
|
@ -1963,7 +1965,7 @@ void ComposeControls::initVoiceRecordBar() {
|
|||
|
||||
_voiceRecordBar->setStartRecordingFilter([=] {
|
||||
const auto error = [&]() -> std::optional<QString> {
|
||||
const auto peer = _history ? _history->peer : nullptr;
|
||||
const auto peer = _history ? _history->peer.get() : nullptr;
|
||||
if (!peer) {
|
||||
const auto type = ChatRestriction::SendMedia;
|
||||
if (const auto error = Data::RestrictionError(peer, type)) {
|
||||
|
|
|
@ -97,6 +97,7 @@ public:
|
|||
ComposeControls(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> window,
|
||||
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted,
|
||||
Mode mode,
|
||||
SendMenu::Type sendMenuType);
|
||||
~ComposeControls();
|
||||
|
@ -309,6 +310,7 @@ private:
|
|||
const std::unique_ptr<Controls::VoiceRecordBar> _voiceRecordBar;
|
||||
|
||||
const SendMenu::Type _sendMenuType;
|
||||
const Fn<void(not_null<DocumentData*>)> _unavailableEmojiPasted;
|
||||
|
||||
rpl::event_stream<Api::SendOptions> _sendCustomRequests;
|
||||
rpl::event_stream<> _cancelRequests;
|
||||
|
|
|
@ -1494,6 +1494,12 @@ void ListWidget::elementStartPremium(
|
|||
not_null<const Element*> view,
|
||||
Element *replacing) {
|
||||
_emojiInteractions->playPremiumEffect(view, replacing);
|
||||
const auto already = !_emojiInteractions->playPremiumEffect(
|
||||
view,
|
||||
replacing);
|
||||
if (already) {
|
||||
showPremiumStickerTooltip(view);
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::elementCancelPremium(not_null<const Element*> view) {
|
||||
|
@ -1599,6 +1605,15 @@ void ListWidget::startMessageSendingAnimation(
|
|||
});
|
||||
}
|
||||
|
||||
void ListWidget::showPremiumStickerTooltip(
|
||||
not_null<const HistoryView::Element*> view) {
|
||||
if (const auto media = view->data()->media()) {
|
||||
if (const auto document = media->document()) {
|
||||
_delegate->listShowPremiumToast(document);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::revealItemsCallback() {
|
||||
auto revealHeight = 0;
|
||||
for (auto i = begin(_itemRevealAnimations)
|
||||
|
|
|
@ -119,6 +119,7 @@ public:
|
|||
virtual CopyRestrictionType listSelectRestrictionType() = 0;
|
||||
virtual auto listAllowedReactionsValue()
|
||||
-> rpl::producer<std::optional<base::flat_set<QString>>> = 0;
|
||||
virtual void listShowPremiumToast(not_null<DocumentData*> document) = 0;
|
||||
};
|
||||
|
||||
struct SelectionData {
|
||||
|
@ -516,6 +517,8 @@ private:
|
|||
void revealItemsCallback();
|
||||
|
||||
void startMessageSendingAnimation(not_null<HistoryItem*> item);
|
||||
void showPremiumStickerTooltip(
|
||||
not_null<const HistoryView::Element*> view);
|
||||
|
||||
// This function finds all history items that are displayed and calls template method
|
||||
// for each found message (in given direction) in the passed history with passed top offset.
|
||||
|
|
|
@ -688,6 +688,9 @@ auto PinnedWidget::listAllowedReactionsValue()
|
|||
return Data::PeerAllowedReactionsValue(_history->peer);
|
||||
}
|
||||
|
||||
void PinnedWidget::listShowPremiumToast(not_null<DocumentData*> document) {
|
||||
}
|
||||
|
||||
void PinnedWidget::confirmDeleteSelected() {
|
||||
ConfirmDeleteSelectedItems(_inner);
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ public:
|
|||
CopyRestrictionType listSelectRestrictionType() override;
|
||||
auto listAllowedReactionsValue()
|
||||
-> rpl::producer<std::optional<base::flat_set<QString>>> override;
|
||||
void listShowPremiumToast(not_null<DocumentData*> document) override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/history_view_list_widget.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "history/view/history_view_pinned_bar.h"
|
||||
#include "history/view/history_view_sticker_toast.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history_item_components.h"
|
||||
|
@ -165,6 +166,7 @@ RepliesWidget::RepliesWidget(
|
|||
, _composeControls(std::make_unique<ComposeControls>(
|
||||
this,
|
||||
controller,
|
||||
[=](not_null<DocumentData*> emoji) { listShowPremiumToast(emoji); },
|
||||
ComposeControls::Mode::Normal,
|
||||
SendMenu::Type::SilentOnly))
|
||||
, _scroll(std::make_unique<Ui::ScrollArea>(
|
||||
|
@ -2043,6 +2045,16 @@ auto RepliesWidget::listAllowedReactionsValue()
|
|||
return Data::PeerAllowedReactionsValue(_history->peer);
|
||||
}
|
||||
|
||||
void RepliesWidget::listShowPremiumToast(not_null<DocumentData*> document) {
|
||||
if (!_stickerToast) {
|
||||
_stickerToast = std::make_unique<HistoryView::StickerToast>(
|
||||
controller(),
|
||||
_scroll.get(),
|
||||
[=] { _stickerToast = nullptr; });
|
||||
}
|
||||
_stickerToast->showFor(document);
|
||||
}
|
||||
|
||||
void RepliesWidget::confirmDeleteSelected() {
|
||||
ConfirmDeleteSelectedItems(_inner);
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ class TopBarWidget;
|
|||
class RepliesMemento;
|
||||
class ComposeControls;
|
||||
class SendActionPainter;
|
||||
class StickerToast;
|
||||
|
||||
class RepliesWidget final
|
||||
: public Window::SectionWidget
|
||||
|
@ -143,6 +144,7 @@ public:
|
|||
CopyRestrictionType listSelectRestrictionType() override;
|
||||
auto listAllowedReactionsValue()
|
||||
-> rpl::producer<std::optional<base::flat_set<QString>>> override;
|
||||
void listShowPremiumToast(not_null<DocumentData*> document) override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
@ -193,6 +195,8 @@ private:
|
|||
void clearSelected();
|
||||
void setPinnedVisibility(bool shown);
|
||||
|
||||
void showPremiumToast(not_null<DocumentData*> document);
|
||||
|
||||
[[nodiscard]] Api::SendAction prepareSendAction(
|
||||
Api::SendOptions options) const;
|
||||
void send();
|
||||
|
@ -284,6 +288,7 @@ private:
|
|||
rpl::variable<bool> _rootVisible = false;
|
||||
|
||||
std::unique_ptr<Ui::ScrollArea> _scroll;
|
||||
std::unique_ptr<HistoryView::StickerToast> _stickerToast;
|
||||
|
||||
std::vector<MsgId> _replyReturns;
|
||||
HistoryItem *_replyReturn = nullptr;
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/history_view_top_bar_widget.h"
|
||||
#include "history/view/history_view_list_widget.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "history/view/history_view_sticker_toast.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history_item.h"
|
||||
|
@ -107,6 +108,7 @@ ScheduledWidget::ScheduledWidget(
|
|||
, _composeControls(std::make_unique<ComposeControls>(
|
||||
this,
|
||||
controller,
|
||||
[=](not_null<DocumentData*> emoji) { listShowPremiumToast(emoji); },
|
||||
ComposeControls::Mode::Scheduled,
|
||||
SendMenu::Type::Disabled))
|
||||
, _scrollDown(
|
||||
|
@ -1360,6 +1362,17 @@ auto ScheduledWidget::listAllowedReactionsValue()
|
|||
return rpl::single(std::optional<base::flat_set<QString>>(empty));
|
||||
}
|
||||
|
||||
void ScheduledWidget::listShowPremiumToast(
|
||||
not_null<DocumentData*> document) {
|
||||
if (!_stickerToast) {
|
||||
_stickerToast = std::make_unique<HistoryView::StickerToast>(
|
||||
controller(),
|
||||
_scroll.data(),
|
||||
[=] { _stickerToast = nullptr; });
|
||||
}
|
||||
_stickerToast->showFor(document);
|
||||
}
|
||||
|
||||
void ScheduledWidget::confirmSendNowSelected() {
|
||||
ConfirmSendNowSelectedItems(_inner);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ class Element;
|
|||
class TopBarWidget;
|
||||
class ScheduledMemento;
|
||||
class ComposeControls;
|
||||
class StickerToast;
|
||||
|
||||
class ScheduledWidget final
|
||||
: public Window::SectionWidget
|
||||
|
@ -128,6 +129,7 @@ public:
|
|||
CopyRestrictionType listSelectRestrictionType() override;
|
||||
auto listAllowedReactionsValue()
|
||||
-> rpl::producer<std::optional<base::flat_set<QString>>> override;
|
||||
void listShowPremiumToast(not_null<DocumentData*> document) override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
@ -236,6 +238,8 @@ private:
|
|||
std::unique_ptr<ComposeControls> _composeControls;
|
||||
bool _skipScrollEvent = false;
|
||||
|
||||
std::unique_ptr<HistoryView::StickerToast> _stickerToast;
|
||||
|
||||
std::vector<MsgId> _replyReturns;
|
||||
HistoryItem *_replyReturn = nullptr;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/toast/toast.h"
|
||||
#include "ui/toast/toast_widget.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -44,9 +45,7 @@ StickerToast::~StickerToast() {
|
|||
|
||||
void StickerToast::showFor(not_null<DocumentData*> document) {
|
||||
const auto sticker = document->sticker();
|
||||
if (!sticker
|
||||
|| sticker->type != StickerType::Tgs
|
||||
|| !document->session().premiumPossible()) {
|
||||
if (!sticker || !document->session().premiumPossible()) {
|
||||
return;
|
||||
} else if (const auto strong = _weak.get()) {
|
||||
if (_for == document) {
|
||||
|
@ -121,10 +120,14 @@ void StickerToast::cancelRequest() {
|
|||
void StickerToast::showWithTitle(const QString &title) {
|
||||
Expects(_for != nullptr);
|
||||
|
||||
const auto setType = _for->sticker()->setType;
|
||||
const auto isEmoji = (setType == Data::StickersType::Emoji);
|
||||
const auto text = Ui::Text::Bold(
|
||||
title
|
||||
).append('\n').append(
|
||||
tr::lng_sticker_premium_text(tr::now)
|
||||
(isEmoji
|
||||
? tr::lng_animated_emoji_text(tr::now, Ui::Text::RichLangValue)
|
||||
: tr::lng_sticker_premium_text(tr::now, Ui::Text::RichLangValue))
|
||||
);
|
||||
_st = st::historyPremiumToast;
|
||||
const auto skip = _st.padding.top();
|
||||
|
@ -167,28 +170,11 @@ void StickerToast::showWithTitle(const QString &title) {
|
|||
preview->resize(size, size);
|
||||
preview->show();
|
||||
|
||||
const auto bytes = _for->createMediaView()->bytes();
|
||||
const auto filepath = _for->filepath();
|
||||
const auto player = preview->lifetime().make_state<Lottie::SinglePlayer>(
|
||||
Lottie::ReadContent(bytes, filepath),
|
||||
Lottie::FrameRequest{ QSize(size, size) },
|
||||
Lottie::Quality::Default);
|
||||
preview->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (!player->ready()) {
|
||||
return;
|
||||
}
|
||||
const auto image = player->frame();
|
||||
QPainter(preview).drawImage(
|
||||
QRect(QPoint(), image.size() / image.devicePixelRatio()),
|
||||
image);
|
||||
player->markFrameShown();
|
||||
}, preview->lifetime());
|
||||
player->updates(
|
||||
) | rpl::start_with_next([=] {
|
||||
preview->update();
|
||||
}, preview->lifetime());
|
||||
|
||||
if (isEmoji) {
|
||||
setupEmojiPreview(preview, size);
|
||||
} else {
|
||||
setupLottiePreview(preview, size);
|
||||
}
|
||||
button->setClickedCallback([=, weak = _weak] {
|
||||
_controller->show(
|
||||
Box<StickerSetBox>(_controller, _for->sticker()->set),
|
||||
|
@ -199,4 +185,95 @@ void StickerToast::showWithTitle(const QString &title) {
|
|||
});
|
||||
}
|
||||
|
||||
void StickerToast::setupEmojiPreview(
|
||||
not_null<Ui::RpWidget*> widget,
|
||||
int size) {
|
||||
Expects(_for != nullptr);
|
||||
|
||||
struct Instance {
|
||||
Instance(
|
||||
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
||||
Fn<void(
|
||||
not_null<Ui::CustomEmoji::Instance*>,
|
||||
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
||||
Fn<void()> repaint)
|
||||
: emoji(
|
||||
Ui::CustomEmoji::Loading(
|
||||
std::move(loader),
|
||||
Ui::CustomEmoji::Preview()),
|
||||
std::move(repaintLater))
|
||||
, object(&emoji, repaint)
|
||||
, timer(repaint) {
|
||||
}
|
||||
|
||||
Ui::CustomEmoji::Instance emoji;
|
||||
Ui::CustomEmoji::Object object;
|
||||
base::Timer timer;
|
||||
};
|
||||
|
||||
const auto repaintDelayed = [=](
|
||||
not_null<Ui::CustomEmoji::Instance*> instance,
|
||||
Ui::CustomEmoji::RepaintRequest request) {
|
||||
if (!request.when) {
|
||||
return;
|
||||
}
|
||||
const auto now = crl::now();
|
||||
if (now > request.when) {
|
||||
reinterpret_cast<Instance*>(instance.get())->timer.callOnce(
|
||||
now - request.when);
|
||||
} else {
|
||||
widget->update();
|
||||
}
|
||||
};
|
||||
const auto instance = widget->lifetime().make_state<Instance>(
|
||||
_for->owner().customEmojiManager().createLoader(
|
||||
_for,
|
||||
Data::CustomEmojiManager::SizeTag::Large),
|
||||
std::move(repaintDelayed),
|
||||
[=] { widget->update(); });
|
||||
|
||||
widget->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto p = QPainter(widget);
|
||||
const auto paused = false;
|
||||
const auto size = Ui::Emoji::GetSizeLarge()
|
||||
/ style::DevicePixelRatio();
|
||||
instance->object.paint(
|
||||
p,
|
||||
(widget->width() - size) / 2,
|
||||
(widget->height() - size) / 2,
|
||||
crl::now(),
|
||||
st::toastBg->c,
|
||||
paused);
|
||||
}, widget->lifetime());
|
||||
}
|
||||
|
||||
void StickerToast::setupLottiePreview(not_null<Ui::RpWidget*> widget, int size) {
|
||||
Expects(_for != nullptr);
|
||||
|
||||
const auto bytes = _for->createMediaView()->bytes();
|
||||
const auto filepath = _for->filepath();
|
||||
const auto player = widget->lifetime().make_state<Lottie::SinglePlayer>(
|
||||
Lottie::ReadContent(bytes, filepath),
|
||||
Lottie::FrameRequest{ QSize(size, size) },
|
||||
Lottie::Quality::Default);
|
||||
|
||||
widget->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (!player->ready()) {
|
||||
return;
|
||||
}
|
||||
const auto image = player->frame();
|
||||
QPainter(widget).drawImage(
|
||||
QRect(QPoint(), image.size() / image.devicePixelRatio()),
|
||||
image);
|
||||
player->markFrameShown();
|
||||
}, widget->lifetime());
|
||||
|
||||
player->updates(
|
||||
) | rpl::start_with_next([=] {
|
||||
widget->update();
|
||||
}, widget->lifetime());
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Ui {
|
||||
class Show;
|
||||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Ui::Toast {
|
||||
|
@ -39,6 +40,9 @@ private:
|
|||
void showWithTitle(const QString &title);
|
||||
[[nodiscard]] QString lookupTitle() const;
|
||||
|
||||
void setupEmojiPreview(not_null<Ui::RpWidget*> widget, int size);
|
||||
void setupLottiePreview(not_null<Ui::RpWidget*> widget, int size);
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<QWidget*> _parent;
|
||||
style::Toast _st;
|
||||
|
|
|
@ -60,7 +60,9 @@ void Document::writeToStream(QDataStream &stream, DocumentData *document) {
|
|||
}
|
||||
stream << qint32(document->getDuration());
|
||||
if (document->type == StickerDocument) {
|
||||
stream << qint32(document->isPremiumSticker() ? 1 : 0);
|
||||
const auto premium = document->isPremiumSticker()
|
||||
|| document->isPremiumEmoji();
|
||||
stream << qint32(premium ? 1 : 0);
|
||||
}
|
||||
writeImageLocation(stream, document->thumbnailLocation());
|
||||
stream << qint32(document->thumbnailByteSize());
|
||||
|
|
Loading…
Add table
Reference in a new issue