mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +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),
|
||||
SupportInfo = (1ULL << 20),
|
||||
IsBot = (1ULL << 21),
|
||||
EmojiStatus = (1ULL << 22),
|
||||
|
||||
// For chats and channels
|
||||
InviteLinks = (1ULL << 22),
|
||||
Members = (1ULL << 23),
|
||||
Admins = (1ULL << 24),
|
||||
BannedUsers = (1ULL << 25),
|
||||
Rights = (1ULL << 26),
|
||||
PendingRequests = (1ULL << 27),
|
||||
Reactions = (1ULL << 28),
|
||||
InviteLinks = (1ULL << 23),
|
||||
Members = (1ULL << 24),
|
||||
Admins = (1ULL << 25),
|
||||
BannedUsers = (1ULL << 26),
|
||||
Rights = (1ULL << 27),
|
||||
PendingRequests = (1ULL << 28),
|
||||
Reactions = (1ULL << 29),
|
||||
|
||||
// For channels
|
||||
ChannelAmIn = (1ULL << 29),
|
||||
StickersSet = (1ULL << 30),
|
||||
ChannelLinkedChat = (1ULL << 31),
|
||||
ChannelLocation = (1ULL << 32),
|
||||
Slowmode = (1ULL << 33),
|
||||
GroupCall = (1ULL << 34),
|
||||
ChannelAmIn = (1ULL << 30),
|
||||
StickersSet = (1ULL << 31),
|
||||
ChannelLinkedChat = (1ULL << 32),
|
||||
ChannelLocation = (1ULL << 33),
|
||||
Slowmode = (1ULL << 34),
|
||||
GroupCall = (1ULL << 35),
|
||||
|
||||
// For iteration
|
||||
LastUsedBit = (1ULL << 34),
|
||||
LastUsedBit = (1ULL << 35),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
|
|
@ -400,6 +400,11 @@ ChannelData *Session::channelLoaded(ChannelId id) const {
|
|||
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) {
|
||||
const auto result = user(data.match([](const auto &data) {
|
||||
return data.vid().v;
|
||||
|
@ -554,6 +559,26 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
|||
}
|
||||
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 (const auto botInfoVersion = data.vbot_info_version()) {
|
||||
result->setBotInfoVersion(botInfoVersion->v);
|
||||
|
@ -2943,6 +2968,23 @@ void Session::documentApplyFields(
|
|||
if (dc != 0 && access != 0) {
|
||||
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) {
|
||||
|
|
|
@ -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
|
||||
-> const std::vector<Data::UnavailableReason> & {
|
||||
return _unavailableReasons;
|
||||
|
|
|
@ -71,6 +71,9 @@ public:
|
|||
const QString &newPhoneName,
|
||||
const QString &newUsername);
|
||||
|
||||
void setEmojiStatus(DocumentId emojiStatusId);
|
||||
[[nodiscard]] DocumentId emojiStatusId() const;
|
||||
|
||||
void setPhone(const QString &newPhone);
|
||||
void setBotInfoVersion(int version);
|
||||
void setBotInfo(const MTPBotInfo &info);
|
||||
|
@ -168,6 +171,8 @@ private:
|
|||
static constexpr auto kInaccessibleAccessHashOld
|
||||
= 0xFFFFFFFFFFFFFFFFULL;
|
||||
|
||||
DocumentId _emojiStatusId = 0;
|
||||
|
||||
};
|
||||
|
||||
namespace Data {
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/flat_map.h"
|
||||
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "ui/unread_badge.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
|
@ -188,6 +189,9 @@ public:
|
|||
}
|
||||
|
||||
[[nodiscard]] const Ui::Text::String &chatListNameText() const;
|
||||
[[nodiscard]] Ui::PeerBadge &chatListBadge() const {
|
||||
return _chatListBadge;
|
||||
}
|
||||
|
||||
protected:
|
||||
void notifyUnreadStateChange(const UnreadState &wasState);
|
||||
|
@ -221,6 +225,7 @@ private:
|
|||
uint64 _sortKeyInChatList = 0;
|
||||
uint64 _sortKeyByDate = 0;
|
||||
base::flat_map<FilterId, int> _pinnedIndex;
|
||||
mutable Ui::PeerBadge _chatListBadge;
|
||||
mutable Ui::Text::String _chatListNameText;
|
||||
mutable int _chatListNameVersion = 0;
|
||||
TimeId _timeId = 0;
|
||||
|
|
|
@ -122,6 +122,7 @@ struct InnerWidget::PeerSearchResult {
|
|||
}
|
||||
not_null<PeerData*> peer;
|
||||
mutable Ui::Text::String name;
|
||||
mutable Ui::PeerBadge badge;
|
||||
BasicRow row;
|
||||
};
|
||||
|
||||
|
@ -614,7 +615,14 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
|||
const auto selected = (from == (isPressed()
|
||||
? _peerSearchPressed
|
||||
: _peerSearchSelected));
|
||||
paintPeerSearchResult(p, result.get(), fullWidth, active, selected);
|
||||
paintPeerSearchResult(
|
||||
p,
|
||||
result.get(),
|
||||
fullWidth,
|
||||
active,
|
||||
selected,
|
||||
ms,
|
||||
videoPaused);
|
||||
p.translate(0, st::dialogsRowHeight);
|
||||
}
|
||||
}
|
||||
|
@ -767,7 +775,9 @@ void InnerWidget::paintPeerSearchResult(
|
|||
not_null<const PeerSearchResult*> result,
|
||||
int fullWidth,
|
||||
bool active,
|
||||
bool selected) const {
|
||||
bool selected,
|
||||
crl::time now,
|
||||
bool paused) {
|
||||
QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight);
|
||||
p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg));
|
||||
if (!active) {
|
||||
|
@ -794,29 +804,37 @@ void InnerWidget::paintPeerSearchResult(
|
|||
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
|
||||
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
|
||||
}
|
||||
const auto badgeStyle = Ui::PeerBadgeStyle{
|
||||
(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,
|
||||
const auto badgeWidth = result->badge.drawGetWidth(
|
||||
p,
|
||||
rectForName,
|
||||
result->name.maxWidth(),
|
||||
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);
|
||||
|
||||
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); });
|
||||
} else if (base::in_range(_searchedPressed, 0, _searchResults.size())) {
|
||||
auto &row = _searchResults[_searchedPressed];
|
||||
row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * st::dialogsRowHeight), QSize(width(), st::dialogsRowHeight), [this, index = _searchedPressed] {
|
||||
rtlupdate(0, searchedOffset() + index * st::dialogsRowHeight, width(), st::dialogsRowHeight);
|
||||
});
|
||||
row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * st::dialogsRowHeight), QSize(width(), st::dialogsRowHeight), row->repaint());
|
||||
}
|
||||
if (anim::Disabled()
|
||||
&& (!_pressed || !_pressed->entry()->isPinnedDialog(_filterId))) {
|
||||
|
@ -2122,10 +2138,12 @@ bool InnerWidget::searchReceived(
|
|||
&& (!_searchInChat
|
||||
|| inject->history() == _searchInChat.history())) {
|
||||
Assert(_searchResults.empty());
|
||||
const auto index = int(_searchResults.size());
|
||||
_searchResults.push_back(
|
||||
std::make_unique<FakeRow>(
|
||||
_searchInChat,
|
||||
inject));
|
||||
inject,
|
||||
[=] { repaintSearchResult(index); }));
|
||||
++fullCount;
|
||||
}
|
||||
for (const auto &message : messages) {
|
||||
|
@ -2140,10 +2158,12 @@ bool InnerWidget::searchReceived(
|
|||
NewMessageType::Existing);
|
||||
const auto history = item->history();
|
||||
if (!uniquePeers || !hasHistoryInResults(history)) {
|
||||
const auto index = int(_searchResults.size());
|
||||
_searchResults.push_back(
|
||||
std::make_unique<FakeRow>(
|
||||
_searchInChat,
|
||||
item));
|
||||
item,
|
||||
[=] { repaintSearchResult(index); }));
|
||||
if (uniquePeers && !history->unreadCountKnown()) {
|
||||
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() {
|
||||
if (_state == WidgetState::Filtered || _searchInChat) {
|
||||
if (_searchInChat) {
|
||||
|
|
|
@ -294,7 +294,9 @@ private:
|
|||
not_null<const PeerSearchResult*> result,
|
||||
int fullWidth,
|
||||
bool active,
|
||||
bool selected) const;
|
||||
bool selected,
|
||||
crl::time now,
|
||||
bool paused);
|
||||
void paintSearchInChat(Painter &p) const;
|
||||
void paintSearchInPeer(
|
||||
Painter &p,
|
||||
|
@ -318,6 +320,7 @@ private:
|
|||
const style::icon *icon,
|
||||
const Ui::Text::String &text) const;
|
||||
void refreshSearchInChatLabel();
|
||||
void repaintSearchResult(int index);
|
||||
|
||||
Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row);
|
||||
Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history);
|
||||
|
|
|
@ -339,9 +339,13 @@ void Row::paintUserpic(
|
|||
p.setOpacity(1.);
|
||||
}
|
||||
|
||||
FakeRow::FakeRow(Key searchInChat, not_null<HistoryItem*> item)
|
||||
FakeRow::FakeRow(
|
||||
Key searchInChat,
|
||||
not_null<HistoryItem*> item,
|
||||
Fn<void()> repaint)
|
||||
: _searchInChat(searchInChat)
|
||||
, _item(item) {
|
||||
, _item(item)
|
||||
, _repaint(std::move(repaint)) {
|
||||
}
|
||||
|
||||
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/effects/animations.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "dialogs/ui/dialogs_message_view.h"
|
||||
|
||||
|
@ -147,7 +148,10 @@ private:
|
|||
|
||||
class FakeRow : public BasicRow {
|
||||
public:
|
||||
FakeRow(Key searchInChat, not_null<HistoryItem*> item);
|
||||
FakeRow(
|
||||
Key searchInChat,
|
||||
not_null<HistoryItem*> item,
|
||||
Fn<void()> repaint);
|
||||
|
||||
[[nodiscard]] Key searchInChat() const {
|
||||
return _searchInChat;
|
||||
|
@ -158,14 +162,22 @@ public:
|
|||
[[nodiscard]] Ui::MessageView &itemView() const {
|
||||
return _itemView;
|
||||
}
|
||||
[[nodiscard]] Fn<void()> repaint() const {
|
||||
return _repaint;
|
||||
}
|
||||
[[nodiscard]] Ui::PeerBadge &badge() const {
|
||||
return _badge;
|
||||
}
|
||||
[[nodiscard]] const Ui::Text::String &name() const;
|
||||
|
||||
private:
|
||||
friend class Ui::RowPainter;
|
||||
|
||||
Key _searchInChat;
|
||||
not_null<HistoryItem*> _item;
|
||||
const Key _searchInChat;
|
||||
const not_null<HistoryItem*> _item;
|
||||
const Fn<void()> _repaint;
|
||||
mutable Ui::MessageView _itemView;
|
||||
mutable Ui::PeerBadge _badge;
|
||||
mutable Ui::Text::String _name;
|
||||
|
||||
};
|
||||
|
|
|
@ -311,6 +311,8 @@ void paintRow(
|
|||
VideoUserpic *videoUserpic,
|
||||
FilterId filterId,
|
||||
PeerData *from,
|
||||
Ui::PeerBadge &fromBadge,
|
||||
Fn<void()> customEmojiRepaint,
|
||||
const Ui::Text::String &fromName,
|
||||
const HiddenSenderInfo *hiddenSenderInfo,
|
||||
HistoryItem *item,
|
||||
|
@ -474,9 +476,7 @@ void paintRow(
|
|||
Text::WithEntities);
|
||||
const auto context = Core::MarkedTextContext{
|
||||
.session = &history->session(),
|
||||
.customEmojiRepaint = [=] {
|
||||
history->updateChatListEntry();
|
||||
},
|
||||
.customEmojiRepaint = customEmojiRepaint,
|
||||
};
|
||||
history->cloudDraftTextCache.setMarkedText(
|
||||
st::dialogsTextStyle,
|
||||
|
@ -570,30 +570,38 @@ void paintRow(
|
|||
: st::dialogsNameFg);
|
||||
p.drawTextLeft(rectForName.left(), rectForName.top(), fullWidth, text);
|
||||
} else if (from) {
|
||||
if (!(flags & Flag::SearchResult)) {
|
||||
const auto badgeStyle = PeerBadgeStyle{
|
||||
(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,
|
||||
if (history && !(flags & Flag::SearchResult)) {
|
||||
const auto badgeWidth = fromBadge.drawGetWidth(
|
||||
p,
|
||||
rectForName,
|
||||
fromName.maxWidth(),
|
||||
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);
|
||||
}
|
||||
p.setPen(active
|
||||
|
@ -911,7 +919,7 @@ void RowPainter::paint(
|
|||
: (selected
|
||||
? st::dialogsTextFgServiceOver
|
||||
: st::dialogsTextFgService);
|
||||
const auto itemRect = QRect(
|
||||
const auto rect = QRect(
|
||||
nameleft,
|
||||
texttop,
|
||||
availableWidth,
|
||||
|
@ -919,23 +927,23 @@ void RowPainter::paint(
|
|||
const auto actionWasPainted = ShowSendActionInDialogs(history)
|
||||
? history->sendActionPainter()->paint(
|
||||
p,
|
||||
itemRect.x(),
|
||||
itemRect.y(),
|
||||
itemRect.width(),
|
||||
rect.x(),
|
||||
rect.y(),
|
||||
rect.width(),
|
||||
fullWidth,
|
||||
color,
|
||||
ms)
|
||||
: false;
|
||||
if (const auto folder = row->folder()) {
|
||||
PaintListEntryText(p, itemRect, active, selected, row);
|
||||
PaintListEntryText(p, rect, active, selected, row);
|
||||
} else if (history && !actionWasPainted) {
|
||||
history->lastItemDialogsView.paint(
|
||||
p,
|
||||
item,
|
||||
itemRect,
|
||||
active,
|
||||
selected,
|
||||
{});
|
||||
if (!history->lastItemDialogsView.prepared(item)) {
|
||||
history->lastItemDialogsView.prepare(
|
||||
item,
|
||||
[=] { history->updateChatListEntry(); },
|
||||
{});
|
||||
}
|
||||
history->lastItemDialogsView.paint(p, rect, active, selected);
|
||||
}
|
||||
};
|
||||
const auto paintCounterCallback = [&] {
|
||||
|
@ -959,6 +967,8 @@ void RowPainter::paint(
|
|||
videoUserpic,
|
||||
filterId,
|
||||
from,
|
||||
entry->chatListBadge(),
|
||||
[=] { history->updateChatListEntry(); },
|
||||
entry->chatListNameText(),
|
||||
nullptr,
|
||||
item,
|
||||
|
@ -1056,13 +1066,11 @@ void RowPainter::paint(
|
|||
texttop,
|
||||
availableWidth,
|
||||
st::dialogsTextFont->height);
|
||||
row->itemView().paint(
|
||||
p,
|
||||
item,
|
||||
itemRect,
|
||||
active,
|
||||
selected,
|
||||
previewOptions);
|
||||
auto &view = row->itemView();
|
||||
if (!view.prepared(item)) {
|
||||
view.prepare(item, row->repaint(), previewOptions);
|
||||
}
|
||||
row->itemView().paint(p, itemRect, active, selected);
|
||||
};
|
||||
const auto paintCounterCallback = [&] {
|
||||
PaintNarrowCounter(
|
||||
|
@ -1094,6 +1102,8 @@ void RowPainter::paint(
|
|||
nullptr,
|
||||
FilterId(),
|
||||
from,
|
||||
row->badge(),
|
||||
row->repaint(),
|
||||
row->name(),
|
||||
hiddenSenderInfo,
|
||||
item,
|
||||
|
|
|
@ -109,63 +109,67 @@ bool MessageView::dependsOn(not_null<const HistoryItem*> item) const {
|
|||
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(
|
||||
Painter &p,
|
||||
not_null<const HistoryItem*> item,
|
||||
const QRect &geometry,
|
||||
bool active,
|
||||
bool selected,
|
||||
ToPreviewOptions options) const {
|
||||
bool selected) const {
|
||||
if (geometry.isEmpty()) {
|
||||
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
|
||||
? st::dialogsTextPaletteActive
|
||||
: selected
|
||||
|
|
|
@ -40,13 +40,16 @@ public:
|
|||
void itemInvalidated(not_null<const HistoryItem*> item);
|
||||
[[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(
|
||||
Painter &p,
|
||||
not_null<const HistoryItem*> item,
|
||||
const QRect &geometry,
|
||||
bool active,
|
||||
bool selected,
|
||||
ToPreviewOptions options) const;
|
||||
bool selected) const;
|
||||
|
||||
private:
|
||||
struct LoadingContext;
|
||||
|
|
|
@ -176,8 +176,14 @@ void ListController::addItems(const MessageIdsList &ids, bool clear) {
|
|||
const auto key = Dialogs::Key{ _history };
|
||||
for (const auto &id : ids) {
|
||||
if (const auto item = owner.message(id)) {
|
||||
delegate()->peerListAppendRow(std::make_unique<Row>(
|
||||
std::make_unique<Dialogs::FakeRow>(key, item)));
|
||||
const auto shared = std::make_shared<Row*>(nullptr);
|
||||
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(),
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
const auto badgeStyle = Ui::PeerBadgeStyle{
|
||||
&st::dialogsVerifiedIcon,
|
||||
&st::dialogsPremiumIcon,
|
||||
&st::attentionButtonFg,
|
||||
};
|
||||
const auto badgeWidth = Ui::DrawPeerBadgeGetWidth(
|
||||
peer,
|
||||
const auto badgeWidth = _titleBadge.drawGetWidth(
|
||||
p,
|
||||
QRect(
|
||||
nameleft,
|
||||
|
@ -541,7 +535,17 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
|||
st::msgNameStyle.font->height),
|
||||
_title.maxWidth(),
|
||||
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;
|
||||
|
||||
p.setPen(st::dialogsNameFg);
|
||||
|
@ -698,6 +702,7 @@ void TopBarWidget::setActiveChat(
|
|||
update();
|
||||
|
||||
if (peerChanged) {
|
||||
_titleBadge.unload();
|
||||
_titleNameVersion = 0;
|
||||
_emojiInteractionSeen = nullptr;
|
||||
_activeChatLifetime.destroy();
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/unread_badge.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/object_ptr.h"
|
||||
|
@ -159,6 +160,7 @@ private:
|
|||
std::unique_ptr<EmojiInteractionSeenAnimation> _emojiInteractionSeen;
|
||||
rpl::lifetime _activeChatLifetime;
|
||||
|
||||
Ui::PeerBadge _titleBadge;
|
||||
Ui::Text::String _title;
|
||||
int _titleNameVersion = 0;
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/unread_badge.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 "dialogs/ui/dialogs_layout.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
@ -103,14 +106,20 @@ void DrawScamBadge(
|
|||
st::dialogsScamFont->width(phrase));
|
||||
}
|
||||
|
||||
int DrawPeerBadgeGetWidth(
|
||||
not_null<PeerData*> peer,
|
||||
PeerBadge::PeerBadge() = default;
|
||||
|
||||
PeerBadge::~PeerBadge() = default;
|
||||
|
||||
int PeerBadge::drawGetWidth(
|
||||
Painter &p,
|
||||
QRect rectForName,
|
||||
int nameWidth,
|
||||
int outerWidth,
|
||||
const PeerBadgeStyle &st) {
|
||||
if ((peer->isScam() || peer->isFake()) && st.scam) {
|
||||
const Descriptor &descriptor) {
|
||||
Expects(descriptor.customEmojiRepaint != nullptr);
|
||||
|
||||
const auto peer = descriptor.peer;
|
||||
if ((peer->isScam() || peer->isFake()) && descriptor.scam) {
|
||||
const auto phrase = peer->isScam()
|
||||
? tr::lng_scam_badge(tr::now)
|
||||
: tr::lng_fake_badge(tr::now);
|
||||
|
@ -129,28 +138,62 @@ int DrawPeerBadgeGetWidth(
|
|||
rectForName.y() + (rectForName.height() - height) / 2,
|
||||
width,
|
||||
height);
|
||||
DrawScamFakeBadge(p, rect, outerWidth, *st.scam, phrase, phraseWidth);
|
||||
DrawScamFakeBadge(
|
||||
p,
|
||||
rect,
|
||||
outerWidth,
|
||||
*descriptor.scam,
|
||||
phrase,
|
||||
phraseWidth);
|
||||
return st::dialogsScamSkip + width;
|
||||
} else if (peer->isVerified() && st.verified) {
|
||||
const auto iconw = st.verified->width();
|
||||
st.verified->paint(
|
||||
} else if (peer->isVerified() && descriptor.verified) {
|
||||
const auto iconw = descriptor.verified->width();
|
||||
descriptor.verified->paint(
|
||||
p,
|
||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
||||
rectForName.y(),
|
||||
outerWidth);
|
||||
return iconw;
|
||||
} else if (peer->isPremium()
|
||||
&& st.premium
|
||||
&& descriptor.premium
|
||||
&& peer->session().premiumBadgesShown()) {
|
||||
const auto iconw = st.premium->width();
|
||||
st.premium->paint(
|
||||
const auto id = peer->isUser() ? peer->asUser()->emojiStatusId() : 0;
|
||||
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,
|
||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
||||
rectForName.y(),
|
||||
outerWidth);
|
||||
return iconw;
|
||||
iconx - _emojiStatus->skip,
|
||||
icony + _emojiStatus->skip,
|
||||
descriptor.now,
|
||||
descriptor.preview,
|
||||
descriptor.paused);
|
||||
return iconw - 2 * _emojiStatus->skip;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PeerBadge::unload() {
|
||||
_emojiStatus = nullptr;
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Ui::Text {
|
||||
class CustomEmoji;
|
||||
} // namespace Ui::Text
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class UnreadBadge : public RpWidget {
|
||||
|
@ -27,18 +31,39 @@ private:
|
|||
|
||||
};
|
||||
|
||||
struct PeerBadgeStyle {
|
||||
const style::icon *verified = nullptr;
|
||||
const style::icon *premium = nullptr;
|
||||
const style::color *scam = nullptr;
|
||||
class PeerBadge {
|
||||
public:
|
||||
PeerBadge();
|
||||
~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);
|
||||
void DrawScamBadge(
|
||||
bool fake,
|
||||
|
|
Loading…
Add table
Reference in a new issue