mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 13:47:05 +02:00
Proof-of-concept custom verify badges.
This commit is contained in:
parent
35e40be550
commit
6f18b9b691
25 changed files with 437 additions and 195 deletions
|
@ -570,9 +570,7 @@ ConfirmInviteBox::ChatInvite ConfirmInviteBox::Parse(
|
|||
[[nodiscard]] Info::Profile::BadgeType ConfirmInviteBox::BadgeForInvite(
|
||||
const ChatInvite &invite) {
|
||||
using Type = Info::Profile::BadgeType;
|
||||
return invite.isVerified
|
||||
? Type::Verified
|
||||
: invite.isScam
|
||||
return invite.isScam
|
||||
? Type::Scam
|
||||
: invite.isFake
|
||||
? Type::Fake
|
||||
|
|
|
@ -74,46 +74,47 @@ struct PeerUpdate {
|
|||
Color = (1ULL << 14),
|
||||
BackgroundEmoji = (1ULL << 15),
|
||||
StoriesState = (1ULL << 16),
|
||||
VerifyInfo = (1ULL << 17),
|
||||
|
||||
// For users
|
||||
CanShareContact = (1ULL << 17),
|
||||
IsContact = (1ULL << 18),
|
||||
PhoneNumber = (1ULL << 19),
|
||||
OnlineStatus = (1ULL << 20),
|
||||
BotCommands = (1ULL << 21),
|
||||
BotCanBeInvited = (1ULL << 22),
|
||||
BotStartToken = (1ULL << 23),
|
||||
CommonChats = (1ULL << 24),
|
||||
PeerGifts = (1ULL << 25),
|
||||
HasCalls = (1ULL << 26),
|
||||
SupportInfo = (1ULL << 27),
|
||||
IsBot = (1ULL << 28),
|
||||
EmojiStatus = (1ULL << 29),
|
||||
BusinessDetails = (1ULL << 30),
|
||||
Birthday = (1ULL << 31),
|
||||
PersonalChannel = (1ULL << 32),
|
||||
StarRefProgram = (1ULL << 33),
|
||||
CanShareContact = (1ULL << 18),
|
||||
IsContact = (1ULL << 19),
|
||||
PhoneNumber = (1ULL << 20),
|
||||
OnlineStatus = (1ULL << 21),
|
||||
BotCommands = (1ULL << 22),
|
||||
BotCanBeInvited = (1ULL << 23),
|
||||
BotStartToken = (1ULL << 24),
|
||||
CommonChats = (1ULL << 25),
|
||||
PeerGifts = (1ULL << 26),
|
||||
HasCalls = (1ULL << 27),
|
||||
SupportInfo = (1ULL << 28),
|
||||
IsBot = (1ULL << 29),
|
||||
EmojiStatus = (1ULL << 30),
|
||||
BusinessDetails = (1ULL << 31),
|
||||
Birthday = (1ULL << 32),
|
||||
PersonalChannel = (1ULL << 33),
|
||||
StarRefProgram = (1ULL << 34),
|
||||
|
||||
// For chats and channels
|
||||
InviteLinks = (1ULL << 34),
|
||||
Members = (1ULL << 35),
|
||||
Admins = (1ULL << 36),
|
||||
BannedUsers = (1ULL << 37),
|
||||
Rights = (1ULL << 38),
|
||||
PendingRequests = (1ULL << 39),
|
||||
Reactions = (1ULL << 40),
|
||||
InviteLinks = (1ULL << 35),
|
||||
Members = (1ULL << 36),
|
||||
Admins = (1ULL << 37),
|
||||
BannedUsers = (1ULL << 38),
|
||||
Rights = (1ULL << 39),
|
||||
PendingRequests = (1ULL << 40),
|
||||
Reactions = (1ULL << 41),
|
||||
|
||||
// For channels
|
||||
ChannelAmIn = (1ULL << 41),
|
||||
StickersSet = (1ULL << 42),
|
||||
EmojiSet = (1ULL << 43),
|
||||
ChannelLinkedChat = (1ULL << 44),
|
||||
ChannelLocation = (1ULL << 45),
|
||||
Slowmode = (1ULL << 46),
|
||||
GroupCall = (1ULL << 47),
|
||||
ChannelAmIn = (1ULL << 42),
|
||||
StickersSet = (1ULL << 43),
|
||||
EmojiSet = (1ULL << 44),
|
||||
ChannelLinkedChat = (1ULL << 45),
|
||||
ChannelLocation = (1ULL << 46),
|
||||
Slowmode = (1ULL << 47),
|
||||
GroupCall = (1ULL << 48),
|
||||
|
||||
// For iteration
|
||||
LastUsedBit = (1ULL << 47),
|
||||
LastUsedBit = (1ULL << 48),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
|
|
@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_chat_invite.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "apiwrap.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "window/notifications_manager.h"
|
||||
|
||||
namespace {
|
||||
|
@ -713,6 +714,24 @@ bool ChannelData::canRestrictParticipant(
|
|||
return adminRights() & AdminRight::BanUsers;
|
||||
}
|
||||
|
||||
void ChannelData::setVerifyDetails(Ui::VerifyDetails details) {
|
||||
if (_verifyDetails && !verifiedByTelegram() && !details) {
|
||||
return; AssertIsDebug();
|
||||
}
|
||||
if (!details) {
|
||||
if (_verifyDetails) {
|
||||
_verifyDetails = nullptr;
|
||||
session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
|
||||
}
|
||||
} else if (!_verifyDetails) {
|
||||
_verifyDetails = std::make_unique<Ui::VerifyDetails>(details);
|
||||
session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
|
||||
} else if (*_verifyDetails != details) {
|
||||
*_verifyDetails = details;
|
||||
session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelData::setAdminRights(ChatAdminRights rights) {
|
||||
if (rights == adminRights()) {
|
||||
return;
|
||||
|
|
|
@ -376,6 +376,11 @@ public:
|
|||
[[nodiscard]] bool canRestrictParticipant(
|
||||
not_null<PeerData*> participant) const;
|
||||
|
||||
void setVerifyDetails(Ui::VerifyDetails details);
|
||||
[[nodiscard]] Ui::VerifyDetails *verifyDetails() const {
|
||||
return _verifyDetails.get();
|
||||
}
|
||||
|
||||
void setInviteLink(const QString &newInviteLink);
|
||||
[[nodiscard]] QString inviteLink() const {
|
||||
return _inviteLink;
|
||||
|
@ -546,6 +551,8 @@ private:
|
|||
std::unique_ptr<Data::GroupCall> _call;
|
||||
PeerId _callDefaultJoinAs = 0;
|
||||
|
||||
std::unique_ptr<Ui::VerifyDetails> _verifyDetails;
|
||||
|
||||
};
|
||||
|
||||
namespace Data {
|
||||
|
|
|
@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/empty_userpic.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "history/history.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
|
@ -1246,6 +1247,22 @@ void PeerData::setStoriesHidden(bool hidden) {
|
|||
}
|
||||
}
|
||||
|
||||
Ui::VerifyDetails *PeerData::verifyDetails() const {
|
||||
if (const auto user = asUser()) {
|
||||
return user->verifyDetails();
|
||||
} else if (const auto channel = asChannel()) {
|
||||
return channel->verifyDetails();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool PeerData::verifiedByTelegram() const {
|
||||
if (const auto details = verifyDetails()) {
|
||||
return (details->iconBgId == owner().verifiedByTelegram().iconBgId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Data::Forum *PeerData::forum() const {
|
||||
if (const auto channel = asChannel()) {
|
||||
return channel->forum();
|
||||
|
|
|
@ -23,6 +23,7 @@ enum class ChatRestriction;
|
|||
|
||||
namespace Ui {
|
||||
class EmptyUserpic;
|
||||
struct VerifyDetails;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Main {
|
||||
|
@ -233,6 +234,9 @@ public:
|
|||
[[nodiscard]] bool hasStoriesHidden() const;
|
||||
void setStoriesHidden(bool hidden);
|
||||
|
||||
[[nodiscard]] Ui::VerifyDetails *verifyDetails() const;
|
||||
[[nodiscard]] bool verifiedByTelegram() const;
|
||||
|
||||
[[nodiscard]] bool isNotificationsUser() const {
|
||||
return (id == peerFromUser(333000))
|
||||
|| (id == kServiceNotificationsId);
|
||||
|
@ -521,7 +525,7 @@ private:
|
|||
base::flat_set<QChar> _nameFirstLetters;
|
||||
|
||||
DocumentId _emojiStatusId = 0;
|
||||
uint64 _backgroundEmojiId = 0;
|
||||
DocumentId _backgroundEmojiId = 0;
|
||||
crl::time _lastFullUpdate = 0;
|
||||
|
||||
QString _name;
|
||||
|
|
|
@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/media/history_view_media.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "inline_bots/inline_bot_layout_item.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "storage/storage_encrypted_file.h"
|
||||
#include "media/player/media_player_instance.h" // instance()->play()
|
||||
|
@ -79,6 +80,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/random.h"
|
||||
#include "spellcheck/spellcheck_highlight_syntax.h"
|
||||
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include <QtCore/QBuffer>
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
|
@ -329,6 +335,25 @@ Session::Session(not_null<Main::Session*> session)
|
|||
}, _lifetime);
|
||||
}
|
||||
|
||||
|
||||
Ui::VerifyDetails Session::verifiedByTelegram() {
|
||||
if (_verifiedByTelegramIconBgId.isEmpty()) {
|
||||
auto &manager = customEmojiManager();
|
||||
_verifiedByTelegramIconBgId = manager.registerInternalEmoji(
|
||||
st::dialogsVerifiedBg);
|
||||
_verifiedByTelegramIconFgId = manager.registerInternalEmoji(
|
||||
st::dialogsVerifiedFg);
|
||||
}
|
||||
return {
|
||||
.iconBgId = _verifiedByTelegramIconBgId,
|
||||
.iconFgId = _verifiedByTelegramIconFgId,
|
||||
.description = {
|
||||
u"This community is verified as official "
|
||||
"by the representatives of Telegram."_q,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
void Session::subscribeForTopicRepliesLists() {
|
||||
repliesReadTillUpdates(
|
||||
) | rpl::start_with_next([=](const RepliesReadTillUpdate &update) {
|
||||
|
@ -569,6 +594,11 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
|||
| (data.is_stories_hidden() ? Flag::StoriesHidden : Flag())
|
||||
: Flag());
|
||||
result->setFlags((result->flags() & ~flagsMask) | flagsSet);
|
||||
if (data.is_verified()) {
|
||||
result->setVerifyDetails(verifiedByTelegram());
|
||||
} else {
|
||||
result->setVerifyDetails({});
|
||||
}
|
||||
if (minimal) {
|
||||
if (result->input.type() == mtpc_inputPeerEmpty) {
|
||||
result->input = MTP_inputPeerUser(
|
||||
|
@ -984,6 +1014,11 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
|||
? Flag::StoriesHidden
|
||||
: Flag());
|
||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||
if (data.is_verified()) {
|
||||
channel->setVerifyDetails(verifiedByTelegram());
|
||||
} else {
|
||||
channel->setVerifyDetails({});
|
||||
}
|
||||
if (!minimal && storiesState) {
|
||||
result->setStoriesState(!storiesState->maxId
|
||||
? UserData::StoriesState::None
|
||||
|
@ -2680,6 +2715,35 @@ void Session::unregisterDependentMessage(
|
|||
|
||||
void Session::registerMessageRandomId(uint64 randomId, FullMsgId itemId) {
|
||||
_messageByRandomId.emplace(randomId, itemId);
|
||||
|
||||
AssertIsDebug();
|
||||
if (peerIsChannel(itemId.peer)) {
|
||||
if (const auto channel = channelLoaded(peerToChannel(itemId.peer))) {
|
||||
auto colored = std::vector<not_null<DocumentData*>>();
|
||||
for (const auto &[id, document] : _documents) {
|
||||
if (const auto sticker = document->sticker()) {
|
||||
if (sticker->setType == Data::StickersType::Emoji) {
|
||||
if (document->emojiUsesTextColor()) {
|
||||
colored.push_back(document.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto count = int(colored.size());
|
||||
if (count > 1) {
|
||||
auto index1 = base::RandomIndex(count);
|
||||
auto index2 = base::RandomIndex(count - 1);
|
||||
if (index2 >= index1) {
|
||||
++index2;
|
||||
}
|
||||
channel->setVerifyDetails({
|
||||
.iconBgId = QString::number(colored[index1]->id),
|
||||
.iconFgId = QString::number(colored[index2]->id),
|
||||
});
|
||||
history(channel)->updateChatListEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Session::unregisterMessageRandomId(uint64 randomId) {
|
||||
|
|
|
@ -177,6 +177,8 @@ public:
|
|||
return ++_nonHistoryEntryId;
|
||||
}
|
||||
|
||||
[[nodiscard]] Ui::VerifyDetails verifiedByTelegram();
|
||||
|
||||
void subscribeForTopicRepliesLists();
|
||||
void clear();
|
||||
|
||||
|
@ -1140,6 +1142,9 @@ private:
|
|||
const std::unique_ptr<BusinessInfo> _businessInfo;
|
||||
std::unique_ptr<ShortcutMessages> _shortcutMessages;
|
||||
|
||||
QString _verifiedByTelegramIconBgId;
|
||||
QString _verifiedByTelegramIconFgId;
|
||||
|
||||
MsgId _nonHistoryEntryId = ShortcutMaxMsgId;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
|
|
@ -514,6 +514,21 @@ bool UserData::isUsernameEditable(QString username) const {
|
|||
return _username.isEditable(username);
|
||||
}
|
||||
|
||||
void UserData::setVerifyDetails(Ui::VerifyDetails details) {
|
||||
if (!details) {
|
||||
if (_verifyDetails) {
|
||||
_verifyDetails = nullptr;
|
||||
session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
|
||||
}
|
||||
} else if (!_verifyDetails) {
|
||||
_verifyDetails = std::make_unique<Ui::VerifyDetails>(details);
|
||||
session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
|
||||
} else if (*_verifyDetails != details) {
|
||||
*_verifyDetails = details;
|
||||
session().changes().peerUpdated(this, UpdateFlag::VerifyInfo);
|
||||
}
|
||||
}
|
||||
|
||||
const QString &UserData::phone() const {
|
||||
return _phone;
|
||||
}
|
||||
|
|
|
@ -177,6 +177,11 @@ public:
|
|||
[[nodiscard]] const std::vector<QString> &usernames() const;
|
||||
[[nodiscard]] bool isUsernameEditable(QString username) const;
|
||||
|
||||
void setVerifyDetails(Ui::VerifyDetails details);
|
||||
[[nodiscard]] Ui::VerifyDetails *verifyDetails() const {
|
||||
return _verifyDetails.get();
|
||||
}
|
||||
|
||||
enum class ContactStatus : char {
|
||||
Unknown,
|
||||
Contact,
|
||||
|
@ -255,6 +260,7 @@ private:
|
|||
std::vector<Data::UnavailableReason> _unavailableReasons;
|
||||
QString _phone;
|
||||
QString _privateForwardName;
|
||||
std::unique_ptr<Ui::VerifyDetails> _verifyDetails;
|
||||
|
||||
ChannelId _personalChannelId = 0;
|
||||
MsgId _personalChannelMessageId = 0;
|
||||
|
|
|
@ -31,6 +31,12 @@ ThreeStateIcon {
|
|||
active: icon;
|
||||
}
|
||||
|
||||
VerifiedBadge {
|
||||
bg: color;
|
||||
fg: color;
|
||||
height: pixels;
|
||||
}
|
||||
|
||||
ForumTopicIcon {
|
||||
size: pixels;
|
||||
font: font;
|
||||
|
@ -401,6 +407,22 @@ dialogsLockIcon: ThreeStateIcon {
|
|||
active: icon {{ "emoji/premium_lock", dialogsUnreadBgMutedActive, point(4px, 0px) }};
|
||||
}
|
||||
|
||||
dialogsVerifiedBg: icon{{ "dialogs/dialogs_verified_star", dialogsVerifiedIconBg }};
|
||||
dialogsVerifiedFg: icon{{ "dialogs/dialogs_verified_check", dialogsVerifiedIconFg }};
|
||||
dialogsVerifiedColors: VerifiedBadge {
|
||||
height: 20px;
|
||||
bg: dialogsVerifiedIconBg;
|
||||
fg: dialogsVerifiedIconFg;
|
||||
}
|
||||
dialogsVerifiedColorsOver: VerifiedBadge(dialogsVerifiedColors) {
|
||||
bg: dialogsVerifiedIconBgOver;
|
||||
fg: dialogsVerifiedIconFgOver;
|
||||
}
|
||||
dialogsVerifiedColorsActive: VerifiedBadge(dialogsVerifiedColors) {
|
||||
bg: dialogsVerifiedIconBgActive;
|
||||
fg: dialogsVerifiedIconFgActive;
|
||||
}
|
||||
|
||||
dialogsVerifiedIcon: icon {
|
||||
{ "dialogs/dialogs_verified_star", dialogsVerifiedIconBg },
|
||||
{ "dialogs/dialogs_verified_check", dialogsVerifiedIconFg },
|
||||
|
|
|
@ -1379,12 +1379,17 @@ void InnerWidget::paintPeerSearchResult(
|
|||
Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
// draw chat icon
|
||||
if (const auto chatTypeIcon = Ui::ChatTypeIcon(peer, context)) {
|
||||
chatTypeIcon->paint(p, rectForName.topLeft(), context.width);
|
||||
rectForName.setLeft(rectForName.left()
|
||||
+ chatTypeIcon->width()
|
||||
+ st::dialogsChatTypeSkip);
|
||||
if (const auto details = peer->verifyDetails()) {
|
||||
if (!result->badge.ready(details)) {
|
||||
result->badge.set(
|
||||
details,
|
||||
peer->owner().customEmojiManager().factory(),
|
||||
[=] { updateSearchResult(peer); });
|
||||
}
|
||||
const auto &st = Ui::VerifiedStyle(context);
|
||||
const auto position = rectForName.topLeft();
|
||||
const auto skip = result->badge.drawVerified(p, position, st);
|
||||
rectForName.setLeft(position.x() + skip + st::dialogsChatTypeSkip);
|
||||
}
|
||||
const auto badgeWidth = result->badge.drawGetWidth(
|
||||
p,
|
||||
|
@ -1461,112 +1466,6 @@ void InnerWidget::paintSearchTags(
|
|||
const auto position = QPoint(_searchTagsLeft, top);
|
||||
_searchTags->paint(p, position, context.now, context.paused);
|
||||
}
|
||||
//
|
||||
//void InnerWidget::paintSearchInChat(
|
||||
// Painter &p,
|
||||
// const Ui::PaintContext &context) const {
|
||||
// auto height = searchInChatSkip();
|
||||
//
|
||||
// auto top = 0;
|
||||
// p.setFont(st::searchedBarFont);
|
||||
// auto fullRect = QRect(0, top, width(), height - top);
|
||||
// p.fillRect(fullRect, currentBg());
|
||||
// if (_searchFromShown) {
|
||||
// p.setPen(st::dialogsTextFg);
|
||||
// p.setTextPalette(st::dialogsSearchFromPalette);
|
||||
// paintSearchInPeer(p, _searchFromShown, _searchFromUserUserpic, top, _searchFromUserText);
|
||||
// p.restoreTextPalette();
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//template <typename PaintUserpic>
|
||||
//void InnerWidget::paintSearchInFilter(
|
||||
// Painter &p,
|
||||
// PaintUserpic paintUserpic,
|
||||
// int top,
|
||||
// const style::icon *icon,
|
||||
// const Ui::Text::String &text) const {
|
||||
// const auto savedPen = p.pen();
|
||||
// const auto userpicLeft = st::defaultDialogRow.padding.left();
|
||||
// const auto userpicTop = top
|
||||
// + (st::dialogsSearchInHeight - st::dialogsSearchInPhotoSize) / 2;
|
||||
// paintUserpic(p, userpicLeft, userpicTop, st::dialogsSearchInPhotoSize);
|
||||
//
|
||||
// const auto nameleft = st::defaultDialogRow.padding.left()
|
||||
// + st::dialogsSearchInPhotoSize
|
||||
// + st::dialogsSearchInPhotoPadding;
|
||||
// const auto namewidth = width()
|
||||
// - nameleft
|
||||
// - st::defaultDialogRow.padding.left()
|
||||
// - st::defaultDialogRow.padding.right()
|
||||
// - st::dialogsCancelSearch.width;
|
||||
// auto rectForName = QRect(
|
||||
// nameleft,
|
||||
// top + (st::dialogsSearchInHeight - st::semiboldFont->height) / 2,
|
||||
// namewidth,
|
||||
// st::semiboldFont->height);
|
||||
// if (icon) {
|
||||
// icon->paint(p, rectForName.topLeft(), width());
|
||||
// rectForName.setLeft(rectForName.left()
|
||||
// + icon->width()
|
||||
// + st::dialogsChatTypeSkip);
|
||||
// }
|
||||
// p.setPen(savedPen);
|
||||
// text.drawLeftElided(
|
||||
// p,
|
||||
// rectForName.left(),
|
||||
// rectForName.top(),
|
||||
// rectForName.width(),
|
||||
// width());
|
||||
//}
|
||||
//
|
||||
//void InnerWidget::paintSearchInPeer(
|
||||
// Painter &p,
|
||||
// not_null<PeerData*> peer,
|
||||
// Ui::PeerUserpicView &userpic,
|
||||
// int top,
|
||||
// const Ui::Text::String &text) const {
|
||||
// const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
|
||||
// peer->paintUserpicLeft(p, userpic, x, y, width(), size);
|
||||
// };
|
||||
// const auto icon = Ui::ChatTypeIcon(peer);
|
||||
// paintSearchInFilter(p, paintUserpic, top, icon, text);
|
||||
//}
|
||||
//
|
||||
//void InnerWidget::paintSearchInSaved(
|
||||
// Painter &p,
|
||||
// int top,
|
||||
// const Ui::Text::String &text) const {
|
||||
// const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
|
||||
// Ui::EmptyUserpic::PaintSavedMessages(p, x, y, width(), size);
|
||||
// };
|
||||
// paintSearchInFilter(p, paintUserpic, top, nullptr, text);
|
||||
//}
|
||||
//
|
||||
//void InnerWidget::paintSearchInReplies(
|
||||
// Painter &p,
|
||||
// int top,
|
||||
// const Ui::Text::String &text) const {
|
||||
// const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
|
||||
// Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, width(), size);
|
||||
// };
|
||||
// paintSearchInFilter(p, paintUserpic, top, nullptr, text);
|
||||
//}
|
||||
//
|
||||
//void InnerWidget::paintSearchInTopic(
|
||||
// Painter &p,
|
||||
// const Ui::PaintContext &context,
|
||||
// not_null<Data::ForumTopic*> topic,
|
||||
// Ui::PeerUserpicView &userpic,
|
||||
// int top,
|
||||
// const Ui::Text::String &text) const {
|
||||
// const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
|
||||
// p.translate(x, y);
|
||||
// topic->paintUserpic(p, userpic, context);
|
||||
// p.translate(-x, -y);
|
||||
// };
|
||||
// paintSearchInFilter(p, paintUserpic, top, nullptr, text);
|
||||
//}
|
||||
|
||||
void InnerWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||
if (_chatPreviewTouchGlobal || _touchDragStartGlobal) {
|
||||
|
|
|
@ -7,8 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/text/text.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/text/text.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "ui/userpic_view.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
|
|
|
@ -449,13 +449,17 @@ void PaintRow(
|
|||
? tr::lng_badge_psa_default(tr::now)
|
||||
: custom;
|
||||
PaintRowTopRight(p, text, rectForName, context);
|
||||
} else if (from) {
|
||||
if (const auto chatTypeIcon = ChatTypeIcon(from, context)) {
|
||||
chatTypeIcon->paint(p, rectForName.topLeft(), context.width);
|
||||
rectForName.setLeft(rectForName.left()
|
||||
+ chatTypeIcon->width()
|
||||
+ st::dialogsChatTypeSkip);
|
||||
} else if (const auto details = from ? from->verifyDetails() : nullptr) {
|
||||
if (!rowBadge.ready(details)) {
|
||||
rowBadge.set(
|
||||
details,
|
||||
from->owner().customEmojiManager().factory(),
|
||||
customEmojiRepaint);
|
||||
}
|
||||
const auto &st = Ui::VerifiedStyle(context);
|
||||
const auto position = rectForName.topLeft();
|
||||
const auto skip = rowBadge.drawVerified(p, position, st);
|
||||
rectForName.setLeft(position.x() + skip + st::dialogsChatTypeSkip);
|
||||
}
|
||||
auto texttop = context.st->textTop;
|
||||
if (const auto folder = entry->asFolder()) {
|
||||
|
@ -839,6 +843,14 @@ const style::icon *ChatTypeIcon(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const style::VerifiedBadge &VerifiedStyle(const PaintContext &context) {
|
||||
return context.active
|
||||
? st::dialogsVerifiedColorsActive
|
||||
: context.selected
|
||||
? st::dialogsVerifiedColorsOver
|
||||
: st::dialogsVerifiedColors;
|
||||
}
|
||||
|
||||
void RowPainter::Paint(
|
||||
Painter &p,
|
||||
not_null<const Row*> row,
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace style {
|
||||
struct DialogRow;
|
||||
struct VerifiedBadge;
|
||||
} // namespace style
|
||||
|
||||
namespace st {
|
||||
|
@ -79,6 +80,9 @@ struct PaintContext {
|
|||
const PaintContext &context);
|
||||
[[nodiscard]] const style::icon *ChatTypeIcon(not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] const style::VerifiedBadge &VerifiedStyle(
|
||||
const PaintContext &context);
|
||||
|
||||
class RowPainter {
|
||||
public:
|
||||
static void Paint(
|
||||
|
|
|
@ -41,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_group_call.h" // GroupCall::input.
|
||||
#include "data/data_folder.h"
|
||||
|
@ -448,12 +449,14 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
return;
|
||||
}
|
||||
auto nameleft = _leftTaken;
|
||||
auto statusleft = nameleft;
|
||||
auto nametop = st::topBarArrowPadding.top();
|
||||
auto statustop = st::topBarHeight - st::topBarArrowPadding.bottom() - st::dialogsTextFont->height;
|
||||
auto availableWidth = width()
|
||||
auto namewidth = width()
|
||||
- _rightTaken
|
||||
- nameleft
|
||||
- st::topBarNameRightPadding;
|
||||
auto statuswidth = namewidth;
|
||||
|
||||
if (_chooseForReportReason) {
|
||||
const auto text = _chooseForReportReason->optionText;
|
||||
|
@ -489,7 +492,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
p,
|
||||
nameleft,
|
||||
nametop,
|
||||
availableWidth);
|
||||
namewidth);
|
||||
|
||||
p.setFont(st::dialogsTextFont);
|
||||
if (!paintConnectingState(p, nameleft, statustop, width())
|
||||
|
@ -497,7 +500,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
p,
|
||||
nameleft,
|
||||
statustop,
|
||||
availableWidth,
|
||||
namewidth,
|
||||
width(),
|
||||
st::historyStatusFgTyping,
|
||||
now)) {
|
||||
|
@ -524,8 +527,8 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
? tr::lng_verification_codes(tr::now)
|
||||
: peer->name();
|
||||
const auto textWidth = st::historySavedFont->width(text);
|
||||
if (availableWidth < textWidth) {
|
||||
text = st::historySavedFont->elided(text, availableWidth);
|
||||
if (namewidth < textWidth) {
|
||||
text = st::historySavedFont->elided(text, namewidth);
|
||||
}
|
||||
p.setPen(st::dialogsNameFg);
|
||||
p.setFont(st::historySavedFont);
|
||||
|
@ -544,16 +547,16 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
tr::lng_manage_discussion_group(tr::now));
|
||||
|
||||
p.setFont(st::dialogsTextFont);
|
||||
if (!paintConnectingState(p, nameleft, statustop, width())
|
||||
if (!paintConnectingState(p, statusleft, statustop, width())
|
||||
&& !paintSendAction(
|
||||
p,
|
||||
nameleft,
|
||||
statusleft,
|
||||
statustop,
|
||||
availableWidth,
|
||||
statuswidth,
|
||||
width(),
|
||||
st::historyStatusFgTyping,
|
||||
now)) {
|
||||
paintStatus(p, nameleft, statustop, availableWidth, width());
|
||||
paintStatus(p, statusleft, statustop, statuswidth, width());
|
||||
}
|
||||
} else if (namePeer) {
|
||||
if (_titleNameVersion < namePeer->nameVersion()) {
|
||||
|
@ -563,12 +566,24 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
TopBarNameText(namePeer, _activeChat.section),
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
if (const auto details = namePeer->verifyDetails()) {
|
||||
if (!_titleBadge.ready(details)) {
|
||||
_titleBadge.set(
|
||||
details,
|
||||
namePeer->owner().customEmojiManager().factory(),
|
||||
[=] { update(); });
|
||||
}
|
||||
const auto position = QPoint{ nameleft, nametop };
|
||||
const auto skip = _titleBadge.drawVerified(p, position, st::dialogsVerifiedColors);
|
||||
nameleft += skip + st::dialogsChatTypeSkip;
|
||||
namewidth -= skip + st::dialogsChatTypeSkip;
|
||||
}
|
||||
const auto badgeWidth = _titleBadge.drawGetWidth(
|
||||
p,
|
||||
QRect(
|
||||
nameleft,
|
||||
nametop,
|
||||
availableWidth,
|
||||
namewidth,
|
||||
st::msgNameStyle.font->height),
|
||||
_title.maxWidth(),
|
||||
width(),
|
||||
|
@ -583,7 +598,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
.paused = _controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::Any),
|
||||
});
|
||||
const auto namewidth = availableWidth - badgeWidth;
|
||||
namewidth -= badgeWidth;
|
||||
|
||||
p.setPen(st::dialogsNameFg);
|
||||
_title.draw(p, {
|
||||
|
@ -593,16 +608,16 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
});
|
||||
|
||||
p.setFont(st::dialogsTextFont);
|
||||
if (!paintConnectingState(p, nameleft, statustop, width())
|
||||
if (!paintConnectingState(p, statusleft, statustop, width())
|
||||
&& !paintSendAction(
|
||||
p,
|
||||
nameleft,
|
||||
statusleft,
|
||||
statustop,
|
||||
availableWidth,
|
||||
statuswidth,
|
||||
width(),
|
||||
st::historyStatusFgTyping,
|
||||
now)) {
|
||||
paintStatus(p, nameleft, statustop, availableWidth, width());
|
||||
paintStatus(p, statusleft, statustop, statuswidth, width());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ InfoPeerBadge {
|
|||
verified: icon;
|
||||
premium: icon;
|
||||
premiumFg: color;
|
||||
premiumInnerFg: color;
|
||||
position: point;
|
||||
sizeTag: int;
|
||||
}
|
||||
|
@ -439,6 +440,7 @@ infoPeerBadge: InfoPeerBadge {
|
|||
verified: infoVerifiedCheck;
|
||||
premium: infoPremiumStar;
|
||||
premiumFg: profileVerifiedCheckBg;
|
||||
premiumInnerFg: profileVerifiedCheckFg;
|
||||
position: infoVerifiedCheckPosition;
|
||||
sizeTag: 1; // Large
|
||||
}
|
||||
|
|
|
@ -113,14 +113,29 @@ void Badge::setContent(Content content) {
|
|||
switch (_content.badge) {
|
||||
case BadgeType::Verified:
|
||||
case BadgeType::Premium: {
|
||||
if (const auto id = _content.emojiStatusId) {
|
||||
_emojiStatus = _session->data().customEmojiManager().create(
|
||||
id,
|
||||
[raw = _view.data()] { raw->update(); },
|
||||
sizeTag());
|
||||
if (_customStatusLoopsLimit > 0) {
|
||||
const auto id = _content.emojiStatusId;
|
||||
const auto innerId = _content.emojiStatusInnerId;
|
||||
if (id || innerId) {
|
||||
_emojiStatus = id
|
||||
? _session->data().customEmojiManager().create(
|
||||
id,
|
||||
[raw = _view.data()] { raw->update(); },
|
||||
sizeTag())
|
||||
: nullptr;
|
||||
_statusInner = innerId
|
||||
? _session->data().customEmojiManager().create(
|
||||
innerId,
|
||||
[raw = _view.data()] { raw->update(); },
|
||||
sizeTag())
|
||||
: nullptr;
|
||||
if (_emojiStatus && _customStatusLoopsLimit > 0) {
|
||||
_emojiStatus = std::make_unique<Ui::Text::LimitedLoopsEmoji>(
|
||||
std::move(_emojiStatus),
|
||||
std::move(_emojiStatus),
|
||||
_customStatusLoopsLimit);
|
||||
}
|
||||
if (_statusInner && _customStatusLoopsLimit > 0) {
|
||||
_statusInner = std::make_unique<Ui::Text::LimitedLoopsEmoji>(
|
||||
std::move(_statusInner),
|
||||
_customStatusLoopsLimit);
|
||||
}
|
||||
const auto emoji = Data::FrameSizeFromTag(sizeTag())
|
||||
|
@ -137,7 +152,13 @@ void Badge::setContent(Content content) {
|
|||
if (!_emojiStatusPanel
|
||||
|| !_emojiStatusPanel->paintBadgeFrame(check)) {
|
||||
Painter p(check);
|
||||
_emojiStatus->paint(p, args);
|
||||
if (_emojiStatus) {
|
||||
_emojiStatus->paint(p, args);
|
||||
}
|
||||
if (_statusInner) {
|
||||
args.textColor = _st.premiumInnerFg->c;
|
||||
_statusInner->paint(p, args);
|
||||
}
|
||||
}
|
||||
}, _view->lifetime());
|
||||
} else {
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
struct Content {
|
||||
BadgeType badge = BadgeType::None;
|
||||
DocumentId emojiStatusId = 0;
|
||||
DocumentId emojiStatusInnerId = 0;
|
||||
|
||||
friend inline constexpr bool operator==(Content, Content) = default;
|
||||
};
|
||||
|
@ -92,6 +93,7 @@ private:
|
|||
EmojiStatusPanel *_emojiStatusPanel = nullptr;
|
||||
const int _customStatusLoopsLimit = 0;
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> _emojiStatus;
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> _statusInner;
|
||||
base::flags<BadgeType> _allowed;
|
||||
Content _content;
|
||||
Fn<void()> _premiumClickCallback;
|
||||
|
|
|
@ -293,6 +293,21 @@ Cover::Cover(
|
|||
std::move(title)) {
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<Badge::Content> VerifyBadgeForPeer(
|
||||
not_null<PeerData*> peer) {
|
||||
return peer->session().changes().peerFlagsValue(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::VerifyInfo
|
||||
) | rpl::map([=] {
|
||||
const auto details = peer->verifyDetails();
|
||||
return Badge::Content{
|
||||
.badge = details ? BadgeType::Verified : BadgeType::None,
|
||||
.emojiStatusId = details->iconBgId.toULongLong(),
|
||||
.emojiStatusInnerId = details->iconFgId.toULongLong(),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
Cover::Cover(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
|
@ -308,6 +323,17 @@ Cover::Cover(
|
|||
, _emojiStatusPanel(peer->isSelf()
|
||||
? std::make_unique<EmojiStatusPanel>()
|
||||
: nullptr)
|
||||
, _verify(
|
||||
std::make_unique<Badge>(
|
||||
this,
|
||||
st::infoPeerBadge,
|
||||
&peer->session(),
|
||||
VerifyBadgeForPeer(peer),
|
||||
nullptr,
|
||||
[=] {
|
||||
return controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::Layer);
|
||||
}))
|
||||
, _badge(
|
||||
std::make_unique<Badge>(
|
||||
this,
|
||||
|
@ -359,7 +385,10 @@ Cover::Cover(
|
|||
::Settings::ShowEmojiStatusPremium(_controller, _peer);
|
||||
}
|
||||
});
|
||||
_badge->updated() | rpl::start_with_next([=] {
|
||||
rpl::merge(
|
||||
_verify->updated(),
|
||||
_badge->updated()
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshNameGeometry(width());
|
||||
}, _name->lifetime());
|
||||
|
||||
|
@ -699,11 +728,17 @@ void Cover::refreshNameGeometry(int newWidth) {
|
|||
if (const auto widget = _badge->widget()) {
|
||||
nameWidth -= st::infoVerifiedCheckPosition.x() + widget->width();
|
||||
}
|
||||
_name->resizeToNaturalWidth(nameWidth);
|
||||
_name->moveToLeft(_st.nameLeft, _st.nameTop, newWidth);
|
||||
const auto badgeLeft = _st.nameLeft + _name->width();
|
||||
auto nameLeft = _st.nameLeft;
|
||||
const auto badgeTop = _st.nameTop;
|
||||
const auto badgeBottom = _st.nameTop + _name->height();
|
||||
_verify->move(nameLeft, badgeTop, badgeBottom);
|
||||
if (const auto widget = _verify->widget()) {
|
||||
nameLeft += widget->width() + st::infoVerifiedCheckPosition.x();
|
||||
nameWidth -= widget->width() + st::infoVerifiedCheckPosition.x();
|
||||
}
|
||||
_name->resizeToNaturalWidth(nameWidth);
|
||||
_name->moveToLeft(nameLeft, _st.nameTop, newWidth);
|
||||
const auto badgeLeft = nameLeft + _name->width();
|
||||
_badge->move(badgeLeft, badgeTop, badgeBottom);
|
||||
}
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ private:
|
|||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<PeerData*> _peer;
|
||||
const std::unique_ptr<EmojiStatusPanel> _emojiStatusPanel;
|
||||
const std::unique_ptr<Badge> _verify;
|
||||
const std::unique_ptr<Badge> _badge;
|
||||
rpl::variable<int> _onlineCount;
|
||||
|
||||
|
|
|
@ -659,8 +659,6 @@ rpl::producer<BadgeType> BadgeValueFromFlags(Peer peer) {
|
|||
? BadgeType::Scam
|
||||
: (value & Flag::Fake)
|
||||
? BadgeType::Fake
|
||||
: (value & Flag::Verified)
|
||||
? BadgeType::Verified
|
||||
: premium
|
||||
? BadgeType::Premium
|
||||
: BadgeType::None;
|
||||
|
|
|
@ -203,6 +203,7 @@ settingsInfoPeerBadge: InfoPeerBadge {
|
|||
};
|
||||
premium: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBg }};
|
||||
premiumFg: dialogsVerifiedIconBg;
|
||||
premiumInnerFg: dialogsVerifiedIconFg;
|
||||
sizeTag: 0; // Normal
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,13 @@ struct PeerBadge::EmojiStatus {
|
|||
int skip = 0;
|
||||
};
|
||||
|
||||
struct PeerBadge::VerifiedData {
|
||||
QImage cache;
|
||||
QImage cacheFg;
|
||||
std::unique_ptr<Text::CustomEmoji> bg;
|
||||
std::unique_ptr<Text::CustomEmoji> fg;
|
||||
};
|
||||
|
||||
void UnreadBadge::setText(const QString &text, bool active) {
|
||||
_text = text;
|
||||
_active = active;
|
||||
|
@ -193,14 +200,6 @@ int PeerBadge::drawGetWidth(
|
|||
.paused = descriptor.paused || On(PowerSaving::kEmojiStatus),
|
||||
});
|
||||
return iconw - 4 * _emojiStatus->skip;
|
||||
} else if (descriptor.verified && peer->isVerified()) {
|
||||
const auto iconw = descriptor.verified->width();
|
||||
descriptor.verified->paint(
|
||||
p,
|
||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
||||
rectForName.y(),
|
||||
outerWidth);
|
||||
return iconw;
|
||||
} else if (descriptor.premium
|
||||
&& peer->isPremium()
|
||||
&& peer->session().premiumBadgesShown()) {
|
||||
|
@ -219,4 +218,70 @@ void PeerBadge::unload() {
|
|||
_emojiStatus = nullptr;
|
||||
}
|
||||
|
||||
bool PeerBadge::ready(const VerifyDetails *details) const {
|
||||
if (!details || !*details) {
|
||||
_verifiedData = nullptr;
|
||||
return true;
|
||||
} else if (!_verifiedData) {
|
||||
return false;
|
||||
}
|
||||
if (details->iconBgId.isEmpty()) {
|
||||
_verifiedData->bg = nullptr;
|
||||
} else if (!_verifiedData->bg
|
||||
|| _verifiedData->bg->entityData() != details->iconBgId) {
|
||||
return false;
|
||||
}
|
||||
if (details->iconFgId.isEmpty()) {
|
||||
_verifiedData->fg = nullptr;
|
||||
} else if (!_verifiedData->fg
|
||||
|| _verifiedData->fg->entityData() != details->iconFgId) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PeerBadge::set(
|
||||
not_null<const VerifyDetails*> details,
|
||||
Ui::Text::CustomEmojiFactory factory,
|
||||
Fn<void()> repaint) {
|
||||
if (!_verifiedData) {
|
||||
_verifiedData = std::make_unique<VerifiedData>();
|
||||
}
|
||||
if (!details->iconBgId.isEmpty()) {
|
||||
_verifiedData->bg = factory(details->iconBgId, repaint);
|
||||
}
|
||||
if (!details->iconFgId.isEmpty()) {
|
||||
_verifiedData->fg = factory(details->iconFgId, repaint);
|
||||
}
|
||||
}
|
||||
|
||||
int PeerBadge::drawVerified(
|
||||
QPainter &p,
|
||||
QPoint position,
|
||||
const style::VerifiedBadge &st) {
|
||||
const auto data = _verifiedData.get();
|
||||
if (!data) {
|
||||
return 0;
|
||||
}
|
||||
const auto now = crl::now();
|
||||
auto result = 0;
|
||||
if (const auto bg = data->bg.get()) {
|
||||
bg->paint(p, {
|
||||
.textColor = st.bg->c,
|
||||
.now = now,
|
||||
.position = position,
|
||||
});
|
||||
result = bg->width();
|
||||
}
|
||||
if (const auto fg = data->fg.get()) {
|
||||
fg->paint(p, {
|
||||
.textColor = st.fg->c,
|
||||
.now = now,
|
||||
.position = position,
|
||||
});
|
||||
result = std::max(result, fg->width());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -7,11 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/text/text_custom_emoji.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Ui::Text {
|
||||
class CustomEmoji;
|
||||
} // namespace Ui::Text
|
||||
namespace style {
|
||||
struct VerifiedBadge;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui {
|
||||
|
||||
|
@ -31,6 +32,19 @@ private:
|
|||
|
||||
};
|
||||
|
||||
struct VerifyDetails {
|
||||
QString iconBgId;
|
||||
QString iconFgId;
|
||||
TextWithEntities description;
|
||||
|
||||
explicit operator bool() const {
|
||||
return !iconBgId.isEmpty() || !iconFgId.isEmpty();
|
||||
}
|
||||
friend inline bool operator==(
|
||||
const VerifyDetails &,
|
||||
const VerifyDetails &) = default;
|
||||
};
|
||||
|
||||
class PeerBadge {
|
||||
public:
|
||||
PeerBadge();
|
||||
|
@ -54,9 +68,24 @@ public:
|
|||
const Descriptor &descriptor);
|
||||
void unload();
|
||||
|
||||
[[nodiscard]] bool ready(const VerifyDetails *details) const;
|
||||
void set(
|
||||
not_null<const VerifyDetails*> details,
|
||||
Text::CustomEmojiFactory factory,
|
||||
Fn<void()> repaint);
|
||||
|
||||
// How much horizontal space the badge took.
|
||||
int drawVerified(
|
||||
QPainter &p,
|
||||
QPoint position,
|
||||
const style::VerifiedBadge &st);
|
||||
|
||||
private:
|
||||
struct EmojiStatus;
|
||||
struct VerifiedData;
|
||||
|
||||
std::unique_ptr<EmojiStatus> _emojiStatus;
|
||||
mutable std::unique_ptr<VerifiedData> _verifiedData;
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue