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);
[[nodiscard]] bool canUpdateDate() const;
void customEmojiRepaint();
[[nodiscard]] TimeId ttlDestroyAt() const {
return _ttlDestroyAt;
@ -463,7 +464,6 @@ protected:
MessageFlags _flags = 0;
void invalidateChatListEntry();
void customEmojiRepaint();
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/media/history_view_document.h"
#include "core/click_handler_types.h"
#include "core/ui_integration.h"
#include "layout/layout_position.h"
#include "mainwindow.h"
#include "media/audio/media_audio.h"
@ -256,10 +257,15 @@ bool HistoryMessageReply::updateData(
}
if (replyToMsg) {
const auto context = Core::MarkedTextContext{
.session = &holder->history()->session(),
.customEmojiRepaint = [=] { holder->customEmojiRepaint(); },
};
replyToText.setMarkedText(
st::messageTextStyle,
replyToMsg->inReplyText(),
Ui::DialogTextOptions());
Ui::DialogTextOptions(),
context);
updateName(holder);
@ -447,6 +453,7 @@ void HistoryMessageReply::paint(
p.setTextPalette(inBubble
? stm->replyTextPalette
: 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);
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 "core/crash_reports.h"
#include "core/shortcuts.h"
#include "core/ui_integration.h"
#include "support/support_common.h"
#include "support/support_autocomplete.h"
#include "support/support_preload.h"
@ -6365,10 +6366,10 @@ void HistoryWidget::checkPinnedBarState() {
return;
}
auto barContent = HistoryView::PinnedBarContent(
&session(),
_pinnedTracker->shownMessageId());
_pinnedBar = std::make_unique<Ui::PinnedBar>(this);
_pinnedBar = std::make_unique<Ui::PinnedBar>(this, [=] {
return controller()->isGifPausedAtLeastFor(
Window::GifPauseReason::Any);
});
rpl::combine(
Info::Profile::SharedMediaCountValue(
_peer,
@ -6389,7 +6390,11 @@ void HistoryWidget::checkPinnedBarState() {
) | rpl::start_with_next([=](bool many, HistoryItem *item) {
refreshPinnedBarButton(many, item);
}, _pinnedBar->lifetime());
_pinnedBar->setContent(std::move(barContent));
_pinnedBar->setContent(HistoryView::PinnedBarContent(
&session(),
_pinnedTracker->shownMessageId(),
[bar = _pinnedBar.get()] { bar->update(); }));
controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) {
@ -7417,10 +7422,15 @@ void HistoryWidget::messageDataReceived(
}
void HistoryWidget::updateReplyEditText(not_null<HistoryItem*> item) {
const auto context = Core::MarkedTextContext{
.session = &session(),
.customEmojiRepaint = [=] { updateField(); },
};
_replyEditMsgText.setMarkedText(
st::messageTextStyle,
item->inReplyText(),
Ui::DialogTextOptions());
Ui::DialogTextOptions(),
context);
if (!_field->isHidden() || isRecording()) {
_fieldBarCancel->show();
updateMouseTracking();
@ -7518,10 +7528,15 @@ void HistoryWidget::updateForwardingTexts() {
}
}
_toForwardFrom.setText(st::msgNameStyle, from, Ui::NameTextOptions());
const auto context = Core::MarkedTextContext{
.session = &session(),
.customEmojiRepaint = [=] { updateField(); },
};
_toForwardText.setMarkedText(
st::messageTextStyle,
text,
Ui::DialogTextOptions());
Ui::DialogTextOptions(),
context);
_toForwardNameVersion = keepNames ? version : keepCaptions ? -1 : -2;
}
@ -7570,7 +7585,7 @@ void HistoryWidget::updateReplyToName() {
}
void HistoryWidget::updateField() {
auto fieldAreaTop = _scroll->y() + _scroll->height();
const auto fieldAreaTop = _scroll->y() + _scroll->height();
rtlupdate(0, fieldAreaTop, width(), height() - fieldAreaTop);
}
@ -7594,6 +7609,8 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
backh += st::historyReplyHeight;
}
auto drawWebPagePreview = (_previewData && _previewData->pendingTill >= 0) && !_replyForwardPressed;
p.setInactive(
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
auto replyLeft = st::historyReplySkip;

View file

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

View file

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

View file

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

View file

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

View file

@ -41,9 +41,13 @@ 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)
, _widget(parent) {
, _widget(parent)
, _customEmojiPaused(std::move(customEmojiPaused)) {
setup();
style::PaletteChanged(
@ -57,6 +61,7 @@ void MessageBar::setup() {
_widget.paintRequest(
) | rpl::start_with_next([=](QRect rect) {
auto p = Painter(&_widget);
p.setInactive(_customEmojiPaused());
paint(p);
}, _widget.lifetime());
}
@ -187,7 +192,11 @@ void MessageBar::tweenTo(MessageBarContent &&content) {
void MessageBar::updateFromContent(MessageBarContent &&content) {
_content = std::move(content);
_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);
}

View file

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

View file

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

View file

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