Display reply background emoji.
This commit is contained in:
parent
60fb5fdaf0
commit
9c23de7f1a
|
@ -627,9 +627,9 @@ bool PeerData::changeColorIndex(
|
||||||
: clearColorIndex();
|
: clearColorIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerData::changeBackgroundEmoji(
|
bool PeerData::changeBackgroundEmojiId(
|
||||||
const tl::conditional<MTPlong> &cloudBackgroundEmoji) {
|
const tl::conditional<MTPlong> &cloudBackgroundEmoji) {
|
||||||
return changeBackgroundEmoji(cloudBackgroundEmoji
|
return changeBackgroundEmojiId(cloudBackgroundEmoji
|
||||||
? cloudBackgroundEmoji->v
|
? cloudBackgroundEmoji->v
|
||||||
: DocumentId());
|
: DocumentId());
|
||||||
}
|
}
|
||||||
|
@ -869,7 +869,11 @@ bool PeerData::clearColorIndex() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerData::changeBackgroundEmoji(uint64 id) {
|
DocumentId PeerData::backgroundEmojiId() const {
|
||||||
|
return _backgroundEmojiId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerData::changeBackgroundEmojiId(DocumentId id) {
|
||||||
if (_backgroundEmojiId == id) {
|
if (_backgroundEmojiId == id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,8 @@ public:
|
||||||
}
|
}
|
||||||
bool changeColorIndex(uint8 index);
|
bool changeColorIndex(uint8 index);
|
||||||
bool clearColorIndex();
|
bool clearColorIndex();
|
||||||
bool changeBackgroundEmoji(uint64 id);
|
[[nodiscard]] DocumentId backgroundEmojiId() const;
|
||||||
|
bool changeBackgroundEmojiId(DocumentId id);
|
||||||
|
|
||||||
[[nodiscard]] bool isUser() const {
|
[[nodiscard]] bool isUser() const {
|
||||||
return peerIsUser(id);
|
return peerIsUser(id);
|
||||||
|
@ -361,7 +362,7 @@ public:
|
||||||
|
|
||||||
void setSettings(const MTPPeerSettings &data);
|
void setSettings(const MTPPeerSettings &data);
|
||||||
bool changeColorIndex(const tl::conditional<MTPint> &cloudColorIndex);
|
bool changeColorIndex(const tl::conditional<MTPint> &cloudColorIndex);
|
||||||
bool changeBackgroundEmoji(
|
bool changeBackgroundEmojiId(
|
||||||
const tl::conditional<MTPlong> &cloudBackgroundEmoji);
|
const tl::conditional<MTPlong> &cloudBackgroundEmoji);
|
||||||
|
|
||||||
enum class BlockStatus : char {
|
enum class BlockStatus : char {
|
||||||
|
|
|
@ -711,7 +711,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||||
flags |= UpdateFlag::Color;
|
flags |= UpdateFlag::Color;
|
||||||
decorationsUpdated = true;
|
decorationsUpdated = true;
|
||||||
}
|
}
|
||||||
if (result->changeBackgroundEmoji(data.vbackground_emoji_id())) {
|
if (result->changeBackgroundEmojiId(data.vbackground_emoji_id())) {
|
||||||
flags |= UpdateFlag::BackgroundEmoji;
|
flags |= UpdateFlag::BackgroundEmoji;
|
||||||
decorationsUpdated = true;
|
decorationsUpdated = true;
|
||||||
}
|
}
|
||||||
|
@ -997,7 +997,7 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||||
flags |= UpdateFlag::Color;
|
flags |= UpdateFlag::Color;
|
||||||
decorationsUpdated = true;
|
decorationsUpdated = true;
|
||||||
}
|
}
|
||||||
if (result->changeBackgroundEmoji(data.vbackground_emoji_id())) {
|
if (result->changeBackgroundEmojiId(data.vbackground_emoji_id())) {
|
||||||
flags |= UpdateFlag::BackgroundEmoji;
|
flags |= UpdateFlag::BackgroundEmoji;
|
||||||
decorationsUpdated = true;
|
decorationsUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "media/audio/media_audio.h"
|
#include "media/audio/media_audio.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
@ -55,6 +56,127 @@ namespace {
|
||||||
|
|
||||||
const auto kPsaForwardedPrefix = "cloud_lng_forwarded_psa_";
|
const auto kPsaForwardedPrefix = "cloud_lng_forwarded_psa_";
|
||||||
|
|
||||||
|
void ValidateBackgroundEmoji(
|
||||||
|
DocumentId backgroundEmojiId,
|
||||||
|
not_null<Ui::BackgroundEmojiData*> data,
|
||||||
|
not_null<Ui::BackgroundEmojiCache*> cache,
|
||||||
|
not_null<Ui::Text::QuotePaintCache*> quote,
|
||||||
|
not_null<const HistoryView::Element*> holder) {
|
||||||
|
if (data->firstFrameMask.isNull()) {
|
||||||
|
if (!cache->frames[0].isNull()) {
|
||||||
|
for (auto &frame : cache->frames) {
|
||||||
|
frame = QImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto tag = Data::CustomEmojiSizeTag::Isolated;
|
||||||
|
if (!data->emoji) {
|
||||||
|
const auto owner = &holder->history()->owner();
|
||||||
|
const auto repaint = crl::guard(holder, [=] {
|
||||||
|
holder->history()->owner().requestViewRepaint(holder);
|
||||||
|
});
|
||||||
|
data->emoji = owner->customEmojiManager().create(
|
||||||
|
backgroundEmojiId,
|
||||||
|
repaint,
|
||||||
|
tag);
|
||||||
|
}
|
||||||
|
if (!data->emoji->ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto size = Data::FrameSizeFromTag(tag);
|
||||||
|
data->firstFrameMask = QImage(
|
||||||
|
QSize(size, size),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
data->firstFrameMask.fill(Qt::transparent);
|
||||||
|
data->firstFrameMask.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
|
auto p = Painter(&data->firstFrameMask);
|
||||||
|
data->emoji->paint(p, {
|
||||||
|
.textColor = QColor(255, 255, 255),
|
||||||
|
.position = QPoint(0, 0),
|
||||||
|
.internal = {
|
||||||
|
.forceFirstFrame = true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
p.end();
|
||||||
|
|
||||||
|
data->emoji = nullptr;
|
||||||
|
}
|
||||||
|
if (!cache->frames[0].isNull() && cache->color == quote->icon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cache->color = quote->icon;
|
||||||
|
const auto ratio = style::DevicePixelRatio();
|
||||||
|
auto colorized = QImage(
|
||||||
|
data->firstFrameMask.size(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
colorized.setDevicePixelRatio(ratio);
|
||||||
|
style::colorizeImage(
|
||||||
|
data->firstFrameMask,
|
||||||
|
cache->color,
|
||||||
|
&colorized,
|
||||||
|
QRect(), // src
|
||||||
|
QPoint(), // dst
|
||||||
|
true); // use alpha
|
||||||
|
const auto make = [&](int size) {
|
||||||
|
size = style::ConvertScale(size) * ratio;
|
||||||
|
auto result = colorized.scaled(
|
||||||
|
size,
|
||||||
|
size,
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
result.setDevicePixelRatio(ratio);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr auto kSize1 = 12;
|
||||||
|
constexpr auto kSize2 = 16;
|
||||||
|
constexpr auto kSize3 = 20;
|
||||||
|
cache->frames[0] = make(kSize1);
|
||||||
|
cache->frames[1] = make(kSize2);
|
||||||
|
cache->frames[2] = make(kSize3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FillBackgroundEmoji(
|
||||||
|
Painter &p,
|
||||||
|
const QRect &rect,
|
||||||
|
bool quote,
|
||||||
|
const Ui::BackgroundEmojiCache &cache) {
|
||||||
|
p.setClipRect(rect);
|
||||||
|
|
||||||
|
const auto &frames = cache.frames;
|
||||||
|
const auto right = rect.x() + rect.width();
|
||||||
|
const auto paint = [&](int x, int y, int index, float64 opacity) {
|
||||||
|
y = style::ConvertScale(y);
|
||||||
|
if (y >= rect.height()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p.setOpacity(opacity);
|
||||||
|
p.drawImage(
|
||||||
|
right - style::ConvertScale(x + (quote ? 12 : 0)),
|
||||||
|
rect.y() + y,
|
||||||
|
frames[index]);
|
||||||
|
};
|
||||||
|
|
||||||
|
paint(28, 4, 2, 0.32);
|
||||||
|
paint(51, 15, 1, 0.32);
|
||||||
|
paint(64, -2, 0, 0.28);
|
||||||
|
paint(87, 11, 1, 0.24);
|
||||||
|
paint(125, -2, 2, 0.16);
|
||||||
|
|
||||||
|
paint(28, 31, 1, 0.24);
|
||||||
|
paint(72, 33, 2, 0.2);
|
||||||
|
|
||||||
|
paint(46, 52, 1, 0.24);
|
||||||
|
paint(24, 55, 2, 0.18);
|
||||||
|
|
||||||
|
if (quote) {
|
||||||
|
paint(4, 23, 1, 0.28);
|
||||||
|
paint(0, 48, 0, 0.24);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setClipping(false);
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void HistoryMessageVia::create(
|
void HistoryMessageVia::create(
|
||||||
|
@ -676,10 +798,18 @@ void HistoryMessageReply::paint(
|
||||||
const auto rect = QRect(x, y, w, _height);
|
const auto rect = QRect(x, y, w, _height);
|
||||||
const auto hasQuote = !_fields.quote.empty();
|
const auto hasQuote = !_fields.quote.empty();
|
||||||
const auto selected = context.selected();
|
const auto selected = context.selected();
|
||||||
const auto colorIndexPlusOne = resolvedMessage
|
const auto colorPeer = resolvedMessage
|
||||||
? (resolvedMessage->colorIndex() + 1)
|
? resolvedMessage->displayFrom()
|
||||||
: resolvedStory
|
: resolvedStory
|
||||||
? (resolvedStory->peer()->colorIndex() + 1)
|
? resolvedStory->peer().get()
|
||||||
|
: nullptr;
|
||||||
|
const auto backgroundEmojiId = colorPeer
|
||||||
|
? colorPeer->backgroundEmojiId()
|
||||||
|
: DocumentId();
|
||||||
|
const auto colorIndexPlusOne = colorPeer
|
||||||
|
? (colorPeer->colorIndex() + 1)
|
||||||
|
: resolvedMessage
|
||||||
|
? (resolvedMessage->hiddenSenderInfo()->colorIndex + 1)
|
||||||
: 0;
|
: 0;
|
||||||
const auto useColorIndex = colorIndexPlusOne && !context.outbg;
|
const auto useColorIndex = colorIndexPlusOne && !context.outbg;
|
||||||
const auto twoColored = colorIndexPlusOne
|
const auto twoColored = colorIndexPlusOne
|
||||||
|
@ -698,12 +828,33 @@ void HistoryMessageReply::paint(
|
||||||
const auto "eSt = hasQuote
|
const auto "eSt = hasQuote
|
||||||
? st::messageTextStyle.blockquote
|
? st::messageTextStyle.blockquote
|
||||||
: st::messageQuoteStyle;
|
: st::messageQuoteStyle;
|
||||||
|
const auto backgroundEmoji = backgroundEmojiId
|
||||||
|
? st->backgroundEmojiData(backgroundEmojiId).get()
|
||||||
|
: nullptr;
|
||||||
|
const auto backgroundEmojiCache = backgroundEmoji
|
||||||
|
? &backgroundEmoji->caches[Ui::BackgroundEmojiData::CacheIndex(
|
||||||
|
selected,
|
||||||
|
context.outbg,
|
||||||
|
inBubble,
|
||||||
|
colorIndexPlusOne)]
|
||||||
|
: nullptr;
|
||||||
const auto rippleColor = cache->bg;
|
const auto rippleColor = cache->bg;
|
||||||
if (!inBubble) {
|
if (!inBubble) {
|
||||||
cache->bg = QColor(0, 0, 0, 0);
|
cache->bg = QColor(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
Ui::Text::ValidateQuotePaintCache(*cache, quoteSt);
|
Ui::Text::ValidateQuotePaintCache(*cache, quoteSt);
|
||||||
Ui::Text::FillQuotePaint(p, rect, *cache, quoteSt);
|
Ui::Text::FillQuotePaint(p, rect, *cache, quoteSt);
|
||||||
|
if (backgroundEmoji) {
|
||||||
|
ValidateBackgroundEmoji(
|
||||||
|
backgroundEmojiId,
|
||||||
|
backgroundEmoji,
|
||||||
|
backgroundEmojiCache,
|
||||||
|
cache,
|
||||||
|
holder);
|
||||||
|
if (!backgroundEmojiCache->frames[0].isNull()) {
|
||||||
|
FillBackgroundEmoji(p, rect, hasQuote, *backgroundEmojiCache);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!inBubble) {
|
if (!inBubble) {
|
||||||
cache->bg = rippleColor;
|
cache->bg = rippleColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "ui/chat/chat_theme.h"
|
#include "ui/chat/chat_theme.h"
|
||||||
#include "ui/image/image_prepare.h" // ImageRoundRadius
|
#include "ui/image/image_prepare.h" // ImageRoundRadius
|
||||||
|
#include "ui/text/text_custom_emoji.h"
|
||||||
#include "ui/color_contrast.h"
|
#include "ui/color_contrast.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
@ -190,6 +191,17 @@ ColorIndexValues SimpleColorIndexValues(QColor color, bool twoColored) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BackgroundEmojiData::CacheIndex(
|
||||||
|
bool selected,
|
||||||
|
bool outbg,
|
||||||
|
bool inbubble,
|
||||||
|
uint8 colorIndexPlusOne) {
|
||||||
|
const auto base = colorIndexPlusOne
|
||||||
|
? (colorIndexPlusOne - 1)
|
||||||
|
: (kColorIndexCount + (!inbubble ? 0 : outbg ? 1 : 2));
|
||||||
|
return (base * 2) + (selected ? 1 : 0);
|
||||||
|
};
|
||||||
|
|
||||||
ChatStyle::ChatStyle() {
|
ChatStyle::ChatStyle() {
|
||||||
finalize();
|
finalize();
|
||||||
make(_historyPsaForwardPalette, st::historyPsaForwardPalette);
|
make(_historyPsaForwardPalette, st::historyPsaForwardPalette);
|
||||||
|
@ -553,6 +565,8 @@ ChatStyle::ChatStyle(not_null<const style::palette*> isolated)
|
||||||
assignPalette(isolated);
|
assignPalette(isolated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatStyle::~ChatStyle() = default;
|
||||||
|
|
||||||
void ChatStyle::apply(not_null<ChatTheme*> theme) {
|
void ChatStyle::apply(not_null<ChatTheme*> theme) {
|
||||||
applyCustomPalette(theme->palette());
|
applyCustomPalette(theme->palette());
|
||||||
}
|
}
|
||||||
|
@ -802,6 +816,11 @@ const style::TextPalette &ChatStyle::coloredTextPalette(
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<BackgroundEmojiData*> ChatStyle::backgroundEmojiData(
|
||||||
|
uint64 id) const {
|
||||||
|
return &_backgroundEmojis[id];
|
||||||
|
}
|
||||||
|
|
||||||
not_null<Text::QuotePaintCache*> ChatStyle::coloredQuoteCache(
|
not_null<Text::QuotePaintCache*> ChatStyle::coloredQuoteCache(
|
||||||
bool selected,
|
bool selected,
|
||||||
uint8 colorIndex) const {
|
uint8 colorIndex) const {
|
||||||
|
|
|
@ -21,6 +21,10 @@ struct TwoIconButton;
|
||||||
struct ScrollArea;
|
struct ScrollArea;
|
||||||
} // namespace style
|
} // namespace style
|
||||||
|
|
||||||
|
namespace Ui::Text {
|
||||||
|
class CustomEmoji;
|
||||||
|
} // namespace Ui::Text
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
class ChatTheme;
|
class ChatTheme;
|
||||||
|
@ -112,6 +116,23 @@ struct ReactionPaintInfo {
|
||||||
Fn<QRect(QPainter&)> effectPaint;
|
Fn<QRect(QPainter&)> effectPaint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BackgroundEmojiCache {
|
||||||
|
QColor color;
|
||||||
|
std::array<QImage, 3> frames;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BackgroundEmojiData {
|
||||||
|
std::unique_ptr<Text::CustomEmoji> emoji;
|
||||||
|
QImage firstFrameMask;
|
||||||
|
std::array<BackgroundEmojiCache, 2 * (3 + kColorIndexCount)> caches;
|
||||||
|
|
||||||
|
[[nodiscard]] static int CacheIndex(
|
||||||
|
bool selected,
|
||||||
|
bool outbg,
|
||||||
|
bool inbubble,
|
||||||
|
uint8 colorIndexPlusOne);
|
||||||
|
};
|
||||||
|
|
||||||
struct ChatPaintContext {
|
struct ChatPaintContext {
|
||||||
not_null<const ChatStyle*> st;
|
not_null<const ChatStyle*> st;
|
||||||
const BubblePattern *bubblesPattern = nullptr;
|
const BubblePattern *bubblesPattern = nullptr;
|
||||||
|
@ -185,6 +206,7 @@ class ChatStyle final : public style::palette {
|
||||||
public:
|
public:
|
||||||
ChatStyle();
|
ChatStyle();
|
||||||
explicit ChatStyle(not_null<const style::palette*> isolated);
|
explicit ChatStyle(not_null<const style::palette*> isolated);
|
||||||
|
~ChatStyle();
|
||||||
|
|
||||||
void apply(not_null<ChatTheme*> theme);
|
void apply(not_null<ChatTheme*> theme);
|
||||||
void applyCustomPalette(const style::palette *palette);
|
void applyCustomPalette(const style::palette *palette);
|
||||||
|
@ -242,6 +264,9 @@ public:
|
||||||
bool selected,
|
bool selected,
|
||||||
uint8 colorIndex) const;
|
uint8 colorIndex) const;
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<BackgroundEmojiData*> backgroundEmojiData(
|
||||||
|
uint64 id) const;
|
||||||
|
|
||||||
[[nodiscard]] const CornersPixmaps &msgBotKbOverBgAddCornersSmall() const;
|
[[nodiscard]] const CornersPixmaps &msgBotKbOverBgAddCornersSmall() const;
|
||||||
[[nodiscard]] const CornersPixmaps &msgBotKbOverBgAddCornersLarge() const;
|
[[nodiscard]] const CornersPixmaps &msgBotKbOverBgAddCornersLarge() const;
|
||||||
[[nodiscard]] const CornersPixmaps &msgSelectOverlayCorners(
|
[[nodiscard]] const CornersPixmaps &msgSelectOverlayCorners(
|
||||||
|
@ -408,6 +433,7 @@ private:
|
||||||
mutable std::array<
|
mutable std::array<
|
||||||
ColoredPalette,
|
ColoredPalette,
|
||||||
2 * kColorIndexCount> _coloredTextPalettes;
|
2 * kColorIndexCount> _coloredTextPalettes;
|
||||||
|
mutable base::flat_map<uint64, BackgroundEmojiData> _backgroundEmojis;
|
||||||
|
|
||||||
style::TextPalette _historyPsaForwardPalette;
|
style::TextPalette _historyPsaForwardPalette;
|
||||||
style::TextPalette _imgReplyTextPalette;
|
style::TextPalette _imgReplyTextPalette;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user