Fly-animate reactions from the new context menu.

This commit is contained in:
John Preston 2022-09-06 17:08:20 +04:00
parent 1877786707
commit d4810713cb
16 changed files with 169 additions and 80 deletions

View file

@ -502,8 +502,8 @@ void EditCaptionBox::setupEmojiPanel() {
_emojiPanel->hide(); _emojiPanel->hide();
_emojiPanel->selector()->setCurrentPeer(_historyItem->history()->peer); _emojiPanel->selector()->setCurrentPeer(_historyItem->history()->peer);
_emojiPanel->selector()->emojiChosen( _emojiPanel->selector()->emojiChosen(
) | rpl::start_with_next([=](EmojiPtr emoji) { ) | rpl::start_with_next([=](Selector::EmojiChosen data) {
Ui::InsertEmojiAtCursor(_field->textCursor(), emoji); Ui::InsertEmojiAtCursor(_field->textCursor(), data.emoji);
}, lifetime()); }, lifetime());
_emojiPanel->selector()->customEmojiChosen( _emojiPanel->selector()->customEmojiChosen(
) | rpl::start_with_next([=](Selector::FileChosen data) { ) | rpl::start_with_next([=](Selector::FileChosen data) {

View file

@ -744,8 +744,8 @@ void SendFilesBox::setupEmojiPanel() {
_emojiPanel->selector()->setAllowEmojiWithoutPremium( _emojiPanel->selector()->setAllowEmojiWithoutPremium(
_allowEmojiWithoutPremium); _allowEmojiWithoutPremium);
_emojiPanel->selector()->emojiChosen( _emojiPanel->selector()->emojiChosen(
) | rpl::start_with_next([=](EmojiPtr emoji) { ) | rpl::start_with_next([=](Selector::EmojiChosen data) {
Ui::InsertEmojiAtCursor(_caption->textCursor(), emoji); Ui::InsertEmojiAtCursor(_caption->textCursor(), data.emoji);
}, lifetime()); }, lifetime());
_emojiPanel->selector()->customEmojiChosen( _emojiPanel->selector()->customEmojiChosen(
) | rpl::start_with_next([=](Selector::FileChosen data) { ) | rpl::start_with_next([=](Selector::FileChosen data) {

View file

@ -46,6 +46,8 @@ constexpr auto kAppearDuration = 0.3;
using Core::RecentEmojiId; using Core::RecentEmojiId;
using Core::RecentEmojiDocument; using Core::RecentEmojiDocument;
using EmojiChosen = TabbedSelector::EmojiChosen;
using FileChosen = TabbedSelector::FileChosen;
} // namespace } // namespace
@ -64,8 +66,8 @@ public:
void hideAnimated(); void hideAnimated();
void hideFast(); void hideFast();
rpl::producer<EmojiPtr> chosen() const; [[nodiscard]] rpl::producer<EmojiChosen> chosen() const;
rpl::producer<> hidden() const; [[nodiscard]] rpl::producer<> hidden() const;
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
@ -98,7 +100,7 @@ private:
QPixmap _cache; QPixmap _cache;
Ui::Animations::Simple _a_opacity; Ui::Animations::Simple _a_opacity;
rpl::event_stream<EmojiPtr> _chosen; rpl::event_stream<EmojiChosen> _chosen;
rpl::event_stream<> _hidden; rpl::event_stream<> _hidden;
}; };
@ -204,7 +206,7 @@ void EmojiColorPicker::handleMouseRelease(QPoint globalPos) {
updateSelected(); updateSelected();
if (_selected >= 0 && (pressed < 0 || _selected == pressed)) { if (_selected >= 0 && (pressed < 0 || _selected == pressed)) {
_chosen.fire_copy(_variants[_selected]); _chosen.fire_copy({ .emoji = _variants[_selected] });
} }
_ignoreShow = true; _ignoreShow = true;
hideAnimated(); hideAnimated();
@ -254,7 +256,7 @@ void EmojiColorPicker::hideFast() {
_hidden.fire({}); _hidden.fire({});
} }
rpl::producer<EmojiPtr> EmojiColorPicker::chosen() const { rpl::producer<EmojiChosen> EmojiColorPicker::chosen() const {
return _chosen.events(); return _chosen.events();
} }
@ -413,8 +415,8 @@ EmojiListWidget::EmojiListWidget(
} }
_picker->chosen( _picker->chosen(
) | rpl::start_with_next([=](EmojiPtr emoji) { ) | rpl::start_with_next([=](EmojiChosen data) {
colorChosen(emoji); colorChosen(data);
}, lifetime()); }, lifetime());
_picker->hidden( _picker->hidden(
@ -494,17 +496,15 @@ void EmojiListWidget::repaintCustom(uint64 setId) {
}); });
} }
rpl::producer<EmojiPtr> EmojiListWidget::chosen() const { rpl::producer<EmojiChosen> EmojiListWidget::chosen() const {
return _chosen.events(); return _chosen.events();
} }
auto EmojiListWidget::customChosen() const rpl::producer<FileChosen> EmojiListWidget::customChosen() const {
-> rpl::producer<TabbedSelector::FileChosen> {
return _customChosen.events(); return _customChosen.events();
} }
auto EmojiListWidget::premiumChosen() const rpl::producer<FileChosen> EmojiListWidget::premiumChosen() const {
-> rpl::producer<not_null<DocumentData*>> {
return _premiumChosen.events(); return _premiumChosen.events();
} }
@ -811,33 +811,37 @@ base::unique_qptr<Ui::PopupMenu> EmojiListWidget::fillContextMenu(
auto menu = base::make_unique_q<Ui::PopupMenu>( auto menu = base::make_unique_q<Ui::PopupMenu>(
this, this,
st::defaultPopupMenu); st::defaultPopupMenu);
const auto selectWith = [=](TimeId scheduled) {
selectCustom(
lookupChosen(chosen, nullptr, { .scheduled = scheduled }));
};
for (const auto &value : { 3600, 3600 * 8, 3600 * 24, 3600 * 24 * 7 }) { for (const auto &value : { 3600, 3600 * 8, 3600 * 24, 3600 * 24 * 7 }) {
const auto text = tr::lng_emoji_status_menu_duration_any( const auto text = tr::lng_emoji_status_menu_duration_any(
tr::now, tr::now,
lt_duration, lt_duration,
Ui::FormatMuteFor(value)); Ui::FormatMuteFor(value));
menu->addAction(text, crl::guard(this, [=] { menu->addAction(text, crl::guard(this, [=] {
selectCustom( selectWith(base::unixtime::now() + value);
chosen,
{ .scheduled = base::unixtime::now() + value } );
})); }));
} }
const auto options = Api::SendOptions{
.scheduled = TabbedSelector::kPickCustomTimeId,
};
menu->addAction( menu->addAction(
tr::lng_manage_messages_ttl_after_custom(tr::now), tr::lng_manage_messages_ttl_after_custom(tr::now),
crl::guard(this, [=] { selectCustom(chosen, options); })); crl::guard(this, [=] { selectWith(
TabbedSelector::kPickCustomTimeId); }));
return menu; return menu;
} }
void EmojiListWidget::paintEvent(QPaintEvent *e) { void EmojiListWidget::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
_repaintsScheduled.clear();
const auto clip = e ? e->rect() : rect(); const auto clip = e ? e->rect() : rect();
if (st().bg->c.alpha() > 0) {
_repaintsScheduled.clear();
if (_grabbingChosen) {
p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect(clip, Qt::transparent);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
} else if (st().bg->c.alpha() > 0) {
p.fillRect(clip, st().bg); p.fillRect(clip, st().bg);
} }
@ -1121,6 +1125,37 @@ EmojiPtr EmojiListWidget::lookupOverEmoji(const OverEmoji *over) const {
: nullptr; : nullptr;
} }
EmojiChosen EmojiListWidget::lookupChosen(
EmojiPtr emoji,
not_null<const OverEmoji*> over) {
return {
.emoji = emoji,
.messageSendingFrom = {
.type = Ui::MessageSendingAnimationFrom::Type::Emoji,
.globalStartGeometry = mapToGlobal(
emojiRect(over->section, over->index)),
},
};
}
FileChosen EmojiListWidget::lookupChosen(
not_null<DocumentData*> custom,
const OverEmoji *over,
Api::SendOptions options) {
_grabbingChosen = true;
const auto guard = gsl::finally([&] { _grabbingChosen = false; });
const auto rect = emojiRect(over->section, over->index);
return {
.document = custom,
.options = options,
.messageSendingFrom = {
.type = Ui::MessageSendingAnimationFrom::Type::Emoji,
.globalStartGeometry = over ? mapToGlobal(rect) : QRect(),
.frame = over ? Ui::GrabWidgetToImage(this, rect) : QImage(),
},
};
}
void EmojiListWidget::mousePressEvent(QMouseEvent *e) { void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos(); _lastMousePos = e->globalPos();
updateSelected(); updateSelected();
@ -1187,9 +1222,9 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
if (emoji->hasVariants() && !_picker->isHidden()) { if (emoji->hasVariants() && !_picker->isHidden()) {
return; return;
} }
selectEmoji(emoji); selectEmoji(lookupChosen(emoji, over));
} else if (const auto custom = lookupCustomEmoji(index, section)) { } else if (const auto custom = lookupCustomEmoji(index, section)) {
selectCustom(custom); selectCustom(lookupChosen(custom, over));
} }
} else if (const auto set = std::get_if<OverSet>(&pressed)) { } else if (const auto set = std::get_if<OverSet>(&pressed)) {
Assert(set->section >= _staticCount Assert(set->section >= _staticCount
@ -1241,18 +1276,17 @@ void EmojiListWidget::removeSet(uint64 setId) {
} }
} }
void EmojiListWidget::selectEmoji(EmojiPtr emoji) { void EmojiListWidget::selectEmoji(EmojiChosen data) {
Core::App().settings().incrementRecentEmoji({ emoji }); Core::App().settings().incrementRecentEmoji({ data.emoji });
_chosen.fire_copy(emoji); _chosen.fire(std::move(data));
} }
void EmojiListWidget::selectCustom( void EmojiListWidget::selectCustom(FileChosen data) {
not_null<DocumentData*> document, const auto document = data.document;
Api::SendOptions options) {
if (document->isPremiumEmoji() if (document->isPremiumEmoji()
&& !document->session().premium() && !document->session().premium()
&& !_allowWithoutPremium) { && !_allowWithoutPremium) {
_premiumChosen.fire_copy(document); _premiumChosen.fire(std::move(data));
return; return;
} }
auto &settings = Core::App().settings(); auto &settings = Core::App().settings();
@ -1262,7 +1296,7 @@ void EmojiListWidget::selectCustom(
document->session().isTestMode(), document->session().isTestMode(),
} }); } });
} }
_customChosen.fire({ .document = document, .options = options }); _customChosen.fire(std::move(data));
} }
void EmojiListWidget::showPicker() { void EmojiListWidget::showPicker() {
@ -1408,7 +1442,8 @@ QRect EmojiListWidget::emojiRect(int section, int index) const {
return QRect(x, y, _singleSize.width(), _singleSize.height()); return QRect(x, y, _singleSize.width(), _singleSize.height());
} }
void EmojiListWidget::colorChosen(EmojiPtr emoji) { void EmojiListWidget::colorChosen(EmojiChosen data) {
const auto emoji = data.emoji;
if (emoji->hasVariants()) { if (emoji->hasVariants()) {
Core::App().settings().saveEmojiVariant(emoji); Core::App().settings().saveEmojiVariant(emoji);
} }
@ -1420,7 +1455,7 @@ void EmojiListWidget::colorChosen(EmojiPtr emoji) {
_emoji[over->section][over->index] = emoji; _emoji[over->section][over->index] = emoji;
rtlupdate(emojiRect(over->section, over->index)); rtlupdate(emojiRect(over->section, over->index));
} }
selectEmoji(emoji); selectEmoji(data);
_picker->hideAnimated(); _picker->hideAnimated();
} }

