Check effects availability in all SendMenu-s.

This commit is contained in:
John Preston 2024-05-10 14:10:53 +04:00
parent 396ba9a984
commit d1106e5ae6
50 changed files with 394 additions and 417 deletions

View file

@ -910,12 +910,12 @@ CreatePollBox::CreatePollBox(
PollData::Flags chosen, PollData::Flags chosen,
PollData::Flags disabled, PollData::Flags disabled,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Type sendMenuType) SendMenu::Details sendMenuDetails)
: _controller(controller) : _controller(controller)
, _chosen(chosen) , _chosen(chosen)
, _disabled(disabled) , _disabled(disabled)
, _sendType(sendType) , _sendType(sendType)
, _sendMenuType(sendMenuType) { , _sendMenuDetails([result = sendMenuDetails] { return result; }) {
} }
rpl::producer<CreatePollBox::Result> CreatePollBox::submitRequests() const { rpl::producer<CreatePollBox::Result> CreatePollBox::submitRequests() const {
@ -1288,20 +1288,9 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
_submitRequests.fire({ collectResult(), sendOptions }); _submitRequests.fire({ collectResult(), sendOptions });
} }
}; };
const auto sendSilent = [=] { const auto sendAction = SendMenu::DefaultCallback(
send({ .silent = true }); _controller->uiShow(),
}; crl::guard(this, send));
const auto sendScheduled = [=] {
_controller->show(
HistoryView::PrepareScheduleBox(
this,
_controller->uiShow(),
SendMenu::Type::Scheduled,
send));
};
const auto sendWhenOnline = [=] {
send(Api::DefaultSendWhenOnlineOptions());
};
options->scrollToWidget( options->scrollToWidget(
) | rpl::start_with_next([=](not_null<QWidget*> widget) { ) | rpl::start_with_next([=](not_null<QWidget*> widget) {
@ -1314,25 +1303,23 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
}, lifetime()); }, lifetime());
const auto isNormal = (_sendType == Api::SendType::Normal); const auto isNormal = (_sendType == Api::SendType::Normal);
const auto schedule = [=] {
sendAction(SendMenu::ActionType::Schedule, _sendMenuDetails());
};
const auto submit = addButton( const auto submit = addButton(
isNormal (isNormal
? tr::lng_polls_create_button() ? tr::lng_polls_create_button()
: tr::lng_schedule_button(), : tr::lng_schedule_button()),
[=] { isNormal ? send({}) : sendScheduled(); }); [=] { isNormal ? send({}) : schedule(); });
const auto sendMenuType = [=] { const auto sendMenuDetails = [=] {
collectError(); collectError();
return (*error) return (*error) ? SendMenu::Details() : _sendMenuDetails();
? SendMenu::Type::Disabled
: _sendMenuType;
}; };
SendMenu::SetupMenuAndShortcuts( SendMenu::SetupMenuAndShortcuts(
submit.data(), submit.data(),
_controller->uiShow(), _controller->uiShow(),
sendMenuType, sendMenuDetails,
sendSilent, sendAction);
sendScheduled,
sendWhenOnline);
addButton(tr::lng_cancel(), [=] { closeBox(); }); addButton(tr::lng_cancel(), [=] { closeBox(); });
return result; return result;

View file

@ -27,7 +27,7 @@ class SessionController;
} // namespace Window } // namespace Window
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
class CreatePollBox : public Ui::BoxContent { class CreatePollBox : public Ui::BoxContent {
@ -43,7 +43,7 @@ public:
PollData::Flags chosen, PollData::Flags chosen,
PollData::Flags disabled, PollData::Flags disabled,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Type sendMenuType); SendMenu::Details sendMenuDetails);
[[nodiscard]] rpl::producer<Result> submitRequests() const; [[nodiscard]] rpl::producer<Result> submitRequests() const;
void submitFailed(const QString &error); void submitFailed(const QString &error);
@ -75,7 +75,7 @@ private:
const PollData::Flags _chosen = PollData::Flags(); const PollData::Flags _chosen = PollData::Flags();
const PollData::Flags _disabled = PollData::Flags(); const PollData::Flags _disabled = PollData::Flags();
const Api::SendType _sendType = Api::SendType(); const Api::SendType _sendType = Api::SendType();
const SendMenu::Type _sendMenuType; const Fn<SendMenu::Details()> _sendMenuDetails;
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel; base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
Fn<void()> _setInnerFocus; Fn<void()> _setInnerFocus;
Fn<rpl::producer<bool>()> _dataIsValidValue; Fn<rpl::producer<bool>()> _dataIsValidValue;

View file

