Show premium emoji toast / send to Saved Messages.

This commit is contained in:
John Preston 2022-08-02 20:59:11 +03:00
parent 59903b0b1c
commit f4b80d8714
16 changed files with 133 additions and 23 deletions

View File

@ -233,6 +233,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_sticker_premium_text" = "This pack contains premium stickers like this one.";
"lng_sticker_premium_view" = "View";
"lng_animated_emoji_text" = "Subscribe to **Telegram Premium** to unlock this emoji.";
"lng_animated_emoji_saved" = "Try sending these emoji in **Saved Messages** for free to test.";
"lng_animated_emoji_saved_open" = "Open";
"lng_reaction_premium_info" = "Click on the reaction to preview the animation.";
"lng_reaction_premium_no_group" = "Some reactions are restricted in this group.";
"lng_reaction_premium_no_channel" = "Some reactions are restricted in this channel.";
@ -499,6 +501,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_section_chat_settings" = "Chat Settings";
"lng_settings_replace_emojis" = "Replace emoji";
"lng_settings_suggest_emoji" = "Suggest emoji replacements";
"lng_settings_suggest_animated_emoji" = "Suggest animated emoji";
"lng_settings_suggest_by_emoji" = "Suggest popular stickers by emoji";
"lng_settings_loop_stickers" = "Loop animated stickers";
"lng_settings_large_emoji" = "Large emoji";

View File

