diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 523b30049..860c85357 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -401,6 +401,8 @@ void InnerWidget::paintEvent(QPaintEvent *e) { return; } const auto activeEntry = _controller->activeChatEntryCurrent(); + const auto videoPaused = _controller->isGifPausedAtLeastFor( + Window::GifPauseReason::Any); auto fullWidth = width(); auto dialogsClip = r; auto ms = crl::now(); @@ -449,7 +451,8 @@ void InnerWidget::paintEvent(QPaintEvent *e) { fullWidth, isActive, isSelected, - ms); + ms, + videoPaused); if (xadd || yadd) { p.translate(-xadd, -yadd); } @@ -568,7 +571,8 @@ void InnerWidget::paintEvent(QPaintEvent *e) { fullWidth, active, selected, - ms); + ms, + videoPaused); p.translate(0, st::dialogsRowHeight); } } @@ -686,13 +690,13 @@ Ui::VideoUserpic *InnerWidget::validateVideoUserpic( if (i != end(_videoUserpics)) { return i->second.get(); } - const auto update = [=] { + const auto repaint = [=] { updateDialogRow({ history, FullMsgId() }); updateSearchResult(history->peer); }; return _videoUserpics.emplace(peer, std::make_unique( peer, - update + repaint )).first->second.get(); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index e736bd78a..f2953d94e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -80,22 +80,6 @@ namespace { : accumulated; } -void PaintUserpic( - Painter &p, - not_null peer, - Ui::VideoUserpic *videoUserpic, - std::shared_ptr &view, - int x, - int y, - int outerWidth, - int size) { - if (videoUserpic) { - videoUserpic->paintLeft(p, view, x, y, outerWidth, size); - } else { - peer->paintUserpicLeft(p, view, x, y, outerWidth, size); - } -} - } // namespace BasicRow::BasicRow() = default; @@ -142,7 +126,8 @@ void BasicRow::paintUserpic( History *historyForCornerBadge, crl::time now, bool active, - int fullWidth) const { + int fullWidth, + bool paused) const { PaintUserpic( p, peer, @@ -151,7 +136,8 @@ void BasicRow::paintUserpic( st::dialogsPadding.x(), st::dialogsPadding.y(), fullWidth, - st::dialogsPhotoSize); + st::dialogsPhotoSize, + paused); } Row::Row(Key key, int pos) : _id(key), _pos(pos) { @@ -232,7 +218,8 @@ void Row::PaintCornerBadgeFrame( not_null data, not_null peer, Ui::VideoUserpic *videoUserpic, - std::shared_ptr &view) { + std::shared_ptr &view, + bool paused) { data->frame.fill(Qt::transparent); Painter q(&data->frame); @@ -244,7 +231,8 @@ void Row::PaintCornerBadgeFrame( 0, 0, data->frame.width() / data->frame.devicePixelRatio(), - st::dialogsPhotoSize); + st::dialogsPhotoSize, + paused); PainterHighQualityEnabler hq(q); q.setCompositionMode(QPainter::CompositionMode_Source); @@ -279,7 +267,8 @@ void Row::paintUserpic( History *historyForCornerBadge, crl::time now, bool active, - int fullWidth) const { + int fullWidth, + bool paused) const { updateCornerBadgeShown(peer); const auto shown = _cornerBadgeUserpic @@ -293,7 +282,8 @@ void Row::paintUserpic( historyForCornerBadge, now, active, - fullWidth); + fullWidth, + paused); if (!historyForCornerBadge || !_cornerBadgeShown) { _cornerBadgeUserpic = nullptr; } @@ -322,7 +312,8 @@ void Row::paintUserpic( _cornerBadgeUserpic.get(), peer, videoUserpic, - userpicView()); + userpicView(), + paused); } p.drawImage(st::dialogsPadding, _cornerBadgeUserpic->frame); if (historyForCornerBadge->peer->isUser()) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index a9601e658..407082581 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -45,7 +45,8 @@ public: History *historyForCornerBadge, crl::time now, bool active, - int fullWidth) const; + int fullWidth, + bool paused) const; void addRipple(QPoint origin, QSize size, Fn updateCallback); void stopLastRipple(); @@ -84,7 +85,8 @@ public: History *historyForCornerBadge, crl::time now, bool active, - int fullWidth) const final override; + int fullWidth, + bool paused) const final override; [[nodiscard]] Key key() const { return _id; @@ -131,7 +133,8 @@ private: not_null data, not_null peer, Ui::VideoUserpic *videoUserpic, - std::shared_ptr &view); + std::shared_ptr &view, + bool paused); Key _id; int _pos = 0; diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index cf9290d0f..d29a52d88 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -302,6 +302,7 @@ enum class Flag { SavedMessages = 0x08, RepliesMessages = 0x10, AllowUserOnline = 0x20, + VideoPaused = 0x40, }; inline constexpr bool is_flag_type(Flag) { return true; } @@ -366,7 +367,8 @@ void paintRow( (flags & Flag::AllowUserOnline) ? history : nullptr, ms, active, - fullWidth); + fullWidth, + (flags & Flag::VideoPaused)); } else if (hiddenSenderInfo) { hiddenSenderInfo->emptyUserpic.paint( p, @@ -798,7 +800,8 @@ void RowPainter::paint( int fullWidth, bool active, bool selected, - crl::time ms) { + crl::time ms, + bool paused) { const auto entry = row->entry(); const auto history = row->history(); const auto peer = history ? history->peer.get() : nullptr; @@ -868,7 +871,8 @@ void RowPainter::paint( | (selected ? Flag::Selected : Flag(0)) | (allowUserOnline ? Flag::AllowUserOnline : Flag(0)) | (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0)) - | (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0)); + | (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0)) + | (paused ? Flag::VideoPaused : Flag(0)); const auto paintItemCallback = [&](int nameleft, int namewidth) { const auto texttop = st::dialogsPadding.y() + st::msgNameFont->height diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h index 00d973d0c..060adf690 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h @@ -37,7 +37,8 @@ public: int fullWidth, bool active, bool selected, - crl::time ms); + crl::time ms, + bool paused); static void paint( Painter &p, not_null row, diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp index 9d0fa8534..dacbf74f5 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp @@ -33,7 +33,8 @@ void VideoUserpic::paintLeft( int x, int y, int w, - int size) { + int size, + bool paused) { _lastSize = size; const auto photoId = _peer->userpicPhotoId(); @@ -76,11 +77,8 @@ void VideoUserpic::paintLeft( if (_video && _video->ready()) { startReady(); - const auto now = crl::now(); - p.drawPixmap( - x, - y, - _video->current(request(size), now)); + const auto now = paused ? crl::time(0) : crl::now(); + p.drawPixmap(x, y, _video->current(request(size), now)); } else { _peer->paintUserpicLeft(p, view, x, y, w, size); } @@ -122,4 +120,21 @@ void VideoUserpic::clipCallback(Media::Clip::Notification notification) { } } +void PaintUserpic( + Painter &p, + not_null peer, + Ui::VideoUserpic *videoUserpic, + std::shared_ptr &view, + int x, + int y, + int outerWidth, + int size, + bool paused) { + if (videoUserpic) { + videoUserpic->paintLeft(p, view, x, y, outerWidth, size, paused); + } else { + peer->paintUserpicLeft(p, view, x, y, outerWidth, size); + } +} + } // namespace Dialogs::Ui diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h b/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h index eecc89dc9..c5cf412b2 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h @@ -33,7 +33,8 @@ public: int x, int y, int w, - int size); + int size, + bool paused); private: void clipCallback(Media::Clip::Notification notification); @@ -51,4 +52,15 @@ private: }; +void PaintUserpic( + Painter &p, + not_null peer, + Ui::VideoUserpic *videoUserpic, + std::shared_ptr &view, + int x, + int y, + int outerWidth, + int size, + bool paused); + } // namespace Dialogs::Ui diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index d5677f8a5..401e3d05c 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -84,6 +84,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_changes.h" #include "data/stickers/data_stickers.h" #include "data/data_sponsored_messages.h" +#include "dialogs/ui/dialogs_video_userpic.h" #include "facades.h" #include "styles/style_chat.h" #include "styles/style_window.h" // st::windowMinWidth @@ -367,8 +368,7 @@ HistoryInner::HistoryInner( setMouseTracking(true); _controller->gifPauseLevelChanged( ) | rpl::start_with_next([=] { - if (!_controller->isGifPausedAtLeastFor( - Window::GifPauseReason::Any)) { + if (!elementIsGifPaused()) { update(); } }, lifetime()); @@ -1079,6 +1079,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { p.translate(0, -top); } + const auto paused = elementIsGifPaused(); enumerateUserpics([&](not_null view, int userpicTop) { // stop the enumeration if the userpic is below the painted rect if (userpicTop >= clip.top() + clip.height()) { @@ -1088,13 +1089,16 @@ void HistoryInner::paintEvent(QPaintEvent *e) { // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { if (const auto from = view->data()->displayFrom()) { - from->paintUserpicLeft( + Dialogs::Ui::PaintUserpic( p, + from, + validateVideoUserpic(from), _userpics[from], st::historyPhotoLeft, userpicTop, width(), - st::msgPhotoSize); + st::msgPhotoSize, + paused); } else if (const auto info = view->data()->hiddenSenderInfo()) { if (info->customUserpic.empty()) { info->emptyUserpic.paint( @@ -1200,6 +1204,46 @@ bool HistoryInner::eventHook(QEvent *e) { return RpWidget::eventHook(e); } +HistoryInner::VideoUserpic *HistoryInner::validateVideoUserpic( + not_null peer) { + if (!peer->isPremium() + || peer->userpicPhotoUnknown() + || !peer->userpicHasVideo()) { + _videoUserpics.remove(peer); + return nullptr; + } + const auto i = _videoUserpics.find(peer); + if (i != end(_videoUserpics)) { + return i->second.get(); + } + const auto repaint = [=] { + enumerateUserpics([&](not_null view, int userpicTop) { + // stop the enumeration if the userpic is below the painted rect + if (userpicTop >= _visibleAreaBottom) { + return false; + } + + // repaint the userpic if it intersects the painted rect + if (userpicTop + st::msgPhotoSize > _visibleAreaTop) { + if (const auto from = view->data()->displayFrom()) { + if (from == peer) { + rtlupdate( + st::historyPhotoLeft, + userpicTop, + st::msgPhotoSize, + st::msgPhotoSize); + } + } + } + return true; + }); + }; + return _videoUserpics.emplace(peer, std::make_unique( + peer, + repaint + )).first->second.get(); +} + void HistoryInner::onTouchScrollTimer() { auto nowTime = crl::now(); if (_touchScrollState == Ui::TouchScrollState::Acceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) { diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 0fcef0e30..beefbfa80 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -49,6 +49,10 @@ struct ChatPaintContext; class PathShiftGradient; } // namespace Ui +namespace Dialogs::Ui { +class VideoUserpic; +} // namespace Dialogs::Ui + class HistoryInner; class HistoryMainElementDelegate; class HistoryMainElementDelegateMixin { @@ -209,6 +213,7 @@ private: void onTouchScrollTimer(); class BotAbout; + using VideoUserpic = Dialogs::Ui::VideoUserpic; using SelectedItems = std::map>; enum class MouseAction { None, @@ -387,6 +392,8 @@ private: bool showCopyRestrictionForSelected(); [[nodiscard]] bool hasSelectRestriction() const; + VideoUserpic *validateVideoUserpic(not_null peer); + // Does any of the shown histories has this flag set. bool hasPendingResizedItems() const; @@ -434,6 +441,9 @@ private: base::flat_map< MsgId, std::shared_ptr> _sponsoredUserpics; + base::flat_map< + not_null, + std::unique_ptr> _videoUserpics; std::unique_ptr _reactionsManager;