tdesktop/Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp

175 lines
3.9 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "dialogs/ui/dialogs_video_userpic.h"
#include "core/file_location.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_file_origin.h"
#include "data/data_session.h"
#include "dialogs/ui/dialogs_layout.h"
#include "ui/painter.h"
#include "styles/style_dialogs.h"
namespace Dialogs::Ui {
VideoUserpic::VideoUserpic(not_null<PeerData*> peer, Fn<void()> repaint)
: _peer(peer)
, _repaint(std::move(repaint)) {
}
VideoUserpic::~VideoUserpic() = default;
int VideoUserpic::frameIndex() const {
return -1;
}
void VideoUserpic::paintLeft(
Painter &p,
Ui::PeerUserpicView &view,
int x,
int y,
int w,
int size,
bool paused) {
_lastSize = size;
const auto photoId = _peer->userpicPhotoId();
if (_videoPhotoId != photoId) {
_videoPhotoId = photoId;
_video = nullptr;
_videoPhotoMedia = nullptr;
const auto photo = _peer->owner().photo(photoId);
if (photo->isNull()) {
_peer->updateFullForced();
} else {
_videoPhotoMedia = photo->createMediaView();
_videoPhotoMedia->videoWanted(
Data::PhotoSize::Small,
_peer->userpicPhotoOrigin());
}
}
if (!_video) {
if (!_videoPhotoMedia) {
const auto photo = _peer->owner().photo(photoId);
if (!photo->isNull()) {
_videoPhotoMedia = photo->createMediaView();
_videoPhotoMedia->videoWanted(
Data::PhotoSize::Small,
_peer->userpicPhotoOrigin());
}
}
if (_videoPhotoMedia) {
auto small = _videoPhotoMedia->videoContent(
Data::PhotoSize::Small);
auto bytes = small.isEmpty()
? _videoPhotoMedia->videoContent(Data::PhotoSize::Large)
: small;
if (!bytes.isEmpty()) {
auto callback = [=](Media::Clip::Notification notification) {
clipCallback(notification);
};
_video = Media::Clip::MakeReader(
Core::FileLocation(),
std::move(bytes),
std::move(callback));
}
}
}
if (rtl()) {
x = w - x - size;
}
if (_video && _video->ready()) {
startReady();
const auto now = paused ? crl::time(0) : crl::now();
p.drawImage(x, y, _video->current(request(size), now));
} else {
_peer->paintUserpicLeft(p, view, x, y, w, size);
}
}
Media::Clip::FrameRequest VideoUserpic::request(int size) const {
return {
.frame = { size, size },
.outer = { size, size },
.factor = style::DevicePixelRatio(),
.radius = ImageRoundRadius::Ellipse,
};
}
bool VideoUserpic::startReady(int size) {
if (!_video->ready() || _video->started()) {
return false;
} else if (!_lastSize) {
_lastSize = size ? size : _video->width();
}
_video->start(request(_lastSize));
_repaint();
return true;
}
void VideoUserpic::clipCallback(Media::Clip::Notification notification) {
using namespace Media::Clip;
switch (notification) {
case Notification::Reinit: {
if (_video->state() == State::Error) {
_video.setBad();
} else if (startReady()) {
_repaint();
}
} break;
case Notification::Repaint: _repaint(); break;
}
}
void PaintUserpic(
Painter &p,
not_null<Entry*> entry,
PeerData *peer,
VideoUserpic *videoUserpic,
PeerUserpicView &view,
const Ui::PaintContext &context) {
if (peer) {
PaintUserpic(
p,
peer,
videoUserpic,
view,
context.st->padding.left(),
context.st->padding.top(),
context.width,
context.st->photoSize,
context.paused);
} else {
entry->paintUserpic(p, view, context);
}
}
void PaintUserpic(
Painter &p,
not_null<PeerData*> peer,
Ui::VideoUserpic *videoUserpic,
Ui::PeerUserpicView &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