@ -328,7 +328,7 @@ SendFilesBox::SendFilesBox(
const TextWithTags &caption, const TextWithTags &caption,
not_null<PeerData*> toPeer, not_null<PeerData*> toPeer,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Type sendMenuType) SendMenu::Details sendMenuDetails)
: SendFilesBox(nullptr, { : SendFilesBox(nullptr, {
.show = controller->uiShow(), .show = controller->uiShow(),
.list = std::move(list), .list = std::move(list),
@ -337,7 +337,7 @@ SendFilesBox::SendFilesBox(
.limits = DefaultLimitsForPeer(toPeer), .limits = DefaultLimitsForPeer(toPeer),
.check = DefaultCheckForPeer(controller, toPeer), .check = DefaultCheckForPeer(controller, toPeer),
.sendType = sendType, .sendType = sendType,
.sendMenuType = sendMenuType, .sendMenuDetails = [=] { return sendMenuDetails; },
}) { }) {
} }
@ -350,7 +350,9 @@ SendFilesBox::SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor)
, _titleHeight(st::boxTitleHeight) , _titleHeight(st::boxTitleHeight)
, _list(std::move(descriptor.list)) , _list(std::move(descriptor.list))
, _limits(descriptor.limits) , _limits(descriptor.limits)
, _sendMenuType(descriptor.sendMenuType) , _sendMenuDetails(descriptor.sendMenuDetails
? descriptor.sendMenuDetails
: [] { return SendMenu::Details(); })
, _captionToPeer(descriptor.captionToPeer) , _captionToPeer(descriptor.captionToPeer)
, _check(std::move(descriptor.check)) , _check(std::move(descriptor.check))
, _confirmedCallback(std::move(descriptor.confirmed)) , _confirmedCallback(std::move(descriptor.confirmed))
@ -530,10 +532,8 @@ void SendFilesBox::refreshButtons() {
SendMenu::SetupMenuAndShortcuts( SendMenu::SetupMenuAndShortcuts(
_send, _send,
_show, _show,
[=] { return _sendMenuType; }, _sendMenuDetails,
[=] { sendSilent(); }, SendMenu::DefaultCallback(_show, sendCallback()));
[=] { sendScheduled(); },
[=] { sendWhenOnline(); });
} }
addButton(tr::lng_cancel(), [=] { closeBox(); }); addButton(tr::lng_cancel(), [=] { closeBox(); });
_addFile = addLeftButton( _addFile = addLeftButton(
@ -546,7 +546,7 @@ void SendFilesBox::refreshButtons() {
} }
bool SendFilesBox::hasSendMenu() const { bool SendFilesBox::hasSendMenu() const {
return (_sendMenuType != SendMenu::Type::Disabled); return (_sendMenuDetails().type != SendMenu::Type::Disabled);
} }
bool SendFilesBox::hasSpoilerMenu() const { bool SendFilesBox::hasSpoilerMenu() const {
@ -607,11 +607,11 @@ void SendFilesBox::addMenuButton() {
if (hasSendMenu()) { if (hasSendMenu()) {
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
_menu.get(), _menu.get(),
_sendMenuType, _show,
[=] { sendSilent(); }, _sendMenuDetails(),
[=] { sendScheduled(); }, SendMenu::DefaultCallback(_show, sendCallback()),
[=] { sendWhenOnline(); }, &_st.tabbed.icons,
&_st.tabbed.icons); QCursor::pos());
} }
_menu->popup(QCursor::pos()); _menu->popup(QCursor::pos());
return true; return true;
@ -1426,7 +1426,9 @@ void SendFilesBox::send(
if ((_sendType == Api::SendType::Scheduled if ((_sendType == Api::SendType::Scheduled
|| _sendType == Api::SendType::ScheduledToUser) || _sendType == Api::SendType::ScheduledToUser)
&& !options.scheduled) { && !options.scheduled) {
return sendScheduled(); return SendMenu::DefaultCallback(_show, sendCallback())(
SendMenu::ActionType::Schedule,
_sendMenuDetails());
} }
if (_preparing) { if (_preparing) {
_whenReadySend = [=] { _whenReadySend = [=] {
@ -1464,25 +1466,10 @@ void SendFilesBox::send(
closeBox(); closeBox();
} }
void SendFilesBox::sendSilent() { Fn<void(Api::SendOptions)> SendFilesBox::sendCallback() {
send({ .silent = true }); return crl::guard(this, [=](Api::SendOptions options) {
} send(options, false);
});
void SendFilesBox::sendScheduled() {
const auto type = (_sendType == Api::SendType::ScheduledToUser)
? SendMenu::Type::ScheduledToUser
: _sendMenuType;
const auto callback = [=](Api::SendOptions options) { send(options); };
auto box = HistoryView::PrepareScheduleBox(this, _show, type, callback);
const auto weak = Ui::MakeWeak(box.data());
_show->showBox(std::move(box));
if (const auto strong = weak.data()) {
strong->setCloseByOutsideClick(false);
}
}
void SendFilesBox::sendWhenOnline() {
send(Api::DefaultSendWhenOnlineOptions());
} }
SendFilesBox::~SendFilesBox() = default; SendFilesBox::~SendFilesBox() = default;

View file

@ -47,7 +47,7 @@ class SessionController;
} // namespace Window } // namespace Window
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace HistoryView::Controls { namespace HistoryView::Controls {
@ -96,7 +96,7 @@ struct SendFilesBoxDescriptor {
SendFilesLimits limits = {}; SendFilesLimits limits = {};
SendFilesCheck check; SendFilesCheck check;
Api::SendType sendType = {}; Api::SendType sendType = {};
SendMenu::Type sendMenuType = {}; Fn<SendMenu::Details()> sendMenuDetails = nullptr;
const style::ComposeControls *stOverride = nullptr; const style::ComposeControls *stOverride = nullptr;
SendFilesConfirmed confirmed; SendFilesConfirmed confirmed;
Fn<void()> cancelled; Fn<void()> cancelled;
@ -115,7 +115,7 @@ public:
const TextWithTags &caption, const TextWithTags &caption,
not_null<PeerData*> toPeer, not_null<PeerData*> toPeer,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Type sendMenuType); SendMenu::Details sendMenuDetails);
SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor); SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor);
void setConfirmedCallback(SendFilesConfirmed callback) { void setConfirmedCallback(SendFilesConfirmed callback) {
@ -202,9 +202,7 @@ private:
void generatePreviewFrom(int fromBlock); void generatePreviewFrom(int fromBlock);
void send(Api::SendOptions options, bool ctrlShiftEnter = false); void send(Api::SendOptions options, bool ctrlShiftEnter = false);
void sendSilent(); [[nodiscard]] Fn<void(Api::SendOptions)> sendCallback();
void sendScheduled();
void sendWhenOnline();
void captionResized(); void captionResized();
void saveSendWaySettings(); void saveSendWaySettings();
@ -238,7 +236,7 @@ private:
std::optional<int> _removingIndex; std::optional<int> _removingIndex;
SendFilesLimits _limits = {}; SendFilesLimits _limits = {};
SendMenu::Type _sendMenuType = {}; Fn<SendMenu::Details()> _sendMenuDetails = nullptr;
PeerData *_captionToPeer = nullptr; PeerData *_captionToPeer = nullptr;
SendFilesCheck _check; SendFilesCheck _check;
SendFilesConfirmed _confirmedCallback; SendFilesConfirmed _confirmedCallback;

View file

@ -473,15 +473,18 @@ void ShareBox::keyPressEvent(QKeyEvent *e) {
} }
} }
SendMenu::Type ShareBox::sendMenuType() const { SendMenu::Details ShareBox::sendMenuDetails() const {
const auto selected = _inner->selected(); const auto selected = _inner->selected();
return ranges::all_of( const auto type = ranges::all_of(
selected | ranges::views::transform(&Data::Thread::peer), selected | ranges::views::transform(&Data::Thread::peer),
HistoryView::CanScheduleUntilOnline) HistoryView::CanScheduleUntilOnline)
? SendMenu::Type::ScheduledToUser ? SendMenu::Type::ScheduledToUser
: (selected.size() == 1 && selected.front()->peer()->isSelf()) : (selected.size() == 1 && selected.front()->peer()->isSelf())
? SendMenu::Type::Reminder ? SendMenu::Type::Reminder
: SendMenu::Type::Scheduled; : SendMenu::Type::Scheduled;
// We can't support effect here because we don't have ChatHelpers::Show.
return { .type = type, .effectAllowed = false };
} }
void ShareBox::showMenu(not_null<Ui::RpWidget*> parent) { void ShareBox::showMenu(not_null<Ui::RpWidget*> parent) {
@ -518,15 +521,25 @@ void ShareBox::showMenu(not_null<Ui::RpWidget*> parent) {
_menu->addSeparator(); _menu->addSeparator();
} }
const auto result = SendMenu::FillSendMenu( using namespace SendMenu;
const auto sendAction = crl::guard(this, [=](Action action, Details) {
const auto options = std::get_if<Api::SendOptions>(&action);
if (options || v::get<ActionType>(action) == ActionType::Send) {
submit(options ? *options : Api::SendOptions());
} else {
submitScheduled();
}
});
_menu->setForcedVerticalOrigin(Ui::PopupMenu::VerticalOrigin::Bottom);
const auto result = FillSendMenu(
_menu.get(), _menu.get(),
sendMenuType(), nullptr, // showForEffect.
[=] { submitSilent(); }, sendMenuDetails(),
[=] { submitScheduled(); }, sendAction);
[=] { submitWhenOnline(); }); if (result == SendMenu::FillMenuResult::Prepared) {
const auto success = (result == SendMenu::FillMenuResult::Success); _menu->popupPrepared();
if (_descriptor.forwardOptions.show || success) { } else if (_descriptor.forwardOptions.show
_menu->setForcedVerticalOrigin(Ui::PopupMenu::VerticalOrigin::Bottom); && result != SendMenu::FillMenuResult::Failed) {
_menu->popup(QCursor::pos()); _menu->popup(QCursor::pos());
} }
} }
@ -607,26 +620,18 @@ void ShareBox::submit(Api::SendOptions options) {
} }
} }
void ShareBox::submitSilent() {
submit({ .silent = true });
}
void ShareBox::submitScheduled() { void ShareBox::submitScheduled() {
const auto callback = [=](Api::SendOptions options) { submit(options); }; const auto callback = [=](Api::SendOptions options) { submit(options); };
uiShow()->showBox( uiShow()->showBox(
HistoryView::PrepareScheduleBox( HistoryView::PrepareScheduleBox(
this, this,
nullptr, // ChatHelpers::Show for effect attachment. nullptr, // ChatHelpers::Show for effect attachment.
sendMenuType(), sendMenuDetails(),
callback, callback,
HistoryView::DefaultScheduleTime(), HistoryView::DefaultScheduleTime(),
_descriptor.scheduleBoxStyle)); _descriptor.scheduleBoxStyle));
} }
void ShareBox::submitWhenOnline() {
submit(Api::DefaultSendWhenOnlineOptions());
}
void ShareBox::copyLink() const { void ShareBox::copyLink() const {
if (const auto onstack = _descriptor.copyCallback) { if (const auto onstack = _descriptor.copyCallback) {
onstack(); onstack();

View file

@ -24,7 +24,7 @@ struct PeerList;
} // namespace style } // namespace style
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace Window { namespace Window {
@ -130,13 +130,11 @@ private:
void scrollAnimationCallback(); void scrollAnimationCallback();
void submit(Api::SendOptions options); void submit(Api::SendOptions options);
void submitSilent();
void submitScheduled(); void submitScheduled();
void submitWhenOnline();
void copyLink() const; void copyLink() const;
bool searchByUsername(bool useCache = false); bool searchByUsername(bool useCache = false);
SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Details sendMenuDetails() const;
void scrollTo(Ui::ScrollToRequest request); void scrollTo(Ui::ScrollToRequest request);
void needSearchByUsername(); void needSearchByUsername();

View file

@ -1014,7 +1014,7 @@ void StickerSetBox::Inner::contextMenuEvent(QContextMenuEvent *e) {
_menu = base::make_unique_q<Ui::PopupMenu>( _menu = base::make_unique_q<Ui::PopupMenu>(
this, this,
st::popupMenuWithIcons); st::popupMenuWithIcons);
const auto type = _show->sendMenuType(); const auto details = _show->sendMenuDetails();
if (setType() == Data::StickersType::Emoji) { if (setType() == Data::StickersType::Emoji) {
if (const auto t = PrepareTextFromEmoji(_pack[index]); !t.empty()) { if (const auto t = PrepareTextFromEmoji(_pack[index]); !t.empty()) {
_menu->addAction(tr::lng_mediaview_copy(tr::now), [=] { _menu->addAction(tr::lng_mediaview_copy(tr::now), [=] {
@ -1023,17 +1023,16 @@ void StickerSetBox::Inner::contextMenuEvent(QContextMenuEvent *e) {
} }
}, &st::menuIconCopy); }, &st::menuIconCopy);
} }
} else if (type != SendMenu::Type::Disabled) { } else if (details.type != SendMenu::Type::Disabled) {
const auto document = _pack[index]; const auto document = _pack[index];
const auto sendSelected = [=](Api::SendOptions options) { const auto send = crl::guard(this, [=](Api::SendOptions options) {
chosen(index, document, options); chosen(index, document, options);
}; });
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
_menu.get(), _menu.get(),
type, _show,
SendMenu::DefaultSilentCallback(sendSelected), details,
SendMenu::DefaultScheduleCallback(_show, type, sendSelected), SendMenu::DefaultCallback(_show, send));
SendMenu::DefaultWhenOnlineCallback(sendSelected));
const auto show = _show; const auto show = _show;
const auto toggleFavedSticker = [=] { const auto toggleFavedSticker = [=] {

View file

@ -23,10 +23,6 @@ namespace Data {
class StickersSet; class StickersSet;
} // namespace Data } // namespace Data
namespace SendMenu {
enum class Type;
} // namespace SendMenu
namespace ChatHelpers { namespace ChatHelpers {
struct FileChosen; struct FileChosen;
class Show; class Show;

View file

@ -22,7 +22,7 @@ class SessionController;
} // namespace Window } // namespace Window
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace ChatHelpers { namespace ChatHelpers {
@ -57,7 +57,7 @@ public:
[[nodiscard]] virtual rpl::producer<> pauseChanged() const = 0; [[nodiscard]] virtual rpl::producer<> pauseChanged() const = 0;
[[nodiscard]] virtual rpl::producer<bool> adjustShadowLeft() const; [[nodiscard]] virtual rpl::producer<bool> adjustShadowLeft() const;
[[nodiscard]] virtual SendMenu::Type sendMenuType() const = 0; [[nodiscard]] virtual SendMenu::Details sendMenuDetails() const = 0;
virtual bool showMediaPreview( virtual bool showMediaPreview(
Data::FileOrigin origin, Data::FileOrigin origin,

View file

@ -1104,7 +1104,7 @@ void EmojiListWidget::fillRecentFrom(const std::vector<DocumentId> &list) {
} }
base::unique_qptr<Ui::PopupMenu> EmojiListWidget::fillContextMenu( base::unique_qptr<Ui::PopupMenu> EmojiListWidget::fillContextMenu(
SendMenu::Type type) { const SendMenu::Details &details) {
if (v::is_null(_selected)) { if (v::is_null(_selected)) {
return nullptr; return nullptr;
} }

View file

@ -144,7 +144,7 @@ public:
RectPart origin); RectPart origin);
base::unique_qptr<Ui::PopupMenu> fillContextMenu( base::unique_qptr<Ui::PopupMenu> fillContextMenu(
SendMenu::Type type) override; const SendMenu::Details &details) override;
protected: protected:
void visibleTopBottomUpdated( void visibleTopBottomUpdated(

View file

@ -87,7 +87,7 @@ public:
Api::SendOptions options = {}) const; Api::SendOptions options = {}) const;
void setRecentInlineBotsInRows(int32 bots); void setRecentInlineBotsInRows(int32 bots);
void setSendMenuType(Fn<SendMenu::Type()> &&callback); void setSendMenuDetails(Fn<SendMenu::Details()> &&callback);
void rowsUpdated(); void rowsUpdated();
rpl::producer<FieldAutocomplete::MentionChosen> mentionChosen() const; rpl::producer<FieldAutocomplete::MentionChosen> mentionChosen() const;
@ -155,7 +155,7 @@ private:
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient; const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
StickerPremiumMark _premiumMark; StickerPremiumMark _premiumMark;
Fn<SendMenu::Type()> _sendMenuType; Fn<SendMenu::Details()> _sendMenuDetails;
rpl::event_stream<FieldAutocomplete::MentionChosen> _mentionChosen; rpl::event_stream<FieldAutocomplete::MentionChosen> _mentionChosen;
rpl::event_stream<FieldAutocomplete::HashtagChosen> _hashtagChosen; rpl::event_stream<FieldAutocomplete::HashtagChosen> _hashtagChosen;
@ -835,8 +835,9 @@ bool FieldAutocomplete::chooseSelected(ChooseMethod method) const {
return _inner->chooseSelected(method); return _inner->chooseSelected(method);
} }
void FieldAutocomplete::setSendMenuType(Fn<SendMenu::Type()> &&callback) { void FieldAutocomplete::setSendMenuDetails(
_inner->setSendMenuType(std::move(callback)); Fn<SendMenu::Details()> &&callback) {
_inner->setSendMenuDetails(std::move(callback));
} }
bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) { bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) {
@ -1364,24 +1365,22 @@ void FieldAutocomplete::Inner::contextMenuEvent(QContextMenuEvent *e) {
return; return;
} }
const auto index = _sel; const auto index = _sel;
const auto type = _sendMenuType const auto details = _sendMenuDetails
? _sendMenuType() ? _sendMenuDetails()
: SendMenu::Type::Disabled; : SendMenu::Details();
const auto method = FieldAutocomplete::ChooseMethod::ByClick; const auto method = FieldAutocomplete::ChooseMethod::ByClick;
_menu = base::make_unique_q<Ui::PopupMenu>( _menu = base::make_unique_q<Ui::PopupMenu>(
this, this,
st::popupMenuWithIcons); st::popupMenuWithIcons);
const auto send = [=](Api::SendOptions options) { const auto send = crl::guard(this, [=](Api::SendOptions options) {
chooseAtIndex(method, index, options); chooseAtIndex(method, index, options);
}; });
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
_menu, _menu,
type, _show,
SendMenu::DefaultSilentCallback(send), details,
SendMenu::DefaultScheduleCallback(_show, type, send), SendMenu::DefaultCallback(_show, send));
SendMenu::DefaultWhenOnlineCallback(send));
if (!_menu->empty()) { if (!_menu->empty()) {
_menu->popup(QCursor::pos()); _menu->popup(QCursor::pos());
} }
@ -1604,9 +1603,9 @@ void FieldAutocomplete::Inner::showPreview() {
} }
} }
void FieldAutocomplete::Inner::setSendMenuType( void FieldAutocomplete::Inner::setSendMenuDetails(
Fn<SendMenu::Type()> &&callback) { Fn<SendMenu::Details()> &&callback) {
_sendMenuType = std::move(callback); _sendMenuDetails = std::move(callback);
} }
auto FieldAutocomplete::Inner::mentionChosen() const auto FieldAutocomplete::Inner::mentionChosen() const

View file

@ -42,7 +42,7 @@ class DocumentMedia;
} // namespace Data } // namespace Data
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace ChatHelpers { namespace ChatHelpers {
@ -123,7 +123,7 @@ public:
void setModerateKeyActivateCallback(Fn<bool(int)> callback) { void setModerateKeyActivateCallback(Fn<bool(int)> callback) {
_moderateKeyActivateCallback = std::move(callback); _moderateKeyActivateCallback = std::move(callback);
} }
void setSendMenuType(Fn<SendMenu::Type()> &&callback); void setSendMenuDetails(Fn<SendMenu::Details()> &&callback);
void hideFast(); void hideFast();
void showAnimated(); void showAnimated();

View file

@ -380,22 +380,22 @@ void GifsListWidget::mousePressEvent(QMouseEvent *e) {
} }
base::unique_qptr<Ui::PopupMenu> GifsListWidget::fillContextMenu( base::unique_qptr<Ui::PopupMenu> GifsListWidget::fillContextMenu(
SendMenu::Type type) { const SendMenu::Details &details) {
if (_selected < 0 || _pressed >= 0) { if (_selected < 0 || _pressed >= 0) {
return nullptr; return nullptr;
} }
auto menu = base::make_unique_q<Ui::PopupMenu>(this, st().menu); auto menu = base::make_unique_q<Ui::PopupMenu>(this, st().menu);
const auto send = [=, selected = _selected](Api::SendOptions options) { const auto selected = _selected;
const auto send = crl::guard(this, [=](Api::SendOptions options) {
selectInlineResult(selected, options, true); selectInlineResult(selected, options, true);
}; });
const auto icons = &st().icons; const auto icons = &st().icons;
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
menu, menu,
type, _show,
SendMenu::DefaultSilentCallback(send), details,
SendMenu::DefaultScheduleCallback(_show, type, send), SendMenu::DefaultCallback(_show, send),
SendMenu::DefaultWhenOnlineCallback(send),
icons); icons);
if (const auto item = _mosaic.maybeItemAt(_selected)) { if (const auto item = _mosaic.maybeItemAt(_selected)) {

View file

@ -40,7 +40,7 @@ class SessionController;
} // namespace Window } // namespace Window
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace Data { namespace Data {
@ -102,7 +102,7 @@ public:
rpl::producer<> cancelRequests() const; rpl::producer<> cancelRequests() const;
base::unique_qptr<Ui::PopupMenu> fillContextMenu( base::unique_qptr<Ui::PopupMenu> fillContextMenu(
SendMenu::Type type) override; const SendMenu::Details &details) override;
~GifsListWidget(); ~GifsListWidget();

View file

@ -1634,7 +1634,7 @@ void StickersListWidget::showStickerSetBox(not_null<DocumentData*> document) {
} }
base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu( base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
SendMenu::Type type) { const SendMenu::Details &details) {
auto selected = _selected; auto selected = _selected;
auto &sets = shownSets(); auto &sets = shownSets();
if (v::is_null(selected) || !v::is_null(_pressed)) { if (v::is_null(selected) || !v::is_null(_pressed)) {
@ -1653,7 +1653,7 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
auto menu = base::make_unique_q<Ui::PopupMenu>(this, st().menu); auto menu = base::make_unique_q<Ui::PopupMenu>(this, st().menu);
const auto document = set.stickers[sticker->index].document; const auto document = set.stickers[sticker->index].document;
const auto send = [=](Api::SendOptions options) { const auto send = crl::guard(this, [=](Api::SendOptions options) {
_chosen.fire({ _chosen.fire({
.document = document, .document = document,
.options = options, .options = options,
@ -1661,14 +1661,13 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
? Ui::MessageSendingAnimationFrom() ? Ui::MessageSendingAnimationFrom()
: messageSentAnimationInfo(section, index, document), : messageSentAnimationInfo(section, index, document),
}); });
}; });
const auto icons = &st().icons; const auto icons = &st().icons;
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
menu, menu,
type, _show,
SendMenu::DefaultSilentCallback(send), details,
SendMenu::DefaultScheduleCallback(_show, type, send), SendMenu::DefaultCallback(_show, send),
SendMenu::DefaultWhenOnlineCallback(send),
icons); icons);
const auto show = _show; const auto show = _show;

View file

@ -116,7 +116,7 @@ public:
std::shared_ptr<Lottie::FrameRenderer> getLottieRenderer(); std::shared_ptr<Lottie::FrameRenderer> getLottieRenderer();
base::unique_qptr<Ui::PopupMenu> fillContextMenu( base::unique_qptr<Ui::PopupMenu> fillContextMenu(
SendMenu::Type type) override; const SendMenu::Details &details) override;
bool mySetsEmpty() const; bool mySetsEmpty() const;

View file

@ -1297,8 +1297,8 @@ void TabbedSelector::scrollToY(int y) {
} }
} }
void TabbedSelector::showMenuWithType(SendMenu::Type type) { void TabbedSelector::showMenuWithDetails(SendMenu::Details details) {
_menu = currentTab()->widget()->fillContextMenu(type); _menu = currentTab()->widget()->fillContextMenu(details);
if (_menu && !_menu->empty()) { if (_menu && !_menu->empty()) {
_menu->popup(QCursor::pos()); _menu->popup(QCursor::pos());
} }

View file

@ -36,7 +36,7 @@ class TabbedSearch;
} // namespace Ui } // namespace Ui
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace style { namespace style {
@ -178,7 +178,7 @@ public:
_beforeHidingCallback = std::move(callback); _beforeHidingCallback = std::move(callback);
} }
void showMenuWithType(SendMenu::Type type); void showMenuWithDetails(SendMenu::Details details);
void setDropDown(bool dropDown); void setDropDown(bool dropDown);
// Float player interface. // Float player interface.
@ -380,7 +380,7 @@ public:
virtual void beforeHiding() { virtual void beforeHiding() {
} }
[[nodiscard]] virtual base::unique_qptr<Ui::PopupMenu> fillContextMenu( [[nodiscard]] virtual base::unique_qptr<Ui::PopupMenu> fillContextMenu(
SendMenu::Type type) { const SendMenu::Details &details) {
return nullptr; return nullptr;
} }

View file

@ -1297,9 +1297,10 @@ std::optional<Reaction> Reactions::parse(const MTPAvailableEffect &entry) {
return std::nullopt; return std::nullopt;
} }
const auto id = DocumentId(data.vid().v); const auto id = DocumentId(data.vid().v);
const auto document = _owner->document(id); const auto stickerId = data.veffect_sticker_id().v;
const auto document = _owner->document(stickerId);
if (!document->sticker()) { if (!document->sticker()) {
LOG(("API Error: Bad sticker in effects: %1").arg(id)); LOG(("API Error: Bad sticker in effects: %1").arg(stickerId));
return std::nullopt; return std::nullopt;
} }
const auto aroundId = data.veffect_animation_id().value_or_empty(); const auto aroundId = data.veffect_animation_id().value_or_empty();

View file

@ -321,14 +321,22 @@ HistoryWidget::HistoryWidget(
_fieldBarCancel->addClickHandler([=] { cancelFieldAreaState(); }); _fieldBarCancel->addClickHandler([=] { cancelFieldAreaState(); });
_send->addClickHandler([=] { sendButtonClicked(); }); _send->addClickHandler([=] { sendButtonClicked(); });
SendMenu::SetupMenuAndShortcuts( {
_send.get(), using namespace SendMenu;
controller->uiShow(), const auto sendAction = [=](Action action, Details) {
[=] { return sendButtonMenuType(); }, const auto options = std::get_if<Api::SendOptions>(&action);
[=] { sendSilent(); }, if (options || v::get<ActionType>(action) == ActionType::Send) {
[=] { sendScheduled(); }, send(options ? *options : Api::SendOptions());
[=] { sendWhenOnline(); }); } else {
sendScheduled();
}
};
SetupMenuAndShortcuts(
_send.get(),
controller->uiShow(),
[=] { return sendButtonMenuDetails(); },
sendAction);
}
_unblock->addClickHandler([=] { unblockUser(); }); _unblock->addClickHandler([=] { unblockUser(); });
_botStart->addClickHandler([=] { sendBotStartCommand(); }); _botStart->addClickHandler([=] { sendBotStartCommand(); });
_joinChannel->addClickHandler([=] { joinChannel(); }); _joinChannel->addClickHandler([=] { joinChannel(); });
@ -514,7 +522,9 @@ HistoryWidget::HistoryWidget(
} }
}, lifetime()); }, lifetime());
_fieldAutocomplete->setSendMenuType([=] { return sendMenuType(); }); _fieldAutocomplete->setSendMenuDetails([=] {
return sendMenuDetails();
});
if (_supportAutocomplete) { if (_supportAutocomplete) {
supportInitAutocomplete(); supportInitAutocomplete();
@ -1185,7 +1195,7 @@ void HistoryWidget::initTabbedSelector() {
selector->contextMenuRequested( selector->contextMenuRequested(
) | filter | rpl::start_with_next([=] { ) | filter | rpl::start_with_next([=] {
selector->showMenuWithType(sendMenuType()); selector->showMenuWithDetails(sendMenuDetails());
}, lifetime()); }, lifetime());
selector->choosingStickerUpdated( selector->choosingStickerUpdated(
@ -1564,7 +1574,9 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
sendInlineResult(result); sendInlineResult(result);
} }
}); });
_inlineResults->setSendMenuType([=] { return sendMenuType(); }); _inlineResults->setSendMenuDetails([=] {
return sendMenuDetails();
});
_inlineResults->requesting( _inlineResults->requesting(
) | rpl::start_with_next([=](bool requesting) { ) | rpl::start_with_next([=](bool requesting) {
_tabbedSelectorToggle->setLoading(requesting); _tabbedSelectorToggle->setLoading(requesting);
@ -4177,10 +4189,6 @@ void HistoryWidget::sendWithModifiers(Qt::KeyboardModifiers modifiers) {
send({ .handleSupportSwitch = Support::HandleSwitch(modifiers) }); send({ .handleSupportSwitch = Support::HandleSwitch(modifiers) });
} }
void HistoryWidget::sendSilent() {
send({ .silent = true });
}
void HistoryWidget::sendScheduled() { void HistoryWidget::sendScheduled() {
if (!_list) { if (!_list) {
return; return;
@ -4196,22 +4204,20 @@ void HistoryWidget::sendScheduled() {
HistoryView::PrepareScheduleBox( HistoryView::PrepareScheduleBox(
_list, _list,
controller()->uiShow(), controller()->uiShow(),
sendMenuType(), sendMenuDetails(),
callback)); callback));
} }
void HistoryWidget::sendWhenOnline() { SendMenu::Details HistoryWidget::sendMenuDetails() const {
send(Api::DefaultSendWhenOnlineOptions()); const auto type = !_peer
}
SendMenu::Type HistoryWidget::sendMenuType() const {
return !_peer
? SendMenu::Type::Disabled ? SendMenu::Type::Disabled
: _peer->isSelf() : _peer->isSelf()
? SendMenu::Type::Reminder ? SendMenu::Type::Reminder
: HistoryView::CanScheduleUntilOnline(_peer) : HistoryView::CanScheduleUntilOnline(_peer)
? SendMenu::Type::ScheduledToUser ? SendMenu::Type::ScheduledToUser
: SendMenu::Type::Scheduled; : SendMenu::Type::Scheduled;
const auto effectAllowed = _peer && _peer->isUser();
return { .type = type, .effectAllowed = effectAllowed };
} }
auto HistoryWidget::computeSendButtonType() const { auto HistoryWidget::computeSendButtonType() const {
@ -4227,10 +4233,11 @@ auto HistoryWidget::computeSendButtonType() const {
return Type::Send; return Type::Send;
} }
SendMenu::Type HistoryWidget::sendButtonMenuType() const { SendMenu::Details HistoryWidget::sendButtonMenuDetails() const {
return (computeSendButtonType() == Ui::SendButton::Type::Send) if (computeSendButtonType() != Ui::SendButton::Type::Send) {
? sendMenuType() return {};
: SendMenu::Type::Disabled; }
return sendMenuDetails();
} }
void HistoryWidget::unblockUser() { void HistoryWidget::unblockUser() {
@ -5609,7 +5616,7 @@ bool HistoryWidget::confirmSendingFiles(
text, text,
_peer, _peer,
Api::SendType::Normal, Api::SendType::Normal,
sendMenuType()); sendMenuDetails());
_field->setTextWithTags({}); _field->setTextWithTags({});
box->setConfirmedCallback(crl::guard(this, [=]( box->setConfirmedCallback(crl::guard(this, [=](
Ui::PreparedList &&list, Ui::PreparedList &&list,

View file

@ -33,7 +33,7 @@ class PhotoMedia;
} // namespace Data } // namespace Data
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace Api { namespace Api {
@ -268,7 +268,7 @@ public:
void confirmDeleteSelected(); void confirmDeleteSelected();
void clearSelected(); void clearSelected();
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Details sendMenuDetails() const;
bool sendExistingDocument( bool sendExistingDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
Api::SendOptions options, Api::SendOptions options,
@ -395,10 +395,8 @@ private:
Api::SendOptions options) const; Api::SendOptions options) const;
void send(Api::SendOptions options); void send(Api::SendOptions options);
void sendWithModifiers(Qt::KeyboardModifiers modifiers); void sendWithModifiers(Qt::KeyboardModifiers modifiers);
void sendSilent();
void sendScheduled(); void sendScheduled();
void sendWhenOnline(); [[nodiscard]] SendMenu::Details sendButtonMenuDetails() const;
[[nodiscard]] SendMenu::Type sendButtonMenuType() const;
void handlePendingHistoryUpdate(); void handlePendingHistoryUpdate();
void fullInfoUpdated(); void fullInfoUpdated();
void toggleTabbedSelectorMode(); void toggleTabbedSelectorMode();

View file

@ -854,7 +854,7 @@ ComposeControls::ComposeControls(
.recorderHeight = st::historySendSize.height(), .recorderHeight = st::historySendSize.height(),
.lockFromBottom = descriptor.voiceLockFromBottom, .lockFromBottom = descriptor.voiceLockFromBottom,
})) }))
, _sendMenuType(descriptor.sendMenuType) , _sendMenuDetails(descriptor.sendMenuDetails)
, _unavailableEmojiPasted(std::move(descriptor.unavailableEmojiPasted)) , _unavailableEmojiPasted(std::move(descriptor.unavailableEmojiPasted))
, _saveDraftTimer([=] { saveDraft(); }) , _saveDraftTimer([=] { saveDraft(); })
, _saveCloudDraftTimer([=] { saveCloudDraft(); }) { , _saveCloudDraftTimer([=] { saveCloudDraft(); }) {
@ -1719,7 +1719,7 @@ void ComposeControls::initAutocomplete() {
} }
}, _autocomplete->lifetime()); }, _autocomplete->lifetime());
_autocomplete->setSendMenuType([=] { return sendMenuType(); }); _autocomplete->setSendMenuDetails([=] { return sendMenuDetails(); });
//_autocomplete->setModerateKeyActivateCallback([=](int key) { //_autocomplete->setModerateKeyActivateCallback([=](int key) {
// return _keyboard->isHidden() // return _keyboard->isHidden()
@ -2162,7 +2162,7 @@ void ComposeControls::initTabbedSelector() {
_selector->contextMenuRequested( _selector->contextMenuRequested(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_selector->showMenuWithType(sendMenuType()); _selector->showMenuWithDetails(sendMenuDetails());
}, wrap->lifetime()); }, wrap->lifetime());
_selector->choosingStickerUpdated( _selector->choosingStickerUpdated(
@ -2191,17 +2191,15 @@ void ComposeControls::initSendButton() {
cancelInlineBot(); cancelInlineBot();
}, _send->lifetime()); }, _send->lifetime());
const auto send = [=](Api::SendOptions options) { const auto send = crl::guard(_send.get(), [=](Api::SendOptions options) {
_sendCustomRequests.fire(std::move(options)); _sendCustomRequests.fire(std::move(options));
}; });
SendMenu::SetupMenuAndShortcuts( SendMenu::SetupMenuAndShortcuts(
_send.get(), _send.get(),
_show, _show,
[=] { return sendButtonMenuType(); }, [=] { return sendButtonMenuDetails(); },
SendMenu::DefaultSilentCallback(send), SendMenu::DefaultCallback(_show, send));
SendMenu::DefaultScheduleCallback(_show, sendMenuType(), send),
SendMenu::DefaultWhenOnlineCallback(send));
} }
void ComposeControls::initSendAsButton(not_null<PeerData*> peer) { void ComposeControls::initSendAsButton(not_null<PeerData*> peer) {
@ -2510,14 +2508,14 @@ auto ComposeControls::computeSendButtonType() const {
return (_mode == Mode::Normal) ? Type::Send : Type::Schedule; return (_mode == Mode::Normal) ? Type::Send : Type::Schedule;
} }
SendMenu::Type ComposeControls::sendMenuType() const { SendMenu::Details ComposeControls::sendMenuDetails() const {
return !_history ? SendMenu::Type::Disabled : _sendMenuType; return !_history ? SendMenu::Details() : _sendMenuDetails();
} }
SendMenu::Type ComposeControls::sendButtonMenuType() const { SendMenu::Details ComposeControls::sendButtonMenuDetails() const {
return (computeSendButtonType() == Ui::SendButton::Type::Send) return (computeSendButtonType() == Ui::SendButton::Type::Send)
? sendMenuType() ? sendMenuDetails()
: SendMenu::Type::Disabled; : SendMenu::Details();
} }
void ComposeControls::updateSendButtonType() { void ComposeControls::updateSendButtonType() {
@ -3325,7 +3323,9 @@ void ComposeControls::applyInlineBotQuery(
_inlineResultChosen.fire_copy(result); _inlineResultChosen.fire_copy(result);
} }
}); });
_inlineResults->setSendMenuType([=] { return sendMenuType(); }); _inlineResults->setSendMenuDetails([=] {
return sendMenuDetails();
});
_inlineResults->requesting( _inlineResults->requesting(
) | rpl::start_with_next([=](bool requesting) { ) | rpl::start_with_next([=](bool requesting) {
_tabbedSelectorToggle->setLoading(requesting); _tabbedSelectorToggle->setLoading(requesting);

View file

@ -29,7 +29,7 @@ struct ComposeControls;
} // namespace style } // namespace style
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace ChatHelpers { namespace ChatHelpers {
@ -104,7 +104,7 @@ struct ComposeControlsDescriptor {
std::shared_ptr<ChatHelpers::Show> show; std::shared_ptr<ChatHelpers::Show> show;
Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted; Fn<void(not_null<DocumentData*>)> unavailableEmojiPasted;
ComposeControlsMode mode = ComposeControlsMode::Normal; ComposeControlsMode mode = ComposeControlsMode::Normal;
SendMenu::Type sendMenuType = {}; Fn<SendMenu::Details()> sendMenuDetails = nullptr;
Window::SessionController *regularWindow = nullptr; Window::SessionController *regularWindow = nullptr;
rpl::producer<ChatHelpers::FileChosen> stickerOrEmojiChosen; rpl::producer<ChatHelpers::FileChosen> stickerOrEmojiChosen;
rpl::producer<QString> customPlaceholder; rpl::producer<QString> customPlaceholder;
@ -282,8 +282,8 @@ private:
void paintBackground(QPainter &p, QRect full, QRect clip); void paintBackground(QPainter &p, QRect full, QRect clip);
[[nodiscard]] auto computeSendButtonType() const; [[nodiscard]] auto computeSendButtonType() const;
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Details sendMenuDetails() const;
[[nodiscard]] SendMenu::Type sendButtonMenuType() const; [[nodiscard]] SendMenu::Details sendButtonMenuDetails() const;
[[nodiscard]] auto sendContentRequests( [[nodiscard]] auto sendContentRequests(
SendRequestType requestType = SendRequestType::Text) const; SendRequestType requestType = SendRequestType::Text) const;
@ -396,7 +396,7 @@ private:
const std::unique_ptr<FieldHeader> _header; const std::unique_ptr<FieldHeader> _header;
const std::unique_ptr<Controls::VoiceRecordBar> _voiceRecordBar; const std::unique_ptr<Controls::VoiceRecordBar> _voiceRecordBar;
const SendMenu::Type _sendMenuType; const Fn<SendMenu::Details()> _sendMenuDetails;
const Fn<void(not_null<DocumentData*>)> _unavailableEmojiPasted; const Fn<void(not_null<DocumentData*>)> _unavailableEmojiPasted;
rpl::event_stream<Api::SendOptions> _sendCustomRequests; rpl::event_stream<Api::SendOptions> _sendCustomRequests;

View file

@ -590,7 +590,7 @@ bool AddRescheduleAction(
HistoryView::PrepareScheduleBox( HistoryView::PrepareScheduleBox(
&request.navigation->session(), &request.navigation->session(),
request.navigation->uiShow(), request.navigation->uiShow(),
sendMenuType, { .type = sendMenuType, .effectAllowed = false },
callback, callback,
date)); date));

View file

@ -224,9 +224,11 @@ RepliesWidget::RepliesWidget(
listShowPremiumToast(emoji); listShowPremiumToast(emoji);
}, },
.mode = ComposeControls::Mode::Normal, .mode = ComposeControls::Mode::Normal,
.sendMenuType = _topic .sendMenuDetails = [=] {
? SendMenu::Type::Scheduled using Type = SendMenu::Type;
: SendMenu::Type::SilentOnly, const auto type = _topic ? Type::Scheduled : Type::SilentOnly;
return SendMenu::Details{ .type = type };
},
.regularWindow = controller, .regularWindow = controller,
.stickerOrEmojiChosen = controller->stickerOrEmojiChosen(), .stickerOrEmojiChosen = controller->stickerOrEmojiChosen(),
.scheduledToggleValue = _topic .scheduledToggleValue = _topic
@ -950,7 +952,7 @@ bool RepliesWidget::confirmSendingFiles(
_composeControls->getTextWithAppliedMarkdown(), _composeControls->getTextWithAppliedMarkdown(),
_history->peer, _history->peer,
Api::SendType::Normal, Api::SendType::Normal,
SendMenu::Type::SilentOnly); // #TODO replies schedule SendMenu::Details{ SendMenu::Type::SilentOnly }); // #TODO replies schedule
box->setConfirmedCallback(crl::guard(this, [=]( box->setConfirmedCallback(crl::guard(this, [=](
Ui::PreparedList &&list, Ui::PreparedList &&list,
@ -1445,13 +1447,14 @@ void RepliesWidget::sendInlineResult(
finishSending(); finishSending();
} }
SendMenu::Type RepliesWidget::sendMenuType() const { SendMenu::Details RepliesWidget::sendMenuDetails() const {
// #TODO replies schedule // #TODO replies schedule
return _history->peer->isSelf() const auto type = _history->peer->isSelf()
? SendMenu::Type::Reminder ? SendMenu::Type::Reminder
: HistoryView::CanScheduleUntilOnline(_history->peer) : HistoryView::CanScheduleUntilOnline(_history->peer)
? SendMenu::Type::ScheduledToUser ? SendMenu::Type::ScheduledToUser
: SendMenu::Type::Scheduled; : SendMenu::Type::Scheduled;
return { .type = type, .effectAllowed = _history->peer->isUser() };
} }
FullReplyTo RepliesWidget::replyTo() const { FullReplyTo RepliesWidget::replyTo() const {

View file

@ -19,7 +19,7 @@ enum class SendMediaType;
struct SendingAlbum; struct SendingAlbum;
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace Api { namespace Api {
@ -249,7 +249,7 @@ private:
mtpRequestId *const saveEditMsgRequestId, mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride); std::optional<bool> spoilerMediaOverride);
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos); void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Details sendMenuDetails() const;
[[nodiscard]] FullReplyTo replyTo() const; [[nodiscard]] FullReplyTo replyTo() const;
[[nodiscard]] HistoryItem *lookupRoot() const; [[nodiscard]] HistoryItem *lookupRoot() const;
[[nodiscard]] Data::ForumTopic *lookupTopic(); [[nodiscard]] Data::ForumTopic *lookupTopic();

View file

@ -70,7 +70,7 @@ bool CanScheduleUntilOnline(not_null<PeerData*> peer) {
void ScheduleBox( void ScheduleBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
SendMenu::Type type, const SendMenu::Details &details,
Fn<void(Api::SendOptions)> done, Fn<void(Api::SendOptions)> done,
TimeId time, TimeId time,
ScheduleBoxStyleArgs style) { ScheduleBoxStyleArgs style) {
@ -87,7 +87,7 @@ void ScheduleBox(
copy(result); copy(result);
}; };
auto descriptor = Ui::ChooseDateTimeBox(box, { auto descriptor = Ui::ChooseDateTimeBox(box, {
.title = (type == SendMenu::Type::Reminder .title = (details.type == SendMenu::Type::Reminder
? tr::lng_remind_title() ? tr::lng_remind_title()
: tr::lng_schedule_title()), : tr::lng_schedule_title()),
.submit = tr::lng_schedule_button(), .submit = tr::lng_schedule_button(),
@ -96,16 +96,26 @@ void ScheduleBox(
.style = style.chooseDateTimeArgs, .style = style.chooseDateTimeArgs,
}); });
using T = SendMenu::Type; using namespace SendMenu;
SendMenu::SetupMenuAndShortcuts( const auto childType = (details.type == Type::Disabled)
? Type::Disabled
: Type::SilentOnly;
const auto childDetails = Details{
.type = childType,
.effectAllowed = details.effectAllowed,
};
const auto sendAction = crl::guard(box, [=](Action action, Details) {
save(
v::get<Api::SendOptions>(action).silent,
descriptor.collect());
});
SetupMenuAndShortcuts(
descriptor.submit.data(), descriptor.submit.data(),
show, show,
[t = type == T::Disabled ? T::Disabled : T::SilentOnly] { return t; }, [=] { return childDetails; },
[=] { save(true, descriptor.collect()); }, sendAction);
nullptr,
nullptr);
if (type == SendMenu::Type::ScheduledToUser) { if (details.type == Type::ScheduledToUser) {
const auto sendUntilOnline = box->addTopButton(*style.topButtonStyle); const auto sendUntilOnline = box->addTopButton(*style.topButtonStyle);
const auto timestamp = Api::kScheduledUntilOnlineTimestamp; const auto timestamp = Api::kScheduledUntilOnlineTimestamp;
FillSendUntilOnlineMenu( FillSendUntilOnlineMenu(

View file

@ -23,7 +23,7 @@ class Show;
} // namespace ChatHelpers } // namespace ChatHelpers
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace HistoryView { namespace HistoryView {
@ -41,7 +41,7 @@ struct ScheduleBoxStyleArgs {
void ScheduleBox( void ScheduleBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
SendMenu::Type type, const SendMenu::Details &details,
Fn<void(Api::SendOptions)> done, Fn<void(Api::SendOptions)> done,
TimeId time, TimeId time,
ScheduleBoxStyleArgs style); ScheduleBoxStyleArgs style);
@ -50,14 +50,14 @@ template <typename Guard, typename Submit>
[[nodiscard]] object_ptr<Ui::GenericBox> PrepareScheduleBox( [[nodiscard]] object_ptr<Ui::GenericBox> PrepareScheduleBox(
Guard &&guard, Guard &&guard,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
SendMenu::Type type, const SendMenu::Details &details,
Submit &&submit, Submit &&submit,
TimeId scheduleTime = DefaultScheduleTime(), TimeId scheduleTime = DefaultScheduleTime(),
ScheduleBoxStyleArgs style = ScheduleBoxStyleArgs()) { ScheduleBoxStyleArgs style = ScheduleBoxStyleArgs()) {
return Box( return Box(
ScheduleBox, ScheduleBox,
std::move(show), std::move(show),
type, details,
crl::guard(std::forward<Guard>(guard), std::forward<Submit>(submit)), crl::guard(std::forward<Guard>(guard), std::forward<Submit>(submit)),
scheduleTime, scheduleTime,
std::move(style)); std::move(style));

View file

@ -115,7 +115,7 @@ ScheduledWidget::ScheduledWidget(
listShowPremiumToast(emoji); listShowPremiumToast(emoji);
}, },
.mode = ComposeControls::Mode::Scheduled, .mode = ComposeControls::Mode::Scheduled,
.sendMenuType = SendMenu::Type::Disabled, .sendMenuDetails = [] { return SendMenu::Details(); },
.regularWindow = controller, .regularWindow = controller,
.stickerOrEmojiChosen = controller->stickerOrEmojiChosen(), .stickerOrEmojiChosen = controller->stickerOrEmojiChosen(),
})) }))
@ -493,7 +493,7 @@ bool ScheduledWidget::confirmSendingFiles(
(CanScheduleUntilOnline(_history->peer) (CanScheduleUntilOnline(_history->peer)
? Api::SendType::ScheduledToUser ? Api::SendType::ScheduledToUser
: Api::SendType::Scheduled), : Api::SendType::Scheduled),
SendMenu::Type::Disabled); SendMenu::Details());
box->setConfirmedCallback(crl::guard(this, [=]( box->setConfirmedCallback(crl::guard(this, [=](
Ui::PreparedList &&list, Ui::PreparedList &&list,
@ -602,7 +602,7 @@ void ScheduledWidget::uploadFile(
prepareSendAction(options)); prepareSendAction(options));
}; };
controller()->show( controller()->show(
PrepareScheduleBox(this, _show, sendMenuType(), callback)); PrepareScheduleBox(this, _show, sendMenuDetails(), callback));
} }
bool ScheduledWidget::showSendingFilesError( bool ScheduledWidget::showSendingFilesError(
@ -681,7 +681,7 @@ void ScheduledWidget::send() {
} }
const auto callback = [=](Api::SendOptions options) { send(options); }; const auto callback = [=](Api::SendOptions options) { send(options); };
controller()->show( controller()->show(
PrepareScheduleBox(this, _show, sendMenuType(), callback)); PrepareScheduleBox(this, _show, sendMenuDetails(), callback));
} }
void ScheduledWidget::send(Api::SendOptions options) { void ScheduledWidget::send(Api::SendOptions options) {
@ -713,7 +713,7 @@ void ScheduledWidget::sendVoice(
sendVoice(bytes, waveform, duration, options); sendVoice(bytes, waveform, duration, options);
}; };
controller()->show( controller()->show(
PrepareScheduleBox(this, _show, sendMenuType(), callback)); PrepareScheduleBox(this, _show, sendMenuDetails(), callback));
} }
void ScheduledWidget::sendVoice( void ScheduledWidget::sendVoice(
@ -814,7 +814,7 @@ void ScheduledWidget::sendExistingDocument(
sendExistingDocument(document, options); sendExistingDocument(document, options);
}; };
controller()->show( controller()->show(
PrepareScheduleBox(this, _show, sendMenuType(), callback)); PrepareScheduleBox(this, _show, sendMenuDetails(), callback));
} }
bool ScheduledWidget::sendExistingDocument( bool ScheduledWidget::sendExistingDocument(
@ -844,7 +844,7 @@ void ScheduledWidget::sendExistingPhoto(not_null<PhotoData*> photo) {
sendExistingPhoto(photo, options); sendExistingPhoto(photo, options);
}; };
controller()->show( controller()->show(
PrepareScheduleBox(this, _show, sendMenuType(), callback)); PrepareScheduleBox(this, _show, sendMenuDetails(), callback));
} }
bool ScheduledWidget::sendExistingPhoto( bool ScheduledWidget::sendExistingPhoto(
@ -879,7 +879,7 @@ void ScheduledWidget::sendInlineResult(
sendInlineResult(result, bot, options); sendInlineResult(result, bot, options);
}; };
controller()->show( controller()->show(
PrepareScheduleBox(this, _show, sendMenuType(), callback)); PrepareScheduleBox(this, _show, sendMenuDetails(), callback));
} }
void ScheduledWidget::sendInlineResult( void ScheduledWidget::sendInlineResult(
@ -911,12 +911,14 @@ void ScheduledWidget::sendInlineResult(
_composeControls->focus(); _composeControls->focus();
} }
SendMenu::Type ScheduledWidget::sendMenuType() const { SendMenu::Details ScheduledWidget::sendMenuDetails() const {
return _history->peer->isSelf() const auto type = _history->peer->isSelf()
? SendMenu::Type::Reminder ? SendMenu::Type::Reminder
: HistoryView::CanScheduleUntilOnline(_history->peer) : HistoryView::CanScheduleUntilOnline(_history->peer)
? SendMenu::Type::ScheduledToUser ? SendMenu::Type::ScheduledToUser
: SendMenu::Type::Scheduled; : SendMenu::Type::Scheduled;
const auto effectAllowed = _history->peer->isUser();
return { .type = type, .effectAllowed = effectAllowed };
} }
void ScheduledWidget::cornerButtonsShowAtPosition( void ScheduledWidget::cornerButtonsShowAtPosition(
@ -1368,7 +1370,7 @@ void ScheduledWidget::listSendBotCommand(
session().api().sendMessage(std::move(message)); session().api().sendMessage(std::move(message));
}; };
controller()->show( controller()->show(
PrepareScheduleBox(this, _show, sendMenuType(), callback)); PrepareScheduleBox(this, _show, sendMenuDetails(), callback));
} }
void ScheduledWidget::listSearch( void ScheduledWidget::listSearch(

View file

@ -22,7 +22,7 @@ class Show;
} // namespace ChatHelpers } // namespace ChatHelpers
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace Api { namespace Api {
@ -221,7 +221,7 @@ private:
std::optional<bool> spoilerMediaOverride); std::optional<bool> spoilerMediaOverride);
void highlightSingleNewMessage(const Data::MessagesSlice &slice); void highlightSingleNewMessage(const Data::MessagesSlice &slice);
void chooseAttach(); void chooseAttach();
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Details sendMenuDetails() const;
void pushReplyReturn(not_null<HistoryItem*> item); void pushReplyReturn(not_null<HistoryItem*> item);
void checkReplyReturns(); void checkReplyReturns();

View file

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "menu/menu_send.h"
#include "chat_helpers/emoji_list_widget.h" #include "chat_helpers/emoji_list_widget.h"
#include "chat_helpers/stickers_list_footer.h" #include "chat_helpers/stickers_list_footer.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
@ -123,15 +124,11 @@ UnifiedFactoryOwner::UnifiedFactoryOwner(
const auto inStrip = _strip ? _strip->count() : 0; const auto inStrip = _strip ? _strip->count() : 0;
_unifiedIdsList.reserve(reactions.size()); _unifiedIdsList.reserve(reactions.size());
for (const auto &reaction : reactions) { for (const auto &reaction : reactions) {
if (const auto id = reaction.id.custom()) { _unifiedIdsList.push_back(reaction.selectAnimation->id);
_unifiedIdsList.push_back(id);
} else {
_unifiedIdsList.push_back(reaction.selectAnimation->id);
}
const auto unifiedId = _unifiedIdsList.back(); const auto unifiedId = _unifiedIdsList.back();
if (!reaction.id.custom()) { if (unifiedId != reaction.id.custom()) {
_defaultReactionIds.emplace(unifiedId, reaction.id.emoji()); _defaultReactionIds.emplace(unifiedId, reaction.id);
} }
if (index + 1 < inStrip) { if (index + 1 < inStrip) {
_defaultReactionInStripMap.emplace(unifiedId, index++); _defaultReactionInStripMap.emplace(unifiedId, index++);
@ -165,7 +162,7 @@ Data::ReactionId UnifiedFactoryOwner::lookupReactionId(
DocumentId unifiedId) const { DocumentId unifiedId) const {
const auto i = _defaultReactionIds.find(unifiedId); const auto i = _defaultReactionIds.find(unifiedId);
return (i != end(_defaultReactionIds)) return (i != end(_defaultReactionIds))
? Data::ReactionId{ i->second } ? i->second
: Data::ReactionId{ unifiedId }; : Data::ReactionId{ unifiedId };
} }
@ -174,21 +171,23 @@ UnifiedFactoryOwner::RecentFactory UnifiedFactoryOwner::factory() {
-> std::unique_ptr<Ui::Text::CustomEmoji> { -> std::unique_ptr<Ui::Text::CustomEmoji> {
const auto tag = Data::CustomEmojiManager::SizeTag::Large; const auto tag = Data::CustomEmojiManager::SizeTag::Large;
const auto sizeOverride = st::reactStripImage; const auto sizeOverride = st::reactStripImage;
const auto isDefaultReaction = _defaultReactionIds.contains(id); const auto i = _defaultReactionIds.find(id);
const auto isDefaultReaction = (i != end(_defaultReactionIds))
&& !i->second.custom();
const auto manager = &_session->data().customEmojiManager(); const auto manager = &_session->data().customEmojiManager();
auto result = isDefaultReaction auto result = isDefaultReaction
? std::make_unique<Ui::Text::ShiftedEmoji>( ? std::make_unique<Ui::Text::ShiftedEmoji>(
manager->create(id, std::move(repaint), tag, sizeOverride), manager->create(id, std::move(repaint), tag, sizeOverride),
_defaultReactionShift) _defaultReactionShift)
: manager->create(id, std::move(repaint), tag); : manager->create(id, std::move(repaint), tag);
const auto i = _defaultReactionInStripMap.find(id); const auto j = _defaultReactionInStripMap.find(id);
if (i != end(_defaultReactionInStripMap)) { if (j != end(_defaultReactionInStripMap)) {
Assert(_strip != nullptr); Assert(_strip != nullptr);
return std::make_unique<StripEmoji>( return std::make_unique<StripEmoji>(
std::move(result), std::move(result),
_strip, _strip,
-_stripPaintOneShift, -_stripPaintOneShift,
i->second); j->second);
} }
return result; return result;
}; };

View file

@ -66,7 +66,7 @@ private:
Strip *_strip = nullptr; Strip *_strip = nullptr;
std::vector<DocumentId> _unifiedIdsList; std::vector<DocumentId> _unifiedIdsList;
base::flat_map<DocumentId, QString> _defaultReactionIds; base::flat_map<DocumentId, Data::ReactionId> _defaultReactionIds;
base::flat_map<DocumentId, int> _defaultReactionInStripMap; base::flat_map<DocumentId, int> _defaultReactionInStripMap;
QPoint _defaultReactionShift; QPoint _defaultReactionShift;

View file

@ -229,7 +229,7 @@ void EmojiStatusPanel::create(const Descriptor &descriptor) {
_panel->selector()->contextMenuRequested( _panel->selector()->contextMenuRequested(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_panel->selector()->showMenuWithType(SendMenu::Type::Scheduled); _panel->selector()->showMenuWithDetails({});
}, _panel->lifetime()); }, _panel->lifetime());
auto statusChosen = _panel->selector()->customEmojiChosen( auto statusChosen = _panel->selector()->customEmojiChosen(

View file

@ -1703,7 +1703,7 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
flag, flag,
flag, flag,
source, source,
sendMenuType); { sendMenuType });
}, &st::menuIconCreatePoll); }, &st::menuIconCreatePoll);
} }
for (const auto &bot : bots->attachBots()) { for (const auto &bot : bots->attachBots()) {

View file

@ -329,23 +329,23 @@ void Inner::contextMenuEvent(QContextMenuEvent *e) {
if (_selected < 0 || _pressed >= 0) { if (_selected < 0 || _pressed >= 0) {
return; return;
} }
const auto type = _sendMenuType const auto details = _sendMenuDetails
? _sendMenuType() ? _sendMenuDetails()
: SendMenu::Type::Disabled; : SendMenu::Details();
_menu = base::make_unique_q<Ui::PopupMenu>( _menu = base::make_unique_q<Ui::PopupMenu>(
this, this,
st::popupMenuWithIcons); st::popupMenuWithIcons);
const auto send = [=, selected = _selected](Api::SendOptions options) { const auto selected = _selected;
const auto send = crl::guard(this, [=](Api::SendOptions options) {
selectInlineResult(selected, options, false); selectInlineResult(selected, options, false);
}; });
SendMenu::FillSendMenu( SendMenu::FillSendMenu(
_menu, _menu,
type, _controller->uiShow(),
SendMenu::DefaultSilentCallback(send), details,
SendMenu::DefaultScheduleCallback(_controller->uiShow(), type, send), SendMenu::DefaultCallback(_controller->uiShow(), send));
SendMenu::DefaultWhenOnlineCallback(send));
const auto item = _mosaic.itemAt(_selected); const auto item = _mosaic.itemAt(_selected);
if (const auto previewDocument = item->getPreviewDocument()) { if (const auto previewDocument = item->getPreviewDocument()) {
@ -689,8 +689,8 @@ void Inner::switchPm() {
} }
} }
void Inner::setSendMenuType(Fn<SendMenu::Type()> &&callback) { void Inner::setSendMenuDetails(Fn<SendMenu::Details()> &&callback) {
_sendMenuType = std::move(callback); _sendMenuDetails = std::move(callback);
} }
} // namespace Layout } // namespace Layout

View file

@ -43,7 +43,7 @@ struct ResultSelected;
} // namespace InlineBots } // namespace InlineBots
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace InlineBots { namespace InlineBots {
@ -89,7 +89,7 @@ public:
void setResultSelectedCallback(Fn<void(ResultSelected)> callback) { void setResultSelectedCallback(Fn<void(ResultSelected)> callback) {
_resultSelectedCallback = std::move(callback); _resultSelectedCallback = std::move(callback);
} }
void setSendMenuType(Fn<SendMenu::Type()> &&callback); void setSendMenuDetails(Fn<SendMenu::Details()> &&callback);
// Ui::AbstractTooltipShower interface. // Ui::AbstractTooltipShower interface.
QString tooltipText() const override; QString tooltipText() const override;
@ -179,7 +179,7 @@ private:
bool _previewShown = false; bool _previewShown = false;
Fn<void(ResultSelected)> _resultSelectedCallback; Fn<void(ResultSelected)> _resultSelectedCallback;
Fn<SendMenu::Type()> _sendMenuType; Fn<SendMenu::Details()> _sendMenuDetails;
}; };

View file

@ -265,8 +265,8 @@ void Widget::setResultSelectedCallback(Fn<void(ResultSelected)> callback) {
_inner->setResultSelectedCallback(std::move(callback)); _inner->setResultSelectedCallback(std::move(callback));
} }
void Widget::setSendMenuType(Fn<SendMenu::Type()> &&callback) { void Widget::setSendMenuDetails(Fn<SendMenu::Details()> &&callback) {
_inner->setSendMenuType(std::move(callback)); _inner->setSendMenuDetails(std::move(callback));
} }
void Widget::hideAnimated() { void Widget::hideAnimated() {

View file

@ -45,7 +45,7 @@ struct ResultSelected;
} // namespace InlineBots } // namespace InlineBots
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace InlineBots { namespace InlineBots {
@ -75,7 +75,7 @@ public:
void hideAnimated(); void hideAnimated();
void setResultSelectedCallback(Fn<void(ResultSelected)> callback); void setResultSelectedCallback(Fn<void(ResultSelected)> callback);
void setSendMenuType(Fn<SendMenu::Type()> &&callback); void setSendMenuDetails(Fn<SendMenu::Details()> &&callback);
[[nodiscard]] rpl::producer<bool> requesting() const { [[nodiscard]] rpl::producer<bool> requesting() const {
return _requesting.events(); return _requesting.events();

View file

@ -1047,8 +1047,8 @@ void MainWidget::exportTopBarHeightUpdated() {
} }
} }
SendMenu::Type MainWidget::sendMenuType() const { SendMenu::Details MainWidget::sendMenuDetails() const {
return _history->sendMenuType(); return _history->sendMenuDetails();
} }
bool MainWidget::sendExistingDocument(not_null<DocumentData*> document) { bool MainWidget::sendExistingDocument(not_null<DocumentData*> document) {

View file

@ -29,7 +29,7 @@ struct SendOptions;
} // namespace Api } // namespace Api
namespace SendMenu { namespace SendMenu {
enum class Type; struct Details;
} // namespace SendMenu } // namespace SendMenu
namespace Main { namespace Main {
@ -157,7 +157,7 @@ public:
QPixmap grabForShowAnimation(const Window::SectionSlideParams &params); QPixmap grabForShowAnimation(const Window::SectionSlideParams &params);
void checkMainSectionToLayer(); void checkMainSectionToLayer();
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Details sendMenuDetails() const;
bool sendExistingDocument(not_null<DocumentData*> document); bool sendExistingDocument(not_null<DocumentData*> document);
bool sendExistingDocument( bool sendExistingDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,

View file

@ -123,7 +123,7 @@ ReplyArea::ReplyArea(not_null<Controller*> controller)
showPremiumToast(emoji); showPremiumToast(emoji);
}, },
.mode = HistoryView::ComposeControlsMode::Normal, .mode = HistoryView::ComposeControlsMode::Normal,
.sendMenuType = SendMenu::Type::SilentOnly, .sendMenuDetails = sendMenuDetails(),
.stickerOrEmojiChosen = _controller->stickerOrEmojiChosen(), .stickerOrEmojiChosen = _controller->stickerOrEmojiChosen(),
.customPlaceholder = PlaceholderText( .customPlaceholder = PlaceholderText(
_controller->uiShow(), _controller->uiShow(),
@ -473,6 +473,15 @@ void ReplyArea::chooseAttach(
crl::guard(this, [=] { _choosingAttach = false; })); crl::guard(this, [=] { _choosingAttach = false; }));
} }
Fn<SendMenu::Details()> ReplyArea::sendMenuDetails() const {
return crl::guard(this, [=] {
return SendMenu::Details{
.type = SendMenu::Type::SilentOnly,
.effectAllowed = _data.peer && _data.peer->isUser(),
};
});
}
bool ReplyArea::confirmSendingFiles( bool ReplyArea::confirmSendingFiles(
not_null<const QMimeData*> data, not_null<const QMimeData*> data,
std::optional<bool> overrideSendImagesAsPhotos, std::optional<bool> overrideSendImagesAsPhotos,
@ -528,7 +537,7 @@ bool ReplyArea::confirmSendingFiles(
.limits = DefaultLimitsForPeer(_data.peer), .limits = DefaultLimitsForPeer(_data.peer),
.check = DefaultCheckForPeer(show, _data.peer), .check = DefaultCheckForPeer(show, _data.peer),
.sendType = Api::SendType::Normal, .sendType = Api::SendType::Normal,
.sendMenuType = SendMenu::Type::SilentOnly, .sendMenuDetails = sendMenuDetails(),
.stOverride = &st::storiesComposeControls, .stOverride = &st::storiesComposeControls,
.confirmed = crl::guard(this, confirmed), .confirmed = crl::guard(this, confirmed),
.cancelled = _controls->restoreTextCallback(insertTextOnCancel), .cancelled = _controls->restoreTextCallback(insertTextOnCancel),

View file

@ -38,6 +38,10 @@ namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
namespace SendMenu {
struct Details;
} // namespace SendMenu
namespace Ui { namespace Ui {
struct PreparedList; struct PreparedList;
class SendFilesWay; class SendFilesWay;
@ -141,6 +145,8 @@ private:
void sendVoice(VoiceToSend &&data); void sendVoice(VoiceToSend &&data);
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos); void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
[[nodiscard]] Fn<SendMenu::Details()> sendMenuDetails() const;
void showPremiumToast(not_null<DocumentData*> emoji); void showPremiumToast(not_null<DocumentData*> emoji);
[[nodiscard]] bool showSlowmodeError(); [[nodiscard]] bool showSlowmodeError();

View file

@ -348,8 +348,8 @@ public:
rpl::producer<bool> adjustShadowLeft() const override { rpl::producer<bool> adjustShadowLeft() const override {
return rpl::single(false); return rpl::single(false);
} }
SendMenu::Type sendMenuType() const override { SendMenu::Details sendMenuDetails() const override {
return SendMenu::Type::SilentOnly; return { SendMenu::Type::SilentOnly };
} }
bool showMediaPreview( bool showMediaPreview(

View file

@ -37,140 +37,121 @@ namespace {
not_null<Main::Session*> session) { not_null<Main::Session*> session) {
auto result = Data::PossibleItemReactionsRef(); auto result = Data::PossibleItemReactionsRef();
const auto reactions = &session->data().reactions(); const auto reactions = &session->data().reactions();
const auto &full = reactions->list(Data::Reactions::Type::Active); const auto &effects = reactions->list(Data::Reactions::Type::Effects);
const auto &top = reactions->list(Data::Reactions::Type::Top);
const auto &recent = reactions->list(Data::Reactions::Type::Recent);
const auto premiumPossible = session->premiumPossible(); const auto premiumPossible = session->premiumPossible();
auto added = base::flat_set<Data::ReactionId>(); auto added = base::flat_set<Data::ReactionId>();
result.recent.reserve(full.size()); result.recent.reserve(effects.size());
for (const auto &reaction : ranges::views::concat(top, recent, full)) { for (const auto &reaction : effects) {
if (premiumPossible || !reaction.id.custom()) { if (premiumPossible || !reaction.premium) {
if (added.emplace(reaction.id).second) { if (added.emplace(reaction.id).second) {
result.recent.push_back(&reaction); 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; return result;
} }
} // namespace } // namespace
Fn<void()> DefaultSilentCallback(Fn<void(Api::SendOptions)> send) { Fn<void(Action, Details)> DefaultCallback(
return [=] { send({ .silent = true }); };
}
Fn<void()> DefaultScheduleCallback(
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
Type type,
Fn<void(Api::SendOptions)> send) { Fn<void(Api::SendOptions)> send) {
return [=, weak = Ui::MakeWeak(show->toastParent())] { const auto guard = Ui::MakeWeak(show->toastParent());
show->showBox( return [=](Action action, Details details) {
HistoryView::PrepareScheduleBox( if (const auto options = std::get_if<Api::SendOptions>(&action)) {
weak, send(*options);
show, } else if (v::get<ActionType>(action) == ActionType::Send) {
type, send({});
[=](Api::SendOptions options) { send(options); }), } else {
Ui::LayerOption::KeepOther); using namespace HistoryView;
auto box = PrepareScheduleBox(guard, show, details, send);
const auto weak = Ui::MakeWeak(box.data());
show->showBox(std::move(box));
if (const auto strong = weak.data()) {
strong->setCloseByOutsideClick(false);
}
}
}; };
} }
Fn<void()> DefaultWhenOnlineCallback(Fn<void(Api::SendOptions)> send) {
return [=] { send(Api::DefaultSendWhenOnlineOptions()); };
}
FillMenuResult FillSendMenu( FillMenuResult FillSendMenu(
not_null<Ui::PopupMenu*> menu, not_null<Ui::PopupMenu*> menu,
Type type, std::shared_ptr<ChatHelpers::Show> showForEffect,
Fn<void()> silent, Details details,
Fn<void()> schedule, Fn<void(Action, Details)> action,
Fn<void()> whenOnline, const style::ComposeIcons *iconsOverride,
const style::ComposeIcons *iconsOverride) { std::optional<QPoint> desiredPositionOverride) {
if (!silent && !schedule) { const auto type = details.type;
return FillMenuResult::None; if (type == Type::Disabled || !action) {
return FillMenuResult::Skipped;
} }
const auto &icons = iconsOverride const auto &icons = iconsOverride
? *iconsOverride ? *iconsOverride
: st::defaultComposeIcons; : st::defaultComposeIcons;
const auto now = type;
if (now == Type::Disabled
|| (!silent && now == Type::SilentOnly)) {
return FillMenuResult::None;
}
if (silent && now != Type::Reminder) { if (type != Type::Reminder) {
menu->addAction( menu->addAction(
tr::lng_send_silent_message(tr::now), tr::lng_send_silent_message(tr::now),
silent, [=] { action(Api::SendOptions{ .silent = true }, details); },
&icons.menuMute); &icons.menuMute);
} }
if (schedule && now != Type::SilentOnly) { if (type != Type::SilentOnly) {
menu->addAction( menu->addAction(
(now == Type::Reminder (type == Type::Reminder
? tr::lng_reminder_message(tr::now) ? tr::lng_reminder_message(tr::now)
: tr::lng_schedule_message(tr::now)), : tr::lng_schedule_message(tr::now)),
schedule, [=] { action(ActionType::Schedule, details); },
&icons.menuSchedule); &icons.menuSchedule);
} }
if (whenOnline && now == Type::ScheduledToUser) { if (type == Type::ScheduledToUser) {
menu->addAction( menu->addAction(
tr::lng_scheduled_send_until_online(tr::now), tr::lng_scheduled_send_until_online(tr::now),
whenOnline, [=] { action(Api::DefaultSendWhenOnlineOptions(), details); },
&icons.menuWhenOnline); &icons.menuWhenOnline);
} }
return FillMenuResult::Success;
using namespace HistoryView::Reactions;
const auto position = desiredPositionOverride.value_or(QCursor::pos());
const auto selector = (showForEffect && details.effectAllowed)
? AttachSelectorToMenu(
menu,
position,
st::reactPanelEmojiPan,
showForEffect,
LookupPossibleEffects(&showForEffect->session()),
{ tr::lng_effect_add_title(tr::now) })
: base::make_unexpected(AttachSelectorResult::Skipped);
if (!selector) {
if (selector.error() == AttachSelectorResult::Failed) {
return FillMenuResult::Failed;
}
menu->prepareGeometryFor(position);
return FillMenuResult::Prepared;
}
(*selector)->chosen(
) | rpl::start_with_next([=](ChosenReaction chosen) {
}, menu->lifetime());
return FillMenuResult::Prepared;
} }
void SetupMenuAndShortcuts( void SetupMenuAndShortcuts(
not_null<Ui::RpWidget*> button, not_null<Ui::RpWidget*> button,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
Fn<Type()> type, Fn<Details()> details,
Fn<void()> silent, Fn<void(Action, Details)> action) {
Fn<void()> schedule,
Fn<void()> whenOnline) {
if (!silent && !schedule && !whenOnline) {
return;
}
const auto menu = std::make_shared<base::unique_qptr<Ui::PopupMenu>>(); const auto menu = std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
const auto showMenu = [=] { const auto showMenu = [=] {
*menu = base::make_unique_q<Ui::PopupMenu>( *menu = base::make_unique_q<Ui::PopupMenu>(
button, button,
st::popupMenuWithIcons); st::popupMenuWithIcons);
const auto result = FillSendMenu( const auto result = FillSendMenu(*menu, show, details(), action);
*menu, if (result != FillMenuResult::Prepared) {
type(),
silent,
schedule,
whenOnline);
if (result != FillMenuResult::Success) {
return false; return false;
} }
const auto desiredPosition = QCursor::pos(); (*menu)->popupPrepared();
using namespace HistoryView::Reactions;
const auto selector = show
? AttachSelectorToMenu(
menu->get(),
desiredPosition,
st::reactPanelEmojiPan,
show,
LookupPossibleEffects(&show->session()),
{ tr::lng_effect_add_title(tr::now) })
: base::make_unexpected(AttachSelectorResult::Skipped);
if (selector) {
//(*selector)->chosen();
(*menu)->popupPrepared();
} else if (selector.error() == AttachSelectorResult::Failed) {
return false;
} else {
(*menu)->popup(desiredPosition);
}
return true; return true;
}; };
base::install_event_filter(button, [=](not_null<QEvent*> e) { base::install_event_filter(button, [=](not_null<QEvent*> e) {
@ -186,24 +167,21 @@ void SetupMenuAndShortcuts(
}) | rpl::start_with_next([=](not_null<Shortcuts::Request*> request) { }) | rpl::start_with_next([=](not_null<Shortcuts::Request*> request) {
using Command = Shortcuts::Command; using Command = Shortcuts::Command;
const auto now = type(); const auto now = details().type;
if (now == Type::Disabled if (now == Type::Disabled) {
|| (!silent && now == Type::SilentOnly)) {
return; return;
} }
(silent ((now != Type::Reminder)
&& (now != Type::Reminder)
&& request->check(Command::SendSilentMessage) && request->check(Command::SendSilentMessage)
&& request->handle([=] { && request->handle([=] {
silent(); action(Api::SendOptions{ .silent = true }, details());
return true; return true;
})) }))
|| ||
(schedule ((now != Type::SilentOnly)
&& (now != Type::SilentOnly)
&& request->check(Command::ScheduleMessage) && request->check(Command::ScheduleMessage)
&& request->handle([=] { && request->handle([=] {
schedule(); action(ActionType::Schedule, details());
return true; return true;
})) }))
|| ||

View file

@ -39,33 +39,39 @@ enum class Type {
Reminder, Reminder,
}; };
enum class FillMenuResult { struct Details {
Success, Type type = Type::Disabled;
None, bool effectAllowed = false;
}; };
Fn<void()> DefaultSilentCallback(Fn<void(Api::SendOptions)> send); enum class FillMenuResult {
Fn<void()> DefaultScheduleCallback( Prepared,
Skipped,
Failed,
};
enum class ActionType {
Send,
Schedule,
};
using Action = std::variant<Api::SendOptions, ActionType>;
[[nodiscard]] Fn<void(Action, Details)> DefaultCallback(
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
Type type,
Fn<void(Api::SendOptions)> send); Fn<void(Api::SendOptions)> send);
Fn<void()> DefaultWhenOnlineCallback(Fn<void(Api::SendOptions)> send);
FillMenuResult FillSendMenu( FillMenuResult FillSendMenu(
not_null<Ui::PopupMenu*> menu, not_null<Ui::PopupMenu*> menu,
Type type, std::shared_ptr<ChatHelpers::Show> showForEffect,
Fn<void()> silent, Details details,
Fn<void()> schedule, Fn<void(Action, Details)> action,
Fn<void()> whenOnline, const style::ComposeIcons *iconsOverride = nullptr,
const style::ComposeIcons *iconsOverride = nullptr); std::optional<QPoint> desiredPositionOverride = std::nullopt);
void SetupMenuAndShortcuts( void SetupMenuAndShortcuts(
not_null<Ui::RpWidget*> button, not_null<Ui::RpWidget*> button,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
Fn<Type()> type, Fn<Details()> details,
Fn<void()> silent, Fn<void(Action, Details)> action);
Fn<void()> schedule,
Fn<void()> whenOnline);
void SetupUnreadMentionsMenu( void SetupUnreadMentionsMenu(
not_null<Ui::RpWidget*> button, not_null<Ui::RpWidget*> button,

View file

@ -242,7 +242,6 @@ private:
mtpRequestId *const saveEditMsgRequestId, mtpRequestId *const saveEditMsgRequestId,
std::optional<bool> spoilerMediaOverride); std::optional<bool> spoilerMediaOverride);
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos); void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
[[nodiscard]] SendMenu::Type sendMenuType() const;
[[nodiscard]] FullReplyTo replyTo() const; [[nodiscard]] FullReplyTo replyTo() const;
void doSetInnerFocus(); void doSetInnerFocus();
void showAtPosition( void showAtPosition(
@ -792,7 +791,7 @@ QPointer<Ui::RpWidget> ShortcutMessages::createPinnedToBottom(
listShowPremiumToast(emoji); listShowPremiumToast(emoji);
}, },
.mode = HistoryView::ComposeControlsMode::Normal, .mode = HistoryView::ComposeControlsMode::Normal,
.sendMenuType = SendMenu::Type::Disabled, .sendMenuDetails = [] { return SendMenu::Details(); },
.regularWindow = _controller, .regularWindow = _controller,
.stickerOrEmojiChosen = _controller->stickerOrEmojiChosen(), .stickerOrEmojiChosen = _controller->stickerOrEmojiChosen(),
.customPlaceholder = std::move(placeholder), .customPlaceholder = std::move(placeholder),
@ -1346,7 +1345,7 @@ bool ShortcutMessages::confirmSendingFiles(
_composeControls->getTextWithAppliedMarkdown(), _composeControls->getTextWithAppliedMarkdown(),
_history->peer, _history->peer,
Api::SendType::Normal, Api::SendType::Normal,
SendMenu::Type::Disabled); SendMenu::Details());
box->setConfirmedCallback(crl::guard(this, [=]( box->setConfirmedCallback(crl::guard(this, [=](
Ui::PreparedList &&list, Ui::PreparedList &&list,
@ -1543,12 +1542,6 @@ void ShortcutMessages::sendInlineResult(
return; return;
} }
sendInlineResult(result, bot, {}, std::nullopt); sendInlineResult(result, bot, {}, std::nullopt);
//const auto callback = [=](Api::SendOptions options) {
// sendInlineResult(result, bot, options);
//};
//Ui::show(
// PrepareScheduleBox(this, sendMenuType(), callback),
// Ui::LayerOption::KeepOther);
} }
void ShortcutMessages::sendInlineResult( void ShortcutMessages::sendInlineResult(

View file

@ -1141,7 +1141,7 @@ void Filler::addCreatePoll() {
flag, flag,
flag, flag,
source, source,
sendMenuType); { sendMenuType });
}; };
_addAction( _addAction(
tr::lng_polls_create(tr::now), tr::lng_polls_create(tr::now),
@ -1589,7 +1589,7 @@ void PeerMenuCreatePoll(
PollData::Flags chosen, PollData::Flags chosen,
PollData::Flags disabled, PollData::Flags disabled,
Api::SendType sendType, Api::SendType sendType,
SendMenu::Type sendMenuType) { SendMenu::Details sendMenuDetails) {
if (peer->isChannel() && !peer->isMegagroup()) { if (peer->isChannel() && !peer->isMegagroup()) {
chosen &= ~PollData::Flag::PublicVotes; chosen &= ~PollData::Flag::PublicVotes;
disabled |= PollData::Flag::PublicVotes; disabled |= PollData::Flag::PublicVotes;
@ -1599,7 +1599,7 @@ void PeerMenuCreatePoll(
chosen, chosen,
disabled, disabled,
sendType, sendType,
sendMenuType); sendMenuDetails);
const auto weak = Ui::MakeWeak(box.data()); const auto weak = Ui::MakeWeak(box.data());
const auto lock = box->lifetime().make_state<bool>(false); const auto lock = box->lifetime().make_state<bool>(false);
box->submitRequests( box->submitRequests(
@ -2071,17 +2071,14 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
state->menu->addSeparator(); state->menu->addSeparator();
} }
const auto type = sendMenuType(); state->menu->setForcedVerticalOrigin(
Ui::PopupMenu::VerticalOrigin::Bottom);
const auto result = SendMenu::FillSendMenu( const auto result = SendMenu::FillSendMenu(
state->menu.get(), state->menu.get(),
type, show,
SendMenu::DefaultSilentCallback(submit), SendMenu::Details{ sendMenuType() },
SendMenu::DefaultScheduleCallback(show, type, submit), SendMenu::DefaultCallback(show, crl::guard(parent, submit)));
SendMenu::DefaultWhenOnlineCallback(submit)); if (showForwardOptions || !state->menu->empty()) {
const auto success = (result == SendMenu::FillMenuResult::Success);
if (showForwardOptions || success) {
state->menu->setForcedVerticalOrigin(
Ui::PopupMenu::VerticalOrigin::Bottom);
state->menu->popup(QCursor::pos()); state->menu->popup(QCursor::pos());
} }
}; };

View file

@ -91,7 +91,7 @@ void PeerMenuCreatePoll(
PollData::Flags chosen = PollData::Flags(), PollData::Flags chosen = PollData::Flags(),
PollData::Flags disabled = PollData::Flags(), PollData::Flags disabled = PollData::Flags(),
Api::SendType sendType = Api::SendType::Normal, Api::SendType sendType = Api::SendType::Normal,
SendMenu::Type sendMenuType = SendMenu::Type::Scheduled); SendMenu::Details sendMenuDetails = SendMenu::Details());
void PeerMenuDeleteTopicWithConfirmation( void PeerMenuDeleteTopicWithConfirmation(
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,
not_null<Data::ForumTopic*> topic); not_null<Data::ForumTopic*> topic);

View file

@ -122,7 +122,7 @@ public:
rpl::producer<> pauseChanged() const override; rpl::producer<> pauseChanged() const override;
rpl::producer<bool> adjustShadowLeft() const override; rpl::producer<bool> adjustShadowLeft() const override;
SendMenu::Type sendMenuType() const override; SendMenu::Details sendMenuDetails() const override;
bool showMediaPreview( bool showMediaPreview(
Data::FileOrigin origin, Data::FileOrigin origin,
@ -272,12 +272,12 @@ rpl::producer<bool> MainWindowShow::adjustShadowLeft() const {
}); });
} }
SendMenu::Type MainWindowShow::sendMenuType() const { SendMenu::Details MainWindowShow::sendMenuDetails() const {
const auto window = _window.get(); const auto window = _window.get();
if (!window) { if (!window) {
return SendMenu::Type::Disabled; return SendMenu::Details();
} }
return window->content()->sendMenuType(); return window->content()->sendMenuDetails();
} }
bool MainWindowShow::showMediaPreview( bool MainWindowShow::showMediaPreview(