Allow sending premium emoji to Saved Messages.

This commit is contained in:
John Preston 2022-08-01 16:24:51 +03:00
parent 087074fea4
commit b42f2784ab
18 changed files with 93 additions and 39 deletions

View file

@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "editor/photo_editor_layer_widget.h" #include "editor/photo_editor_layer_widget.h"
#include "history/history_drag_area.h" #include "history/history_drag_area.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_session_settings.h" #include "main/main_session_settings.h"
@ -242,10 +243,12 @@ void EditCaptionBox::rebuildPreview() {
} }
void EditCaptionBox::setupField() { void EditCaptionBox::setupField() {
const auto peer = _historyItem->history()->peer;
InitMessageFieldHandlers( InitMessageFieldHandlers(
_controller, _controller,
_field.get(), _field.get(),
Window::GifPauseReason::Layer); Window::GifPauseReason::Layer,
[=](const auto&) { return Data::AllowEmojiWithoutPremium(peer); });
Ui::Emoji::SuggestionsController::Init( Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(), getDelegate()->outerContainer(),
_field, _field,
@ -488,6 +491,7 @@ void EditCaptionBox::setupEmojiPanel() {
st::emojiPanMinHeight / 2, st::emojiPanMinHeight / 2,
st::emojiPanMinHeight); st::emojiPanMinHeight);
_emojiPanel->hide(); _emojiPanel->hide();
_emojiPanel->selector()->setCurrentPeer(_historyItem->history()->peer);
_emojiPanel->selector()->emojiChosen( _emojiPanel->selector()->emojiChosen(
) | rpl::start_with_next([=](EmojiPtr emoji) { ) | rpl::start_with_next([=](EmojiPtr emoji) {
Ui::InsertEmojiAtCursor(_field->textCursor(), emoji); Ui::InsertEmojiAtCursor(_field->textCursor(), emoji);

View file

@ -250,15 +250,16 @@ SendFilesBox::SendFilesBox(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
Ui::PreparedList &&list, Ui::PreparedList &&list,
const TextWithTags &caption, const TextWithTags &caption,
SendLimit limit, not_null<PeerData*> peer,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Type sendMenuType) SendMenu::Type sendMenuType)
: _controller(controller) : _controller(controller)
, _sendType(sendType) , _sendType(sendType)
, _titleHeight(st::boxTitleHeight) , _titleHeight(st::boxTitleHeight)
, _list(std::move(list)) , _list(std::move(list))
, _sendLimit(limit) , _sendLimit(peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many)
, _sendMenuType(sendMenuType) , _sendMenuType(sendMenuType)
, _allowEmojiWithoutPremium(Data::AllowEmojiWithoutPremium(peer))
, _caption( , _caption(
this, this,
st::confirmCaptionArea, st::confirmCaptionArea,
@ -676,7 +677,8 @@ void SendFilesBox::setupCaption() {
InitMessageFieldHandlers( InitMessageFieldHandlers(
_controller, _controller,
_caption.data(), _caption.data(),
Window::GifPauseReason::Layer); Window::GifPauseReason::Layer,
[=](const auto&) { return _allowEmojiWithoutPremium; });
Ui::Emoji::SuggestionsController::Init( Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(), getDelegate()->outerContainer(),
_caption, _caption,
@ -730,6 +732,8 @@ void SendFilesBox::setupEmojiPanel() {
st::emojiPanMinHeight / 2, st::emojiPanMinHeight / 2,
st::emojiPanMinHeight); st::emojiPanMinHeight);
_emojiPanel->hide(); _emojiPanel->hide();
_emojiPanel->selector()->setAllowEmojiWithoutPremium(
_allowEmojiWithoutPremium);
_emojiPanel->selector()->emojiChosen( _emojiPanel->selector()->emojiChosen(
) | rpl::start_with_next([=](EmojiPtr emoji) { ) | rpl::start_with_next([=](EmojiPtr emoji) {
Ui::InsertEmojiAtCursor(_caption->textCursor(), emoji); Ui::InsertEmojiAtCursor(_caption->textCursor(), emoji);

View file

@ -57,7 +57,7 @@ public:
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
Ui::PreparedList &&list, Ui::PreparedList &&list,
const TextWithTags &caption, const TextWithTags &caption,
SendLimit limit, not_null<PeerData*> peer,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Type sendMenuType); SendMenu::Type sendMenuType);
@ -168,6 +168,7 @@ private:
SendLimit _sendLimit = SendLimit::Many; SendLimit _sendLimit = SendLimit::Many;
SendMenu::Type _sendMenuType = SendMenu::Type(); SendMenu::Type _sendMenuType = SendMenu::Type();
bool _allowEmojiWithoutPremium = false;
Fn<void( Fn<void(
Ui::PreparedList &&list, Ui::PreparedList &&list,

View file

@ -422,13 +422,14 @@ void StickerSetBox::updateButtons() {
if (!_controller->session().premium() if (!_controller->session().premium()
&& _controller->session().premiumPossible() && _controller->session().premiumPossible()
&& _inner->premiumEmojiSet()) { && _inner->premiumEmojiSet()) {
setStyle(st::premiumPreviewBox); const auto &st = st::premiumPreviewDoubledLimitsBox;
setStyle(st);
auto button = CreateUnlockButton( auto button = CreateUnlockButton(
this, this,
tr::lng_premium_unlock_emoji()); tr::lng_premium_unlock_emoji());
button->resizeToWidth(st::boxWideWidth button->resizeToWidth(st::boxWideWidth
- st::premiumPreviewBox.buttonPadding.left() - st.buttonPadding.left()
- st::premiumPreviewBox.buttonPadding.left()); - st.buttonPadding.left());
button->setClickedCallback([=] { button->setClickedCallback([=] {
Settings::ShowPremium(_controller, u"animated_emoji"_q); Settings::ShowPremium(_controller, u"animated_emoji"_q);
}); });

View file

@ -776,7 +776,7 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
drawCollapsedBadge(p, w - _areaPosition, info.count); drawCollapsedBadge(p, w - _areaPosition, info.count);
continue; continue;
} }
if (selected && !info.premiumRequired) { if (selected) {
auto tl = w; auto tl = w;
if (rtl()) { if (rtl()) {
tl.setX(width() - tl.x() - st::emojiPanArea.width()); tl.setX(width() - tl.x() - st::emojiPanArea.width());
@ -1023,7 +1023,9 @@ void EmojiListWidget::selectEmoji(EmojiPtr emoji) {
} }
void EmojiListWidget::selectCustom(not_null<DocumentData*> document) { void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
if (document->isPremiumEmoji() && !document->session().premium()) { if (document->isPremiumEmoji()
&& !document->session().premium()
&& !_allowWithoutPremium) {
ShowPremiumPreviewBox( ShowPremiumPreviewBox(
controller(), controller(),
PremiumPreview::AnimatedEmoji, PremiumPreview::AnimatedEmoji,
@ -1231,6 +1233,15 @@ uint64 EmojiListWidget::currentSet(int yOffset) const {
return sectionSetId(sectionInfoByOffset(yOffset).section); return sectionSetId(sectionInfoByOffset(yOffset).section);
} }
void EmojiListWidget::setAllowWithoutPremium(bool allow) {
if (_allowWithoutPremium == allow) {
return;
}
_allowWithoutPremium = allow;
refreshCustom();
resizeToWidth(width());
}
QString EmojiListWidget::tooltipText() const { QString EmojiListWidget::tooltipText() const {
const auto &replacements = Ui::Emoji::internal::GetAllReplacements(); const auto &replacements = Ui::Emoji::internal::GetAllReplacements();
const auto over = std::get_if<OverEmoji>(&_selected); const auto over = std::get_if<OverEmoji>(&_selected);
@ -1285,7 +1296,9 @@ void EmojiListWidget::refreshCustom() {
auto old = base::take(_custom); auto old = base::take(_custom);
const auto session = &controller()->session(); const auto session = &controller()->session();
const auto premiumPossible = session->premiumPossible(); const auto premiumPossible = session->premiumPossible();
const auto premiumMayBeBought = premiumPossible && !session->premium(); const auto premiumMayBeBought = premiumPossible
&& !session->premium()
&& !_allowWithoutPremium;
const auto owner = &session->data(); const auto owner = &session->data();
const auto &sets = owner->stickers().sets(); const auto &sets = owner->stickers().sets();
const auto push = [&](uint64 setId, bool installed) { const auto push = [&](uint64 setId, bool installed) {

View file

@ -70,6 +70,7 @@ public:
void showSet(uint64 setId); void showSet(uint64 setId);
[[nodiscard]] uint64 currentSet(int yOffset) const; [[nodiscard]] uint64 currentSet(int yOffset) const;
void setAllowWithoutPremium(bool allow);
// Ui::AbstractTooltipShower interface. // Ui::AbstractTooltipShower interface.
QString tooltipText() const override; QString tooltipText() const override;
@ -274,6 +275,7 @@ private:
QVector<EmojiPtr> _emoji[kEmojiSectionCount]; QVector<EmojiPtr> _emoji[kEmojiSectionCount];
std::vector<CustomSet> _custom; std::vector<CustomSet> _custom;
base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji; base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji;
bool _allowWithoutPremium = false;
int _rowsLeft = 0; int _rowsLeft = 0;
int _columnCount = 1; int _columnCount = 1;

View file

@ -56,21 +56,21 @@ class FieldTagMimeProcessor final {
public: public:
FieldTagMimeProcessor( FieldTagMimeProcessor(
not_null<Main::Session*> _session, not_null<Main::Session*> _session,
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted); Fn<bool(not_null<DocumentData*>)> allowPremiumEmoji);
QString operator()(QStringView mimeTag); QString operator()(QStringView mimeTag);
private: private:
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
const Fn<void(not_null<DocumentData*>)> _unavailableEmojiPasted; const Fn<bool(not_null<DocumentData*>)> _allowPremiumEmoji;
}; };
FieldTagMimeProcessor::FieldTagMimeProcessor( FieldTagMimeProcessor::FieldTagMimeProcessor(
not_null<Main::Session*> session, not_null<Main::Session*> session,
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted) Fn<bool(not_null<DocumentData*>)> allowPremiumEmoji)
: _session(session) : _session(session)
, _unavailableEmojiPasted(unavailableEmojiPasted) { , _allowPremiumEmoji(allowPremiumEmoji) {
} }
QString FieldTagMimeProcessor::operator()(QStringView mimeTag) { QString FieldTagMimeProcessor::operator()(QStringView mimeTag) {
@ -93,19 +93,19 @@ QString FieldTagMimeProcessor::operator()(QStringView mimeTag) {
if (!_session->premium()) { if (!_session->premium()) {
const auto document = _session->data().document(emoji.id); const auto document = _session->data().document(emoji.id);
if (document->isPremiumEmoji()) { if (document->isPremiumEmoji()) {
premiumSkipped = document; if (!_allowPremiumEmoji
i = all.erase(i); || premiumSkipped
continue; || !_session->premiumPossible()
|| !_allowPremiumEmoji(document)) {
premiumSkipped = document;
i = all.erase(i);
continue;
}
} }
} }
} }
++i; ++i;
} }
if (premiumSkipped
&& _session->premiumPossible()
&& _unavailableEmojiPasted) {
_unavailableEmojiPasted(premiumSkipped);
}
return TextUtilities::JoinTag(all); return TextUtilities::JoinTag(all);
} }
@ -313,10 +313,10 @@ void InitMessageFieldHandlers(
std::shared_ptr<Ui::Show> show, std::shared_ptr<Ui::Show> show,
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
Fn<bool()> customEmojiPaused, Fn<bool()> customEmojiPaused,
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted, Fn<bool(not_null<DocumentData*>)> allowPremiumEmoji,
const style::InputField *fieldStyle) { const style::InputField *fieldStyle) {
field->setTagMimeProcessor( field->setTagMimeProcessor(
FieldTagMimeProcessor(session, unavailableEmojiPasted)); FieldTagMimeProcessor(session, allowPremiumEmoji));
field->setCustomEmojiFactory([=](QStringView data, Fn<void()> update) { field->setCustomEmojiFactory([=](QStringView data, Fn<void()> update) {
return session->data().customEmojiManager().create( return session->data().customEmojiManager().create(
data, data,
@ -337,13 +337,13 @@ void InitMessageFieldHandlers(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
Window::GifPauseReason pauseReasonLevel, Window::GifPauseReason pauseReasonLevel,
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted) { Fn<bool(not_null<DocumentData*>)> allowPremiumEmoji) {
InitMessageFieldHandlers( InitMessageFieldHandlers(
&controller->session(), &controller->session(),
std::make_shared<Window::Show>(controller), std::make_shared<Window::Show>(controller),
field, field,
[=] { return controller->isGifPausedAtLeastFor(pauseReasonLevel); }, [=] { return controller->isGifPausedAtLeastFor(pauseReasonLevel); },
unavailableEmojiPasted); allowPremiumEmoji);
} }
void InitMessageFieldGeometry(not_null<Ui::InputField*> field) { void InitMessageFieldGeometry(not_null<Ui::InputField*> field) {
@ -358,12 +358,12 @@ void InitMessageFieldGeometry(not_null<Ui::InputField*> field) {
void InitMessageField( void InitMessageField(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted) { Fn<bool(not_null<DocumentData*>)> allowPremiumEmoji) {
InitMessageFieldHandlers( InitMessageFieldHandlers(
controller, controller,
field, field,
Window::GifPauseReason::Any, Window::GifPauseReason::Any,
unavailableEmojiPasted); allowPremiumEmoji);
InitMessageFieldGeometry(field); InitMessageFieldGeometry(field);
field->customTab(true); field->customTab(true);
} }

View file

@ -49,17 +49,17 @@ void InitMessageFieldHandlers(
std::shared_ptr<Ui::Show> show, std::shared_ptr<Ui::Show> show,
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
Fn<bool()> customEmojiPaused, Fn<bool()> customEmojiPaused,
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted = nullptr, Fn<bool(not_null<DocumentData*>)> allowPremiumEmoji = nullptr,
const style::InputField *fieldStyle = nullptr); const style::InputField *fieldStyle = nullptr);
void InitMessageFieldHandlers( void InitMessageFieldHandlers(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
Window::GifPauseReason pauseReasonLevel, Window::GifPauseReason pauseReasonLevel,
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted = nullptr); Fn<bool(not_null<DocumentData*>)> allowPremiumEmoji = nullptr);
void InitMessageField( void InitMessageField(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted); Fn<bool(not_null<DocumentData*>)> allowPremiumEmoji);
void InitSpellchecker( void InitSpellchecker(
std::shared_ptr<Ui::Show> show, std::shared_ptr<Ui::Show> show,

View file

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/stickers/data_stickers.h" #include "data/stickers/data_stickers.h"
#include "data/stickers/data_custom_emoji.h" // AllowEmojiWithoutPremium.
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "apiwrap.h" #include "apiwrap.h"
@ -839,6 +840,8 @@ void TabbedSelector::setCurrentPeer(PeerData *peer) {
if (hasStickersTab()) { if (hasStickersTab()) {
stickers()->showMegagroupSet(peer ? peer->asMegagroup() : nullptr); stickers()->showMegagroupSet(peer ? peer->asMegagroup() : nullptr);
} }
setAllowEmojiWithoutPremium(
peer && Data::AllowEmojiWithoutPremium(peer));
} }
void TabbedSelector::checkRestrictedPeer() { void TabbedSelector::checkRestrictedPeer() {
@ -924,6 +927,15 @@ void TabbedSelector::setRoundRadius(int radius) {
} }
} }
void TabbedSelector::setAllowEmojiWithoutPremium(bool allow) {
for (const auto &tab : _tabs) {
if (tab.type() == SelectorTab::Emoji) {
const auto emoji = static_cast<EmojiListWidget*>(tab.widget());
emoji->setAllowWithoutPremium(allow);
}
}
}
void TabbedSelector::createTabsSlider() { void TabbedSelector::createTabsSlider() {
_tabsSlider.create(this, st::emojiTabs); _tabsSlider.create(this, st::emojiTabs);

View file

@ -98,6 +98,7 @@ public:
rpl::producer<> contextMenuRequested() const; rpl::producer<> contextMenuRequested() const;
rpl::producer<Action> choosingStickerUpdated() const; rpl::producer<Action> choosingStickerUpdated() const;
void setAllowEmojiWithoutPremium(bool allow);
void setRoundRadius(int radius); void setRoundRadius(int radius);
void refreshStickers(); void refreshStickers();
void setCurrentPeer(PeerData *peer); void setCurrentPeer(PeerData *peer);

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_document_media.h" #include "data/data_document_media.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_peer.h"
#include "lottie/lottie_common.h" #include "lottie/lottie_common.h"
#include "lottie/lottie_emoji.h" #include "lottie/lottie_emoji.h"
#include "ffmpeg/ffmpeg_emoji.h" #include "ffmpeg/ffmpeg_emoji.h"
@ -646,6 +647,10 @@ CustomEmojiId ParseCustomEmojiData(QStringView data) {
}; };
} }
bool AllowEmojiWithoutPremium(not_null<PeerData*> peer) {
return peer->isSelf();
}
void InsertCustomEmoji( void InsertCustomEmoji(
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
not_null<DocumentData*> document) { not_null<DocumentData*> document) {

View file

@ -122,6 +122,8 @@ private:
not_null<DocumentData*> document); not_null<DocumentData*> document);
[[nodiscard]] CustomEmojiId ParseCustomEmojiData(QStringView data); [[nodiscard]] CustomEmojiId ParseCustomEmojiData(QStringView data);
[[nodiscard]] bool AllowEmojiWithoutPremium(not_null<PeerData*> peer);
void InsertCustomEmoji( void InsertCustomEmoji(
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
not_null<DocumentData*> document); not_null<DocumentData*> document);

View file

@ -404,7 +404,6 @@ HistoryMessage::HistoryMessage(
const auto dropForwardInfo = (originalMedia const auto dropForwardInfo = (originalMedia
&& originalMedia->dropForwardedInfo()) && originalMedia->dropForwardedInfo())
|| (original->history()->peer->isSelf() || (original->history()->peer->isSelf()
&& !history->peer->isSelf()
&& !original->Has<HistoryMessageForwarded>() && !original->Has<HistoryMessageForwarded>()
&& (!originalMedia || !originalMedia->forceForwardedInfo())); && (!originalMedia || !originalMedia->forceForwardedInfo()));
if (!dropForwardInfo) { if (!dropForwardInfo) {

View file

@ -396,7 +396,11 @@ HistoryWidget::HistoryWidget(
InitMessageField(controller, _field, [=]( InitMessageField(controller, _field, [=](
not_null<DocumentData*> document) { not_null<DocumentData*> document) {
if (_peer && Data::AllowEmojiWithoutPremium(_peer)) {
return true;
}
showPremiumToast(document); showPremiumToast(document);
return false;
}); });
_keyboard->sendCommandRequests( _keyboard->sendCommandRequests(
@ -5001,7 +5005,7 @@ bool HistoryWidget::confirmSendingFiles(
controller(), controller(),
std::move(list), std::move(list),
text, text,
_peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many, _peer,
Api::SendType::Normal, Api::SendType::Normal,
sendMenuType()); sendMenuType());
_field->setTextWithTags({}); _field->setTextWithTags({});

View file

@ -1422,7 +1422,15 @@ void ComposeControls::initField() {
Ui::Connect(_field, &Ui::InputField::resized, [=] { updateHeight(); }); Ui::Connect(_field, &Ui::InputField::resized, [=] { updateHeight(); });
//Ui::Connect(_field, &Ui::InputField::focused, [=] { fieldFocused(); }); //Ui::Connect(_field, &Ui::InputField::focused, [=] { fieldFocused(); });
Ui::Connect(_field, &Ui::InputField::changed, [=] { fieldChanged(); }); Ui::Connect(_field, &Ui::InputField::changed, [=] { fieldChanged(); });
InitMessageField(_window, _field, _unavailableEmojiPasted); InitMessageField(_window, _field, [=](not_null<DocumentData*> emoji) {
if (_history && Data::AllowEmojiWithoutPremium(_history->peer)) {
return true;
}
if (_unavailableEmojiPasted) {
_unavailableEmojiPasted(emoji);
}
return false;
});
initAutocomplete(); initAutocomplete();
const auto suggestions = Ui::Emoji::SuggestionsController::Init( const auto suggestions = Ui::Emoji::SuggestionsController::Init(
_parent, _parent,

View file

@ -747,7 +747,7 @@ bool RepliesWidget::confirmSendingFiles(
controller(), controller(),
std::move(list), std::move(list),
_composeControls->getTextWithAppliedMarkdown(), _composeControls->getTextWithAppliedMarkdown(),
_history->peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many, _history->peer,
Api::SendType::Normal, Api::SendType::Normal,
SendMenu::Type::SilentOnly); // #TODO replies schedule SendMenu::Type::SilentOnly); // #TODO replies schedule

View file

@ -195,8 +195,6 @@ private:
void clearSelected(); void clearSelected();
void setPinnedVisibility(bool shown); void setPinnedVisibility(bool shown);
void showPremiumToast(not_null<DocumentData*> document);
[[nodiscard]] Api::SendAction prepareSendAction( [[nodiscard]] Api::SendAction prepareSendAction(
Api::SendOptions options) const; Api::SendOptions options) const;
void send(); void send();

View file

@ -405,7 +405,7 @@ bool ScheduledWidget::confirmSendingFiles(
controller(), controller(),
std::move(list), std::move(list),
_composeControls->getTextWithAppliedMarkdown(), _composeControls->getTextWithAppliedMarkdown(),
_history->peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many, _history->peer,
CanScheduleUntilOnline(_history->peer) CanScheduleUntilOnline(_history->peer)
? Api::SendType::ScheduledToUser ? Api::SendType::ScheduledToUser
: Api::SendType::Scheduled, : Api::SendType::Scheduled,