Fix send menus with additional items.

This commit is contained in:
John Preston 2024-10-11 18:19:40 +04:00
parent ba31756bf9
commit 5767cbd0e3
6 changed files with 122 additions and 54 deletions

View file

@ -1428,9 +1428,13 @@ void StickerSetBox::Inner::contextMenuEvent(QContextMenuEvent *e) {
const auto send = crl::guard(this, [=](Api::SendOptions options) {
chosen(index, document, options);
});
// In case we're adding items after FillSendMenu we have
// to pass nullptr for showForEffect and attach selector later.
// Otherwise added items widths won't be respected in menu geometry.
SendMenu::FillSendMenu(
_menu.get(),
_show,
nullptr, // showForEffect
details,
SendMenu::DefaultCallback(_show, send));
@ -1464,6 +1468,12 @@ void StickerSetBox::Inner::contextMenuEvent(QContextMenuEvent *e) {
.isAttention = true,
});
}
SendMenu::AttachSendMenuEffect(
_menu.get(),
_show,
details,
SendMenu::DefaultCallback(_show, send));
}
if (_menu->empty()) {
_menu = nullptr;

View file

@ -402,9 +402,13 @@ base::unique_qptr<Ui::PopupMenu> GifsListWidget::fillContextMenu(
// inline results don't have effects
copyDetails.effectAllowed = false;
}
// In case we're adding items after FillSendMenu we have
// to pass nullptr for showForEffect and attach selector later.
// Otherwise added items widths won't be respected in menu geometry.
SendMenu::FillSendMenu(
menu,
_show,
nullptr, // showForMenu
copyDetails,
SendMenu::DefaultCallback(_show, send),
icons);
@ -441,6 +445,13 @@ base::unique_qptr<Ui::PopupMenu> GifsListWidget::fillContextMenu(
AddGifAction(std::move(callback), _show, document, icons);
}
}
SendMenu::AttachSendMenuEffect(
menu,
_show,
copyDetails,
SendMenu::DefaultCallback(_show, send));
return menu;
}

View file

@ -1780,9 +1780,13 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
});
});
const auto icons = &st().icons;
// In case we're adding items after FillSendMenu we have
// to pass nullptr for showForEffect and attach selector later.
// Otherwise added items widths won't be respected in menu geometry.
SendMenu::FillSendMenu(
menu,
_show,
nullptr, // showForEffect
details,
SendMenu::DefaultCallback(_show, send),
icons);
@ -1816,6 +1820,13 @@ base::unique_qptr<Ui::PopupMenu> StickersListWidget::fillContextMenu(
false);
}, &icons->menuRecentRemove);
}
SendMenu::AttachSendMenuEffect(
menu,
_show,
details,
SendMenu::DefaultCallback(_show, send));
return menu;
}

View file

@ -346,11 +346,16 @@ void Inner::contextMenuEvent(QContextMenuEvent *e) {
const auto send = crl::guard(this, [=](Api::SendOptions options) {
selectInlineResult(selected, options, false);
});
const auto show = _controller->uiShow();
// In case we're adding items after FillSendMenu we have
// to pass nullptr for showForEffect and attach selector later.
// Otherwise added items widths won't be respected in menu geometry.
SendMenu::FillSendMenu(
_menu,
_controller->uiShow(),
nullptr, // showForEffect
details,
SendMenu::DefaultCallback(_controller->uiShow(), send));
SendMenu::DefaultCallback(show, send));
const auto item = _mosaic.itemAt(_selected);
if (const auto previewDocument = item->getPreviewDocument()) {
@ -366,6 +371,12 @@ void Inner::contextMenuEvent(QContextMenuEvent *e) {
previewDocument);
}
SendMenu::AttachSendMenuEffect(
_menu,
show,
details,
SendMenu::DefaultCallback(show, send));
if (!_menu->empty()) {
_menu->popup(QCursor::pos());
}

View file

