mirror of
https://github.com/vale981/tdesktop
synced 2025-03-05 09:41:41 -05:00
Optimize online dots + add animations.
This commit is contained in:
parent
61c66994a2
commit
d0b86e1229
12 changed files with 306 additions and 130 deletions
|
@ -366,4 +366,11 @@ bool OnlineTextActive(not_null<UserData*> user, TimeId now) {
|
|||
return OnlineTextActive(user->onlineTill, now);
|
||||
}
|
||||
|
||||
bool IsPeerAnOnlineUser(not_null<PeerData*> peer) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
return OnlineTextActive(user, unixtime());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -110,13 +110,14 @@ rpl::producer<bool> CanWriteValue(ChatData *chat);
|
|||
rpl::producer<bool> CanWriteValue(ChannelData *channel);
|
||||
rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer);
|
||||
|
||||
TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now);
|
||||
crl::time OnlineChangeTimeout(TimeId online, TimeId now);
|
||||
crl::time OnlineChangeTimeout(not_null<UserData*> user, TimeId now);
|
||||
QString OnlineText(TimeId online, TimeId now);
|
||||
QString OnlineText(not_null<UserData*> user, TimeId now);
|
||||
QString OnlineTextFull(not_null<UserData*> user, TimeId now);
|
||||
bool OnlineTextActive(TimeId online, TimeId now);
|
||||
bool OnlineTextActive(not_null<UserData*> user, TimeId now);
|
||||
[[nodiscard]] TimeId SortByOnlineValue(not_null<UserData*> user, TimeId now);
|
||||
[[nodiscard]] crl::time OnlineChangeTimeout(TimeId online, TimeId now);
|
||||
[[nodiscard]] crl::time OnlineChangeTimeout(not_null<UserData*> user, TimeId now);
|
||||
[[nodiscard]] QString OnlineText(TimeId online, TimeId now);
|
||||
[[nodiscard]] QString OnlineText(not_null<UserData*> user, TimeId now);
|
||||
[[nodiscard]] QString OnlineTextFull(not_null<UserData*> user, TimeId now);
|
||||
[[nodiscard]] bool OnlineTextActive(TimeId online, TimeId now);
|
||||
[[nodiscard]] bool OnlineTextActive(not_null<UserData*> user, TimeId now);
|
||||
[[nodiscard]] bool IsPeerAnOnlineUser(not_null<PeerData*> peer);
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -37,6 +37,7 @@ dialogsPadding: point(10px, 8px);
|
|||
dialogsOnlineBadgeStroke: 2px;
|
||||
dialogsOnlineBadgeSize: 10px;
|
||||
dialogsOnlineBadgeSkip: point(10px, 12px);
|
||||
dialogsOnlineBadgeDuration: 150;
|
||||
|
||||
dialogsImportantBarHeight: 37px;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwindow.h"
|
||||
#include "mainwidget.h"
|
||||
|
@ -79,21 +80,21 @@ struct InnerWidget::CollapsedRow {
|
|||
}
|
||||
|
||||
Data::Folder *folder = nullptr;
|
||||
RippleRow row;
|
||||
BasicRow row;
|
||||
};
|
||||
|
||||
struct InnerWidget::HashtagResult {
|
||||
HashtagResult(const QString &tag) : tag(tag) {
|
||||
}
|
||||
QString tag;
|
||||
RippleRow row;
|
||||
BasicRow row;
|
||||
};
|
||||
|
||||
struct InnerWidget::PeerSearchResult {
|
||||
PeerSearchResult(not_null<PeerData*> peer) : peer(peer) {
|
||||
}
|
||||
not_null<PeerData*> peer;
|
||||
RippleRow row;
|
||||
BasicRow row;
|
||||
};
|
||||
|
||||
InnerWidget::InnerWidget(
|
||||
|
@ -177,39 +178,7 @@ InnerWidget::InnerWidget(
|
|||
UpdateRowSection::Default | UpdateRowSection::Filtered);
|
||||
}, lifetime());
|
||||
|
||||
const auto handleUserOnline = [=](const Notify::PeerUpdate &peerUpdate) {
|
||||
if (peerUpdate.peer->isSelf()) {
|
||||
return;
|
||||
}
|
||||
const auto history = session().data().historyLoaded(peerUpdate.peer);
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
const auto size = st::dialogsOnlineBadgeSize;
|
||||
const auto stroke = st::dialogsOnlineBadgeStroke;
|
||||
const auto skip = st::dialogsOnlineBadgeSkip;
|
||||
const auto edge = st::dialogsPadding.x() + st::dialogsPhotoSize;
|
||||
const auto updateRect = QRect(
|
||||
edge - skip.x() - size,
|
||||
edge - skip.y() - size,
|
||||
size,
|
||||
size
|
||||
).marginsAdded(
|
||||
{ stroke, stroke, stroke, stroke }
|
||||
).translated(
|
||||
st::dialogsPadding
|
||||
);
|
||||
updateDialogRow(
|
||||
RowDescriptor(
|
||||
history,
|
||||
FullMsgId()),
|
||||
updateRect,
|
||||
UpdateRowSection::Default | UpdateRowSection::Filtered);
|
||||
};
|
||||
|
||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(
|
||||
Notify::PeerUpdate::Flag::UserOnlineChanged,
|
||||
handleUserOnline));
|
||||
setupOnlineStatusCheck();
|
||||
|
||||
session().data().chatsListChanges(
|
||||
) | rpl::filter([=](Data::Folder *folder) {
|
||||
|
@ -1507,6 +1476,15 @@ void InnerWidget::repaintCollapsedFolderRow(not_null<Data::Folder*> folder) {
|
|||
}
|
||||
}
|
||||
|
||||
int InnerWidget::defaultRowTop(not_null<Row*> row) const {
|
||||
const auto position = row->pos();
|
||||
auto top = dialogsOffset();
|
||||
if (base::in_range(position, 0, _pinnedRows.size())) {
|
||||
top += qRound(_pinnedRows[position].yadd.current());
|
||||
}
|
||||
return top + position * st::dialogsRowHeight;
|
||||
}
|
||||
|
||||
void InnerWidget::repaintDialogRow(
|
||||
Mode list,
|
||||
not_null<Row*> row) {
|
||||
|
@ -1515,12 +1493,7 @@ void InnerWidget::repaintDialogRow(
|
|||
if (const auto folder = row->folder()) {
|
||||
repaintCollapsedFolderRow(folder);
|
||||
}
|
||||
auto position = row->pos();
|
||||
auto top = dialogsOffset();
|
||||
if (base::in_range(position, 0, _pinnedRows.size())) {
|
||||
top += qRound(_pinnedRows[position].yadd.current());
|
||||
}
|
||||
update(0, top + position * st::dialogsRowHeight, width(), st::dialogsRowHeight);
|
||||
update(0, defaultRowTop(row), width(), st::dialogsRowHeight);
|
||||
}
|
||||
} else if (_state == WidgetState::Filtered) {
|
||||
if (list == Mode::All) {
|
||||
|
@ -2816,6 +2789,71 @@ MsgId InnerWidget::lastSearchMigratedId() const {
|
|||
return _lastSearchMigratedId;
|
||||
}
|
||||
|
||||
void InnerWidget::setupOnlineStatusCheck() {
|
||||
using namespace Notify;
|
||||
subscribe(PeerUpdated(), PeerUpdatedHandler(
|
||||
PeerUpdate::Flag::UserOnlineChanged,
|
||||
[=](const PeerUpdate &update) { userOnlineUpdated(update); }));
|
||||
}
|
||||
|
||||
void InnerWidget::userOnlineUpdated(const Notify::PeerUpdate &update) {
|
||||
const auto user = update.peer->isSelf()
|
||||
? nullptr
|
||||
: update.peer->asUser();
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
const auto history = session().data().historyLoaded(user);
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
const auto size = st::dialogsOnlineBadgeSize;
|
||||
const auto stroke = st::dialogsOnlineBadgeStroke;
|
||||
const auto skip = st::dialogsOnlineBadgeSkip;
|
||||
const auto edge = st::dialogsPadding.x() + st::dialogsPhotoSize;
|
||||
const auto updateRect = QRect(
|
||||
edge - skip.x() - size,
|
||||
edge - skip.y() - size,
|
||||
size,
|
||||
size
|
||||
).marginsAdded(
|
||||
{ stroke, stroke, stroke, stroke }
|
||||
).translated(
|
||||
st::dialogsPadding
|
||||
);
|
||||
const auto repaint = [=] {
|
||||
updateDialogRow(
|
||||
RowDescriptor(
|
||||
history,
|
||||
FullMsgId()),
|
||||
updateRect,
|
||||
UpdateRowSection::Default | UpdateRowSection::Filtered);
|
||||
};
|
||||
repaint();
|
||||
|
||||
const auto findRow = [&](not_null<History*> history)
|
||||
-> std::pair<Row*, int> {
|
||||
if (state() == WidgetState::Default) {
|
||||
const auto row = shownDialogs()->getRow({ history });
|
||||
return { row, row ? defaultRowTop(row) : 0 };
|
||||
}
|
||||
const auto i = ranges::find(
|
||||
_filterResults,
|
||||
history.get(),
|
||||
[](not_null<Row*> row) { return row->history(); });
|
||||
const auto index = (i - begin(_filterResults));
|
||||
const auto row = (i == end(_filterResults)) ? nullptr : i->get();
|
||||
return { row, filteredOffset() + index * st::dialogsRowHeight };
|
||||
};
|
||||
if (const auto &[row, top] = findRow(history); row != nullptr) {
|
||||
const auto visible = (top < _visibleBottom)
|
||||
&& (top + st::dialogsRowHeight > _visibleTop);
|
||||
row->setOnline(
|
||||
Data::OnlineTextActive(user, unixtime()),
|
||||
visible ? Fn<void()>(crl::guard(this, repaint)) : nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void InnerWidget::setupShortcuts() {
|
||||
Shortcuts::Requests(
|
||||
) | rpl::filter([=] {
|
||||
|
|
|
@ -25,6 +25,10 @@ namespace Window {
|
|||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Notify {
|
||||
struct PeerUpdate;
|
||||
} // namespace Notify
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
class Row;
|
||||
|
@ -204,6 +208,10 @@ private:
|
|||
bool uniqueSearchResults() const;
|
||||
bool hasHistoryInResults(not_null<History*> history) const;
|
||||
|
||||
int defaultRowTop(not_null<Row*> row) const;
|
||||
void setupOnlineStatusCheck();
|
||||
void userOnlineUpdated(const Notify::PeerUpdate &update);
|
||||
|
||||
void setupShortcuts();
|
||||
RowDescriptor computeJump(
|
||||
const RowDescriptor &to,
|
||||
|
|
|
@ -204,7 +204,7 @@ enum class Flag {
|
|||
Selected = 0x02,
|
||||
SearchResult = 0x04,
|
||||
SavedMessages = 0x08,
|
||||
UserOnline = 0x10,
|
||||
AllowUserOnline = 0x10,
|
||||
//FeedSearchResult = 0x10, // #feed
|
||||
};
|
||||
inline constexpr bool is_flag_type(Flag) { return true; }
|
||||
|
@ -212,7 +212,7 @@ inline constexpr bool is_flag_type(Flag) { return true; }
|
|||
template <typename PaintItemCallback, typename PaintCounterCallback>
|
||||
void paintRow(
|
||||
Painter &p,
|
||||
not_null<const RippleRow*> row,
|
||||
not_null<const BasicRow*> row,
|
||||
not_null<Entry*> entry,
|
||||
Dialogs::Key chat,
|
||||
PeerData *from,
|
||||
|
@ -252,51 +252,12 @@ void paintRow(
|
|||
fullWidth,
|
||||
st::dialogsPhotoSize);
|
||||
} else if (from) {
|
||||
if (flags & Flag::UserOnline) {
|
||||
auto frame = QImage(
|
||||
st::dialogsPhotoSize * cRetinaFactor(),
|
||||
st::dialogsPhotoSize * cRetinaFactor(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
frame.setDevicePixelRatio(cRetinaFactor());
|
||||
frame.fill(Qt::transparent);
|
||||
{
|
||||
Painter q(&frame);
|
||||
from->paintUserpicLeft(
|
||||
q,
|
||||
0,
|
||||
0,
|
||||
fullWidth,
|
||||
st::dialogsPhotoSize);
|
||||
|
||||
PainterHighQualityEnabler hq(q);
|
||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
|
||||
const auto size = st::dialogsOnlineBadgeSize;
|
||||
const auto stroke = st::dialogsOnlineBadgeStroke;
|
||||
const auto skip = st::dialogsOnlineBadgeSkip;
|
||||
const auto edge = st::dialogsPadding.x() + st::dialogsPhotoSize;
|
||||
|
||||
auto pen = QPen(Qt::transparent);
|
||||
pen.setWidth(stroke);
|
||||
q.setPen(pen);
|
||||
q.setBrush(active
|
||||
? st::dialogsOnlineBadgeFgActive
|
||||
: st::dialogsOnlineBadgeFg);
|
||||
q.drawEllipse(
|
||||
edge - skip.x() - size,
|
||||
edge - skip.y() - size,
|
||||
size,
|
||||
size);
|
||||
}
|
||||
p.drawImage(st::dialogsPadding, frame);
|
||||
} else {
|
||||
from->paintUserpicLeft(
|
||||
p,
|
||||
st::dialogsPadding.x(),
|
||||
st::dialogsPadding.y(),
|
||||
fullWidth,
|
||||
st::dialogsPhotoSize);
|
||||
}
|
||||
row->paintUserpic(
|
||||
p,
|
||||
from,
|
||||
(flags & Flag::AllowUserOnline),
|
||||
active,
|
||||
fullWidth);
|
||||
} else if (hiddenSenderInfo) {
|
||||
hiddenSenderInfo->userpic.paint(
|
||||
p,
|
||||
|
@ -690,14 +651,11 @@ void RowPainter::paint(
|
|||
? history->peer->migrateTo()
|
||||
: history->peer.get())
|
||||
: nullptr;
|
||||
const auto showUserOnline = peer
|
||||
&& peer->isUser()
|
||||
&& Data::OnlineTextActive(peer->asUser(), unixtime())
|
||||
&& !(fullWidth < st::columnMinimalWidthLeft
|
||||
&& (displayUnreadCounter || displayUnreadMark));
|
||||
const auto allowUserOnline = (fullWidth >= st::columnMinimalWidthLeft)
|
||||
|| (!displayUnreadCounter && !displayUnreadMark);
|
||||
const auto flags = (active ? Flag::Active : Flag(0))
|
||||
| (selected ? Flag::Selected : Flag(0))
|
||||
| (showUserOnline ? Flag::UserOnline : Flag(0))
|
||||
| (allowUserOnline ? Flag::AllowUserOnline : Flag(0))
|
||||
| (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0));
|
||||
const auto paintItemCallback = [&](int nameleft, int namewidth) {
|
||||
const auto texttop = st::dialogsPadding.y()
|
||||
|
@ -908,7 +866,7 @@ QRect RowPainter::sendActionAnimationRect(int animationWidth, int animationHeigh
|
|||
|
||||
void PaintCollapsedRow(
|
||||
Painter &p,
|
||||
const RippleRow &row,
|
||||
const BasicRow &row,
|
||||
Data::Folder *folder,
|
||||
const QString &text,
|
||||
int unread,
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Dialogs {
|
|||
|
||||
class Row;
|
||||
class FakeRow;
|
||||
class RippleRow;
|
||||
class BasicRow;
|
||||
|
||||
namespace Layout {
|
||||
|
||||
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
void PaintCollapsedRow(
|
||||
Painter &p,
|
||||
const RippleRow &row,
|
||||
const BasicRow &row,
|
||||
Data::Folder *folder,
|
||||
const QString &text,
|
||||
int unread,
|
||||
|
|
|
@ -31,7 +31,7 @@ not_null<Row*> List::addToEnd(Key key) {
|
|||
key,
|
||||
std::make_unique<Row>(key, _rows.size())
|
||||
).first->second.get();
|
||||
_rows.push_back(result);
|
||||
_rows.emplace_back(result);
|
||||
if (_sortMode == SortMode::Date) {
|
||||
adjustByDate(result);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/text_options.h"
|
||||
#include "dialogs/dialogs_entry.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
|
@ -66,24 +67,59 @@ QString ComposeFolderListEntryText(not_null<Data::Folder*> folder) {
|
|||
|
||||
} // namespace
|
||||
|
||||
RippleRow::RippleRow() = default;
|
||||
RippleRow::~RippleRow() = default;
|
||||
BasicRow::BasicRow() = default;
|
||||
BasicRow::~BasicRow() = default;
|
||||
|
||||
void RippleRow::addRipple(QPoint origin, QSize size, Fn<void()> updateCallback) {
|
||||
void BasicRow::setOnline(bool online, Fn<void()> updateCallback) const {
|
||||
if (_online == online) {
|
||||
return;
|
||||
}
|
||||
_online = online;
|
||||
if (_onlineUserpic && _onlineUserpic->animation.animating()) {
|
||||
_onlineUserpic->animation.change(
|
||||
_online ? 1. : 0.,
|
||||
st::dialogsOnlineBadgeDuration);
|
||||
} else if (updateCallback) {
|
||||
ensureOnlineUserpic();
|
||||
_onlineUserpic->animation.start(
|
||||
std::move(updateCallback),
|
||||
_online ? 0. : 1.,
|
||||
_online ? 1. : 0.,
|
||||
st::dialogsOnlineBadgeDuration);
|
||||
}
|
||||
if (!_online
|
||||
&& _onlineUserpic
|
||||
&& !_onlineUserpic->animation.animating()) {
|
||||
_onlineUserpic = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BasicRow::addRipple(
|
||||
QPoint origin,
|
||||
QSize size,
|
||||
Fn<void()> updateCallback) {
|
||||
if (!_ripple) {
|
||||
auto mask = Ui::RippleAnimation::rectMask(size);
|
||||
_ripple = std::make_unique<Ui::RippleAnimation>(st::dialogsRipple, std::move(mask), std::move(updateCallback));
|
||||
_ripple = std::make_unique<Ui::RippleAnimation>(
|
||||
st::dialogsRipple,
|
||||
std::move(mask),
|
||||
std::move(updateCallback));
|
||||
}
|
||||
_ripple->add(origin);
|
||||
}
|
||||
|
||||
void RippleRow::stopLastRipple() {
|
||||
void BasicRow::stopLastRipple() {
|
||||
if (_ripple) {
|
||||
_ripple->lastStop();
|
||||
}
|
||||
}
|
||||
|
||||
void RippleRow::paintRipple(Painter &p, int x, int y, int outerWidth, const QColor *colorOverride) const {
|
||||
void BasicRow::paintRipple(
|
||||
Painter &p,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth,
|
||||
const QColor *colorOverride) const {
|
||||
if (_ripple) {
|
||||
_ripple->paint(p, x, y, outerWidth, colorOverride);
|
||||
if (_ripple->empty()) {
|
||||
|
@ -92,6 +128,97 @@ void RippleRow::paintRipple(Painter &p, int x, int y, int outerWidth, const QCol
|
|||
}
|
||||
}
|
||||
|
||||
void BasicRow::ensureOnlineUserpic() const {
|
||||
if (_onlineUserpic) {
|
||||
return;
|
||||
}
|
||||
_onlineUserpic = std::make_unique<OnlineUserpic>();
|
||||
}
|
||||
|
||||
void BasicRow::PaintOnlineFrame(
|
||||
not_null<OnlineUserpic*> data,
|
||||
not_null<PeerData*> peer) {
|
||||
data->frame.fill(Qt::transparent);
|
||||
|
||||
Painter q(&data->frame);
|
||||
peer->paintUserpic(
|
||||
q,
|
||||
0,
|
||||
0,
|
||||
st::dialogsPhotoSize);
|
||||
|
||||
PainterHighQualityEnabler hq(q);
|
||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
|
||||
const auto size = st::dialogsOnlineBadgeSize;
|
||||
const auto stroke = st::dialogsOnlineBadgeStroke;
|
||||
const auto skip = st::dialogsOnlineBadgeSkip;
|
||||
const auto edge = st::dialogsPadding.x() + st::dialogsPhotoSize;
|
||||
const auto shrink = (size / 2) * (1. - data->online);
|
||||
|
||||
auto pen = QPen(Qt::transparent);
|
||||
pen.setWidthF(stroke * data->online);
|
||||
q.setPen(pen);
|
||||
q.setBrush(data->active
|
||||
? st::dialogsOnlineBadgeFgActive
|
||||
: st::dialogsOnlineBadgeFg);
|
||||
q.drawEllipse(QRectF(
|
||||
edge - skip.x() - size,
|
||||
edge - skip.y() - size,
|
||||
size,
|
||||
size
|
||||
).marginsRemoved({ shrink, shrink, shrink, shrink }));
|
||||
}
|
||||
|
||||
void BasicRow::paintUserpic(
|
||||
Painter &p,
|
||||
not_null<PeerData*> peer,
|
||||
bool allowOnline,
|
||||
bool active,
|
||||
int fullWidth) const {
|
||||
setOnline(Data::IsPeerAnOnlineUser(peer));
|
||||
|
||||
const auto online = _onlineUserpic
|
||||
? _onlineUserpic->animation.value(_online ? 1. : 0.)
|
||||
: (_online ? 1. : 0.);
|
||||
if (!allowOnline || online == 0.) {
|
||||
peer->paintUserpicLeft(
|
||||
p,
|
||||
st::dialogsPadding.x(),
|
||||
st::dialogsPadding.y(),
|
||||
fullWidth,
|
||||
st::dialogsPhotoSize);
|
||||
if (!allowOnline || !_online) {
|
||||
_onlineUserpic = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
ensureOnlineUserpic();
|
||||
if (_onlineUserpic->frame.isNull()) {
|
||||
_onlineUserpic->frame = QImage(
|
||||
st::dialogsPhotoSize * cRetinaFactor(),
|
||||
st::dialogsPhotoSize * cRetinaFactor(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
_onlineUserpic->frame.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
const auto key = peer->userpicUniqueKey();
|
||||
if (_onlineUserpic->online != online
|
||||
|| _onlineUserpic->key != key
|
||||
|| _onlineUserpic->active != active) {
|
||||
_onlineUserpic->online = online;
|
||||
_onlineUserpic->key = key;
|
||||
_onlineUserpic->active = active;
|
||||
PaintOnlineFrame(_onlineUserpic.get(), peer);
|
||||
}
|
||||
p.drawImage(st::dialogsPadding, _onlineUserpic->frame);
|
||||
}
|
||||
|
||||
Row::Row(Key key, int pos) : _id(key), _pos(pos) {
|
||||
if (const auto history = key.history()) {
|
||||
setOnline(Data::IsPeerAnOnlineUser(history->peer));
|
||||
}
|
||||
}
|
||||
|
||||
uint64 Row::sortKey() const {
|
||||
return _id.entry()->sortKeyInChatList();
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "ui/text/text.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
|
||||
class History;
|
||||
|
@ -22,28 +23,55 @@ namespace Layout {
|
|||
class RowPainter;
|
||||
} // namespace Layout
|
||||
|
||||
class RippleRow {
|
||||
class BasicRow {
|
||||
public:
|
||||
RippleRow();
|
||||
~RippleRow();
|
||||
BasicRow();
|
||||
~BasicRow();
|
||||
|
||||
void setOnline(bool online, Fn<void()> updateCallback = nullptr) const;
|
||||
void paintUserpic(
|
||||
Painter &p,
|
||||
not_null<PeerData*> peer,
|
||||
bool allowOnline,
|
||||
bool active,
|
||||
int fullWidth) const;
|
||||
|
||||
void addRipple(QPoint origin, QSize size, Fn<void()> updateCallback);
|
||||
void stopLastRipple();
|
||||
|
||||
void paintRipple(Painter &p, int x, int y, int outerWidth, const QColor *colorOverride = nullptr) const;
|
||||
void paintRipple(
|
||||
Painter &p,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth,
|
||||
const QColor *colorOverride = nullptr) const;
|
||||
|
||||
private:
|
||||
struct OnlineUserpic {
|
||||
InMemoryKey key;
|
||||
float64 online = 0.;
|
||||
bool active = false;
|
||||
QImage frame;
|
||||
Ui::Animations::Simple animation;
|
||||
};
|
||||
|
||||
void ensureOnlineUserpic() const;
|
||||
static void PaintOnlineFrame(
|
||||
not_null<OnlineUserpic*> data,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
mutable std::unique_ptr<Ui::RippleAnimation> _ripple;
|
||||
mutable std::unique_ptr<OnlineUserpic> _onlineUserpic;
|
||||
mutable bool _online = false;
|
||||
|
||||
};
|
||||
|
||||
class List;
|
||||
class Row : public RippleRow {
|
||||
class Row : public BasicRow {
|
||||
public:
|
||||
explicit Row(std::nullptr_t) {
|
||||
}
|
||||
Row(Key key, int pos) : _id(key), _pos(pos) {
|
||||
}
|
||||
Row(Key key, int pos);
|
||||
|
||||
Key key() const {
|
||||
return _id;
|
||||
|
@ -80,7 +108,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class FakeRow : public RippleRow {
|
||||
class FakeRow : public BasicRow {
|
||||
public:
|
||||
FakeRow(Key searchInChat, not_null<HistoryItem*> item);
|
||||
|
||||
|
|
|
@ -96,13 +96,7 @@ inline bool UseEmptyUserpic(PeerData *peer) {
|
|||
}
|
||||
|
||||
inline bool IsSelfPeer(PeerData *peer) {
|
||||
return (peer && peer->id == Auth().userPeerId());
|
||||
}
|
||||
|
||||
inline bool IsUserOnline(PeerData *peer) {
|
||||
return peer
|
||||
&& peer->isUser()
|
||||
&& Data::OnlineTextActive(peer->asUser(), unixtime());
|
||||
return (peer && peer->isSelf());
|
||||
}
|
||||
|
||||
inline int UnreadCount(PeerData *peer) {
|
||||
|
@ -266,7 +260,7 @@ void SendKeyEvent(int command) {
|
|||
themeChanged
|
||||
) | rpl::filter([=](const Update &update) {
|
||||
return update.type == Update::Type::ApplyingTheme
|
||||
&& (UnreadCount(_peer) || IsUserOnline(_peer));
|
||||
&& (UnreadCount(_peer) || Data::IsPeerAnOnlineUser(_peer));
|
||||
}) | rpl::start_with_next([=] {
|
||||
[self updateBadge];
|
||||
}, _lifetime);
|
||||
|
@ -373,7 +367,7 @@ void SendKeyEvent(int command) {
|
|||
// Draw unread or online badge.
|
||||
auto pixmap = App::pixmapFromImageInPlace(_userpic.toImage());
|
||||
Painter p(&pixmap);
|
||||
if (!PaintUnreadBadge(p, _peer) && IsUserOnline(_peer)) {
|
||||
if (!PaintUnreadBadge(p, _peer) && Data::IsPeerAnOnlineUser(_peer)) {
|
||||
PaintOnlineCircle(p);
|
||||
}
|
||||
[self updateImage:pixmap];
|
||||
|
|
|
@ -58,6 +58,10 @@ public:
|
|||
float64 to,
|
||||
crl::time duration,
|
||||
anim::transition transition = anim::linear);
|
||||
void change(
|
||||
float64 to,
|
||||
crl::time duration,
|
||||
anim::transition transition = anim::linear);
|
||||
void stop();
|
||||
[[nodiscard]] bool animating() const;
|
||||
[[nodiscard]] float64 value(float64 final) const;
|
||||
|
@ -328,6 +332,16 @@ inline void Simple::start(
|
|||
startPrepared(to, duration, transition);
|
||||
}
|
||||
|
||||
inline void Simple::change(
|
||||
float64 to,
|
||||
crl::time duration,
|
||||
anim::transition transition) {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
prepare(0. /* ignored */, duration);
|
||||
startPrepared(to, duration, transition);
|
||||
}
|
||||
|
||||
inline void Simple::prepare(float64 from, crl::time duration) {
|
||||
const auto isLong = (duration > kLongAnimationDuration);
|
||||
if (!_data) {
|
||||
|
|
Loading…
Add table
Reference in a new issue