mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Animate video userpics in chat history.
This commit is contained in:
parent
201edb2e69
commit
73bacfc650
9 changed files with 129 additions and 45 deletions
|
@ -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<Ui::VideoUserpic>(
|
||||
peer,
|
||||
update
|
||||
repaint
|
||||
)).first->second.get();
|
||||
}
|
||||
|
||||
|
|
|
@ -80,22 +80,6 @@ namespace {
|
|||
: accumulated;
|
||||
}
|
||||
|
||||
void PaintUserpic(
|
||||
Painter &p,
|
||||
not_null<PeerData*> peer,
|
||||
Ui::VideoUserpic *videoUserpic,
|
||||
std::shared_ptr<Data::CloudImageView> &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<CornerBadgeUserpic*> data,
|
||||
not_null<PeerData*> peer,
|
||||
Ui::VideoUserpic *videoUserpic,
|
||||
std::shared_ptr<Data::CloudImageView> &view) {
|
||||
std::shared_ptr<Data::CloudImageView> &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()) {
|
||||
|
|
|
@ -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<void()> 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<CornerBadgeUserpic*> data,
|
||||
not_null<PeerData*> peer,
|
||||
Ui::VideoUserpic *videoUserpic,
|
||||
std::shared_ptr<Data::CloudImageView> &view);
|
||||
std::shared_ptr<Data::CloudImageView> &view,
|
||||
bool paused);
|
||||
|
||||
Key _id;
|
||||
int _pos = 0;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<const FakeRow*> row,
|
||||
|
|
|
@ -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<PeerData*> peer,
|
||||
Ui::VideoUserpic *videoUserpic,
|
||||
std::shared_ptr<Data::CloudImageView> &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
|
||||
|
|
|
@ -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<PeerData*> peer,
|
||||
Ui::VideoUserpic *videoUserpic,
|
||||
std::shared_ptr<Data::CloudImageView> &view,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth,
|
||||
int size,
|
||||
bool paused);
|
||||
|
||||
} // namespace Dialogs::Ui
|
||||
|
|
|
@ -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<Element*> 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<PeerData*> 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<Element*> 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<VideoUserpic>(
|
||||
peer,
|
||||
repaint
|
||||
)).first->second.get();
|
||||
}
|
||||
|
||||
void HistoryInner::onTouchScrollTimer() {
|
||||
auto nowTime = crl::now();
|
||||
if (_touchScrollState == Ui::TouchScrollState::Acceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) {
|
||||
|
|
|
@ -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<HistoryItem*, TextSelection, std::less<>>;
|
||||
enum class MouseAction {
|
||||
None,
|
||||
|
@ -387,6 +392,8 @@ private:
|
|||
bool showCopyRestrictionForSelected();
|
||||
[[nodiscard]] bool hasSelectRestriction() const;
|
||||
|
||||
VideoUserpic *validateVideoUserpic(not_null<PeerData*> 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<Data::CloudImageView>> _sponsoredUserpics;
|
||||
base::flat_map<
|
||||
not_null<PeerData*>,
|
||||
std::unique_ptr<VideoUserpic>> _videoUserpics;
|
||||
|
||||
std::unique_ptr<HistoryView::Reactions::Manager> _reactionsManager;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue