From d0b86e12295a34f60822ba4d2c1e1cba63060ca9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 17 Jun 2019 16:37:29 +0200 Subject: [PATCH] Optimize online dots + add animations. --- .../SourceFiles/data/data_peer_values.cpp | 7 + Telegram/SourceFiles/data/data_peer_values.h | 17 ++- Telegram/SourceFiles/dialogs/dialogs.style | 1 + .../dialogs/dialogs_inner_widget.cpp | 122 +++++++++------ .../dialogs/dialogs_inner_widget.h | 8 + .../SourceFiles/dialogs/dialogs_layout.cpp | 66 ++------- Telegram/SourceFiles/dialogs/dialogs_layout.h | 4 +- Telegram/SourceFiles/dialogs/dialogs_list.cpp | 2 +- Telegram/SourceFiles/dialogs/dialogs_row.cpp | 139 +++++++++++++++++- Telegram/SourceFiles/dialogs/dialogs_row.h | 44 +++++- .../SourceFiles/platform/mac/mac_touchbar.mm | 12 +- Telegram/SourceFiles/ui/effects/animations.h | 14 ++ 12 files changed, 306 insertions(+), 130 deletions(-) diff --git a/Telegram/SourceFiles/data/data_peer_values.cpp b/Telegram/SourceFiles/data/data_peer_values.cpp index 0accf6bf7..0265f3a18 100644 --- a/Telegram/SourceFiles/data/data_peer_values.cpp +++ b/Telegram/SourceFiles/data/data_peer_values.cpp @@ -366,4 +366,11 @@ bool OnlineTextActive(not_null user, TimeId now) { return OnlineTextActive(user->onlineTill, now); } +bool IsPeerAnOnlineUser(not_null peer) { + if (const auto user = peer->asUser()) { + return OnlineTextActive(user, unixtime()); + } + return false; +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer_values.h b/Telegram/SourceFiles/data/data_peer_values.h index 8744a46ad..339e031df 100644 --- a/Telegram/SourceFiles/data/data_peer_values.h +++ b/Telegram/SourceFiles/data/data_peer_values.h @@ -110,13 +110,14 @@ rpl::producer CanWriteValue(ChatData *chat); rpl::producer CanWriteValue(ChannelData *channel); rpl::producer CanWriteValue(not_null peer); -TimeId SortByOnlineValue(not_null user, TimeId now); -crl::time OnlineChangeTimeout(TimeId online, TimeId now); -crl::time OnlineChangeTimeout(not_null user, TimeId now); -QString OnlineText(TimeId online, TimeId now); -QString OnlineText(not_null user, TimeId now); -QString OnlineTextFull(not_null user, TimeId now); -bool OnlineTextActive(TimeId online, TimeId now); -bool OnlineTextActive(not_null user, TimeId now); +[[nodiscard]] TimeId SortByOnlineValue(not_null user, TimeId now); +[[nodiscard]] crl::time OnlineChangeTimeout(TimeId online, TimeId now); +[[nodiscard]] crl::time OnlineChangeTimeout(not_null user, TimeId now); +[[nodiscard]] QString OnlineText(TimeId online, TimeId now); +[[nodiscard]] QString OnlineText(not_null user, TimeId now); +[[nodiscard]] QString OnlineTextFull(not_null user, TimeId now); +[[nodiscard]] bool OnlineTextActive(TimeId online, TimeId now); +[[nodiscard]] bool OnlineTextActive(not_null user, TimeId now); +[[nodiscard]] bool IsPeerAnOnlineUser(not_null peer); } // namespace Data diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 6e0701927..f33e81e50 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -37,6 +37,7 @@ dialogsPadding: point(10px, 8px); dialogsOnlineBadgeStroke: 2px; dialogsOnlineBadgeSize: 10px; dialogsOnlineBadgeSkip: point(10px, 12px); +dialogsOnlineBadgeDuration: 150; dialogsImportantBarHeight: 37px; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 3d6460216..e6da771ea 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -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 peer) : peer(peer) { } not_null 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 folder) { } } +int InnerWidget::defaultRowTop(not_null 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) { @@ -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) + -> std::pair { + 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) { 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(crl::guard(this, repaint)) : nullptr); + } +} + void InnerWidget::setupShortcuts() { Shortcuts::Requests( ) | rpl::filter([=] { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 342603d47..e275dcfc5 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -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) const; + int defaultRowTop(not_null row) const; + void setupOnlineStatusCheck(); + void userOnlineUpdated(const Notify::PeerUpdate &update); + void setupShortcuts(); RowDescriptor computeJump( const RowDescriptor &to, diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 7e0871f10..9f6582d4c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -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 void paintRow( Painter &p, - not_null row, + not_null row, not_null 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, diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.h b/Telegram/SourceFiles/dialogs/dialogs_layout.h index b0ca4843f..c8b03e792 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.h +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.h @@ -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, diff --git a/Telegram/SourceFiles/dialogs/dialogs_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_list.cpp index 00e1ac599..37302ace8 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_list.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_list.cpp @@ -31,7 +31,7 @@ not_null List::addToEnd(Key key) { key, std::make_unique(key, _rows.size()) ).first->second.get(); - _rows.push_back(result); + _rows.emplace_back(result); if (_sortMode == SortMode::Date) { adjustByDate(result); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 156fcf7c1..ed280b55c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -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 folder) { } // namespace -RippleRow::RippleRow() = default; -RippleRow::~RippleRow() = default; +BasicRow::BasicRow() = default; +BasicRow::~BasicRow() = default; -void RippleRow::addRipple(QPoint origin, QSize size, Fn updateCallback) { +void BasicRow::setOnline(bool online, Fn 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 updateCallback) { if (!_ripple) { auto mask = Ui::RippleAnimation::rectMask(size); - _ripple = std::make_unique(st::dialogsRipple, std::move(mask), std::move(updateCallback)); + _ripple = std::make_unique( + 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(); +} + +void BasicRow::PaintOnlineFrame( + not_null data, + not_null 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 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(); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index d081ce8ef..189211718 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -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 updateCallback = nullptr) const; + void paintUserpic( + Painter &p, + not_null peer, + bool allowOnline, + bool active, + int fullWidth) const; void addRipple(QPoint origin, QSize size, Fn 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 data, + not_null peer); + mutable std::unique_ptr _ripple; + mutable std::unique_ptr _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 item); diff --git a/Telegram/SourceFiles/platform/mac/mac_touchbar.mm b/Telegram/SourceFiles/platform/mac/mac_touchbar.mm index 3c4b7cf89..ca7d0bdff 100644 --- a/Telegram/SourceFiles/platform/mac/mac_touchbar.mm +++ b/Telegram/SourceFiles/platform/mac/mac_touchbar.mm @@ -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]; diff --git a/Telegram/SourceFiles/ui/effects/animations.h b/Telegram/SourceFiles/ui/effects/animations.h index 7c1cacc7f..96bf6e511 100644 --- a/Telegram/SourceFiles/ui/effects/animations.h +++ b/Telegram/SourceFiles/ui/effects/animations.h @@ -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) {