@ -504,6 +504,7 @@ void EditCaptionBox::setupEmojiPanel() {
) | rpl::start_with_next([=](Selector::FileChosen data) {
Data::InsertCustomEmoji(_field.get(), data.document);
}, lifetime());
_emojiPanel->selector()->showPromoForPremiumEmoji();
const auto filterCallback = [=](not_null<QEvent*> event) {
emojiFilterForGeometry(event);

View File

@ -746,6 +746,7 @@ void SendFilesBox::setupEmojiPanel() {
) | rpl::start_with_next([=](Selector::FileChosen data) {
Data::InsertCustomEmoji(_caption.data(), data.document);
}, lifetime());
_emojiPanel->selector()->showPromoForPremiumEmoji();
const auto filterCallback = [=](not_null<QEvent*> event) {
emojiFilterForGeometry(event);

View File

@ -17,7 +17,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/ui_utility.h"
#include "ui/cached_round_corners.h"
#include "boxes/sticker_set_box.h"
#include "boxes/premium_preview_box.h"
#include "lang/lang_keys.h"
#include "layout/layout_position.h"
#include "data/data_session.h"
@ -453,6 +452,11 @@ auto EmojiListWidget::customChosen() const
return _customChosen.events();
}
auto EmojiListWidget::premiumChosen() const
-> rpl::producer<not_null<DocumentData*>> {
return _premiumChosen.events();
}
void EmojiListWidget::visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) {
@ -1026,13 +1030,7 @@ void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
if (document->isPremiumEmoji()
&& !document->session().premium()
&& !_allowWithoutPremium) {
ShowPremiumPreviewBox(
controller(),
PremiumPreview::AnimatedEmoji,
{},
crl::guard(this, [=](not_null<Ui::BoxContent*> box) {
checkHideWithBox(box.get());
}));
_premiumChosen.fire_copy(document);
return;
}
Core::App().settings().incrementRecentEmoji({ RecentEmojiDocument{

View File

@ -82,6 +82,8 @@ public:
[[nodiscard]] rpl::producer<EmojiPtr> chosen() const;
[[nodiscard]] auto customChosen() const
-> rpl::producer<TabbedSelector::FileChosen>;
[[nodiscard]] auto premiumChosen() const
-> rpl::producer<not_null<DocumentData*>>;
protected:
void visibleTopBottomUpdated(
@ -298,6 +300,7 @@ private:
rpl::event_stream<EmojiPtr> _chosen;
rpl::event_stream<TabbedSelector::FileChosen> _customChosen;
rpl::event_stream<not_null<DocumentData*>> _premiumChosen;
};

View File

@ -111,7 +111,9 @@ auto SuggestionsWidget::appendCustom(std::vector<Row> rows)
auto SuggestionsWidget::lookupCustom(const std::vector<Row> &rows) const
-> base::flat_multi_map<int, Custom> {
if (rows.empty() || !_suggestCustomEmoji) {
if (rows.empty()
|| !_suggestCustomEmoji
|| !Core::App().settings().suggestAnimatedEmoji()) {
return {};
}
auto custom = base::flat_multi_map<int, Custom>();

View File

@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_changes.h"
#include "data/stickers/data_stickers.h"
#include "data/stickers/data_custom_emoji.h" // AllowEmojiWithoutPremium.
#include "boxes/premium_preview_box.h"
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "apiwrap.h"
@ -491,6 +492,11 @@ auto TabbedSelector::customEmojiChosen() const -> rpl::producer<FileChosen> {
return emoji()->customChosen();
}
auto TabbedSelector::premiumEmojiChosen() const
-> rpl::producer<not_null<DocumentData*>> {
return emoji()->premiumChosen();
}
auto TabbedSelector::fileChosen() const -> rpl::producer<FileChosen> {
auto never = rpl::never<TabbedSelector::FileChosen>(
) | rpl::type_erased();
@ -844,6 +850,16 @@ void TabbedSelector::setCurrentPeer(PeerData *peer) {
peer && Data::AllowEmojiWithoutPremium(peer));
}
void TabbedSelector::showPromoForPremiumEmoji() {
premiumEmojiChosen(
) | rpl::start_with_next([=] {
ShowPremiumPreviewBox(
_controller,
PremiumPreview::AnimatedEmoji,
{});
}, lifetime());
}
void TabbedSelector::checkRestrictedPeer() {
if (_currentPeer) {
const auto error = (_currentTabType == SelectorTab::Stickers)

View File

@ -88,6 +88,7 @@ public:
rpl::producer<EmojiPtr> emojiChosen() const;
rpl::producer<FileChosen> customEmojiChosen() const;
rpl::producer<not_null<DocumentData*>> premiumEmojiChosen() const;
rpl::producer<FileChosen> fileChosen() const;
rpl::producer<PhotoChosen> photoChosen() const;
rpl::producer<InlineChosen> inlineResultChosen() const;
@ -102,6 +103,7 @@ public:
void setRoundRadius(int radius);
void refreshStickers();
void setCurrentPeer(PeerData *peer);
void showPromoForPremiumEmoji();
void hideFinished();
void showStarted();

View File

@ -137,8 +137,7 @@ QByteArray Settings::serialize() const {
+ sizeof(qint64)
+ sizeof(qint32) * 2
+ Serialize::bytearraySize(windowPosition)
+ sizeof(qint32) * 2
+ (_accountsOrder.size() * sizeof(quint64));
+ sizeof(qint32);
for (const auto &[id, rating] : recentEmojiPreloadData) {
size += Serialize::stringSize(id) + sizeof(quint16);
}
@ -152,6 +151,8 @@ QByteArray Settings::serialize() const {
+ Serialize::bytearraySize(_photoEditorBrush)
+ sizeof(qint32) * 3
+ Serialize::stringSize(_customDeviceModel.current())
+ sizeof(qint32) * 4
+ (_accountsOrder.size() * sizeof(quint64))
+ sizeof(qint32) * 4;
auto result = QByteArray();
@ -264,7 +265,8 @@ QByteArray Settings::serialize() const {
stream
<< qint32(0) // old hardwareAcceleratedVideo
<< qint32(_chatQuickAction)
<< qint32(_hardwareAcceleratedVideo ? 1 : 0);
<< qint32(_hardwareAcceleratedVideo ? 1 : 0)
<< qint32(_suggestAnimatedEmoji ? 1 : 0);
}
return result;
}
@ -356,6 +358,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
std::vector<uint64> accountsOrder;
qint32 hardwareAcceleratedVideo = _hardwareAcceleratedVideo ? 1 : 0;
qint32 chatQuickAction = static_cast<qint32>(_chatQuickAction);
qint32 suggestAnimatedEmoji = _suggestAnimatedEmoji ? 1 : 0;
stream >> themesAccentColors;
if (!stream.atEnd()) {
@ -547,6 +550,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> hardwareAcceleratedVideo;
}
if (!stream.atEnd()) {
stream >> suggestAnimatedEmoji;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
@ -714,6 +720,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
case Quick::React: _chatQuickAction = uncheckedChatQuickAction; break;
}
}
_suggestAnimatedEmoji = (suggestAnimatedEmoji == 1);
}
QString Settings::getSoundPath(const QString &key) const {
@ -986,6 +993,7 @@ void Settings::resetOnLastLogout() {
_replaceEmoji = true;
_suggestEmoji = true;
_suggestStickersByEmoji = true;
_suggestAnimatedEmoji = true;
_spellcheckerEnabled = true;
_videoPlaybackSpeed = 1.;
_voicePlaybackSpeed = 1.;

View File

@ -404,6 +404,12 @@ public:
void setSuggestStickersByEmoji(bool value) {
_suggestStickersByEmoji = value;
}
[[nodiscard]] bool suggestAnimatedEmoji() const {
return _suggestAnimatedEmoji;
}
void setSuggestAnimatedEmoji(bool value) {
_suggestAnimatedEmoji = value;
}
void setSpellcheckerEnabled(bool value) {
_spellcheckerEnabled = value;
@ -775,6 +781,7 @@ private:
rpl::variable<bool> _replaceEmoji = true;
bool _suggestEmoji = true;
bool _suggestStickersByEmoji = true;
bool _suggestAnimatedEmoji = true;
rpl::variable<bool> _spellcheckerEnabled = true;
rpl::variable<float64> _videoPlaybackSpeed = 1.;
float64 _voicePlaybackSpeed = 2.;

View File

@ -1078,6 +1078,13 @@ void HistoryWidget::initTabbedSelector() {
Data::InsertCustomEmoji(_field.data(), data.document);
}, lifetime());
selector->premiumEmojiChosen(
) | rpl::filter([=] {
return !isHidden() && !_field->isHidden();
}) | rpl::start_with_next([=](not_null<DocumentData*> document) {
showPremiumToast(document);
}, lifetime());
selector->fileChosen(
) | filter | rpl::start_with_next([=](Selector::FileChosen data) {
controller()->sendingAnimation().appendSending(
@ -5004,7 +5011,6 @@ bool HistoryWidget::confirmSendingFiles(
const auto position = cursor.position();
const auto anchor = cursor.anchor();
const auto text = _field->getTextWithTags();
using SendLimit = SendFilesBox::SendLimit;
auto box = Box<SendFilesBox>(
controller(),
std::move(list),
@ -6763,7 +6769,7 @@ void HistoryWidget::showPremiumToast(not_null<DocumentData*> document) {
if (!_stickerToast) {
_stickerToast = std::make_unique<HistoryView::StickerToast>(
controller(),
_scroll.data(),
this,
[=] { _stickerToast = nullptr; });
}
_stickerToast->showFor(document);

View File

@ -1850,6 +1850,13 @@ void ComposeControls::initTabbedSelector() {
Data::InsertCustomEmoji(_field, data.document);
}, wrap->lifetime());
selector->premiumEmojiChosen(
) | rpl::start_with_next([=](not_null<DocumentData*> document) {
if (_unavailableEmojiPasted) {
_unavailableEmojiPasted(document);
}
}, wrap->lifetime());
selector->fileChosen(
) | rpl::start_to_stream(_fileChosen, wrap->lifetime());

View File

@ -742,7 +742,6 @@ bool RepliesWidget::confirmSendingFiles(
return false;
}
using SendLimit = SendFilesBox::SendLimit;
auto box = Box<SendFilesBox>(
controller(),
std::move(list),
@ -2049,7 +2048,7 @@ void RepliesWidget::listShowPremiumToast(not_null<DocumentData*> document) {
if (!_stickerToast) {
_stickerToast = std::make_unique<HistoryView::StickerToast>(
controller(),
_scroll.get(),
this,
[=] { _stickerToast = nullptr; });
}
_stickerToast->showFor(document);

View File

@ -400,7 +400,6 @@ bool ScheduledWidget::confirmSendingFiles(
return false;
}
using SendLimit = SendFilesBox::SendLimit;
auto box = Box<SendFilesBox>(
controller(),
std::move(list),
@ -1367,7 +1366,7 @@ void ScheduledWidget::listShowPremiumToast(
if (!_stickerToast) {
_stickerToast = std::make_unique<HistoryView::StickerToast>(
controller(),
_scroll.data(),
this,
[=] { _stickerToast = nullptr; });
}
_stickerToast->showFor(document);

View File

@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "ui/text/text_utilities.h"
#include "boxes/sticker_set_box.h"
#include "boxes/premium_preview_box.h"
#include "lottie/lottie_single_player.h"
#include "window/window_session_controller.h"
#include "apiwrap.h"
@ -120,19 +121,25 @@ void StickerToast::cancelRequest() {
void StickerToast::showWithTitle(const QString &title) {
Expects(_for != nullptr);
static auto counter = 0;
const auto setType = _for->sticker()->setType;
const auto isEmoji = (setType == Data::StickersType::Emoji);
const auto toSaved = isEmoji && !(++counter % 2);
const auto text = Ui::Text::Bold(
title
).append('\n').append(
(isEmoji
(toSaved
? tr::lng_animated_emoji_saved(tr::now, Ui::Text::RichLangValue)
: 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();
const auto size = _st.style.font->height * 2;
const auto view = tr::lng_sticker_premium_view(tr::now);
const auto view = toSaved
? tr::lng_animated_emoji_saved_open(tr::now)
: tr::lng_sticker_premium_view(tr::now);
_st.padding.setLeft(skip + size + skip);
_st.padding.setRight(st::historyPremiumViewSet.font->width(view)
- st::historyPremiumViewSet.width);
@ -194,9 +201,27 @@ void StickerToast::showWithTitle(const QString &title) {
setupLottiePreview(preview, size);
}
button->setClickedCallback([=] {
_controller->show(
Box<StickerSetBox>(_controller, _for->sticker()->set, setType),
Ui::LayerOption::KeepOther);
if (toSaved) {
_controller->showPeerHistory(
_controller->session().userPeerId(),
Window::SectionShow::Way::Forward);
hideToast();
return;
}
const auto id = _for->sticker()->set.id;
const auto &sets = _for->owner().stickers().sets();
const auto i = sets.find(id);
if (i != end(sets)
&& (i->second->flags & Data::StickersSetFlag::Installed)) {
ShowPremiumPreviewBox(
_controller,
PremiumPreview::AnimatedEmoji);
} else {
_controller->show(Box<StickerSetBox>(
_controller,
_for->sticker()->set,
setType));
}
hideToast();
});
}

View File

@ -52,6 +52,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_cloud_themes.h"
#include "data/data_file_origin.h"
#include "data/data_message_reactions.h"
#include "data/data_peer_values.h"
#include "chat_helpers/emoji_sets_manager.h"
#include "base/platform/base_platform_info.h"
#include "platform/platform_specific.h"
@ -710,6 +711,21 @@ void SetupStickersEmoji(
std::move(handle),
inner->lifetime());
};
const auto addSliding = [&](
const QString &label,
bool checked,
auto &&handle,
rpl::producer<bool> shown) {
inner->add(
object_ptr<Ui::SlideWrap<Ui::Checkbox>>(
inner,
checkbox(label, checked),
st::settingsCheckboxPadding)
)->setDuration(0)->toggleOn(std::move(shown))->entity()->checkedChanges(
) | rpl::start_with_next(
std::move(handle),
inner->lifetime());
};
add(
tr::lng_settings_large_emoji(tr::now),
@ -727,14 +743,31 @@ void SetupStickersEmoji(
Core::App().saveSettingsDelayed();
});
const auto suggestEmoji = inner->lifetime().make_state<
rpl::variable<bool>
>(Core::App().settings().suggestEmoji());
add(
tr::lng_settings_suggest_emoji(tr::now),
Core::App().settings().suggestEmoji(),
[=](bool checked) {
*suggestEmoji = checked;
Core::App().settings().setSuggestEmoji(checked);
Core::App().saveSettingsDelayed();
});
using namespace rpl::mappers;
addSliding(
tr::lng_settings_suggest_animated_emoji(tr::now),
Core::App().settings().suggestAnimatedEmoji(),
[=](bool checked) {
Core::App().settings().setSuggestAnimatedEmoji(checked);
Core::App().saveSettingsDelayed();
},
rpl::combine(
Data::AmPremiumValue(session),
suggestEmoji->value(),
_1 && _2));
add(
tr::lng_settings_suggest_by_emoji(tr::now),
Core::App().settings().suggestStickersByEmoji(),