@ -609,6 +609,67 @@ Fn<void(Action, Details)> DefaultCallback(
};
}
FillMenuResult AttachSendMenuEffect(
not_null<Ui::PopupMenu*> menu,
std::shared_ptr<ChatHelpers::Show> show,
Details details,
Fn<void(Action, Details)> action,
std::optional<QPoint> desiredPositionOverride) {
Expects(show != nullptr);
using namespace HistoryView::Reactions;
const auto effect = std::make_shared<QPointer<EffectPreview>>();
const auto position = desiredPositionOverride.value_or(QCursor::pos());
const auto selector = (show && details.effectAllowed)
? AttachSelectorToMenu(
menu,
position,
st::reactPanelEmojiPan,
show,
LookupPossibleEffects(&show->session()),
{ tr::lng_effect_add_title(tr::now) },
nullptr, // iconFactory
[=] { return (*effect) != nullptr; }) // paused
: 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) {
const auto &reactions = show->session().data().reactions();
const auto &effects = reactions.list(Data::Reactions::Type::Effects);
const auto i = ranges::find(effects, chosen.id, &Data::Reaction::id);
if (i != end(effects)) {
if (const auto strong = effect->data()) {
strong->hideAnimated();
}
const auto weak = Ui::MakeWeak(menu);
const auto done = [=] {
delete effect->data();
if (const auto strong = weak.data()) {
strong->hideMenu(true);
}
};
*effect = Ui::CreateChild<EffectPreview>(
menu,
show,
details,
menu->mapFromGlobal(chosen.globalGeometry.center()),
*i,
action,
crl::guard(menu, done));
(*effect)->show();
}
}, menu->lifetime());
return FillMenuResult::Prepared;
}
FillMenuResult FillSendMenu(
not_null<Ui::PopupMenu*> menu,
std::shared_ptr<ChatHelpers::Show> showForEffect,
@ -691,57 +752,14 @@ FillMenuResult FillSendMenu(
&icons.menuPrice);
}
using namespace HistoryView::Reactions;
const auto effect = std::make_shared<QPointer<EffectPreview>>();
const auto position = desiredPositionOverride.value_or(QCursor::pos());
const auto selector = (showForEffect && details.effectAllowed)
? AttachSelectorToMenu(
return showForEffect
? AttachSendMenuEffect(
menu,
position,
st::reactPanelEmojiPan,
showForEffect,
LookupPossibleEffects(&showForEffect->session()),
{ tr::lng_effect_add_title(tr::now) },
nullptr, // iconFactory
[=] { return (*effect) != nullptr; }) // paused
: 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) {
const auto &reactions = showForEffect->session().data().reactions();
const auto &effects = reactions.list(Data::Reactions::Type::Effects);
const auto i = ranges::find(effects, chosen.id, &Data::Reaction::id);
if (i != end(effects)) {
if (const auto strong = effect->data()) {
strong->hideAnimated();
}
const auto weak = Ui::MakeWeak(menu);
const auto done = [=] {
delete effect->data();
if (const auto strong = weak.data()) {
strong->hideMenu(true);
}
};
*effect = Ui::CreateChild<EffectPreview>(
menu,
showForEffect,
details,
menu->mapFromGlobal(chosen.globalGeometry.center()),
*i,
action,
crl::guard(menu, done));
(*effect)->show();
}
}, menu->lifetime());
return FillMenuResult::Prepared;
details,
action,
desiredPositionOverride)
: FillMenuResult::Prepared;
}
void SetupMenuAndShortcuts(

View file

@ -90,6 +90,13 @@ FillMenuResult FillSendMenu(
const style::ComposeIcons *iconsOverride = nullptr,
std::optional<QPoint> desiredPositionOverride = std::nullopt);
FillMenuResult AttachSendMenuEffect(
not_null<Ui::PopupMenu*> menu,
std::shared_ptr<ChatHelpers::Show> show,
Details details,
Fn<void(Action, Details)> action,
std::optional<QPoint> desiredPositionOverride = std::nullopt);
void SetupMenuAndShortcuts(
not_null<Ui::RpWidget*> button,
std::shared_ptr<ChatHelpers::Show> show,