Allow editing caption above/below media.

This commit is contained in:
John Preston 2024-05-29 23:09:51 +04:00
parent 67f7816088
commit 8c0351be4e
10 changed files with 200 additions and 91 deletions

View file

@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_session_settings.h" #include "main/main_session_settings.h"
#include "mainwidget.h" // controller->content() -> QWidget* #include "mainwidget.h" // controller->content() -> QWidget*
#include "menu/menu_send.h"
#include "mtproto/mtproto_config.h" #include "mtproto/mtproto_config.h"
#include "platform/platform_specific.h" #include "platform/platform_specific.h"
#include "storage/localimageloader.h" // SendMediaType #include "storage/localimageloader.h" // SendMediaType
@ -225,13 +226,6 @@ void EditPhotoImage(
} // namespace } // namespace
EditCaptionBox::EditCaptionBox(
QWidget*,
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item)
: EditCaptionBox({}, controller, item, PrepareEditText(item), {}, {}) {
}
EditCaptionBox::EditCaptionBox( EditCaptionBox::EditCaptionBox(
QWidget*, QWidget*,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
@ -365,9 +359,21 @@ void EditCaptionBox::StartPhotoEdit(
} }
void EditCaptionBox::prepare() { void EditCaptionBox::prepare() {
addButton(tr::lng_settings_save(), [=] { save(); }); const auto button = addButton(tr::lng_settings_save(), [=] { save(); });
addButton(tr::lng_cancel(), [=] { closeBox(); }); addButton(tr::lng_cancel(), [=] { closeBox(); });
const auto details = crl::guard(this, [=] {
return SendMenu::Details();
});
const auto callback = [=](SendMenu::Action action, const auto &) {
};
SendMenu::SetupMenuAndShortcuts(
button,
nullptr,
details,
crl::guard(this, callback));
updateBoxSize(); updateBoxSize();
setupField(); setupField();
@ -899,6 +905,7 @@ void EditCaptionBox::save() {
auto options = Api::SendOptions(); auto options = Api::SendOptions();
options.scheduled = item->isScheduled() ? item->date() : 0; options.scheduled = item->isScheduled() ? item->date() : 0;
options.shortcutId = item->shortcutId(); options.shortcutId = item->shortcutId();
//options.invertCaption = _invertCaption;
if (!_preparedList.files.empty()) { if (!_preparedList.files.empty()) {
if ((_albumType != Ui::AlbumType::None) if ((_albumType != Ui::AlbumType::None)

View file

@ -32,10 +32,6 @@ enum class AlbumType;
class EditCaptionBox final : public Ui::BoxContent { class EditCaptionBox final : public Ui::BoxContent {
public: public:
EditCaptionBox(
QWidget*,
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item);
EditCaptionBox( EditCaptionBox(
QWidget*, QWidget*,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,

View file

@ -379,7 +379,7 @@ Fn<SendMenu::Details()> SendFilesBox::prepareSendMenuDetails(
const auto canMoveCaption = _list.canMoveCaption( const auto canMoveCaption = _list.canMoveCaption(
way.groupFiles() && way.sendImagesAsPhotos(), way.groupFiles() && way.sendImagesAsPhotos(),
way.sendImagesAsPhotos() way.sendImagesAsPhotos()
) && _caption && !_caption->getLastText().isEmpty(); ) && _caption && HasSendText(_caption);
result.caption = !canMoveCaption result.caption = !canMoveCaption
? SendMenu::CaptionState::None ? SendMenu::CaptionState::None
: _invertCaption : _invertCaption
@ -638,14 +638,15 @@ void SendFilesBox::addMenuButton() {
const auto &tabbed = _st.tabbed; const auto &tabbed = _st.tabbed;
const auto &icons = tabbed.icons; const auto &icons = tabbed.icons;
_menu = base::make_unique_q<Ui::PopupMenu>(top, tabbed.menu); _menu = base::make_unique_q<Ui::PopupMenu>(top, tabbed.menu);
const auto position = QCursor::pos();
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
_menu.get(), _menu.get(),
_show, _show,
_sendMenuDetails(), _sendMenuDetails(),
_sendMenuCallback, _sendMenuCallback,
&_st.tabbed.icons, &_st.tabbed.icons,
QCursor::pos()); position);
_menu->popup(QCursor::pos()); _menu->popup(position);
return true; return true;
}); });
} }

View file

@ -324,7 +324,12 @@ HistoryWidget::HistoryWidget(
{ {
using namespace SendMenu; using namespace SendMenu;
const auto sendAction = [=](Action action, Details) { const auto sendAction = [=](Action action, Details) {
if (action.type == ActionType::Send) { if (action.type == ActionType::CaptionUp
|| action.type == ActionType::CaptionDown
|| action.type == ActionType::SpoilerOn
|| action.type == ActionType::SpoilerOff) {
_mediaEditSpoiler.apply(action);
} else if (action.type == ActionType::Send) {
send(action.options); send(action.options);
} else { } else {
sendScheduled(action.options); sendScheduled(action.options);
@ -2672,7 +2677,7 @@ void HistoryWidget::setEditMsgId(MsgId msgId) {
unregisterDraftSources(); unregisterDraftSources();
_editMsgId = msgId; _editMsgId = msgId;
if (!msgId) { if (!msgId) {
_mediaEditSpoiler.setSpoilerOverride(std::nullopt); _mediaEditSpoiler.cancel();
_canReplaceMedia = false; _canReplaceMedia = false;
if (_preview) { if (_preview) {
_preview->setDisabled(false); _preview->setDisabled(false);
@ -4056,15 +4061,14 @@ void HistoryWidget::saveEditMsg() {
})(); })();
}; };
auto options = Api::SendOptions();
_saveEditMsgRequestId = Api::EditTextMessage( _saveEditMsgRequestId = Api::EditTextMessage(
item, item,
sending, sending,
webPageDraft, webPageDraft,
options, { .invertCaption = _mediaEditSpoiler.invertCaption() },
done, done,
fail, fail,
_mediaEditSpoiler.spoilerOverride()); _mediaEditSpoiler.spoilered());
} }
void HistoryWidget::hideChildWidgets() { void HistoryWidget::hideChildWidgets() {
@ -4222,6 +4226,12 @@ SendMenu::Details HistoryWidget::sendMenuDetails() const {
return { .type = type, .effectAllowed = effectAllowed }; return { .type = type, .effectAllowed = effectAllowed };
} }
SendMenu::Details HistoryWidget::saveMenuDetails() const {
return (_editMsgId && _replyEditMsg)
? _mediaEditSpoiler.sendMenuDetails(HasSendText(_field))
: SendMenu::Details();
}
auto HistoryWidget::computeSendButtonType() const { auto HistoryWidget::computeSendButtonType() const {
using Type = Ui::SendButton::Type; using Type = Ui::SendButton::Type;
@ -4236,7 +4246,11 @@ auto HistoryWidget::computeSendButtonType() const {
} }
SendMenu::Details HistoryWidget::sendButtonMenuDetails() const { SendMenu::Details HistoryWidget::sendButtonMenuDetails() const {
if (computeSendButtonType() != Ui::SendButton::Type::Send) { using Type = Ui::SendButton::Type;
const auto type = computeSendButtonType();
if (type == Type::Save) {
return saveMenuDetails();
} else if (type != Type::Send) {
return {}; return {};
} }
return sendMenuDetails(); return sendMenuDetails();
@ -6587,8 +6601,8 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
&& (e->button() == Qt::RightButton)) { && (e->button() == Qt::RightButton)) {
_mediaEditSpoiler.showMenu( _mediaEditSpoiler.showMenu(
_list, _list,
session().data().message(_history->peer, _editMsgId), [=] { mouseMoveEvent(nullptr); },
[=](bool) { mouseMoveEvent(nullptr); }); HasSendText(_field));
} else if (_inPhotoEdit && _photoEditMedia) { } else if (_inPhotoEdit && _photoEditMedia) {
EditCaptionBox::StartPhotoEdit( EditCaptionBox::StartPhotoEdit(
controller(), controller(),
@ -8171,6 +8185,9 @@ void HistoryWidget::updateReplyEditTexts(bool force) {
const auto editMedia = _editMsgId const auto editMedia = _editMsgId
? _replyEditMsg->media() ? _replyEditMsg->media()
: nullptr; : nullptr;
if (_editMsgId && _replyEditMsg) {
_mediaEditSpoiler.start(_replyEditMsg);
}
_canReplaceMedia = editMedia && editMedia->allowsEditMedia(); _canReplaceMedia = editMedia && editMedia->allowsEditMedia();
_photoEditMedia = (_canReplaceMedia _photoEditMedia = (_canReplaceMedia
&& editMedia->photo() && editMedia->photo()
@ -8264,14 +8281,12 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
? drawMsgText->media() ? drawMsgText->media()
: nullptr; : nullptr;
const auto hasPreview = media && media->hasReplyPreview(); const auto hasPreview = media && media->hasReplyPreview();
const auto preview = _mediaEditSpoiler.spoilerOverride() const auto preview = _mediaEditSpoiler
? _mediaEditSpoiler.mediaPreview(drawMsgText) ? _mediaEditSpoiler.mediaPreview()
: hasPreview : hasPreview
? media->replyPreview() ? media->replyPreview()
: nullptr; : nullptr;
const auto spoilered = _mediaEditSpoiler.spoilerOverride() const auto spoilered = _mediaEditSpoiler.spoilered();
? (*_mediaEditSpoiler.spoilerOverride())
: (preview && media->hasSpoiler());
if (!spoilered) { if (!spoilered) {
_replySpoiler = nullptr; _replySpoiler = nullptr;
} else if (!_replySpoiler) { } else if (!_replySpoiler) {

View file

@ -269,6 +269,7 @@ public:
void clearSelected(); void clearSelected();
[[nodiscard]] SendMenu::Details sendMenuDetails() const; [[nodiscard]] SendMenu::Details sendMenuDetails() const;
[[nodiscard]] SendMenu::Details saveMenuDetails() const;
bool sendExistingDocument( bool sendExistingDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
Api::SendOptions options, Api::SendOptions options,

View file

@ -124,7 +124,8 @@ class FieldHeader final : public Ui::RpWidget {
public: public:
FieldHeader( FieldHeader(
QWidget *parent, QWidget *parent,
std::shared_ptr<ChatHelpers::Show> show); std::shared_ptr<ChatHelpers::Show> show,
Fn<bool()> hasSendText);
void setHistory(const SetHistoryArgs &args); void setHistory(const SetHistoryArgs &args);
void updateTopicRootId(MsgId topicRootId); void updateTopicRootId(MsgId topicRootId);
@ -187,6 +188,8 @@ private:
}; };
const std::shared_ptr<ChatHelpers::Show> _show; const std::shared_ptr<ChatHelpers::Show> _show;
const Fn<bool()> _hasSendText;
History *_history = nullptr; History *_history = nullptr;
MsgId _topicRootId = 0; MsgId _topicRootId = 0;
@ -230,9 +233,11 @@ private:
FieldHeader::FieldHeader( FieldHeader::FieldHeader(
QWidget *parent, QWidget *parent,
std::shared_ptr<ChatHelpers::Show> show) std::shared_ptr<ChatHelpers::Show> show,
Fn<bool()> hasSendText)
: RpWidget(parent) : RpWidget(parent)
, _show(std::move(show)) , _show(std::move(show))
, _hasSendText(std::move(hasSendText))
, _forwardPanel( , _forwardPanel(
std::make_unique<ForwardPanel>([=] { customEmojiRepaint(); })) std::make_unique<ForwardPanel>([=] { customEmojiRepaint(); }))
, _data(&_show->session().data()) , _data(&_show->session().data())
@ -406,8 +411,8 @@ void FieldHeader::init() {
if (inPreviewRect && isEditingMessage()) { if (inPreviewRect && isEditingMessage()) {
_mediaEditSpoiler.showMenu( _mediaEditSpoiler.showMenu(
this, this,
_data->message(_editMsgId.current()), [=] { update(); },
[=](bool) { update(); }); _hasSendText());
} else if (const auto reply = replyingToMessage()) { } else if (const auto reply = replyingToMessage()) {
_jumpToItemRequests.fire_copy(reply); _jumpToItemRequests.fire_copy(reply);
} }
@ -582,14 +587,12 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) {
const auto media = _shownMessage->media(); const auto media = _shownMessage->media();
_shownMessageHasPreview = media && media->hasReplyPreview(); _shownMessageHasPreview = media && media->hasReplyPreview();
const auto preview = _mediaEditSpoiler.spoilerOverride() const auto preview = _mediaEditSpoiler
? _mediaEditSpoiler.mediaPreview(_shownMessage) ? _mediaEditSpoiler.mediaPreview()
: _shownMessageHasPreview : _shownMessageHasPreview
? media->replyPreview() ? media->replyPreview()
: nullptr; : nullptr;
const auto spoilered = _mediaEditSpoiler.spoilerOverride() const auto spoilered = _mediaEditSpoiler.spoilered();
? (*_mediaEditSpoiler.spoilerOverride())
: (preview && media->hasSpoiler());
if (!spoilered) { if (!spoilered) {
_shownPreviewSpoiler = nullptr; _shownPreviewSpoiler = nullptr;
} else if (!_shownPreviewSpoiler) { } else if (!_shownPreviewSpoiler) {
@ -734,7 +737,7 @@ void FieldHeader::editMessage(FullMsgId id, bool photoEditAllowed) {
_photoEditAllowed = photoEditAllowed; _photoEditAllowed = photoEditAllowed;
_editMsgId = id; _editMsgId = id;
if (!photoEditAllowed) { if (!photoEditAllowed) {
_mediaEditSpoiler.setSpoilerOverride(std::nullopt); _mediaEditSpoiler.cancel();
_inPhotoEdit = false; _inPhotoEdit = false;
_inPhotoEditOver.stop(); _inPhotoEditOver.stop();
} }
@ -781,8 +784,9 @@ MessageToEdit FieldHeader::queryToEdit() {
.options = { .options = {
.scheduled = item->isScheduled() ? item->date() : 0, .scheduled = item->isScheduled() ? item->date() : 0,
.shortcutId = item->shortcutId(), .shortcutId = item->shortcutId(),
.invertCaption = _mediaEditSpoiler.invertCaption(),
}, },
.spoilerMediaOverride = _mediaEditSpoiler.spoilerOverride(), .spoilerMediaOverride = _mediaEditSpoiler.spoilered(),
}; };
} }
@ -842,7 +846,10 @@ ComposeControls::ComposeControls(
parent, parent,
_show, _show,
&_st.tabbed)) &_st.tabbed))
, _header(std::make_unique<FieldHeader>(_wrap.get(), _show)) , _header(std::make_unique<FieldHeader>(
_wrap.get(),
_show,
[=] { return HasSendText(_field); }))
, _voiceRecordBar(std::make_unique<VoiceRecordBar>( , _voiceRecordBar(std::make_unique<VoiceRecordBar>(
_wrap.get(), _wrap.get(),
Controls::VoiceRecordBarDescriptor{ Controls::VoiceRecordBarDescriptor{

View file

@ -10,74 +10,134 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_session.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "menu/menu_send.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_menu_icons.h" #include "styles/style_menu_icons.h"
namespace HistoryView { namespace HistoryView {
MediaEditSpoilerManager::MediaEditSpoilerManager() = default; MediaEditSpoilerManager::MediaEditSpoilerManager() = default;
void MediaEditSpoilerManager::start(not_null<HistoryItem*> item) {
const auto media = item->media();
if (!media) {
return;
}
_item = item;
_spoilered = media->hasSpoiler();
_invertCaption = item->invertMedia();
_lifetime = item->history()->owner().itemRemoved(
) | rpl::start_with_next([=](not_null<const HistoryItem*> removed) {
if (removed == _item) {
cancel();
}
});
}
void MediaEditSpoilerManager::apply(SendMenu::Action action) {
using Type = SendMenu::Action::Type;
if (action.type == Type::CaptionUp) {
_invertCaption = true;
} else if (action.type == Type::CaptionDown) {
_invertCaption = false;
} else if (action.type == Type::SpoilerOn) {
_spoilered = true;
} else if (action.type == Type::SpoilerOff) {
_spoilered = false;
}
}
void MediaEditSpoilerManager::cancel() {
_menu = nullptr;
_item = nullptr;
_lifetime.destroy();
}
void MediaEditSpoilerManager::showMenu( void MediaEditSpoilerManager::showMenu(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item, Fn<void()> finished,
Fn<void(bool)> callback) { bool hasCaptionText) {
const auto media = item->media(); if (!_item) {
return;
}
const auto media = _item->media();
const auto hasPreview = media && media->hasReplyPreview(); const auto hasPreview = media && media->hasReplyPreview();
const auto preview = hasPreview ? media->replyPreview() : nullptr; const auto preview = hasPreview ? media->replyPreview() : nullptr;
if (!preview || (media && media->webpage())) { if (!preview || (media && media->webpage())) {
return; return;
} }
const auto spoilered = _spoilerOverride _menu = base::make_unique_q<Ui::PopupMenu>(
? (*_spoilerOverride)
: (preview && media->hasSpoiler());
const auto menu = Ui::CreateChild<Ui::PopupMenu>(
parent, parent,
st::popupMenuWithIcons); st::popupMenuWithIcons);
menu->addAction( const auto callback = [=](SendMenu::Action action, const auto &) {
spoilered apply(action);
? tr::lng_context_disable_spoiler(tr::now) };
: tr::lng_context_spoiler_effect(tr::now), const auto position = QCursor::pos();
[=] { SendMenu::FillSendMenu(
_spoilerOverride = (!spoilered); _menu.get(),
if (callback) { nullptr,
callback(!spoilered); sendMenuDetails(hasCaptionText),
} callback,
}, &st::defaultComposeIcons,
spoilered ? &st::menuIconSpoilerOff : &st::menuIconSpoiler); position);
menu->popup(QCursor::pos()); _menu->popup(position);
} }
[[nodiscard]] Image *MediaEditSpoilerManager::mediaPreview( [[nodiscard]] Image *MediaEditSpoilerManager::mediaPreview() {
not_null<HistoryItem*> item) { if (const auto media = _item ? _item->media() : nullptr) {
if (!_spoilerOverride) {
return nullptr;
}
if (const auto media = item->media()) {
if (const auto photo = media->photo()) { if (const auto photo = media->photo()) {
return photo->getReplyPreview( return photo->getReplyPreview(
item->fullId(), _item->fullId(),
item->history()->peer, _item->history()->peer,
*_spoilerOverride); _spoilered);
} else if (const auto document = media->document()) { } else if (const auto document = media->document()) {
return document->getReplyPreview( return document->getReplyPreview(
item->fullId(), _item->fullId(),
item->history()->peer, _item->history()->peer,
*_spoilerOverride); _spoilered);
} }
} }
return nullptr; return nullptr;
} }
void MediaEditSpoilerManager::setSpoilerOverride( bool MediaEditSpoilerManager::spoilered() const {
std::optional<bool> spoilerOverride) { return _spoilered;
_spoilerOverride = spoilerOverride;
} }
std::optional<bool> MediaEditSpoilerManager::spoilerOverride() const { bool MediaEditSpoilerManager::invertCaption() const {
return _spoilerOverride; return _invertCaption;
}
SendMenu::Details MediaEditSpoilerManager::sendMenuDetails(
bool hasCaptionText) const {
const auto media = _item ? _item->media() : nullptr;
if (!media) {
return {};
}
const auto editingMedia = media->allowsEditMedia();
const auto editPhoto = editingMedia ? media->photo() : nullptr;
const auto editDocument = editingMedia ? media->document() : nullptr;
const auto canSaveSpoiler = (editPhoto && !editPhoto->isNull())
|| (editDocument
&& (editDocument->isVideoFile() || editDocument->isGifv()));
const auto canMoveCaption = media->allowsEditCaption() && hasCaptionText;
return {
.spoiler = (!canSaveSpoiler
? SendMenu::SpoilerState::None
: _spoilered
? SendMenu::SpoilerState::Enabled
: SendMenu::SpoilerState::Possible),
.caption = (!canMoveCaption
? SendMenu::CaptionState::None
: _invertCaption
? SendMenu::CaptionState::Above
: SendMenu::CaptionState::Below),
};
} }
} // namespace HistoryView } // namespace HistoryView

View file

@ -7,8 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/unique_qptr.h"
namespace SendMenu {
struct Details;
struct Action;
} // namespace SendMenu
namespace Ui { namespace Ui {
class RpWidget; class RpWidget;
class PopupMenu;
} // namespace Ui } // namespace Ui
class Image; class Image;
@ -20,19 +28,34 @@ class MediaEditSpoilerManager final {
public: public:
MediaEditSpoilerManager(); MediaEditSpoilerManager();
void start(not_null<HistoryItem*> item);
void apply(SendMenu::Action action);
void cancel();
void showMenu( void showMenu(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item, Fn<void()> finished,
Fn<void(bool)> callback); bool hasCaptionText);
[[nodiscard]] Image *mediaPreview(not_null<HistoryItem*> item); [[nodiscard]] Image *mediaPreview();
void setSpoilerOverride(std::optional<bool> spoilerOverride); [[nodiscard]] bool spoilered() const;
[[nodiscard]] bool invertCaption() const;
std::optional<bool> spoilerOverride() const; [[nodiscard]] SendMenu::Details sendMenuDetails(
bool hasCaptionText) const;
[[nodiscard]] explicit operator bool() const {
return _item != nullptr;
}
private: private:
std::optional<bool> _spoilerOverride; base::unique_qptr<Ui::PopupMenu> _menu;
HistoryItem *_item = nullptr;
bool _spoilered = false;
bool _invertCaption = false;
rpl::lifetime _lifetime;
}; };

View file

@ -396,7 +396,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
} }
// date // date
if (_parent->media() == this) { if (_parent->media() == this && isBubbleBottom()) {
auto fullRight = width(); auto fullRight = width();
auto fullBottom = height(); auto fullBottom = height();
if (needInfoDisplay()) { if (needInfoDisplay()) {

View file

@ -615,7 +615,8 @@ FillMenuResult FillSendMenu(
const style::ComposeIcons *iconsOverride, const style::ComposeIcons *iconsOverride,
std::optional<QPoint> desiredPositionOverride) { std::optional<QPoint> desiredPositionOverride) {
const auto type = details.type; const auto type = details.type;
const auto empty = (type == Type::Disabled) const auto sending = (type != Type::Disabled);
const auto empty = !sending
&& (details.spoiler == SpoilerState::None) && (details.spoiler == SpoilerState::None)
&& (details.caption == CaptionState::None); && (details.caption == CaptionState::None);
if (empty || !action) { if (empty || !action) {
@ -653,18 +654,16 @@ FillMenuResult FillSendMenu(
toggles = true; toggles = true;
} }
if (toggles && type != Type::Disabled) { if (toggles && type != Type::Disabled) {
menu->addSeparator(); menu->addSeparator(&st::expandedMenuSeparator);
} }
if (type != Type::Reminder) { if (sending && type != Type::Reminder) {
menu->addAction( menu->addAction(
tr::lng_send_silent_message(tr::now), tr::lng_send_silent_message(tr::now),
[=] { action( [=] { action({ Api::SendOptions{ .silent = true } }, details); },
{ Api::SendOptions{ .silent = true } },
details); },
&icons.menuMute); &icons.menuMute);
} }
if (type != Type::SilentOnly) { if (sending && type != Type::SilentOnly) {
menu->addAction( menu->addAction(
(type == Type::Reminder (type == Type::Reminder
? tr::lng_reminder_message(tr::now) ? tr::lng_reminder_message(tr::now)
@ -672,7 +671,7 @@ FillMenuResult FillSendMenu(
[=] { action({ .type = ActionType::Schedule }, details); }, [=] { action({ .type = ActionType::Schedule }, details); },
&icons.menuSchedule); &icons.menuSchedule);
} }
if (type == Type::ScheduledToUser) { if (sending && type == Type::ScheduledToUser) {
menu->addAction( menu->addAction(
tr::lng_scheduled_send_until_online(tr::now), tr::lng_scheduled_send_until_online(tr::now),
[=] { action( [=] { action(