Display reply/link area style from collectibles.

This commit is contained in:
John Preston
2025-09-25 23:22:24 +04:00
parent ccdff5baef
commit e0f4aca336
5 changed files with 211 additions and 11 deletions
+56 -9
View File
@@ -88,6 +88,28 @@ using UpdateFlag = Data::PeerUpdate::Flag;
return (month > 0 && month <= 12) ? month : 0;
}
[[nodiscard]] Ui::ColorCollectible ParseColorCollectible(
const MTPDpeerColorCollectible &data) {
return {
.giftEmojiId = data.vgift_emoji_id().v,
.accentColor = Ui::ColorFromSerialized(data.vaccent_color()),
.strip = ranges::views::all(
data.vcolors().v
) | ranges::views::transform(
&Ui::ColorFromSerialized
) | ranges::to_vector,
.darkAccentColor = Ui::MaybeColorFromSerialized(
data.vdark_accent_color()).value_or(QColor(0, 0, 0, 0)),
.darkStrip = (data.vdark_colors()
? ranges::views::all(
data.vdark_colors()->v
) | ranges::views::transform(
&Ui::ColorFromSerialized
) | ranges::to_vector
: std::vector<QColor>()),
};
}
} // namespace
namespace Data {
@@ -998,13 +1020,6 @@ TimeId PeerData::photoChangeDate() const {
return _barDetails ? _barDetails->photoChangeDate : 0;
}
bool PeerData::changeColorIndex(
const tl::conditional<MTPint> &cloudColorIndex) {
return cloudColorIndex
? changeColorIndex(cloudColorIndex->v)
: clearColorIndex();
}
bool PeerData::changeBackgroundEmojiId(
const tl::conditional<MTPlong> &cloudBackgroundEmoji) {
return changeBackgroundEmojiId(cloudBackgroundEmoji
@@ -1012,6 +1027,36 @@ bool PeerData::changeBackgroundEmojiId(
: DocumentId());
}
bool PeerData::changeColorCollectible(
const tl::conditional<MTPPeerColor> &cloudColor) {
const auto clear = [&] {
if (_colorCollectible) {
_colorCollectible = nullptr;
return true;
}
return false;
};
if (!cloudColor) {
return clear();
}
return cloudColor->match([&](const MTPDpeerColorCollectible &data) {
auto parsed = ParseColorCollectible(data);
if (!_colorCollectible) {
_colorCollectible = std::make_shared<Ui::ColorCollectible>(
std::move(parsed));
return true;
} else if (*_colorCollectible != parsed) {
*_colorCollectible = std::move(parsed);
return true;
}
return false;
}, [&](const MTPDpeerColor &) {
return clear();
}, [&](const MTPDinputPeerColorCollectible &) {
return clear();
});
}
bool PeerData::changeColor(
const tl::conditional<MTPPeerColor> &cloudColor) {
const auto changed1 = cloudColor
@@ -1019,7 +1064,8 @@ bool PeerData::changeColor(
: clearColorIndex();
const auto changed2 = changeBackgroundEmojiId(
Data::BackgroundEmojiIdFromColor(cloudColor));
return changed1 || changed2;
const auto changed3 = changeColorCollectible(cloudColor);
return changed1 || changed2 || changed3;
}
void PeerData::fillNames() {
@@ -1344,6 +1390,7 @@ bool PeerData::clearColorIndex() {
}
_colorIndexCloud = 0;
_colorIndex = Data::DecideColorIndex(id);
_colorCollectible = nullptr;
return true;
}
@@ -2036,7 +2083,7 @@ uint8 ColorIndexFromColor(const MTPPeerColor *color) {
return color->match([](const MTPDpeerColor &data) -> uint8 {
return data.vcolor().value_or_empty();
}, [](const MTPDpeerColorCollectible &data) -> uint8 {
return 0; // themes
return 0;
}, [](const MTPDinputPeerColorCollectible &) -> uint8 {
return 0;
});
+8 -1
View File
@@ -25,6 +25,7 @@ enum class ChatRestriction;
namespace Ui {
class EmptyUserpic;
struct BotVerifyDetails;
struct ColorCollectible;
} // namespace Ui
namespace Main {
@@ -214,6 +215,10 @@ public:
[[nodiscard]] uint8 colorIndex() const {
return _colorIndex;
}
[[nodiscard]] auto colorCollectible() const
-> const std::shared_ptr<Ui::ColorCollectible> & {
return _colorCollectible;
}
bool changeColorIndex(uint8 index);
bool clearColorIndex();
[[nodiscard]] DocumentId backgroundEmojiId() const;
@@ -489,9 +494,10 @@ public:
void saveTranslationDisabled(bool disabled);
void setBarSettings(const MTPPeerSettings &data);
bool changeColorIndex(const tl::conditional<MTPint> &cloudColorIndex);
bool changeBackgroundEmojiId(
const tl::conditional<MTPlong> &cloudBackgroundEmoji);
bool changeColorCollectible(
const tl::conditional<MTPPeerColor> &cloudColor);
bool changeColor(const tl::conditional<MTPPeerColor> &cloudColor);
enum class BlockStatus : char {
@@ -609,6 +615,7 @@ private:
BarSettings _barSettings = PeerBarSettings(PeerBarSetting::Unknown);
std::unique_ptr<PeerBarDetails> _barDetails;
std::shared_ptr<Ui::ColorCollectible> _colorCollectible;
BlockStatus _blockStatus = BlockStatus::Unknown;
LoadedStatus _loadedStatus = LoadedStatus::Not;
@@ -699,14 +699,24 @@ void Reply::paint(
const auto colorIndexPlusOne = _colorPeer
? (_colorPeer->colorIndex() + 1)
: _hiddenSenderColorIndexPlusOne;
const auto &colorCollectible = _colorPeer
? _colorPeer->colorCollectible()
: nullptr;
const auto useColorCollectible = colorCollectible && !context.outbg;
const auto useColorIndex = colorIndexPlusOne && !context.outbg;
const auto colorPattern = colorIndexPlusOne
const auto colorPattern = colorCollectible
? 2
: colorIndexPlusOne
? st->colorPatternIndex(colorIndexPlusOne - 1)
: 0;
const auto cache = !inBubble
? (_hasQuoteIcon
? st->serviceQuoteCache(colorPattern)
: st->serviceReplyCache(colorPattern)).get()
: useColorCollectible
? (_hasQuoteIcon
? st->collectibleQuoteCache(selected, colorCollectible)
: st->collectibleReplyCache(selected, colorCollectible)).get()
: useColorIndex
? (_hasQuoteIcon
? st->coloredQuoteCache(selected, colorIndexPlusOne - 1)
@@ -832,6 +842,8 @@ void Reply::paint(
if (namew > 0) {
p.setPen(!inBubble
? st->msgImgReplyBarColor()->c
: useColorCollectible
? cache->icon
: useColorIndex
? FromNameFg(context, colorIndexPlusOne - 1)
: stm->msgServiceFg->c);
@@ -849,6 +861,8 @@ void Reply::paint(
view->prepareCustomEmojiPaint(p, context, _text);
auto replyToTextPalette = &(!inBubble
? st->imgReplyTextPalette()
: useColorCollectible
? st->collectibleTextPalette(selected, colorCollectible)
: useColorIndex
? st->coloredTextPalette(selected, colorIndexPlusOne - 1)
: stm->replyTextPalette);
@@ -871,6 +871,13 @@ const ColorIndexValues &ChatStyle::coloredValues(
return *result;
}
QColor ChatStyle::collectibleNameColor(
const std::shared_ptr<ColorCollectible> &collectible) const {
return (_dark && collectible->darkAccentColor.alpha() > 0)
? collectible->darkAccentColor
: collectible->accentColor;
}
const style::TextPalette &ChatStyle::coloredTextPalette(
bool selected,
uint8 colorIndex) const {
@@ -891,6 +898,24 @@ const style::TextPalette &ChatStyle::coloredTextPalette(
return result.data;
}
const style::TextPalette &ChatStyle::collectibleTextPalette(
bool selected,
const std::shared_ptr<ColorCollectible> &collectible) const {
auto &entry = resolveCollectibleCaches(collectible);
auto &result = selected ? entry.paletteSelected : entry.palette;
if (!result.linkFg) {
result.linkFg.emplace(collectibleNameColor(collectible));
make(
result.data,
(selected
? st::inReplyTextPaletteSelected
: st::inReplyTextPalette));
result.data.linkFg = result.linkFg->color();
result.data.selectLinkFg = result.data.linkFg;
}
return result.data;
}
not_null<BackgroundEmojiData*> ChatStyle::backgroundEmojiData(
uint64 id) const {
return &_backgroundEmojis[id];
@@ -908,6 +933,24 @@ not_null<Text::QuotePaintCache*> ChatStyle::coloredReplyCache(
return coloredCache(_coloredReplyCaches, selected, colorIndex);
}
not_null<Text::QuotePaintCache*> ChatStyle::collectibleQuoteCache(
bool selected,
const std::shared_ptr<ColorCollectible> &collectible) const {
auto &entry = resolveCollectibleCaches(collectible);
return collectibleCache(
selected ? entry.quoteSelected : entry.quote,
collectible);
}
not_null<Text::QuotePaintCache*> ChatStyle::collectibleReplyCache(
bool selected,
const std::shared_ptr<ColorCollectible> &collectible) const {
auto &entry = resolveCollectibleCaches(collectible);
return collectibleCache(
selected ? entry.replySelected : entry.reply,
collectible);
}
not_null<Text::QuotePaintCache*> ChatStyle::coloredCache(
ColoredQuotePaintCaches &caches,
bool selected,
@@ -922,6 +965,46 @@ not_null<Text::QuotePaintCache*> ChatStyle::coloredCache(
return cache.get();
}
not_null<Text::QuotePaintCache*> ChatStyle::collectibleCache(
std::unique_ptr<Text::QuotePaintCache> &cache,
const std::shared_ptr<ColorCollectible> &collectible) const {
EnsureBlockquoteCache(cache, [&] {
const auto name = collectibleNameColor(collectible);
auto bg = name;
bg.setAlpha(kDefaultBgOpacity * 255);
const auto &strip = (_dark && !collectible->darkStrip.empty())
? collectible->darkStrip
: collectible->strip;
return ColorIndexValues{
.outlines = {
strip.empty() ? name : strip[0],
(strip.size() < 2) ? QColor(0, 0, 0, 0) : strip[1],
(strip.size() < 3) ? QColor(0, 0, 0, 0) : strip[2],
},
.name = name,
.bg = bg,
};
});
return cache.get();
}
ChatStyle::CollectibleColors &ChatStyle::resolveCollectibleCaches(
const std::shared_ptr<ColorCollectible> &collectible) const {
const auto i = _collectibleCaches.find(collectible);
if (i != end(_collectibleCaches)) {
return i->second;
}
for (auto i = begin(_collectibleCaches); i != end(_collectibleCaches);) {
if (i->first.expired()) {
i = _collectibleCaches.erase(i);
} else {
++i;
}
}
return _collectibleCaches.emplace(collectible).first->second;
}
const CornersPixmaps &ChatStyle::msgBotKbOverBgAddCornersSmall() const {
EnsureCorners(
_msgBotKbOverBgAddCornersSmall,
+49
View File
@@ -267,6 +267,26 @@ struct ColorIndexValues {
QColor color,
int patternIndex);
struct ColorCollectible {
uint64 giftEmojiId = 0;
QColor accentColor;
std::vector<QColor> strip;
QColor darkAccentColor;
std::vector<QColor> darkStrip;
friend inline bool operator==(
const ColorCollectible &,
const ColorCollectible &) = default;
};
struct ColorCollectiblePtrCompare {
bool operator()(
const std::weak_ptr<ColorCollectible> &a,
const std::weak_ptr<ColorCollectible> &b) const {
return a.owner_before(b);
}
};
class ChatStyle final : public style::palette {
public:
explicit ChatStyle(rpl::producer<ColorIndicesCompressed> colorIndices);
@@ -325,16 +345,27 @@ public:
[[nodiscard]] const ColorIndexValues &coloredValues(
bool selected,
uint8 colorIndex) const;
[[nodiscard]] QColor collectibleNameColor(
const std::shared_ptr<ColorCollectible> &collectible) const;
[[nodiscard]] not_null<Text::QuotePaintCache*> coloredQuoteCache(
bool selected,
uint8 colorIndex) const;
[[nodiscard]] not_null<Text::QuotePaintCache*> coloredReplyCache(
bool selected,
uint8 colorIndex) const;
[[nodiscard]] not_null<Text::QuotePaintCache*> collectibleQuoteCache(
bool selected,
const std::shared_ptr<ColorCollectible> &collectible) const;
[[nodiscard]] not_null<Text::QuotePaintCache*> collectibleReplyCache(
bool selected,
const std::shared_ptr<ColorCollectible> &collectible) const;
[[nodiscard]] const style::TextPalette &coloredTextPalette(
bool selected,
uint8 colorIndex) const;
[[nodiscard]] const style::TextPalette &collectibleTextPalette(
bool selected,
const std::shared_ptr<ColorCollectible> &collectible) const;
[[nodiscard]] not_null<BackgroundEmojiData*> backgroundEmojiData(
uint64 id) const;
@@ -448,6 +479,15 @@ private:
style::TextPalette data;
};
struct CollectibleColors {
std::unique_ptr<Text::QuotePaintCache> quote;
std::unique_ptr<Text::QuotePaintCache> quoteSelected;
std::unique_ptr<Text::QuotePaintCache> reply;
std::unique_ptr<Text::QuotePaintCache> replySelected;
ColoredPalette palette;
ColoredPalette paletteSelected;
};
void assignPalette(not_null<const style::palette*> palette);
void clearColorIndexCaches();
void updateDarkValue();
@@ -456,6 +496,11 @@ private:
ColoredQuotePaintCaches &caches,
bool selected,
uint8 colorIndex) const;
[[nodiscard]] not_null<Text::QuotePaintCache*> collectibleCache(
std::unique_ptr<Text::QuotePaintCache> &cache,
const std::shared_ptr<ColorCollectible> &collectible) const;
[[nodiscard]] CollectibleColors &resolveCollectibleCaches(
const std::shared_ptr<ColorCollectible> &collectible) const;
void make(style::color &my, const style::color &original) const;
void make(style::icon &my, const style::icon &original) const;
@@ -521,6 +566,10 @@ private:
mutable std::array<
ColoredPalette,
2 * kColorIndexCount> _coloredTextPalettes;
mutable base::flat_map<
std::weak_ptr<ColorCollectible>,
CollectibleColors,
ColorCollectiblePtrCompare> _collectibleCaches;
mutable base::flat_map<uint64, BackgroundEmojiData> _backgroundEmojis;
style::TextPalette _historyPsaForwardPalette;