View file

@ -85,6 +85,9 @@ class EmojiListWidget
, public Ui::AbstractTooltipShower { , public Ui::AbstractTooltipShower {
public: public:
using Mode = EmojiListMode; using Mode = EmojiListMode;
using EmojiChosen = TabbedSelector::EmojiChosen;
using FileChosen = TabbedSelector::FileChosen;
EmojiListWidget( EmojiListWidget(
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
@ -110,11 +113,9 @@ public:
void refreshEmoji(); void refreshEmoji();
[[nodiscard]] rpl::producer<EmojiPtr> chosen() const; [[nodiscard]] rpl::producer<EmojiChosen> chosen() const;
[[nodiscard]] auto customChosen() const [[nodiscard]] rpl::producer<FileChosen> customChosen() const;
-> rpl::producer<TabbedSelector::FileChosen>; [[nodiscard]] rpl::producer<FileChosen> premiumChosen() const;
[[nodiscard]] auto premiumChosen() const
-> rpl::producer<not_null<DocumentData*>>;
[[nodiscard]] rpl::producer<> jumpedToPremium() const; [[nodiscard]] rpl::producer<> jumpedToPremium() const;
void provideRecent(const std::vector<DocumentId> &customRecentList); void provideRecent(const std::vector<DocumentId> &customRecentList);
@ -237,7 +238,7 @@ private:
void showPicker(); void showPicker();
void pickerHidden(); void pickerHidden();
void colorChosen(EmojiPtr emoji); void colorChosen(EmojiChosen data);
bool checkPickerHide(); bool checkPickerHide();
void refreshCustom(); void refreshCustom();
void unloadNotSeenCustom(int visibleTop, int visibleBottom); void unloadNotSeenCustom(int visibleTop, int visibleBottom);
@ -253,10 +254,15 @@ private:
[[nodiscard]] DocumentData *lookupCustomEmoji( [[nodiscard]] DocumentData *lookupCustomEmoji(
int index, int index,
int section) const; int section) const;
void selectEmoji(EmojiPtr emoji); [[nodiscard]] EmojiChosen lookupChosen(
void selectCustom( EmojiPtr emoji,
not_null<DocumentData*> document, not_null<const OverEmoji*> over);
[[nodiscard]] FileChosen lookupChosen(
not_null<DocumentData*> custom,
const OverEmoji *over,
Api::SendOptions options = Api::SendOptions()); Api::SendOptions options = Api::SendOptions());
void selectEmoji(EmojiChosen data);
void selectCustom(FileChosen data);
void paint(QPainter &p, ExpandingContext context, QRect clip); void paint(QPainter &p, ExpandingContext context, QRect clip);
void drawCollapsedBadge(QPainter &p, QPoint position, int count); void drawCollapsedBadge(QPainter &p, QPoint position, int count);
void drawRecent( void drawRecent(
@ -343,6 +349,7 @@ private:
base::flat_set<uint64> _repaintsScheduled; base::flat_set<uint64> _repaintsScheduled;
std::unique_ptr<Ui::Text::CustomEmojiColored> _emojiStatusColor; std::unique_ptr<Ui::Text::CustomEmojiColored> _emojiStatusColor;
bool _recentPainted = false; bool _recentPainted = false;
bool _grabbingChosen = false;
QVector<EmojiPtr> _emoji[kEmojiSectionCount]; QVector<EmojiPtr> _emoji[kEmojiSectionCount];
std::vector<CustomSet> _custom; std::vector<CustomSet> _custom;
base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji; base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji;
@ -373,9 +380,9 @@ private:
object_ptr<EmojiColorPicker> _picker; object_ptr<EmojiColorPicker> _picker;
base::Timer _showPickerTimer; base::Timer _showPickerTimer;
rpl::event_stream<EmojiPtr> _chosen; rpl::event_stream<EmojiChosen> _chosen;
rpl::event_stream<TabbedSelector::FileChosen> _customChosen; rpl::event_stream<FileChosen> _customChosen;
rpl::event_stream<not_null<DocumentData*>> _premiumChosen; rpl::event_stream<FileChosen> _premiumChosen;
rpl::event_stream<> _jumpedToPremium; rpl::event_stream<> _jumpedToPremium;
}; };

View file

@ -492,7 +492,7 @@ bool TabbedSelector::hasMasksTab() const {
return _hasMasksTab; return _hasMasksTab;
} }
rpl::producer<EmojiPtr> TabbedSelector::emojiChosen() const { auto TabbedSelector::emojiChosen() const -> rpl::producer<EmojiChosen> {
return emoji()->chosen(); return emoji()->chosen();
} }
@ -501,7 +501,7 @@ auto TabbedSelector::customEmojiChosen() const -> rpl::producer<FileChosen> {
} }
auto TabbedSelector::premiumEmojiChosen() const auto TabbedSelector::premiumEmojiChosen() const
-> rpl::producer<not_null<DocumentData*>> { -> rpl::producer<FileChosen> {
return emoji()->premiumChosen(); return emoji()->premiumChosen();
} }

View file

@ -70,6 +70,10 @@ public:
not_null<PhotoData*> photo; not_null<PhotoData*> photo;
Api::SendOptions options; Api::SendOptions options;
}; };
struct EmojiChosen {
EmojiPtr emoji;
Ui::MessageSendingAnimationFrom messageSendingFrom;
};
using InlineChosen = InlineBots::ResultSelected; using InlineChosen = InlineBots::ResultSelected;
enum class Mode { enum class Mode {
Full, Full,
@ -92,9 +96,9 @@ public:
Main::Session &session() const; Main::Session &session() const;
Window::GifPauseReason level() const; Window::GifPauseReason level() const;
rpl::producer<EmojiPtr> emojiChosen() const; rpl::producer<EmojiChosen> emojiChosen() const;
rpl::producer<FileChosen> customEmojiChosen() const; rpl::producer<FileChosen> customEmojiChosen() const;
rpl::producer<not_null<DocumentData*>> premiumEmojiChosen() const; rpl::producer<FileChosen> premiumEmojiChosen() const;
rpl::producer<FileChosen> fileChosen() const; rpl::producer<FileChosen> fileChosen() const;
rpl::producer<PhotoChosen> photoChosen() const; rpl::producer<PhotoChosen> photoChosen() const;
rpl::producer<InlineChosen> inlineResultChosen() const; rpl::producer<InlineChosen> inlineResultChosen() const;

View file

@ -480,10 +480,13 @@ void HistoryInner::reactionChosen(const ChosenReaction &reaction) {
return; return;
} else if (const auto view = item->mainView()) { } else if (const auto view = item->mainView()) {
if (const auto top = itemTop(view); top >= 0) { if (const auto top = itemTop(view); top >= 0) {
const auto geometry = reaction.localGeometry.isEmpty()
? mapFromGlobal(reaction.globalGeometry)
: reaction.localGeometry;
view->animateReaction({ view->animateReaction({
.id = reaction.id, .id = reaction.id,
.flyIcon = reaction.icon, .flyIcon = reaction.icon,
.flyFrom = reaction.geometry.translated(0, -top), .flyFrom = geometry.translated(0, -top),
}); });
} }
} }

View file

@ -1067,8 +1067,8 @@ void HistoryWidget::initTabbedSelector() {
selector->emojiChosen( selector->emojiChosen(
) | rpl::filter([=] { ) | rpl::filter([=] {
return !isHidden() && !_field->isHidden(); return !isHidden() && !_field->isHidden();
}) | rpl::start_with_next([=](EmojiPtr emoji) { }) | rpl::start_with_next([=](Selector::EmojiChosen data) {
Ui::InsertEmojiAtCursor(_field->textCursor(), emoji); Ui::InsertEmojiAtCursor(_field->textCursor(), data.emoji);
}, lifetime()); }, lifetime());
selector->customEmojiChosen( selector->customEmojiChosen(
@ -1081,8 +1081,8 @@ void HistoryWidget::initTabbedSelector() {
selector->premiumEmojiChosen( selector->premiumEmojiChosen(
) | rpl::filter([=] { ) | rpl::filter([=] {
return !isHidden() && !_field->isHidden(); return !isHidden() && !_field->isHidden();
}) | rpl::start_with_next([=](not_null<DocumentData*> document) { }) | rpl::start_with_next([=](Selector::FileChosen data) {
showPremiumToast(document); showPremiumToast(data.document);
}, lifetime()); }, lifetime());
selector->fileChosen( selector->fileChosen(

View file

@ -1857,9 +1857,10 @@ void ComposeControls::initTabbedSelector() {
return base::EventFilterResult::Continue; return base::EventFilterResult::Continue;
}); });
using EmojiChosen = ChatHelpers::TabbedSelector::EmojiChosen;
selector->emojiChosen( selector->emojiChosen(
) | rpl::start_with_next([=](EmojiPtr emoji) { ) | rpl::start_with_next([=](EmojiChosen data) {
Ui::InsertEmojiAtCursor(_field->textCursor(), emoji); Ui::InsertEmojiAtCursor(_field->textCursor(), data.emoji);
}, wrap->lifetime()); }, wrap->lifetime());
using FileChosen = ChatHelpers::TabbedSelector::FileChosen; using FileChosen = ChatHelpers::TabbedSelector::FileChosen;
@ -1869,9 +1870,9 @@ void ComposeControls::initTabbedSelector() {
}, wrap->lifetime()); }, wrap->lifetime());
selector->premiumEmojiChosen( selector->premiumEmojiChosen(
) | rpl::start_with_next([=](not_null<DocumentData*> document) { ) | rpl::start_with_next([=](FileChosen data) {
if (_unavailableEmojiPasted) { if (_unavailableEmojiPasted) {
_unavailableEmojiPasted(document); _unavailableEmojiPasted(data.document);
} }
}, wrap->lifetime()); }, wrap->lifetime());

View file

@ -374,11 +374,14 @@ ListWidget::ListWidget(
if (!ranges::contains(item->chosenReactions(), reaction.id)) { if (!ranges::contains(item->chosenReactions(), reaction.id)) {
return; return;
} else if (const auto view = viewForItem(item)) { } else if (const auto view = viewForItem(item)) {
const auto geometry = reaction.localGeometry.isEmpty()
? mapFromGlobal(reaction.globalGeometry)
: reaction.localGeometry;
if (const auto top = itemTop(view); top >= 0) { if (const auto top = itemTop(view); top >= 0) {
view->animateReaction({ view->animateReaction({
.id = reaction.id, .id = reaction.id,
.flyIcon = reaction.icon, .flyIcon = reaction.icon,
.flyFrom = reaction.geometry.translated(0, -top), .flyFrom = geometry.translated(0, -top),
}); });
} }
} }

View file

@ -374,7 +374,7 @@ ChosenReaction Manager::lookupChosen(const ReactionId &id) const {
: local; : local;
const auto rect = QRect(geometry.topLeft() + QPoint(0, top), _outer); const auto rect = QRect(geometry.topLeft() + QPoint(0, top), _outer);
const auto imageSize = _strip.computeOverSize(); const auto imageSize = _strip.computeOverSize();
result.geometry = QRect( result.localGeometry = QRect(
rect.x() + (rect.width() - imageSize) / 2, rect.x() + (rect.width() - imageSize) / 2,
rect.y() + (rect.height() - imageSize) / 2, rect.y() + (rect.height() - imageSize) / 2,
imageSize, imageSize,

View file

@ -624,11 +624,33 @@ void Selector::mouseReleaseEvent(QMouseEvent *e) {
expand(); expand();
} else if (const auto id = std::get_if<Data::ReactionId>(&selected)) { } else if (const auto id = std::get_if<Data::ReactionId>(&selected)) {
if (!id->empty()) { if (!id->empty()) {
_chosen.fire({ .id = *id }); _chosen.fire(lookupChosen(*id));
} }
} }
} }
ChosenReaction Selector::lookupChosen(const Data::ReactionId &id) const {
Expects(_strip != nullptr);
auto result = ChosenReaction{
.id = id,
};
const auto index = _strip->fillChosenIconGetIndex(result);
if (result.icon.isNull()) {
return result;
}
const auto between = st::reactionCornerSkip;
const auto oneHeight = (st::reactionCornerSize.height() + between);
const auto rect = QRect(_skipx + index * _size, _skipy, _size, _size);
const auto imageSize = _strip->computeOverSize();
result.globalGeometry = mapToGlobal(QRect(
_inner.x() + rect.x() + (rect.width() - imageSize) / 2,
_inner.y() + rect.y() + (rect.height() - imageSize) / 2,
imageSize,
imageSize));
return result;
}
void Selector::expand() { void Selector::expand() {
if (_expandScheduled) { if (_expandScheduled) {
return; return;
@ -759,19 +781,19 @@ void Selector::createList(not_null<Window::SessionController*> controller) {
).data(); ).data();
rpl::merge( rpl::merge(
_list->customChosen( _list->customChosen(),
) | rpl::map([=](const TabbedSelector::FileChosen &chosen) {
return chosen.document;
}),
_list->premiumChosen() _list->premiumChosen()
) | rpl::start_with_next([=](not_null<DocumentData*> document) { ) | rpl::start_with_next([=](TabbedSelector::FileChosen data) {
const auto id = DocumentId{ document->id }; const auto id = DocumentId{ data.document->id };
const auto i = defaultReactionIds.find(id); const auto i = defaultReactionIds.find(id);
if (i != end(defaultReactionIds)) { const auto reactionId = (i != end(defaultReactionIds))
_chosen.fire({ .id = { i->second } }); ? Data::ReactionId{ i->second }
} else { : Data::ReactionId{ id };
_chosen.fire({ .id = { id } }); _chosen.fire({
} .id = reactionId,
.icon = data.messageSendingFrom.frame,
.globalGeometry = data.messageSendingFrom.globalStartGeometry,
});
}, _list->lifetime()); }, _list->lifetime());
_list->jumpedToPremium( _list->jumpedToPremium(

View file

@ -117,6 +117,7 @@ private:
void cacheExpandIcon(); void cacheExpandIcon();
void createList(not_null<Window::SessionController*> controller); void createList(not_null<Window::SessionController*> controller);
void finishExpand(); void finishExpand();
ChosenReaction lookupChosen(const Data::ReactionId &id) const;
const base::weak_ptr<Window::SessionController> _parentController; const base::weak_ptr<Window::SessionController> _parentController;
const Data::PossibleItemReactions _reactions; const Data::PossibleItemReactions _reactions;

View file

@ -28,7 +28,8 @@ struct ChosenReaction {
FullMsgId context; FullMsgId context;
Data::ReactionId id; Data::ReactionId id;
QImage icon; QImage icon;
QRect geometry; QRect localGeometry;
QRect globalGeometry;
explicit operator bool() const { explicit operator bool() const {
return context && !id.empty(); return context && !id.empty();

View file

@ -327,6 +327,7 @@ void EmojiStatusPanel::create(
struct Chosen { struct Chosen {
DocumentId id = 0; DocumentId id = 0;
TimeId until = 0; TimeId until = 0;
Ui::MessageSendingAnimationFrom animation;
}; };
_panel->selector()->contextMenuRequested( _panel->selector()->contextMenuRequested(
@ -336,12 +337,21 @@ void EmojiStatusPanel::create(
auto statusChosen = _panel->selector()->customEmojiChosen( auto statusChosen = _panel->selector()->customEmojiChosen(
) | rpl::map([=](Selector::FileChosen data) { ) | rpl::map([=](Selector::FileChosen data) {
return Chosen{ data.document->id, data.options.scheduled }; return Chosen{
.id = data.document->id,
.until = data.options.scheduled,
.animation = data.messageSendingFrom,
};
});
auto emojiChosen = _panel->selector()->emojiChosen(
) | rpl::map([=](Selector::EmojiChosen data) {
return Chosen{ .animation = data.messageSendingFrom };
}); });
rpl::merge( rpl::merge(
std::move(statusChosen), std::move(statusChosen),
_panel->selector()->emojiChosen() | rpl::map_to(Chosen()) std::move(emojiChosen)
) | rpl::start_with_next([=](const Chosen chosen) { ) | rpl::start_with_next([=](const Chosen chosen) {
if (chosen.until == ChatHelpers::TabbedSelector::kPickCustomTimeId) { if (chosen.until == ChatHelpers::TabbedSelector::kPickCustomTimeId) {
controller->show(Box(PickUntilBox, [=](TimeId seconds) { controller->show(Box(PickUntilBox, [=](TimeId seconds) {

View file

@ -14,10 +14,12 @@ struct MessageSendingAnimationFrom {
None, None,
Sticker, Sticker,
Gif, Gif,
Emoji,
}; };
Type type = Type::None; Type type = Type::None;
std::optional<MsgId> localId; std::optional<MsgId> localId;
QRect globalStartGeometry; QRect globalStartGeometry;
QImage frame;
bool crop = false; bool crop = false;
}; };