mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Fly-animate reactions from the new context menu.
This commit is contained in:
parent
1877786707
commit
d4810713cb
16 changed files with 169 additions and 80 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue