Support custom emoji in reply / pinned / forward bars.

This commit is contained in:
John Preston 2022-07-04 12:49:31 +04:00
parent 2fc43a44a4
commit 3238cf2b4b
12 changed files with 112 additions and 39 deletions

View file

@ -431,6 +431,7 @@ public:
void updateDate(TimeId newDate); void updateDate(TimeId newDate);
[[nodiscard]] bool canUpdateDate() const; [[nodiscard]] bool canUpdateDate() const;
void customEmojiRepaint();
[[nodiscard]] TimeId ttlDestroyAt() const { [[nodiscard]] TimeId ttlDestroyAt() const {
return _ttlDestroyAt; return _ttlDestroyAt;
@ -463,7 +464,6 @@ protected:
MessageFlags _flags = 0; MessageFlags _flags = 0;
void invalidateChatListEntry(); void invalidateChatListEntry();
void customEmojiRepaint();
void setGroupId(MessageGroupId groupId); void setGroupId(MessageGroupId groupId);

View file

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_service_message.h" #include "history/view/history_view_service_message.h"
#include "history/view/media/history_view_document.h" #include "history/view/media/history_view_document.h"
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "core/ui_integration.h"
#include "layout/layout_position.h" #include "layout/layout_position.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "media/audio/media_audio.h" #include "media/audio/media_audio.h"
@ -256,10 +257,15 @@ bool HistoryMessageReply::updateData(
} }
if (replyToMsg) { if (replyToMsg) {
const auto context = Core::MarkedTextContext{
.session = &holder->history()->session(),
.customEmojiRepaint = [=] { holder->customEmojiRepaint(); },
};
replyToText.setMarkedText( replyToText.setMarkedText(
st::messageTextStyle, st::messageTextStyle,
replyToMsg->inReplyText(), replyToMsg->inReplyText(),
Ui::DialogTextOptions()); Ui::DialogTextOptions(),
context);
updateName(holder); updateName(holder);
@ -447,6 +453,7 @@ void HistoryMessageReply::paint(
p.setTextPalette(inBubble p.setTextPalette(inBubble
? stm->replyTextPalette ? stm->replyTextPalette
: st->imgReplyTextPalette()); : st->imgReplyTextPalette());
holder->prepareCustomEmojiPaint(p, replyToText);
replyToText.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top() + st::msgServiceNameFont->height, w - st::msgReplyBarSkip - previewSkip, w + 2 * x); replyToText.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top() + st::msgServiceNameFont->height, w - st::msgReplyBarSkip - previewSkip, w + 2 * x);
p.setTextPalette(stm->textPalette); p.setTextPalette(stm->textPalette);
} }

View file

