mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show emoji status in chats list / top bar.
This commit is contained in:
parent
285ce81b7b
commit
21fd381778
17 changed files with 386 additions and 177 deletions
|
@ -78,26 +78,27 @@ struct PeerUpdate {
|
||||||
HasCalls = (1ULL << 19),
|
HasCalls = (1ULL << 19),
|
||||||
SupportInfo = (1ULL << 20),
|
SupportInfo = (1ULL << 20),
|
||||||
IsBot = (1ULL << 21),
|
IsBot = (1ULL << 21),
|
||||||
|
EmojiStatus = (1ULL << 22),
|
||||||
|
|
||||||
// For chats and channels
|
// For chats and channels
|
||||||
InviteLinks = (1ULL << 22),
|
InviteLinks = (1ULL << 23),
|
||||||
Members = (1ULL << 23),
|
Members = (1ULL << 24),
|
||||||
Admins = (1ULL << 24),
|
Admins = (1ULL << 25),
|
||||||
BannedUsers = (1ULL << 25),
|
BannedUsers = (1ULL << 26),
|
||||||
Rights = (1ULL << 26),
|
Rights = (1ULL << 27),
|
||||||
PendingRequests = (1ULL << 27),
|
PendingRequests = (1ULL << 28),
|
||||||
Reactions = (1ULL << 28),
|
Reactions = (1ULL << 29),
|
||||||
|
|
||||||
// For channels
|
// For channels
|
||||||
ChannelAmIn = (1ULL << 29),
|
ChannelAmIn = (1ULL << 30),
|
||||||
StickersSet = (1ULL << 30),
|
StickersSet = (1ULL << 31),
|
||||||
ChannelLinkedChat = (1ULL << 31),
|
ChannelLinkedChat = (1ULL << 32),
|
||||||
ChannelLocation = (1ULL << 32),
|
ChannelLocation = (1ULL << 33),
|
||||||
Slowmode = (1ULL << 33),
|
Slowmode = (1ULL << 34),
|
||||||
GroupCall = (1ULL << 34),
|
GroupCall = (1ULL << 35),
|
||||||
|
|
||||||
// For iteration
|
// For iteration
|
||||||
LastUsedBit = (1ULL << 34),
|
LastUsedBit = (1ULL << 35),
|
||||||
};
|
};
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||||
|
|
|
@ -400,6 +400,11 @@ ChannelData *Session::channelLoaded(ChannelId id) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AssertIsDebug();
|
||||||
|
base::flat_map<
|
||||||
|
not_null<Data::Session*>,
|
||||||
|
base::flat_set<not_null<DocumentData*>>> Emojis;
|
||||||
|
|
||||||
not_null<UserData*> Session::processUser(const MTPUser &data) {
|
not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||||
const auto result = user(data.match([](const auto &data) {
|
const auto result = user(data.match([](const auto &data) {
|
||||||
return data.vid().v;
|
return data.vid().v;
|
||||||
|
@ -554,6 +559,26 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||||
}
|
}
|
||||||
status = data.vstatus();
|
status = data.vstatus();
|
||||||
}
|
}
|
||||||
|
if (const auto &status = data.vemoji_status()) {
|
||||||
|
result->setEmojiStatus(status->match([&](
|
||||||
|
const MTPDemojiStatus &data) {
|
||||||
|
return DocumentId(data.vdocument_id().v);
|
||||||
|
}, [&](const MTPDemojiStatusEmpty &) {
|
||||||
|
//return DocumentId();
|
||||||
|
auto &emojis = Emojis[this];
|
||||||
|
return emojis.empty()
|
||||||
|
? DocumentId()
|
||||||
|
: (*(emojis.begin()
|
||||||
|
+ base::RandomIndex(emojis.size())))->id;
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
//result->setEmojiStatus(0);
|
||||||
|
auto &emojis = Emojis[this];
|
||||||
|
result->setEmojiStatus(emojis.empty()
|
||||||
|
? DocumentId()
|
||||||
|
: (*(emojis.begin()
|
||||||
|
+ base::RandomIndex(emojis.size())))->id);
|
||||||
|
}
|
||||||
if (!minimal) {
|
if (!minimal) {
|
||||||
if (const auto botInfoVersion = data.vbot_info_version()) {
|
if (const auto botInfoVersion = data.vbot_info_version()) {
|
||||||
result->setBotInfoVersion(botInfoVersion->v);
|
result->setBotInfoVersion(botInfoVersion->v);
|
||||||
|
@ -2943,6 +2968,23 @@ void Session::documentApplyFields(
|
||||||
if (dc != 0 && access != 0) {
|
if (dc != 0 && access != 0) {
|
||||||
document->setRemoteLocation(dc, access, fileReference);
|
document->setRemoteLocation(dc, access, fileReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AssertIsDebug();
|
||||||
|
if (document->isPremiumEmoji()) {
|
||||||
|
auto &emojis = Emojis[this];
|
||||||
|
if (emojis.emplace(document).second) {
|
||||||
|
const auto size = int(emojis.size());
|
||||||
|
crl::on_main(_session, [=] {
|
||||||
|
for (auto &[id, peer] : _peers) {
|
||||||
|
if (const auto user = peer->asUser()) {
|
||||||
|
if (user->isPremium() && !base::RandomIndex(size)) {
|
||||||
|
user->setEmojiStatus(document->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<WebPageData*> Session::webpage(WebPageId id) {
|
not_null<WebPageData*> Session::webpage(WebPageId id) {
|
||||||
|
|
|
@ -57,6 +57,17 @@ void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserData::setEmojiStatus(DocumentId emojiStatusId) {
|
||||||
|
if (_emojiStatusId != emojiStatusId) {
|
||||||
|
_emojiStatusId = emojiStatusId;
|
||||||
|
session().changes().peerUpdated(this, UpdateFlag::EmojiStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentId UserData::emojiStatusId() const {
|
||||||
|
return _emojiStatusId;
|
||||||
|
}
|
||||||
|
|
||||||
auto UserData::unavailableReasons() const
|
auto UserData::unavailableReasons() const
|
||||||
-> const std::vector<Data::UnavailableReason> & {
|
-> const std::vector<Data::UnavailableReason> & {
|
||||||
return _unavailableReasons;
|
return _unavailableReasons;
|
||||||
|
|
|
@ -71,6 +71,9 @@ public:
|
||||||
const QString &newPhoneName,
|
const QString &newPhoneName,
|
||||||
const QString &newUsername);
|
const QString &newUsername);
|
||||||
|
|
||||||
|
void setEmojiStatus(DocumentId emojiStatusId);
|
||||||
|
[[nodiscard]] DocumentId emojiStatusId() const;
|
||||||
|
|
||||||
void setPhone(const QString &newPhone);
|
void setPhone(const QString &newPhone);
|
||||||
void setBotInfoVersion(int version);
|
void setBotInfoVersion(int version);
|
||||||
void setBotInfo(const MTPBotInfo &info);
|
void setBotInfo(const MTPBotInfo &info);
|
||||||
|
@ -168,6 +171,8 @@ private:
|
||||||
static constexpr auto kInaccessibleAccessHashOld
|
static constexpr auto kInaccessibleAccessHashOld
|
||||||
= 0xFFFFFFFFFFFFFFFFULL;
|
= 0xFFFFFFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
DocumentId _emojiStatusId = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/flat_map.h"
|
#include "base/flat_map.h"
|
||||||
|
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
|
#include "ui/unread_badge.h"
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
|
@ -188,6 +189,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const Ui::Text::String &chatListNameText() const;
|
[[nodiscard]] const Ui::Text::String &chatListNameText() const;
|
||||||
|
[[nodiscard]] Ui::PeerBadge &chatListBadge() const {
|
||||||
|
return _chatListBadge;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void notifyUnreadStateChange(const UnreadState &wasState);
|
void notifyUnreadStateChange(const UnreadState &wasState);
|
||||||
|
@ -221,6 +225,7 @@ private:
|
||||||
uint64 _sortKeyInChatList = 0;
|
uint64 _sortKeyInChatList = 0;
|
||||||
uint64 _sortKeyByDate = 0;
|
uint64 _sortKeyByDate = 0;
|
||||||
base::flat_map<FilterId, int> _pinnedIndex;
|
base::flat_map<FilterId, int> _pinnedIndex;
|
||||||
|
mutable Ui::PeerBadge _chatListBadge;
|
||||||
mutable Ui::Text::String _chatListNameText;
|
mutable Ui::Text::String _chatListNameText;
|
||||||
mutable int _chatListNameVersion = 0;
|
mutable int _chatListNameVersion = 0;
|
||||||
TimeId _timeId = 0;
|
TimeId _timeId = 0;
|
||||||
|
|
|
@ -122,6 +122,7 @@ struct InnerWidget::PeerSearchResult {
|
||||||
}
|
}
|
||||||
not_null<PeerData*> peer;
|
not_null<PeerData*> peer;
|
||||||
mutable Ui::Text::String name;
|
mutable Ui::Text::String name;
|
||||||
|
mutable Ui::PeerBadge badge;
|
||||||
BasicRow row;
|
BasicRow row;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -614,7 +615,14 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
const auto selected = (from == (isPressed()
|
const auto selected = (from == (isPressed()
|
||||||
? _peerSearchPressed
|
? _peerSearchPressed
|
||||||
: _peerSearchSelected));
|
: _peerSearchSelected));
|
||||||
paintPeerSearchResult(p, result.get(), fullWidth, active, selected);
|
paintPeerSearchResult(
|
||||||
|
p,
|
||||||
|
result.get(),
|
||||||
|
fullWidth,
|
||||||
|
active,
|
||||||
|
selected,
|
||||||
|
ms,
|
||||||
|
videoPaused);
|
||||||
p.translate(0, st::dialogsRowHeight);
|
p.translate(0, st::dialogsRowHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -767,7 +775,9 @@ void InnerWidget::paintPeerSearchResult(
|
||||||
not_null<const PeerSearchResult*> result,
|
not_null<const PeerSearchResult*> result,
|
||||||
int fullWidth,
|
int fullWidth,
|
||||||
bool active,
|
bool active,
|
||||||
bool selected) const {
|
bool selected,
|
||||||
|
crl::time now,
|
||||||
|
bool paused) {
|
||||||
QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight);
|
QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight);
|
||||||
p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg));
|
p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg));
|
||||||
if (!active) {
|
if (!active) {
|
||||||
|
@ -794,29 +804,37 @@ void InnerWidget::paintPeerSearchResult(
|
||||||
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
|
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
|
||||||
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
|
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
|
||||||
}
|
}
|
||||||
const auto badgeStyle = Ui::PeerBadgeStyle{
|
const auto badgeWidth = result->badge.drawGetWidth(
|
||||||
(active
|
|
||||||
? &st::dialogsVerifiedIconActive
|
|
||||||
: selected
|
|
||||||
? &st::dialogsVerifiedIconOver
|
|
||||||
: &st::dialogsVerifiedIcon),
|
|
||||||
(active
|
|
||||||
? &st::dialogsPremiumIconActive
|
|
||||||
: selected
|
|
||||||
? &st::dialogsPremiumIconOver
|
|
||||||
: &st::dialogsPremiumIcon),
|
|
||||||
(active
|
|
||||||
? &st::dialogsScamFgActive
|
|
||||||
: selected
|
|
||||||
? &st::dialogsScamFgOver
|
|
||||||
: &st::dialogsScamFg) };
|
|
||||||
const auto badgeWidth = Ui::DrawPeerBadgeGetWidth(
|
|
||||||
peer,
|
|
||||||
p,
|
p,
|
||||||
rectForName,
|
rectForName,
|
||||||
result->name.maxWidth(),
|
result->name.maxWidth(),
|
||||||
fullWidth,
|
fullWidth,
|
||||||
badgeStyle);
|
{
|
||||||
|
.peer = peer,
|
||||||
|
.verified = (active
|
||||||
|
? &st::dialogsVerifiedIconActive
|
||||||
|
: selected
|
||||||
|
? &st::dialogsVerifiedIconOver
|
||||||
|
: &st::dialogsVerifiedIcon),
|
||||||
|
.premium = (active
|
||||||
|
? &st::dialogsPremiumIconActive
|
||||||
|
: selected
|
||||||
|
? &st::dialogsPremiumIconOver
|
||||||
|
: &st::dialogsPremiumIcon),
|
||||||
|
.scam = (active
|
||||||
|
? &st::dialogsScamFgActive
|
||||||
|
: selected
|
||||||
|
? &st::dialogsScamFgOver
|
||||||
|
: &st::dialogsScamFg),
|
||||||
|
.preview = (active
|
||||||
|
? st::dialogsScamFgActive
|
||||||
|
: selected
|
||||||
|
? st::windowBgRipple
|
||||||
|
: st::windowBgOver)->c,
|
||||||
|
.customEmojiRepaint = [=] { updateSearchResult(peer); },
|
||||||
|
.now = now,
|
||||||
|
.paused = paused,
|
||||||
|
});
|
||||||
rectForName.setWidth(rectForName.width() - badgeWidth);
|
rectForName.setWidth(rectForName.width() - badgeWidth);
|
||||||
|
|
||||||
QRect tr(nameleft, st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip, namewidth, st::dialogsTextFont->height);
|
QRect tr(nameleft, st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip, namewidth, st::dialogsTextFont->height);
|
||||||
|
@ -1119,9 +1137,7 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
[this, peer = result->peer] { updateSearchResult(peer); });
|
[this, peer = result->peer] { updateSearchResult(peer); });
|
||||||
} else if (base::in_range(_searchedPressed, 0, _searchResults.size())) {
|
} else if (base::in_range(_searchedPressed, 0, _searchResults.size())) {
|
||||||
auto &row = _searchResults[_searchedPressed];
|
auto &row = _searchResults[_searchedPressed];
|
||||||
row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * st::dialogsRowHeight), QSize(width(), st::dialogsRowHeight), [this, index = _searchedPressed] {
|
row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * st::dialogsRowHeight), QSize(width(), st::dialogsRowHeight), row->repaint());
|
||||||
rtlupdate(0, searchedOffset() + index * st::dialogsRowHeight, width(), st::dialogsRowHeight);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (anim::Disabled()
|
if (anim::Disabled()
|
||||||
&& (!_pressed || !_pressed->entry()->isPinnedDialog(_filterId))) {
|
&& (!_pressed || !_pressed->entry()->isPinnedDialog(_filterId))) {
|
||||||
|
@ -2122,10 +2138,12 @@ bool InnerWidget::searchReceived(
|
||||||
&& (!_searchInChat
|
&& (!_searchInChat
|
||||||
|| inject->history() == _searchInChat.history())) {
|
|| inject->history() == _searchInChat.history())) {
|
||||||
Assert(_searchResults.empty());
|
Assert(_searchResults.empty());
|
||||||
|
const auto index = int(_searchResults.size());
|
||||||
_searchResults.push_back(
|
_searchResults.push_back(
|
||||||
std::make_unique<FakeRow>(
|
std::make_unique<FakeRow>(
|
||||||
_searchInChat,
|
_searchInChat,
|
||||||
inject));
|
inject,
|
||||||
|
[=] { repaintSearchResult(index); }));
|
||||||
++fullCount;
|
++fullCount;
|
||||||
}
|
}
|
||||||
for (const auto &message : messages) {
|
for (const auto &message : messages) {
|
||||||
|
@ -2140,10 +2158,12 @@ bool InnerWidget::searchReceived(
|
||||||
NewMessageType::Existing);
|
NewMessageType::Existing);
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
if (!uniquePeers || !hasHistoryInResults(history)) {
|
if (!uniquePeers || !hasHistoryInResults(history)) {
|
||||||
|
const auto index = int(_searchResults.size());
|
||||||
_searchResults.push_back(
|
_searchResults.push_back(
|
||||||
std::make_unique<FakeRow>(
|
std::make_unique<FakeRow>(
|
||||||
_searchInChat,
|
_searchInChat,
|
||||||
item));
|
item,
|
||||||
|
[=] { repaintSearchResult(index); }));
|
||||||
if (uniquePeers && !history->unreadCountKnown()) {
|
if (uniquePeers && !history->unreadCountKnown()) {
|
||||||
history->owner().histories().requestDialogEntry(history);
|
history->owner().histories().requestDialogEntry(history);
|
||||||
}
|
}
|
||||||
|
@ -2459,6 +2479,14 @@ void InnerWidget::refreshSearchInChatLabel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerWidget::repaintSearchResult(int index) {
|
||||||
|
rtlupdate(
|
||||||
|
0,
|
||||||
|
searchedOffset() + index * st::dialogsRowHeight,
|
||||||
|
|
||||||
|
width(), st::dialogsRowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
void InnerWidget::clearFilter() {
|
void InnerWidget::clearFilter() {
|
||||||
if (_state == WidgetState::Filtered || _searchInChat) {
|
if (_state == WidgetState::Filtered || _searchInChat) {
|
||||||
if (_searchInChat) {
|
if (_searchInChat) {
|
||||||
|
|
|
@ -294,7 +294,9 @@ private:
|
||||||
not_null<const PeerSearchResult*> result,
|
not_null<const PeerSearchResult*> result,
|
||||||
int fullWidth,
|
int fullWidth,
|
||||||
bool active,
|
bool active,
|
||||||
bool selected) const;
|
bool selected,
|
||||||
|
crl::time now,
|
||||||
|
bool paused);
|
||||||
void paintSearchInChat(Painter &p) const;
|
void paintSearchInChat(Painter &p) const;
|
||||||
void paintSearchInPeer(
|
void paintSearchInPeer(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
|
@ -318,6 +320,7 @@ private:
|
||||||
const style::icon *icon,
|
const style::icon *icon,
|
||||||
const Ui::Text::String &text) const;
|
const Ui::Text::String &text) const;
|
||||||
void refreshSearchInChatLabel();
|
void refreshSearchInChatLabel();
|
||||||
|
void repaintSearchResult(int index);
|
||||||
|
|
||||||
Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row);
|
Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row);
|
||||||
Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history);
|
Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history);
|
||||||
|
|
|
@ -339,9 +339,13 @@ void Row::paintUserpic(
|
||||||
p.setOpacity(1.);
|
p.setOpacity(1.);
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeRow::FakeRow(Key searchInChat, not_null<HistoryItem*> item)
|
FakeRow::FakeRow(
|
||||||
|
Key searchInChat,
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
Fn<void()> repaint)
|
||||||
: _searchInChat(searchInChat)
|
: _searchInChat(searchInChat)
|
||||||
, _item(item) {
|
, _item(item)
|
||||||
|
, _repaint(std::move(repaint)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Ui::Text::String &FakeRow::name() const {
|
const Ui::Text::String &FakeRow::name() const {
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "ui/text/text.h"
|
#include "ui/text/text.h"
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
|
#include "ui/unread_badge.h"
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
#include "dialogs/ui/dialogs_message_view.h"
|
#include "dialogs/ui/dialogs_message_view.h"
|
||||||
|
|
||||||
|
@ -147,7 +148,10 @@ private:
|
||||||
|
|
||||||
class FakeRow : public BasicRow {
|
class FakeRow : public BasicRow {
|
||||||
public:
|
public:
|
||||||
FakeRow(Key searchInChat, not_null<HistoryItem*> item);
|
FakeRow(
|
||||||
|
Key searchInChat,
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
Fn<void()> repaint);
|
||||||
|
|
||||||
[[nodiscard]] Key searchInChat() const {
|
[[nodiscard]] Key searchInChat() const {
|
||||||
return _searchInChat;
|
return _searchInChat;
|
||||||
|
@ -158,14 +162,22 @@ public:
|
||||||
[[nodiscard]] Ui::MessageView &itemView() const {
|
[[nodiscard]] Ui::MessageView &itemView() const {
|
||||||
return _itemView;
|
return _itemView;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] Fn<void()> repaint() const {
|
||||||
|
return _repaint;
|
||||||
|
}
|
||||||
|
[[nodiscard]] Ui::PeerBadge &badge() const {
|
||||||
|
return _badge;
|
||||||
|
}
|
||||||
[[nodiscard]] const Ui::Text::String &name() const;
|
[[nodiscard]] const Ui::Text::String &name() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Ui::RowPainter;
|
friend class Ui::RowPainter;
|
||||||
|
|
||||||
Key _searchInChat;
|
const Key _searchInChat;
|
||||||
not_null<HistoryItem*> _item;
|
const not_null<HistoryItem*> _item;
|
||||||
|
const Fn<void()> _repaint;
|
||||||
mutable Ui::MessageView _itemView;
|
mutable Ui::MessageView _itemView;
|
||||||
|
mutable Ui::PeerBadge _badge;
|
||||||
mutable Ui::Text::String _name;
|
mutable Ui::Text::String _name;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -311,6 +311,8 @@ void paintRow(
|
||||||
VideoUserpic *videoUserpic,
|
VideoUserpic *videoUserpic,
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
PeerData *from,
|
PeerData *from,
|
||||||
|
Ui::PeerBadge &fromBadge,
|
||||||
|
Fn<void()> customEmojiRepaint,
|
||||||
const Ui::Text::String &fromName,
|
const Ui::Text::String &fromName,
|
||||||
const HiddenSenderInfo *hiddenSenderInfo,
|
const HiddenSenderInfo *hiddenSenderInfo,
|
||||||
HistoryItem *item,
|
HistoryItem *item,
|
||||||
|
@ -474,9 +476,7 @@ void paintRow(
|
||||||
Text::WithEntities);
|
Text::WithEntities);
|
||||||
const auto context = Core::MarkedTextContext{
|
const auto context = Core::MarkedTextContext{
|
||||||
.session = &history->session(),
|
.session = &history->session(),
|
||||||
.customEmojiRepaint = [=] {
|
.customEmojiRepaint = customEmojiRepaint,
|
||||||
history->updateChatListEntry();
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
history->cloudDraftTextCache.setMarkedText(
|
history->cloudDraftTextCache.setMarkedText(
|
||||||
st::dialogsTextStyle,
|
st::dialogsTextStyle,
|
||||||
|
@ -570,30 +570,38 @@ void paintRow(
|
||||||
: st::dialogsNameFg);
|
: st::dialogsNameFg);
|
||||||
p.drawTextLeft(rectForName.left(), rectForName.top(), fullWidth, text);
|
p.drawTextLeft(rectForName.left(), rectForName.top(), fullWidth, text);
|
||||||
} else if (from) {
|
} else if (from) {
|
||||||
if (!(flags & Flag::SearchResult)) {
|
if (history && !(flags & Flag::SearchResult)) {
|
||||||
const auto badgeStyle = PeerBadgeStyle{
|
const auto badgeWidth = fromBadge.drawGetWidth(
|
||||||
(active
|
|
||||||
? &st::dialogsVerifiedIconActive
|
|
||||||
: selected
|
|
||||||
? &st::dialogsVerifiedIconOver
|
|
||||||
: &st::dialogsVerifiedIcon),
|
|
||||||
(active
|
|
||||||
? &st::dialogsPremiumIconActive
|
|
||||||
: selected
|
|
||||||
? &st::dialogsPremiumIconOver
|
|
||||||
: &st::dialogsPremiumIcon),
|
|
||||||
(active
|
|
||||||
? &st::dialogsScamFgActive
|
|
||||||
: selected
|
|
||||||
? &st::dialogsScamFgOver
|
|
||||||
: &st::dialogsScamFg) };
|
|
||||||
const auto badgeWidth = DrawPeerBadgeGetWidth(
|
|
||||||
from,
|
|
||||||
p,
|
p,
|
||||||
rectForName,
|
rectForName,
|
||||||
fromName.maxWidth(),
|
fromName.maxWidth(),
|
||||||
fullWidth,
|
fullWidth,
|
||||||
badgeStyle);
|
{
|
||||||
|
.peer = from,
|
||||||
|
.verified = (active
|
||||||
|
? &st::dialogsVerifiedIconActive
|
||||||
|
: selected
|
||||||
|
? &st::dialogsVerifiedIconOver
|
||||||
|
: &st::dialogsVerifiedIcon),
|
||||||
|
.premium = (active
|
||||||
|
? &st::dialogsPremiumIconActive
|
||||||
|
: selected
|
||||||
|
? &st::dialogsPremiumIconOver
|
||||||
|
: &st::dialogsPremiumIcon),
|
||||||
|
.scam = (active
|
||||||
|
? &st::dialogsScamFgActive
|
||||||
|
: selected
|
||||||
|
? &st::dialogsScamFgOver
|
||||||
|
: &st::dialogsScamFg),
|
||||||
|
.preview = (active
|
||||||
|
? st::dialogsScamFgActive
|
||||||
|
: selected
|
||||||
|
? st::windowBgRipple
|
||||||
|
: st::windowBgOver)->c,
|
||||||
|
.customEmojiRepaint = customEmojiRepaint,
|
||||||
|
.now = ms,
|
||||||
|
.paused = bool(flags & Flag::VideoPaused),
|
||||||
|
});
|
||||||
rectForName.setWidth(rectForName.width() - badgeWidth);
|
rectForName.setWidth(rectForName.width() - badgeWidth);
|
||||||
}
|
}
|
||||||
p.setPen(active
|
p.setPen(active
|
||||||
|
@ -911,7 +919,7 @@ void RowPainter::paint(
|
||||||
: (selected
|
: (selected
|
||||||
? st::dialogsTextFgServiceOver
|
? st::dialogsTextFgServiceOver
|
||||||
: st::dialogsTextFgService);
|
: st::dialogsTextFgService);
|
||||||
const auto itemRect = QRect(
|
const auto rect = QRect(
|
||||||
nameleft,
|
nameleft,
|
||||||
texttop,
|
texttop,
|
||||||
availableWidth,
|
availableWidth,
|
||||||
|
@ -919,23 +927,23 @@ void RowPainter::paint(
|
||||||
const auto actionWasPainted = ShowSendActionInDialogs(history)
|
const auto actionWasPainted = ShowSendActionInDialogs(history)
|
||||||
? history->sendActionPainter()->paint(
|
? history->sendActionPainter()->paint(
|
||||||
p,
|
p,
|
||||||
itemRect.x(),
|
rect.x(),
|
||||||
itemRect.y(),
|
rect.y(),
|
||||||
itemRect.width(),
|
rect.width(),
|
||||||
fullWidth,
|
fullWidth,
|
||||||
color,
|
color,
|
||||||
ms)
|
ms)
|
||||||
: false;
|
: false;
|
||||||
if (const auto folder = row->folder()) {
|
if (const auto folder = row->folder()) {
|
||||||
PaintListEntryText(p, itemRect, active, selected, row);
|
PaintListEntryText(p, rect, active, selected, row);
|
||||||
} else if (history && !actionWasPainted) {
|
} else if (history && !actionWasPainted) {
|
||||||
history->lastItemDialogsView.paint(
|
if (!history->lastItemDialogsView.prepared(item)) {
|
||||||
p,
|
history->lastItemDialogsView.prepare(
|
||||||
item,
|
item,
|
||||||
itemRect,
|
[=] { history->updateChatListEntry(); },
|
||||||
active,
|
{});
|
||||||
selected,
|
}
|
||||||
{});
|
history->lastItemDialogsView.paint(p, rect, active, selected);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto paintCounterCallback = [&] {
|
const auto paintCounterCallback = [&] {
|
||||||
|
@ -959,6 +967,8 @@ void RowPainter::paint(
|
||||||
videoUserpic,
|
videoUserpic,
|
||||||
filterId,
|
filterId,
|
||||||
from,
|
from,
|
||||||
|
entry->chatListBadge(),
|
||||||
|
[=] { history->updateChatListEntry(); },
|
||||||
entry->chatListNameText(),
|
entry->chatListNameText(),
|
||||||
nullptr,
|
nullptr,
|
||||||
item,
|
item,
|
||||||
|
@ -1056,13 +1066,11 @@ void RowPainter::paint(
|
||||||
texttop,
|
texttop,
|
||||||
availableWidth,
|
availableWidth,
|
||||||
st::dialogsTextFont->height);
|
st::dialogsTextFont->height);
|
||||||
row->itemView().paint(
|
auto &view = row->itemView();
|
||||||
p,
|
if (!view.prepared(item)) {
|
||||||
item,
|
view.prepare(item, row->repaint(), previewOptions);
|
||||||
itemRect,
|
}
|
||||||
active,
|
row->itemView().paint(p, itemRect, active, selected);
|
||||||
selected,
|
|
||||||
previewOptions);
|
|
||||||
};
|
};
|
||||||
const auto paintCounterCallback = [&] {
|
const auto paintCounterCallback = [&] {
|
||||||
PaintNarrowCounter(
|
PaintNarrowCounter(
|
||||||
|
@ -1094,6 +1102,8 @@ void RowPainter::paint(
|
||||||
nullptr,
|
nullptr,
|
||||||
FilterId(),
|
FilterId(),
|
||||||
from,
|
from,
|
||||||
|
row->badge(),
|
||||||
|
row->repaint(),
|
||||||
row->name(),
|
row->name(),
|
||||||
hiddenSenderInfo,
|
hiddenSenderInfo,
|
||||||
item,
|
item,
|
||||||
|
|
|
@ -109,63 +109,67 @@ bool MessageView::dependsOn(not_null<const HistoryItem*> item) const {
|
||||||
return (_textCachedFor == item.get());
|
return (_textCachedFor == item.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MessageView::prepared(not_null<const HistoryItem*> item) const {
|
||||||
|
return (_textCachedFor == item.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageView::prepare(
|
||||||
|
not_null<const HistoryItem*> item,
|
||||||
|
Fn<void()> customEmojiRepaint,
|
||||||
|
ToPreviewOptions options) {
|
||||||
|
options.existing = &_imagesCache;
|
||||||
|
auto preview = item->toPreview(options);
|
||||||
|
if (!preview.images.empty() && preview.imagesInTextPosition > 0) {
|
||||||
|
auto sender = ::Ui::Text::Mid(
|
||||||
|
preview.text,
|
||||||
|
0,
|
||||||
|
preview.imagesInTextPosition);
|
||||||
|
TextUtilities::Trim(sender);
|
||||||
|
_senderCache.setMarkedText(
|
||||||
|
st::dialogsTextStyle,
|
||||||
|
std::move(sender),
|
||||||
|
DialogTextOptions());
|
||||||
|
preview.text = ::Ui::Text::Mid(
|
||||||
|
preview.text,
|
||||||
|
preview.imagesInTextPosition);
|
||||||
|
} else {
|
||||||
|
_senderCache = { st::dialogsTextWidthMin };
|
||||||
|
}
|
||||||
|
TextUtilities::Trim(preview.text);
|
||||||
|
const auto history = item->history();
|
||||||
|
const auto context = Core::MarkedTextContext{
|
||||||
|
.session = &history->session(),
|
||||||
|
.customEmojiRepaint = customEmojiRepaint,
|
||||||
|
};
|
||||||
|
_textCache.setMarkedText(
|
||||||
|
st::dialogsTextStyle,
|
||||||
|
DialogsPreviewText(std::move(preview.text)),
|
||||||
|
DialogTextOptions(),
|
||||||
|
context);
|
||||||
|
_textCachedFor = item;
|
||||||
|
_imagesCache = std::move(preview.images);
|
||||||
|
if (preview.loadingContext.has_value()) {
|
||||||
|
if (!_loadingContext) {
|
||||||
|
_loadingContext = std::make_unique<LoadingContext>();
|
||||||
|
item->history()->session().downloaderTaskFinished(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_textCachedFor = nullptr;
|
||||||
|
}, _loadingContext->lifetime);
|
||||||
|
}
|
||||||
|
_loadingContext->context = std::move(preview.loadingContext);
|
||||||
|
} else {
|
||||||
|
_loadingContext = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageView::paint(
|
void MessageView::paint(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<const HistoryItem*> item,
|
|
||||||
const QRect &geometry,
|
const QRect &geometry,
|
||||||
bool active,
|
bool active,
|
||||||
bool selected,
|
bool selected) const {
|
||||||
ToPreviewOptions options) const {
|
|
||||||
if (geometry.isEmpty()) {
|
if (geometry.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_textCachedFor != item.get()) {
|
|
||||||
options.existing = &_imagesCache;
|
|
||||||
auto preview = item->toPreview(options);
|
|
||||||
if (!preview.images.empty() && preview.imagesInTextPosition > 0) {
|
|
||||||
auto sender = ::Ui::Text::Mid(
|
|
||||||
preview.text,
|
|
||||||
0,
|
|
||||||
preview.imagesInTextPosition);
|
|
||||||
TextUtilities::Trim(sender);
|
|
||||||
_senderCache.setMarkedText(
|
|
||||||
st::dialogsTextStyle,
|
|
||||||
std::move(sender),
|
|
||||||
DialogTextOptions());
|
|
||||||
preview.text = ::Ui::Text::Mid(
|
|
||||||
preview.text,
|
|
||||||
preview.imagesInTextPosition);
|
|
||||||
} else {
|
|
||||||
_senderCache = { st::dialogsTextWidthMin };
|
|
||||||
}
|
|
||||||
TextUtilities::Trim(preview.text);
|
|
||||||
const auto history = item->history();
|
|
||||||
const auto context = Core::MarkedTextContext{
|
|
||||||
.session = &history->session(),
|
|
||||||
.customEmojiRepaint = [=] {
|
|
||||||
history->updateChatListEntry();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
_textCache.setMarkedText(
|
|
||||||
st::dialogsTextStyle,
|
|
||||||
DialogsPreviewText(std::move(preview.text)),
|
|
||||||
DialogTextOptions(),
|
|
||||||
context);
|
|
||||||
_textCachedFor = item;
|
|
||||||
_imagesCache = std::move(preview.images);
|
|
||||||
if (preview.loadingContext.has_value()) {
|
|
||||||
if (!_loadingContext) {
|
|
||||||
_loadingContext = std::make_unique<LoadingContext>();
|
|
||||||
item->history()->session().downloaderTaskFinished(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
_textCachedFor = nullptr;
|
|
||||||
}, _loadingContext->lifetime);
|
|
||||||
}
|
|
||||||
_loadingContext->context = std::move(preview.loadingContext);
|
|
||||||
} else {
|
|
||||||
_loadingContext = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.setTextPalette(active
|
p.setTextPalette(active
|
||||||
? st::dialogsTextPaletteActive
|
? st::dialogsTextPaletteActive
|
||||||
: selected
|
: selected
|
||||||
|
|
|
@ -40,13 +40,16 @@ public:
|
||||||
void itemInvalidated(not_null<const HistoryItem*> item);
|
void itemInvalidated(not_null<const HistoryItem*> item);
|
||||||
[[nodiscard]] bool dependsOn(not_null<const HistoryItem*> item) const;
|
[[nodiscard]] bool dependsOn(not_null<const HistoryItem*> item) const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool prepared(not_null<const HistoryItem*> item) const;
|
||||||
|
void prepare(
|
||||||
|
not_null<const HistoryItem*> item,
|
||||||
|
Fn<void()> customEmojiRepaint,
|
||||||
|
ToPreviewOptions options);
|
||||||
void paint(
|
void paint(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<const HistoryItem*> item,
|
|
||||||
const QRect &geometry,
|
const QRect &geometry,
|
||||||
bool active,
|
bool active,
|
||||||
bool selected,
|
bool selected) const;
|
||||||
ToPreviewOptions options) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct LoadingContext;
|
struct LoadingContext;
|
||||||
|
|
|
@ -176,8 +176,14 @@ void ListController::addItems(const MessageIdsList &ids, bool clear) {
|
||||||
const auto key = Dialogs::Key{ _history };
|
const auto key = Dialogs::Key{ _history };
|
||||||
for (const auto &id : ids) {
|
for (const auto &id : ids) {
|
||||||
if (const auto item = owner.message(id)) {
|
if (const auto item = owner.message(id)) {
|
||||||
delegate()->peerListAppendRow(std::make_unique<Row>(
|
const auto shared = std::make_shared<Row*>(nullptr);
|
||||||
std::make_unique<Dialogs::FakeRow>(key, item)));
|
auto row = std::make_unique<Row>(
|
||||||
|
std::make_unique<Dialogs::FakeRow>(
|
||||||
|
key,
|
||||||
|
item,
|
||||||
|
[=] { delegate()->peerListUpdateRow(*shared); }));
|
||||||
|
*shared = row.get();
|
||||||
|
delegate()->peerListAppendRow(std::move(row));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -526,13 +526,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
||||||
peer->topBarNameText(),
|
peer->topBarNameText(),
|
||||||
Ui::NameTextOptions());
|
Ui::NameTextOptions());
|
||||||
}
|
}
|
||||||
const auto badgeStyle = Ui::PeerBadgeStyle{
|
const auto badgeWidth = _titleBadge.drawGetWidth(
|
||||||
&st::dialogsVerifiedIcon,
|
|
||||||
&st::dialogsPremiumIcon,
|
|
||||||
&st::attentionButtonFg,
|
|
||||||
};
|
|
||||||
const auto badgeWidth = Ui::DrawPeerBadgeGetWidth(
|
|
||||||
peer,
|
|
||||||
p,
|
p,
|
||||||
QRect(
|
QRect(
|
||||||
nameleft,
|
nameleft,
|
||||||
|
@ -541,7 +535,17 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
||||||
st::msgNameStyle.font->height),
|
st::msgNameStyle.font->height),
|
||||||
_title.maxWidth(),
|
_title.maxWidth(),
|
||||||
width(),
|
width(),
|
||||||
badgeStyle);
|
{
|
||||||
|
.peer = peer,
|
||||||
|
.verified = &st::dialogsVerifiedIcon,
|
||||||
|
.premium = &st::dialogsPremiumIcon,
|
||||||
|
.scam = &st::attentionButtonFg,
|
||||||
|
.preview = st::windowBgOver->c,
|
||||||
|
.customEmojiRepaint = [=] { update(); },
|
||||||
|
.now = now,
|
||||||
|
.paused = _controller->isGifPausedAtLeastFor(
|
||||||
|
Window::GifPauseReason::Any),
|
||||||
|
});
|
||||||
const auto namewidth = availableWidth - badgeWidth;
|
const auto namewidth = availableWidth - badgeWidth;
|
||||||
|
|
||||||
p.setPen(st::dialogsNameFg);
|
p.setPen(st::dialogsNameFg);
|
||||||
|
@ -698,6 +702,7 @@ void TopBarWidget::setActiveChat(
|
||||||
update();
|
update();
|
||||||
|
|
||||||
if (peerChanged) {
|
if (peerChanged) {
|
||||||
|
_titleBadge.unload();
|
||||||
_titleNameVersion = 0;
|
_titleNameVersion = 0;
|
||||||
_emojiInteractionSeen = nullptr;
|
_emojiInteractionSeen = nullptr;
|
||||||
_activeChatLifetime.destroy();
|
_activeChatLifetime.destroy();
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
#include "ui/unread_badge.h"
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "base/object_ptr.h"
|
#include "base/object_ptr.h"
|
||||||
|
@ -159,6 +160,7 @@ private:
|
||||||
std::unique_ptr<EmojiInteractionSeenAnimation> _emojiInteractionSeen;
|
std::unique_ptr<EmojiInteractionSeenAnimation> _emojiInteractionSeen;
|
||||||
rpl::lifetime _activeChatLifetime;
|
rpl::lifetime _activeChatLifetime;
|
||||||
|
|
||||||
|
Ui::PeerBadge _titleBadge;
|
||||||
Ui::Text::String _title;
|
Ui::Text::String _title;
|
||||||
int _titleNameVersion = 0;
|
int _titleNameVersion = 0;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/unread_badge.h"
|
#include "ui/unread_badge.h"
|
||||||
|
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
|
#include "data/data_user.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "dialogs/ui/dialogs_layout.h"
|
#include "dialogs/ui/dialogs_layout.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -103,14 +106,20 @@ void DrawScamBadge(
|
||||||
st::dialogsScamFont->width(phrase));
|
st::dialogsScamFont->width(phrase));
|
||||||
}
|
}
|
||||||
|
|
||||||
int DrawPeerBadgeGetWidth(
|
PeerBadge::PeerBadge() = default;
|
||||||
not_null<PeerData*> peer,
|
|
||||||
|
PeerBadge::~PeerBadge() = default;
|
||||||
|
|
||||||
|
int PeerBadge::drawGetWidth(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
QRect rectForName,
|
QRect rectForName,
|
||||||
int nameWidth,
|
int nameWidth,
|
||||||
int outerWidth,
|
int outerWidth,
|
||||||
const PeerBadgeStyle &st) {
|
const Descriptor &descriptor) {
|
||||||
if ((peer->isScam() || peer->isFake()) && st.scam) {
|
Expects(descriptor.customEmojiRepaint != nullptr);
|
||||||
|
|
||||||
|
const auto peer = descriptor.peer;
|
||||||
|
if ((peer->isScam() || peer->isFake()) && descriptor.scam) {
|
||||||
const auto phrase = peer->isScam()
|
const auto phrase = peer->isScam()
|
||||||
? tr::lng_scam_badge(tr::now)
|
? tr::lng_scam_badge(tr::now)
|
||||||
: tr::lng_fake_badge(tr::now);
|
: tr::lng_fake_badge(tr::now);
|
||||||
|
@ -129,28 +138,62 @@ int DrawPeerBadgeGetWidth(
|
||||||
rectForName.y() + (rectForName.height() - height) / 2,
|
rectForName.y() + (rectForName.height() - height) / 2,
|
||||||
width,
|
width,
|
||||||
height);
|
height);
|
||||||
DrawScamFakeBadge(p, rect, outerWidth, *st.scam, phrase, phraseWidth);
|
DrawScamFakeBadge(
|
||||||
|
p,
|
||||||
|
rect,
|
||||||
|
outerWidth,
|
||||||
|
*descriptor.scam,
|
||||||
|
phrase,
|
||||||
|
phraseWidth);
|
||||||
return st::dialogsScamSkip + width;
|
return st::dialogsScamSkip + width;
|
||||||
} else if (peer->isVerified() && st.verified) {
|
} else if (peer->isVerified() && descriptor.verified) {
|
||||||
const auto iconw = st.verified->width();
|
const auto iconw = descriptor.verified->width();
|
||||||
st.verified->paint(
|
descriptor.verified->paint(
|
||||||
p,
|
p,
|
||||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
||||||
rectForName.y(),
|
rectForName.y(),
|
||||||
outerWidth);
|
outerWidth);
|
||||||
return iconw;
|
return iconw;
|
||||||
} else if (peer->isPremium()
|
} else if (peer->isPremium()
|
||||||
&& st.premium
|
&& descriptor.premium
|
||||||
&& peer->session().premiumBadgesShown()) {
|
&& peer->session().premiumBadgesShown()) {
|
||||||
const auto iconw = st.premium->width();
|
const auto id = peer->isUser() ? peer->asUser()->emojiStatusId() : 0;
|
||||||
st.premium->paint(
|
const auto iconw = descriptor.premium->width();
|
||||||
|
const auto iconx = rectForName.x()
|
||||||
|
+ qMin(nameWidth, rectForName.width() - iconw);
|
||||||
|
const auto icony = rectForName.y();
|
||||||
|
if (!id) {
|
||||||
|
_emojiStatus = nullptr;
|
||||||
|
descriptor.premium->paint(p, iconx, icony, outerWidth);
|
||||||
|
return iconw;
|
||||||
|
}
|
||||||
|
if (!_emojiStatus) {
|
||||||
|
_emojiStatus = std::make_unique<EmojiStatus>();
|
||||||
|
const auto size = st::emojiSize * 1.;
|
||||||
|
const auto emoji = Ui::Text::AdjustCustomEmojiSize(st::emojiSize);
|
||||||
|
_emojiStatus->skip = (st::emojiSize - emoji) / 2;
|
||||||
|
}
|
||||||
|
if (_emojiStatus->id != id) {
|
||||||
|
auto &manager = peer->session().data().customEmojiManager();
|
||||||
|
_emojiStatus->id = id;
|
||||||
|
_emojiStatus->emoji = manager.create(
|
||||||
|
id,
|
||||||
|
descriptor.customEmojiRepaint);
|
||||||
|
}
|
||||||
|
_emojiStatus->emoji->paint(
|
||||||
p,
|
p,
|
||||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
iconx - _emojiStatus->skip,
|
||||||
rectForName.y(),
|
icony + _emojiStatus->skip,
|
||||||
outerWidth);
|
descriptor.now,
|
||||||
return iconw;
|
descriptor.preview,
|
||||||
|
descriptor.paused);
|
||||||
|
return iconw - 2 * _emojiStatus->skip;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerBadge::unload() {
|
||||||
|
_emojiStatus = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
|
namespace Ui::Text {
|
||||||
|
class CustomEmoji;
|
||||||
|
} // namespace Ui::Text
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
class UnreadBadge : public RpWidget {
|
class UnreadBadge : public RpWidget {
|
||||||
|
@ -27,18 +31,39 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PeerBadgeStyle {
|
class PeerBadge {
|
||||||
const style::icon *verified = nullptr;
|
public:
|
||||||
const style::icon *premium = nullptr;
|
PeerBadge();
|
||||||
const style::color *scam = nullptr;
|
~PeerBadge();
|
||||||
|
|
||||||
|
struct Descriptor {
|
||||||
|
not_null<PeerData*> peer;
|
||||||
|
const style::icon *verified = nullptr;
|
||||||
|
const style::icon *premium = nullptr;
|
||||||
|
const style::color *scam = nullptr;
|
||||||
|
QColor preview;
|
||||||
|
Fn<void()> customEmojiRepaint;
|
||||||
|
crl::time now = 0;
|
||||||
|
bool paused = false;
|
||||||
|
};
|
||||||
|
int drawGetWidth(
|
||||||
|
Painter &p,
|
||||||
|
QRect rectForName,
|
||||||
|
int nameWidth,
|
||||||
|
int outerWidth,
|
||||||
|
const Descriptor &descriptor);
|
||||||
|
void unload();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct EmojiStatus {
|
||||||
|
DocumentId id = 0;
|
||||||
|
std::unique_ptr<Ui::Text::CustomEmoji> emoji;
|
||||||
|
int skip = 0;
|
||||||
|
};
|
||||||
|
std::unique_ptr<EmojiStatus> _emojiStatus;
|
||||||
|
|
||||||
};
|
};
|
||||||
int DrawPeerBadgeGetWidth(
|
|
||||||
not_null<PeerData*> peer,
|
|
||||||
Painter &p,
|
|
||||||
QRect rectForName,
|
|
||||||
int nameWidth,
|
|
||||||
int outerWidth,
|
|
||||||
const PeerBadgeStyle &st);
|
|
||||||
QSize ScamBadgeSize(bool fake);
|
QSize ScamBadgeSize(bool fake);
|
||||||
void DrawScamBadge(
|
void DrawScamBadge(
|
||||||
bool fake,
|
bool fake,
|
||||||
|
|
Loading…
Add table
Reference in a new issue