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

View file

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

View file

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

View file

@ -47,7 +47,7 @@ class SessionController;
} // namespace Window
namespace SendMenu {
enum class Type;
struct Details;
} // namespace SendMenu
namespace HistoryView::Controls {
@ -96,7 +96,7 @@ struct SendFilesBoxDescriptor {
SendFilesLimits limits = {};
SendFilesCheck check;
Api::SendType sendType = {};
SendMenu::Type sendMenuType = {};
Fn<SendMenu::Details()> sendMenuDetails = nullptr;
const style::ComposeControls *stOverride = nullptr;
SendFilesConfirmed confirmed;
Fn<void()> cancelled;
@ -115,7 +115,7 @@ public:
const TextWithTags &caption,
not_null<PeerData*> toPeer,
Api::SendType sendType,
SendMenu::Type sendMenuType);
SendMenu::Details sendMenuDetails);
SendFilesBox(QWidget*, SendFilesBoxDescriptor &&descriptor);
void setConfirmedCallback(SendFilesConfirmed callback) {
@ -202,9 +202,7 @@ private:
void generatePreviewFrom(int fromBlock);
void send(Api::SendOptions options, bool ctrlShiftEnter = false);
void sendSilent();
void sendScheduled();
void sendWhenOnline();
[[nodiscard]] Fn<void(Api::SendOptions)> sendCallback();
void captionResized();
void saveSendWaySettings();
@ -238,7 +236,7 @@ private:
std::optional<int> _removingIndex;
SendFilesLimits _limits = {};
SendMenu::Type _sendMenuType = {};
Fn<SendMenu::Details()> _sendMenuDetails = nullptr;
PeerData *_captionToPeer = nullptr;
SendFilesCheck _check;
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();
return ranges::all_of(
const auto type = ranges::all_of(
selected | ranges::views::transform(&Data::Thread::peer),
HistoryView::CanScheduleUntilOnline)
? SendMenu::Type::ScheduledToUser
: (selected.size() == 1 && selected.front()->peer()->isSelf())
? SendMenu::Type::Reminder
: 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) {
@ -518,15 +521,25 @@ void ShareBox::showMenu(not_null<Ui::RpWidget*> parent) {
_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(),
sendMenuType(),
[=] { submitSilent(); },
[=] { submitScheduled(); },
[=] { submitWhenOnline(); });
const auto success = (result == SendMenu::FillMenuResult::Success);
if (_descriptor.forwardOptions.show || success) {
_menu->setForcedVerticalOrigin(Ui::PopupMenu::VerticalOrigin::Bottom);
nullptr, // showForEffect.
sendMenuDetails(),
sendAction);
if (result == SendMenu::FillMenuResult::Prepared) {
_menu->popupPrepared();
} else if (_descriptor.forwardOptions.show
&& result != SendMenu::FillMenuResult::Failed) {
_menu->popup(QCursor::pos());
}
}
@ -607,26 +620,18 @@ void ShareBox::submit(Api::SendOptions options) {
}
}
void ShareBox::submitSilent() {
submit({ .silent = true });
}
void ShareBox::submitScheduled() {
const auto callback = [=](Api::SendOptions options) { submit(options); };
uiShow()->showBox(
HistoryView::PrepareScheduleBox(
this,
nullptr, // ChatHelpers::Show for effect attachment.
sendMenuType(),
sendMenuDetails(),
callback,
HistoryView::DefaultScheduleTime(),
_descriptor.scheduleBoxStyle));
}
void ShareBox::submitWhenOnline() {
submit(Api::DefaultSendWhenOnlineOptions());
}
void ShareBox::copyLink() const {
if (const auto onstack = _descriptor.copyCallback) {
onstack();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -380,22 +380,22 @@ void GifsListWidget::mousePressEvent(QMouseEvent *e) {
}
base::unique_qptr<Ui::PopupMenu> GifsListWidget::fillContextMenu(
SendMenu::Type type) {
const SendMenu::Details &details) {
if (_selected < 0 || _pressed >= 0) {
return nullptr;
}
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);
};
});
const auto icons = &st().icons;
SendMenu::FillSendMenu(
menu,
type,
SendMenu::DefaultSilentCallback(send),
SendMenu::DefaultScheduleCallback(_show, type, send),
SendMenu::DefaultWhenOnlineCallback(send),
_show,
details,
SendMenu::DefaultCallback(_show, send),
icons);
if (const auto item = _mosaic.maybeItemAt(_selected)) {

View file

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

View file

@ -1634,7 +1634,7 @@ void StickersListWidget::showStickerSetBox(not_null<DocumentData*> document) {
}
base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
SendMenu::Type type) {
const SendMenu::Details &details) {
auto selected = _selected;
auto &sets = shownSets();
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);
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({
.document = document,
.options = options,
@ -1661,14 +1661,13 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
? Ui::MessageSendingAnimationFrom()
: messageSentAnimationInfo(section, index, document),
});
};
});
const auto icons = &st().icons;
SendMenu::FillSendMenu(
menu,
type,
SendMenu::DefaultSilentCallback(send),
SendMenu::DefaultScheduleCallback(_show, type, send),
SendMenu::DefaultWhenOnlineCallback(send),
_show,
details,
SendMenu::DefaultCallback(_show, send),
icons);
const auto show = _show;

View file

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

View file

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

View file

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

View file

@ -1297,9 +1297,10 @@ std::optional<Reaction> Reactions::parse(const MTPAvailableEffect &entry) {
return std::nullopt;
}
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()) {
LOG(("API Error: Bad sticker in effects: %1").arg(id));
LOG(("API Error: Bad sticker in effects: %1").arg(stickerId));
return std::nullopt;
}
const auto aroundId = data.veffect_animation_id().value_or_empty();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -122,7 +122,7 @@ public:
rpl::producer<> pauseChanged() const override;
rpl::producer<bool> adjustShadowLeft() const override;
SendMenu::Type sendMenuType() const override;
SendMenu::Details sendMenuDetails() const override;
bool showMediaPreview(
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();
if (!window) {
return SendMenu::Type::Disabled;
return SendMenu::Details();
}
return window->content()->sendMenuType();
return window->content()->sendMenuDetails();
}
bool MainWindowShow::showMediaPreview(