@ -149,6 +149,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/emoji_suggestions_widget.h" #include "chat_helpers/emoji_suggestions_widget.h"
#include "core/crash_reports.h" #include "core/crash_reports.h"
#include "core/shortcuts.h" #include "core/shortcuts.h"
#include "core/ui_integration.h"
#include "support/support_common.h" #include "support/support_common.h"
#include "support/support_autocomplete.h" #include "support/support_autocomplete.h"
#include "support/support_preload.h" #include "support/support_preload.h"
@ -6365,10 +6366,10 @@ void HistoryWidget::checkPinnedBarState() {
return; return;
} }
auto barContent = HistoryView::PinnedBarContent( _pinnedBar = std::make_unique<Ui::PinnedBar>(this, [=] {
&session(), return controller()->isGifPausedAtLeastFor(
_pinnedTracker->shownMessageId()); Window::GifPauseReason::Any);
_pinnedBar = std::make_unique<Ui::PinnedBar>(this); });
rpl::combine( rpl::combine(
Info::Profile::SharedMediaCountValue( Info::Profile::SharedMediaCountValue(
_peer, _peer,
@ -6389,7 +6390,11 @@ void HistoryWidget::checkPinnedBarState() {
) | rpl::start_with_next([=](bool many, HistoryItem *item) { ) | rpl::start_with_next([=](bool many, HistoryItem *item) {
refreshPinnedBarButton(many, item); refreshPinnedBarButton(many, item);
}, _pinnedBar->lifetime()); }, _pinnedBar->lifetime());
_pinnedBar->setContent(std::move(barContent));
_pinnedBar->setContent(HistoryView::PinnedBarContent(
&session(),
_pinnedTracker->shownMessageId(),
[bar = _pinnedBar.get()] { bar->update(); }));
controller()->adaptive().oneColumnValue( controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) { ) | rpl::start_with_next([=](bool one) {
@ -7417,10 +7422,15 @@ void HistoryWidget::messageDataReceived(
} }
void HistoryWidget::updateReplyEditText(not_null<HistoryItem*> item) { void HistoryWidget::updateReplyEditText(not_null<HistoryItem*> item) {
const auto context = Core::MarkedTextContext{
.session = &session(),
.customEmojiRepaint = [=] { updateField(); },
};
_replyEditMsgText.setMarkedText( _replyEditMsgText.setMarkedText(
st::messageTextStyle, st::messageTextStyle,
item->inReplyText(), item->inReplyText(),
Ui::DialogTextOptions()); Ui::DialogTextOptions(),
context);
if (!_field->isHidden() || isRecording()) { if (!_field->isHidden() || isRecording()) {
_fieldBarCancel->show(); _fieldBarCancel->show();
updateMouseTracking(); updateMouseTracking();
@ -7518,10 +7528,15 @@ void HistoryWidget::updateForwardingTexts() {
} }
} }
_toForwardFrom.setText(st::msgNameStyle, from, Ui::NameTextOptions()); _toForwardFrom.setText(st::msgNameStyle, from, Ui::NameTextOptions());
const auto context = Core::MarkedTextContext{
.session = &session(),
.customEmojiRepaint = [=] { updateField(); },
};
_toForwardText.setMarkedText( _toForwardText.setMarkedText(
st::messageTextStyle, st::messageTextStyle,
text, text,
Ui::DialogTextOptions()); Ui::DialogTextOptions(),
context);
_toForwardNameVersion = keepNames ? version : keepCaptions ? -1 : -2; _toForwardNameVersion = keepNames ? version : keepCaptions ? -1 : -2;
} }
@ -7570,7 +7585,7 @@ void HistoryWidget::updateReplyToName() {
} }
void HistoryWidget::updateField() { void HistoryWidget::updateField() {
auto fieldAreaTop = _scroll->y() + _scroll->height(); const auto fieldAreaTop = _scroll->y() + _scroll->height();
rtlupdate(0, fieldAreaTop, width(), height() - fieldAreaTop); rtlupdate(0, fieldAreaTop, width(), height() - fieldAreaTop);
} }
@ -7594,6 +7609,8 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
backh += st::historyReplyHeight; backh += st::historyReplyHeight;
} }
auto drawWebPagePreview = (_previewData && _previewData->pendingTill >= 0) && !_replyForwardPressed; auto drawWebPagePreview = (_previewData && _previewData->pendingTill >= 0) && !_replyForwardPressed;
p.setInactive(
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg); p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) { if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
auto replyLeft = st::historyReplySkip; auto replyLeft = st::historyReplySkip;

View file

@ -944,6 +944,9 @@ void Element::unloadHeavyPart() {
if (_heavyCustomEmoji) { if (_heavyCustomEmoji) {
_heavyCustomEmoji = false; _heavyCustomEmoji = false;
data()->_text.unloadCustomEmoji(); data()->_text.unloadCustomEmoji();
if (const auto reply = data()->Get<HistoryMessageReply>()) {
reply->replyToText.unloadCustomEmoji();
}
} }
} }

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_pinned_tracker.h" #include "history/view/history_view_pinned_tracker.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history.h" #include "history/history.h"
#include "core/ui_integration.h"
#include "base/weak_ptr.h" #include "base/weak_ptr.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
@ -23,16 +24,22 @@ namespace HistoryView {
namespace { namespace {
[[nodiscard]] Ui::MessageBarContent ContentWithoutPreview( [[nodiscard]] Ui::MessageBarContent ContentWithoutPreview(
not_null<HistoryItem*> item) { not_null<HistoryItem*> item,
Fn<void()> repaint) {
return Ui::MessageBarContent{ return Ui::MessageBarContent{
.text = item->inReplyText(), .text = item->inReplyText(),
.context = Core::MarkedTextContext{
.session = &item->history()->session(),
.customEmojiRepaint = std::move(repaint),
},
}; };
} }
[[nodiscard]] Ui::MessageBarContent ContentWithPreview( [[nodiscard]] Ui::MessageBarContent ContentWithPreview(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
Image *preview) { Image *preview,
auto result = ContentWithoutPreview(item); Fn<void()> repaint) {
auto result = ContentWithoutPreview(item, std::move(repaint));
if (!preview) { if (!preview) {
static const auto kEmpty = [&] { static const auto kEmpty = [&] {
const auto size = st::historyReplyHeight * cIntRetinaFactor(); const auto size = st::historyReplyHeight * cIntRetinaFactor();
@ -51,14 +58,15 @@ namespace {
} }
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItem( [[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItem(
not_null<HistoryItem*> item) { not_null<HistoryItem*> item,
Fn<void()> repaint) {
return item->history()->session().changes().messageFlagsValue( return item->history()->session().changes().messageFlagsValue(
item, item,
Data::MessageUpdate::Flag::Edited Data::MessageUpdate::Flag::Edited
) | rpl::map([=]() -> rpl::producer<Ui::MessageBarContent> { ) | rpl::map([=]() -> rpl::producer<Ui::MessageBarContent> {
const auto media = item->media(); const auto media = item->media();
if (!media || !media->hasReplyPreview()) { if (!media || !media->hasReplyPreview()) {
return rpl::single(ContentWithoutPreview(item)); return rpl::single(ContentWithoutPreview(item, repaint));
} }
constexpr auto kFullLoaded = 2; constexpr auto kFullLoaded = 2;
constexpr auto kSomeLoaded = 1; constexpr auto kSomeLoaded = 1;
@ -82,7 +90,7 @@ namespace {
}) | rpl::then( }) | rpl::then(
rpl::single(kFullLoaded) rpl::single(kFullLoaded)
) | rpl::map([=] { ) | rpl::map([=] {
return ContentWithPreview(item, media->replyPreview()); return ContentWithPreview(item, media->replyPreview(), repaint);
}); });
}) | rpl::flatten_latest(); }) | rpl::flatten_latest();
} }
@ -90,11 +98,12 @@ namespace {
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItemId( [[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItemId(
not_null<Main::Session*> session, not_null<Main::Session*> session,
FullMsgId id, FullMsgId id,
Fn<void()> repaint,
bool alreadyLoaded = false) { bool alreadyLoaded = false) {
if (!id) { if (!id) {
return rpl::single(Ui::MessageBarContent()); return rpl::single(Ui::MessageBarContent());
} else if (const auto item = session->data().message(id)) { } else if (const auto item = session->data().message(id)) {
return ContentByItem(item); return ContentByItem(item, repaint);
} else if (alreadyLoaded) { } else if (alreadyLoaded) {
return rpl::single(Ui::MessageBarContent()); // Deleted message?.. return rpl::single(Ui::MessageBarContent()); // Deleted message?..
} }
@ -110,7 +119,7 @@ namespace {
return std::move( return std::move(
load load
) | rpl::then(rpl::deferred([=] { ) | rpl::then(rpl::deferred([=] {
return ContentByItemId(session, id, true); return ContentByItemId(session, id, repaint, true);
})); }));
} }
@ -137,20 +146,23 @@ auto WithPinnedTitle(not_null<Main::Session*> session, PinnedId id) {
rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId( rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId(
not_null<Main::Session*> session, not_null<Main::Session*> session,
FullMsgId id) { FullMsgId id,
return ContentByItemId(session, id); Fn<void()> repaint) {
return ContentByItemId(session, id, std::move(repaint));
} }
rpl::producer<Ui::MessageBarContent> PinnedBarContent( rpl::producer<Ui::MessageBarContent> PinnedBarContent(
not_null<Main::Session*> session, not_null<Main::Session*> session,
rpl::producer<PinnedId> id) { rpl::producer<PinnedId> id,
Fn<void()> repaint) {
return std::move( return std::move(
id id
) | rpl::distinct_until_changed( ) | rpl::distinct_until_changed(
) | rpl::map([=](PinnedId id) { ) | rpl::map([=](PinnedId id) {
return ContentByItemId( return ContentByItemId(
session, session,
id.message id.message,
repaint
) | rpl::map(WithPinnedTitle(session, id)); ) | rpl::map(WithPinnedTitle(session, id));
}) | rpl::flatten_latest(); }) | rpl::flatten_latest();
} }

View file

@ -25,7 +25,8 @@ namespace HistoryView {
[[nodiscard]] rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId( [[nodiscard]] rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId(
not_null<Main::Session*> session, not_null<Main::Session*> session,
FullMsgId id); FullMsgId id,
Fn<void()> repaint);
enum class PinnedIdType; enum class PinnedIdType;
struct PinnedId { struct PinnedId {
@ -47,7 +48,8 @@ struct PinnedId {
}; };
[[nodiscard]] rpl::producer<Ui::MessageBarContent> PinnedBarContent( [[nodiscard]] rpl::producer<Ui::MessageBarContent> PinnedBarContent(
not_null<Main::Session*> session, not_null<Main::Session*> session,
rpl::producer<PinnedId> id); rpl::producer<PinnedId> id,
Fn<void()> repaint);
[[nodiscard]] rpl::producer<HistoryItem*> PinnedBarItemWithReplyMarkup( [[nodiscard]] rpl::producer<HistoryItem*> PinnedBarItemWithReplyMarkup(
not_null<Main::Session*> session, not_null<Main::Session*> session,

View file

@ -90,10 +90,12 @@ bool CanSendFiles(not_null<const QMimeData*> data) {
rpl::producer<Ui::MessageBarContent> RootViewContent( rpl::producer<Ui::MessageBarContent> RootViewContent(
not_null<History*> history, not_null<History*> history,
MsgId rootId) { MsgId rootId,
Fn<void()> repaint) {
return MessageBarContentByItemId( return MessageBarContentByItemId(
&history->session(), &history->session(),
FullMsgId(history->peer->id, rootId) FullMsgId(history->peer->id, rootId),
std::move(repaint)
) | rpl::map([=](Ui::MessageBarContent &&content) { ) | rpl::map([=](Ui::MessageBarContent &&content) {
const auto item = history->owner().message(history->peer, rootId); const auto item = history->owner().message(history->peer, rootId);
if (!item) { if (!item) {
@ -387,14 +389,19 @@ void RepliesWidget::setupRoot() {
} }
void RepliesWidget::setupRootView() { void RepliesWidget::setupRootView() {
auto content = rpl::combine( _rootView = std::make_unique<Ui::PinnedBar>(this, [=] {
RootViewContent(_history, _rootId), return controller()->isGifPausedAtLeastFor(
Window::GifPauseReason::Any);
});
_rootView->setContent(rpl::combine(
RootViewContent(
_history,
_rootId,
[bar = _rootView.get()] { bar->update(); }),
_rootVisible.value() _rootVisible.value()
) | rpl::map([=](Ui::MessageBarContent &&content, bool shown) { ) | rpl::map([=](Ui::MessageBarContent &&content, bool shown) {
return shown ? std::move(content) : Ui::MessageBarContent(); return shown ? std::move(content) : Ui::MessageBarContent();
}); }));
_rootView = std::make_unique<Ui::PinnedBar>(this);
_rootView->setContent(std::move(content));
controller()->adaptive().oneColumnValue( controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) { ) | rpl::start_with_next([=](bool one) {

View file

@ -250,6 +250,7 @@ void BotAction::validateIcon() {
_mask = QImage( _mask = QImage(
size * style::DevicePixelRatio(), size * style::DevicePixelRatio(),
QImage::Format_ARGB32_Premultiplied); QImage::Format_ARGB32_Premultiplied);
_mask.setDevicePixelRatio(style::DevicePixelRatio());
_mask.fill(Qt::transparent); _mask.fill(Qt::transparent);
{ {
auto p = QPainter(&_mask); auto p = QPainter(&_mask);

View file

@ -41,9 +41,13 @@ namespace {
} // namespace } // namespace
MessageBar::MessageBar(not_null<QWidget*> parent, const style::MessageBar &st) MessageBar::MessageBar(
not_null<QWidget*> parent,
const style::MessageBar &st,
Fn<bool()> customEmojiPaused)
: _st(st) : _st(st)
, _widget(parent) { , _widget(parent)
, _customEmojiPaused(std::move(customEmojiPaused)) {
setup(); setup();
style::PaletteChanged( style::PaletteChanged(
@ -57,6 +61,7 @@ void MessageBar::setup() {
_widget.paintRequest( _widget.paintRequest(
) | rpl::start_with_next([=](QRect rect) { ) | rpl::start_with_next([=](QRect rect) {
auto p = Painter(&_widget); auto p = Painter(&_widget);
p.setInactive(_customEmojiPaused());
paint(p); paint(p);
}, _widget.lifetime()); }, _widget.lifetime());
} }
@ -187,7 +192,11 @@ void MessageBar::tweenTo(MessageBarContent &&content) {
void MessageBar::updateFromContent(MessageBarContent &&content) { void MessageBar::updateFromContent(MessageBarContent &&content) {
_content = std::move(content); _content = std::move(content);
_title.setText(_st.title, _content.title); _title.setText(_st.title, _content.title);
_text.setMarkedText(_st.text, _content.text, Ui::DialogTextOptions()); _text.setMarkedText(
_st.text,
_content.text,
Ui::DialogTextOptions(),
_content.context);
_image = prepareImage(_content.preview); _image = prepareImage(_content.preview);
} }

View file

@ -23,13 +23,17 @@ struct MessageBarContent {
int count = 1; int count = 1;
QString title; QString title;
TextWithEntities text; TextWithEntities text;
std::any context;
QImage preview; QImage preview;
style::margins margins; style::margins margins;
}; };
class MessageBar final { class MessageBar final {
public: public:
MessageBar(not_null<QWidget*> parent, const style::MessageBar &st); MessageBar(
not_null<QWidget*> parent,
const style::MessageBar &st,
Fn<bool()> customEmojiPaused);
void set(MessageBarContent &&content); void set(MessageBarContent &&content);
void set(rpl::producer<MessageBarContent> content); void set(rpl::producer<MessageBarContent> content);
@ -100,6 +104,7 @@ private:
const style::MessageBar &_st; const style::MessageBar &_st;
Ui::RpWidget _widget; Ui::RpWidget _widget;
Fn<bool()> _customEmojiPaused;
MessageBarContent _content; MessageBarContent _content;
rpl::lifetime _contentLifetime; rpl::lifetime _contentLifetime;
Ui::Text::String _title, _text; Ui::Text::String _title, _text;

View file

@ -18,9 +18,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui { namespace Ui {
PinnedBar::PinnedBar(not_null<QWidget*> parent) PinnedBar::PinnedBar(not_null<QWidget*> parent, Fn<bool()> customEmojiPaused)
: _wrap(parent, object_ptr<RpWidget>(parent)) : _wrap(parent, object_ptr<RpWidget>(parent))
, _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget())) { , _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget()))
, _customEmojiPaused(std::move(customEmojiPaused)) {
_wrap.hide(anim::type::instant); _wrap.hide(anim::type::instant);
_shadow->hide(); _shadow->hide();
@ -133,7 +134,8 @@ void PinnedBar::createControls() {
_bar = std::make_unique<MessageBar>( _bar = std::make_unique<MessageBar>(
_wrap.entity(), _wrap.entity(),
st::defaultMessageBar); st::defaultMessageBar,
_customEmojiPaused);
if (_right.button) { if (_right.button) {
_right.button->raise(); _right.button->raise();
} }
@ -205,6 +207,12 @@ void PinnedBar::raise() {
_shadow->raise(); _shadow->raise();
} }
void PinnedBar::update() {
if (_bar) {
_bar->widget()->update();
}
}
void PinnedBar::finishAnimating() { void PinnedBar::finishAnimating() {
_wrap.finishAnimating(); _wrap.finishAnimating();
} }

View file

@ -22,12 +22,13 @@ class RpWidget;
class PinnedBar final { class PinnedBar final {
public: public:
PinnedBar(not_null<QWidget*> parent); PinnedBar(not_null<QWidget*> parent, Fn<bool()> customEmojiPaused);
~PinnedBar(); ~PinnedBar();
void show(); void show();
void hide(); void hide();
void raise(); void raise();
void update();
void finishAnimating(); void finishAnimating();
void setShadowGeometryPostprocess(Fn<QRect(QRect)> postprocess); void setShadowGeometryPostprocess(Fn<QRect(QRect)> postprocess);
@ -60,6 +61,7 @@ private:
} _right; } _right;
std::unique_ptr<Ui::PlainShadow> _shadow; std::unique_ptr<Ui::PlainShadow> _shadow;
Fn<bool()> _customEmojiPaused;
rpl::event_stream<> _barClicks; rpl::event_stream<> _barClicks;
Fn<QRect(QRect)> _shadowGeometryPostprocess; Fn<QRect(QRect)> _shadowGeometryPostprocess;
bool _shouldBeShown = false; bool _shouldBeShown = false;