Paint two-loops of custom emoji statuses.

This commit is contained in:
John Preston 2022-08-31 17:51:41 +04:00
parent da281c4d3d
commit 2618ee3d75
8 changed files with 153 additions and 48 deletions

View file

@ -246,7 +246,6 @@ dialogsVerifiedIconActive: icon {
dialogsPremiumIcon: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBg }};
dialogsPremiumIconOver: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBgOver }};
dialogsPremiumIconActive: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBgActive }};
dialogsPremiumIconOffset: point(5px, 0px);
historySendingIcon: icon {{ "dialogs/dialogs_sending", historySendingOutIconFg, point(5px, 5px) }};
historySendingInvertedIcon: icon {{ "dialogs/dialogs_sending", historySendingInvertedIconFg, point(5px, 5px) }};

View file

@ -1172,6 +1172,9 @@ void ShowWhoReactedMenu(
const Data::ReactionId &id,
not_null<Window::SessionController*> controller,
rpl::lifetime &lifetime) {
struct State {
int addedToBottom = 0;
};
const auto participantChosen = [=](uint64 id) {
controller->showPeerInfo(PeerId(id));
};
@ -1194,6 +1197,7 @@ void ShowWhoReactedMenu(
Data::ReactedMenuFactory(&controller->session()),
participantChosen,
showAllChosen);
const auto state = lifetime.make_state<State>();
Api::WhoReacted(
item,
id,
@ -1203,7 +1207,7 @@ void ShowWhoReactedMenu(
return !content.unknown;
}) | rpl::start_with_next([=, &lifetime](Ui::WhoReadContent &&content) {
const auto creating = !*menu;
const auto refill = [=] {
const auto refillTop = [=] {
if (activeNonQuick) {
(*menu)->addAction(tr::lng_context_set_as_quick(tr::now), [=] {
reactions->setFavorite(id);
@ -1211,26 +1215,34 @@ void ShowWhoReactedMenu(
(*menu)->addSeparator();
}
};
const auto appendBottom = [=] {
state->addedToBottom = 0;
if (const auto custom = id.custom()) {
if (const auto set = owner->document(custom)->sticker()) {
if (set->set.id) {
state->addedToBottom = 2;
AddEmojiPacksAction(
menu->get(),
{ set->set },
EmojiPacksSource::Reaction,
controller);
}
}
}
};
if (creating) {
*menu = base::make_unique_q<Ui::PopupMenu>(
context,
st::whoReadMenu);
(*menu)->lifetime().add(base::take(lifetime));
refill();
}
filler->populate(menu->get(), content);
if (const auto custom = id.custom()) {
if (const auto set = owner->document(custom)->sticker()) {
if (set->set.id) {
AddEmojiPacksAction(
menu->get(),
{ set->set },
EmojiPacksSource::Reaction,
controller);
}
}
refillTop();
}
filler->populate(
menu->get(),
content,
refillTop,
state->addedToBottom,
appendBottom);
if (creating) {
(*menu)->popup(position);
}

View file

@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView {
namespace {
constexpr auto kPlayStatusLimit = 2;
const auto kPsaTooltipPrefix = "cloud_lng_tooltip_psa_";
std::optional<Window::SessionController*> ExtractController(
@ -234,6 +235,13 @@ struct Message::CommentsButton {
int rightActionCountWidth = 0;
};
struct Message::FromNameStatus {
DocumentId id = 0;
std::unique_ptr<Ui::Text::CustomEmoji> custom;
Ui::Text::CustomEmojiColored colored;
int skip = 0;
};
LogEntryOriginal::LogEntryOriginal() = default;
LogEntryOriginal::LogEntryOriginal(LogEntryOriginal &&other)
@ -277,8 +285,9 @@ Message::Message(
}
Message::~Message() {
if (_comments) {
if (_comments || (_fromNameStatus && _fromNameStatus->custom)) {
_comments = nullptr;
_fromNameStatus = nullptr;
checkHeavyPart();
}
}
@ -547,6 +556,9 @@ QSize Message::performCountOptimalSize() {
: item->hiddenSenderInfo()->nameText();
auto namew = st::msgPadding.left()
+ name.maxWidth()
+ (_fromNameStatus
? st::dialogsPremiumIcon.width()
: 0)
+ st::msgPadding.right();
if (via && !displayForwardedFrom()) {
namew += st::msgServiceFont->spacew + via->maxWidth;
@ -1087,32 +1099,71 @@ void Message::paintFromName(
availableWidth -= st::msgPadding.right() + rightWidth;
}
p.setFont(st::msgNameFont);
const auto stm = context.messageStyle();
const auto nameText = [&]() -> const Ui::Text::String * {
const auto from = item->displayFrom();
const auto service = (context.outbg || item->isPost());
const auto st = context.st;
const auto from = item->displayFrom();
const auto info = from ? nullptr : item->hiddenSenderInfo();
Assert(from || info);
const auto service = (context.outbg || item->isPost());
const auto st = context.st;
const auto nameFg = !service
? FromNameFg(context, from ? from->id : info->colorPeerId)
: item->isSponsored()
? st->boxTextFgGood()
: stm->msgServiceFg;
const auto nameText = [&] {
if (from) {
p.setPen(!service
? FromNameFg(context, from->id)
: item->isSponsored()
? st->boxTextFgGood()
: stm->msgServiceFg);
validateFromNameText(from);
return &_fromName;
} else if (const auto info = item->hiddenSenderInfo()) {
p.setPen(!service
? FromNameFg(context, info->colorPeerId)
: item->isSponsored()
? st->boxTextFgGood()
: stm->msgServiceFg);
return &info->nameText();
} else {
Unexpected("Corrupt sender information in message.");
return static_cast<const Ui::Text::String*>(&_fromName);
}
return &info->nameText();
}();
const auto statusWidth = _fromNameStatus ? st::dialogsPremiumIcon.width() : 0;
if (statusWidth && availableWidth > statusWidth) {
const auto x = availableLeft
+ std::min(availableWidth - statusWidth, nameText->maxWidth());
const auto y = trect.top();
const auto color = QColor(
nameFg->c.red(),
nameFg->c.green(),
nameFg->c.blue(),
nameFg->c.alpha() * 115 / 255);
const auto user = from->asUser();
const auto id = user ? user->emojiStatusId() : 0;
if (_fromNameStatus->id != id) {
const auto that = const_cast<Message*>(this);
_fromNameStatus->custom = id
? std::make_unique<Ui::Text::LimitedLoopsEmoji>(
user->owner().customEmojiManager().create(
id,
[=] { that->customEmojiRepaint(); }),
kPlayStatusLimit)
: nullptr;
if (id && !_fromNameStatus->id) {
history()->owner().registerHeavyViewPart(that);
} else if (!id && _fromNameStatus->id) {
that->checkHeavyPart();
}
_fromNameStatus->id = id;
}
if (_fromNameStatus->custom) {
clearCustomEmojiRepaint();
_fromNameStatus->colored.color = color;
_fromNameStatus->custom->paint(p, {
.preview = color,
.colored = &_fromNameStatus->colored,
.now = context.now,
.position = QPoint(
x - 2 * _fromNameStatus->skip,
y + _fromNameStatus->skip),
.paused = delegate()->elementIsGifPaused(),
});
} else {
st::dialogsPremiumIcon.paint(p, x, y, width(), color);
}
availableWidth -= statusWidth;
}
p.setFont(st::msgNameFont);
p.setPen(nameFg);
nameText->drawElided(p, availableLeft, trect.top(), availableWidth);
const auto skipWidth = nameText->maxWidth() + st::msgServiceFont->spacew;
availableLeft += skipWidth;
@ -1382,7 +1433,9 @@ void Message::toggleCommentsButtonRipple(bool pressed) {
}
bool Message::hasHeavyPart() const {
return _comments || Element::hasHeavyPart();
return _comments
|| (_fromNameStatus && _fromNameStatus->custom)
|| Element::hasHeavyPart();
}
void Message::unloadHeavyPart() {
@ -1391,6 +1444,9 @@ void Message::unloadHeavyPart() {
_reactions->unloadCustomEmoji();
}
_comments = nullptr;
if (_fromNameStatus) {
_fromNameStatus->custom = nullptr;
}
}
bool Message::showForwardsFromSender(
@ -2245,7 +2301,13 @@ void Message::refreshReactions() {
}
void Message::validateFromNameText(PeerData *from) const {
const auto version = from ? from->nameVersion() : 0;
if (!from) {
if (_fromNameStatus) {
_fromNameStatus = nullptr;
}
return;
}
const auto version = from->nameVersion();
if (_fromNameVersion < version) {
_fromNameVersion = version;
_fromName.setText(
@ -2253,6 +2315,16 @@ void Message::validateFromNameText(PeerData *from) const {
from->name(),
Ui::NameTextOptions());
}
if (from->isPremium()) {
if (!_fromNameStatus) {
_fromNameStatus = std::make_unique<FromNameStatus>();
const auto size = st::emojiSize;
const auto emoji = Ui::Text::AdjustCustomEmojiSize(size);
_fromNameStatus->skip = (size - emoji) / 2;
}
} else if (_fromNameStatus) {
_fromNameStatus = nullptr;
}
}
void Message::itemDataChanged() {

View file

@ -151,6 +151,7 @@ protected:
private:
struct CommentsButton;
struct FromNameStatus;
void initLogEntryOriginal();
void initPsa();
@ -258,6 +259,7 @@ private:
mutable std::unique_ptr<CommentsButton> _comments;
mutable Ui::Text::String _fromName;
mutable std::unique_ptr<FromNameStatus> _fromNameStatus;
Ui::Text::String _rightBadge;
mutable int _fromNameVersion = 0;
int _bubbleWidthLimit = 0;

View file

@ -636,7 +636,9 @@ void WhoReactedListMenu::clear() {
void WhoReactedListMenu::populate(
not_null<PopupMenu*> menu,
const WhoReadContent &content,
Fn<void()> refillTopActions) {
Fn<void()> refillTopActions,
int addedToBottom,
Fn<void()> appendBottomActions) {
const auto reactions = ranges::count_if(
content.participants,
[](const auto &p) { return !p.customEntityData.isEmpty(); });
@ -649,6 +651,7 @@ void WhoReactedListMenu::populate(
if (refillTopActions) {
refillTopActions();
}
addedToBottom = 0;
}
auto index = 0;
const auto append = [&](EntryData &&data) {
@ -661,7 +664,12 @@ void WhoReactedListMenu::populate(
menu->menu()->st(),
std::move(data));
_actions.push_back(item.get());
menu->addAction(std::move(item));
const auto count = int(menu->actions().size());
if (addedToBottom > 0 && addedToBottom <= count) {
menu->insertAction(count - addedToBottom, std::move(item));
} else {
menu->addAction(std::move(item));
}
}
++index;
};
@ -682,7 +690,9 @@ void WhoReactedListMenu::populate(
.callback = _showAllChosen,
});
}
if (!addedToBottom && appendBottomActions) {
appendBottomActions();
}
}
} // namespace Ui

View file

@ -65,7 +65,9 @@ public:
void populate(
not_null<PopupMenu*> menu,
const WhoReadContent &content,
Fn<void()> refillTopActions = nullptr);
Fn<void()> refillTopActions = nullptr,
int addedToBottom = 0,
Fn<void()> appendBottomActions = nullptr);
private:
class EntryAction;

View file

@ -17,6 +17,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_dialogs.h"
namespace Ui {
namespace {
constexpr auto kPlayStatusLimit = 2;
} // namespace
void UnreadBadge::setText(const QString &text, bool active) {
_text = text;
@ -177,11 +182,14 @@ int PeerBadge::drawGetWidth(
>();
}
if (_emojiStatus->id != id) {
using namespace Ui::Text;
auto &manager = peer->session().data().customEmojiManager();
_emojiStatus->id = id;
_emojiStatus->emoji = manager.create(
id,
descriptor.customEmojiRepaint);
_emojiStatus->emoji = std::make_unique<LimitedLoopsEmoji>(
manager.create(
id,
descriptor.customEmojiRepaint),
kPlayStatusLimit);
}
_emojiStatus->colored->color = (*descriptor.premiumFg)->c;
_emojiStatus->emoji->paint(p, {

@ -1 +1 @@
Subproject commit 51657b3c8a643c9ca2721029fd48f63390417042
Subproject commit a5766cb1f6bfcd208814b0b71322128ecb47039a