mirror of https://github.com/procxx/kepka.git
Load and show video thumbnails in the panel.
This commit is contained in:
parent
33c1c48ad9
commit
3c9ca2eb94
|
@ -606,7 +606,8 @@ bool DocumentData::checkWallPaperProperties() {
|
|||
|
||||
void DocumentData::updateThumbnails(
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
const ImageWithLocation &thumbnail) {
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &videoThumbnail) {
|
||||
if (!inlineThumbnailBytes.isEmpty()
|
||||
&& _inlineThumbnailBytes.isEmpty()) {
|
||||
_inlineThumbnailBytes = inlineThumbnailBytes;
|
||||
|
@ -636,10 +637,16 @@ void DocumentData::updateThumbnails(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ImageLocation &DocumentData::thumbnailLocation() const {
|
||||
return _thumbnailLocation;
|
||||
if (videoThumbnail.location.valid()
|
||||
&& !_videoThumbnailLocation.valid()) {
|
||||
_videoThumbnailLocation = videoThumbnail.location;
|
||||
_videoThumbnailByteSize = videoThumbnail.bytesCount;
|
||||
if (_videoThumbnailLoader) {
|
||||
const auto origin
|
||||
= base::take(_videoThumbnailLoader)->fileOrigin();
|
||||
loadVideoThumbnail(origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DocumentData::isWallPaper() const {
|
||||
|
@ -702,6 +709,67 @@ void DocumentData::loadThumbnail(Data::FileOrigin origin) {
|
|||
_thumbnailLoader->start();
|
||||
}
|
||||
|
||||
const ImageLocation &DocumentData::thumbnailLocation() const {
|
||||
return _thumbnailLocation;
|
||||
}
|
||||
|
||||
bool DocumentData::hasVideoThumbnail() const {
|
||||
return _videoThumbnailLocation.valid()
|
||||
&& (_videoThumbnailLocation.width() > 0)
|
||||
&& (_videoThumbnailLocation.height() > 0);
|
||||
}
|
||||
|
||||
bool DocumentData::videoThumbnailLoading() const {
|
||||
return _videoThumbnailLoader != nullptr;
|
||||
}
|
||||
|
||||
bool DocumentData::videoThumbnailFailed() const {
|
||||
return (_flags & Flag::VideoThumbnailFailed);
|
||||
}
|
||||
|
||||
void DocumentData::loadVideoThumbnail(Data::FileOrigin origin) {
|
||||
if (_videoThumbnailLoader || (_flags & Flag::VideoThumbnailFailed)) {
|
||||
return;
|
||||
} else if (const auto active = activeMediaView()) {
|
||||
if (!active->videoThumbnailContent().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto autoLoading = false;
|
||||
_videoThumbnailLoader = CreateFileLoader(
|
||||
_videoThumbnailLocation.file(),
|
||||
origin,
|
||||
QString(),
|
||||
_videoThumbnailByteSize,
|
||||
UnknownFileLocation,
|
||||
LoadToCacheAsWell,
|
||||
LoadFromCloudOrLocal,
|
||||
autoLoading,
|
||||
Data::kAnimationCacheTag);
|
||||
|
||||
_videoThumbnailLoader->updates(
|
||||
) | rpl::start_with_error_done([=](bool started) {
|
||||
_videoThumbnailLoader = nullptr;
|
||||
_flags |= Flag::VideoThumbnailFailed;
|
||||
}, [=] {
|
||||
if (_videoThumbnailLoader && !_videoThumbnailLoader->cancelled()) {
|
||||
auto bytes = _videoThumbnailLoader->bytes();
|
||||
if (bytes.isEmpty()) {
|
||||
_flags |= Flag::VideoThumbnailFailed;
|
||||
} else if (const auto active = activeMediaView()) {
|
||||
active->setVideoThumbnail(std::move(bytes));
|
||||
}
|
||||
}
|
||||
_videoThumbnailLoader = nullptr;
|
||||
}, _videoThumbnailLoader->lifetime());
|
||||
|
||||
_videoThumbnailLoader->start();
|
||||
}
|
||||
|
||||
const ImageLocation &DocumentData::videoThumbnailLocation() const {
|
||||
return _videoThumbnailLocation;
|
||||
}
|
||||
|
||||
Storage::Cache::Key DocumentData::goodThumbnailCacheKey() const {
|
||||
return Data::DocumentThumbCacheKey(_dc, id);
|
||||
}
|
||||
|
|
|
@ -159,10 +159,18 @@ public:
|
|||
[[nodiscard]] bool thumbnailLoading() const;
|
||||
[[nodiscard]] bool thumbnailFailed() const;
|
||||
void loadThumbnail(Data::FileOrigin origin);
|
||||
const ImageLocation &thumbnailLocation() const;
|
||||
|
||||
[[nodiscard]] bool hasVideoThumbnail() const;
|
||||
[[nodiscard]] bool videoThumbnailLoading() const;
|
||||
[[nodiscard]] bool videoThumbnailFailed() const;
|
||||
void loadVideoThumbnail(Data::FileOrigin origin);
|
||||
const ImageLocation &videoThumbnailLocation() const;
|
||||
|
||||
void updateThumbnails(
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
const ImageWithLocation &thumbnail);
|
||||
const ImageLocation &thumbnailLocation() const;
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &videoThumbnail);
|
||||
|
||||
[[nodiscard]] QByteArray inlineThumbnailBytes() const {
|
||||
return _inlineThumbnailBytes;
|
||||
|
@ -247,6 +255,7 @@ private:
|
|||
DownloadCancelled = 0x10,
|
||||
LoadedInMediaCache = 0x20,
|
||||
ThumbnailFailed = 0x40,
|
||||
VideoThumbnailFailed = 0x80,
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend constexpr bool is_flag_type(Flag) { return true; };
|
||||
|
@ -300,8 +309,11 @@ private:
|
|||
|
||||
QByteArray _inlineThumbnailBytes;
|
||||
ImageLocation _thumbnailLocation;
|
||||
ImageLocation _videoThumbnailLocation;
|
||||
std::unique_ptr<FileLoader> _thumbnailLoader;
|
||||
std::unique_ptr<FileLoader> _videoThumbnailLoader;
|
||||
int _thumbnailByteSize = 0;
|
||||
int _videoThumbnailByteSize = 0;
|
||||
std::unique_ptr<Data::ReplyPreview> _replyPreview;
|
||||
std::weak_ptr<Data::DocumentMedia> _media;
|
||||
PhotoData *_goodThumbnailPhoto = nullptr;
|
||||
|
|
|
@ -154,6 +154,25 @@ void DocumentMedia::setThumbnail(QImage thumbnail) {
|
|||
_owner->session().downloaderTaskFinished().notify();
|
||||
}
|
||||
|
||||
QByteArray DocumentMedia::videoThumbnailContent() const {
|
||||
return _videoThumbnailBytes;
|
||||
}
|
||||
|
||||
QSize DocumentMedia::videoThumbnailSize() const {
|
||||
const auto &location = _owner->videoThumbnailLocation();
|
||||
return { location.width(), location.height() };
|
||||
}
|
||||
|
||||
void DocumentMedia::videoThumbnailWanted(Data::FileOrigin origin) {
|
||||
if (_videoThumbnailBytes.isEmpty()) {
|
||||
_owner->loadVideoThumbnail(origin);
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentMedia::setVideoThumbnail(QByteArray content) {
|
||||
_videoThumbnailBytes = std::move(content);
|
||||
}
|
||||
|
||||
void DocumentMedia::checkStickerLarge() {
|
||||
if (_sticker) {
|
||||
return;
|
||||
|
|
|
@ -25,11 +25,17 @@ public:
|
|||
void setGoodThumbnail(QImage thumbnail);
|
||||
|
||||
[[nodiscard]] Image *thumbnailInline() const;
|
||||
|
||||
[[nodiscard]] Image *thumbnail() const;
|
||||
[[nodiscard]] QSize thumbnailSize() const;
|
||||
void thumbnailWanted(Data::FileOrigin origin);
|
||||
void setThumbnail(QImage thumbnail);
|
||||
|
||||
[[nodiscard]] QByteArray videoThumbnailContent() const;
|
||||
[[nodiscard]] QSize videoThumbnailSize() const;
|
||||
void videoThumbnailWanted(Data::FileOrigin origin);
|
||||
void setVideoThumbnail(QByteArray content);
|
||||
|
||||
void checkStickerLarge();
|
||||
void checkStickerSmall();
|
||||
[[nodiscard]] Image *getStickerSmall();
|
||||
|
@ -67,6 +73,7 @@ private:
|
|||
std::unique_ptr<Image> _thumbnail;
|
||||
std::unique_ptr<Image> _sticker;
|
||||
QByteArray _bytes;
|
||||
QByteArray _videoThumbnailBytes;
|
||||
Flags _flags;
|
||||
|
||||
};
|
||||
|
|
|
@ -165,6 +165,25 @@ MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
|
|||
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string()));
|
||||
}
|
||||
|
||||
std::optional<MTPVideoSize> FindDocumentVideoThumbnail(
|
||||
const MTPDdocument &data) {
|
||||
const auto area = [](const MTPVideoSize &size) {
|
||||
static constexpr auto kInvalid = 0;
|
||||
return size.match([](const MTPDvideoSize &data) {
|
||||
return (data.vw().v * data.vh().v);
|
||||
});
|
||||
};
|
||||
const auto thumbs = data.vvideo_thumbs();
|
||||
if (!thumbs) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto &list = thumbs->v;
|
||||
const auto i = ranges::max_element(list, std::less<>(), area);
|
||||
return (i != list.end() && area(*i) > 0)
|
||||
? std::make_optional(*i)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
rpl::producer<int> PinnedDialogsCountMaxValue(
|
||||
not_null<Main::Session*> session) {
|
||||
return rpl::single(
|
||||
|
@ -2382,6 +2401,7 @@ not_null<DocumentData*> Session::processDocument(
|
|||
qs(data.vmime_type()),
|
||||
QByteArray(),
|
||||
thumbnail,
|
||||
ImageWithLocation(),
|
||||
data.vdc_id().v,
|
||||
data.vsize().v);
|
||||
}, [&](const MTPDdocumentEmpty &data) {
|
||||
|
@ -2398,6 +2418,7 @@ not_null<DocumentData*> Session::document(
|
|||
const QString &mime,
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &videoThumbnail,
|
||||
int32 dc,
|
||||
int32 size) {
|
||||
const auto result = document(id);
|
||||
|
@ -2410,6 +2431,7 @@ not_null<DocumentData*> Session::document(
|
|||
mime,
|
||||
inlineThumbnailBytes,
|
||||
thumbnail,
|
||||
videoThumbnail,
|
||||
dc,
|
||||
size);
|
||||
return result;
|
||||
|
@ -2478,6 +2500,7 @@ DocumentData *Session::documentFromWeb(
|
|||
data.vmime_type().v,
|
||||
QByteArray(),
|
||||
ImageWithLocation{ .location = thumbnailLocation },
|
||||
ImageWithLocation(),
|
||||
MTP::maindc(),
|
||||
int32(0)); // data.vsize().v
|
||||
result->setWebLocation(WebFileLocation(
|
||||
|
@ -2498,6 +2521,7 @@ DocumentData *Session::documentFromWeb(
|
|||
data.vmime_type().v,
|
||||
QByteArray(),
|
||||
ImageWithLocation{ .location = thumbnailLocation },
|
||||
ImageWithLocation(),
|
||||
MTP::maindc(),
|
||||
int32(0)); // data.vsize().v
|
||||
result->setContentUrl(qs(data.vurl()));
|
||||
|
@ -2517,10 +2541,14 @@ void Session::documentApplyFields(
|
|||
const MTPDdocument &data) {
|
||||
const auto inlineThumbnailBytes = FindDocumentInlineThumbnail(data);
|
||||
const auto thumbnailSize = FindDocumentThumbnail(data);
|
||||
const auto videoThumbnailSize = FindDocumentVideoThumbnail(data);
|
||||
const auto prepared = Images::FromPhotoSize(
|
||||
_session,
|
||||
data,
|
||||
thumbnailSize);
|
||||
const auto videoThumbnail = videoThumbnailSize
|
||||
? Images::FromVideoSize(_session, data, *videoThumbnailSize)
|
||||
: ImageWithLocation();
|
||||
documentApplyFields(
|
||||
document,
|
||||
data.vaccess_hash().v,
|
||||
|
@ -2530,6 +2558,7 @@ void Session::documentApplyFields(
|
|||
qs(data.vmime_type()),
|
||||
inlineThumbnailBytes,
|
||||
prepared,
|
||||
videoThumbnail,
|
||||
data.vdc_id().v,
|
||||
data.vsize().v);
|
||||
}
|
||||
|
@ -2543,6 +2572,7 @@ void Session::documentApplyFields(
|
|||
const QString &mime,
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &videoThumbnail,
|
||||
int32 dc,
|
||||
int32 size) {
|
||||
if (!date) {
|
||||
|
@ -2550,7 +2580,10 @@ void Session::documentApplyFields(
|
|||
}
|
||||
document->date = date;
|
||||
document->setMimeString(mime);
|
||||
document->updateThumbnails(inlineThumbnailBytes, thumbnail);
|
||||
document->updateThumbnails(
|
||||
inlineThumbnailBytes,
|
||||
thumbnail,
|
||||
videoThumbnail);
|
||||
document->size = size;
|
||||
document->setattributes(attributes);
|
||||
|
||||
|
|
|
@ -500,6 +500,7 @@ public:
|
|||
const QString &mime,
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &videoThumbnail,
|
||||
int32 dc,
|
||||
int32 size);
|
||||
void documentConvert(
|
||||
|
@ -754,6 +755,7 @@ private:
|
|||
const QString &mime,
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &videoThumbnail,
|
||||
int32 dc,
|
||||
int32 size);
|
||||
DocumentData *documentFromWeb(
|
||||
|
|
|
@ -134,26 +134,41 @@ int Gif::resizeGetHeight(int width) {
|
|||
void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||
const auto document = getShownDocument();
|
||||
const auto displayLoading = document->displayLoading();
|
||||
|
||||
const auto useVideoThumbnail = document->hasVideoThumbnail();
|
||||
ensureDataMediaCreated(document);
|
||||
_dataMedia->automaticLoad(fileOrigin(), nullptr);
|
||||
if (!useVideoThumbnail) {
|
||||
_dataMedia->automaticLoad(fileOrigin(), nullptr);
|
||||
}
|
||||
|
||||
bool loaded = _dataMedia->loaded(), loading = document->loading();
|
||||
const auto loaded = useVideoThumbnail
|
||||
? !_dataMedia->videoThumbnailContent().isEmpty()
|
||||
: _dataMedia->loaded();
|
||||
const auto loading = useVideoThumbnail
|
||||
? document->videoThumbnailLoading()
|
||||
: document->loading();
|
||||
if (loaded
|
||||
&& !_gif
|
||||
&& !_gif.isBad()
|
||||
&& CanPlayInline(document)) {
|
||||
auto that = const_cast<Gif*>(this);
|
||||
that->_gif = Media::Clip::MakeReader(_dataMedia.get(), FullMsgId(), [that](Media::Clip::Notification notification) {
|
||||
const auto callback = [=](Media::Clip::Notification notification) {
|
||||
that->clipCallback(notification);
|
||||
});
|
||||
};
|
||||
that->_gif = useVideoThumbnail
|
||||
? Media::Clip::MakeReader(
|
||||
_dataMedia->videoThumbnailContent(),
|
||||
callback)
|
||||
: Media::Clip::MakeReader(
|
||||
_dataMedia.get(),
|
||||
FullMsgId(),
|
||||
callback);
|
||||
}
|
||||
|
||||
const auto animating = (_gif && _gif->started());
|
||||
if (displayLoading) {
|
||||
ensureAnimation();
|
||||
if (!_animation->radial.animating()) {
|
||||
_animation->radial.start(_dataMedia->progress());
|
||||
_animation->radial.start(_dataMedia->progress()); // #TODO video_thumbs
|
||||
}
|
||||
}
|
||||
const auto radial = isRadialAnimation();
|
||||
|
@ -177,6 +192,10 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
|
|||
p.drawPixmap(r.topLeft(), _thumb);
|
||||
}
|
||||
}
|
||||
if (useVideoThumbnail) {
|
||||
AssertIsDebug();
|
||||
p.fillRect(QRect(r.topLeft(), QSize(20, 20)), Qt::green);
|
||||
}
|
||||
|
||||
if (radial || _gif.isBad() || (!_gif && !loaded && !loading)) {
|
||||
auto radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1.;
|
||||
|
@ -250,7 +269,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
|
|||
bool wasactive = (_state & StateFlag::Over);
|
||||
if (active != wasactive) {
|
||||
ensureDataMediaCreated(getShownDocument());
|
||||
if (!_dataMedia->loaded()) {
|
||||
if (!_dataMedia->loaded()) { // #TODO video_thumbs
|
||||
ensureAnimation();
|
||||
auto from = active ? 0. : 1., to = active ? 1. : 0.;
|
||||
_animation->_a_over.start([this] { update(); }, from, to, st::stickersRowDuration);
|
||||
|
@ -333,6 +352,7 @@ void Gif::ensureDataMediaCreated(not_null<DocumentData*> document) const {
|
|||
}
|
||||
_dataMedia = document->createMediaView();
|
||||
_dataMedia->thumbnailWanted(fileOrigin());
|
||||
_dataMedia->videoThumbnailWanted(fileOrigin());
|
||||
}
|
||||
|
||||
void Gif::ensureAnimation() const {
|
||||
|
@ -349,7 +369,7 @@ bool Gif::isRadialAnimation() const {
|
|||
return true;
|
||||
} else {
|
||||
ensureDataMediaCreated(getShownDocument());
|
||||
if (_dataMedia->loaded()) {
|
||||
if (_dataMedia->loaded()) { // #TODO video_thumbs
|
||||
_animation = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -362,7 +382,7 @@ void Gif::radialAnimationCallback(crl::time now) const {
|
|||
ensureDataMediaCreated(document);
|
||||
const auto updated = [&] {
|
||||
return _animation->radial.update(
|
||||
_dataMedia->progress(),
|
||||
_dataMedia->progress(), // #TODO video_thumbs
|
||||
!document->loading() || _dataMedia->loaded(),
|
||||
now);
|
||||
}();
|
||||
|
|
|
@ -3945,6 +3945,7 @@ void importOldRecentStickers() {
|
|||
mime,
|
||||
QByteArray(),
|
||||
ImageWithLocation(),
|
||||
ImageWithLocation(),
|
||||
dc,
|
||||
size);
|
||||
if (!doc->sticker()) {
|
||||
|
|
|
@ -143,6 +143,7 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &
|
|||
mime,
|
||||
QByteArray(),
|
||||
ImageWithLocation{ .location = *thumb },
|
||||
ImageWithLocation(),
|
||||
dc,
|
||||
size);
|
||||
}
|
||||
|
|
|
@ -121,4 +121,26 @@ ImageLocation FromWebDocument(const MTPWebDocument &document) {
|
|||
});
|
||||
}
|
||||
|
||||
ImageWithLocation FromVideoSize(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDdocument &document,
|
||||
const MTPVideoSize &size) {
|
||||
return size.match([&](const MTPDvideoSize &data) {
|
||||
return ImageWithLocation{
|
||||
.location = ImageLocation(
|
||||
DownloadLocation{ StorageFileLocation(
|
||||
document.vdc_id().v,
|
||||
session->userId(),
|
||||
MTP_inputDocumentFileLocation(
|
||||
document.vid(),
|
||||
document.vaccess_hash(),
|
||||
document.vfile_reference(),
|
||||
data.vtype())) },
|
||||
data.vw().v,
|
||||
data.vh().v),
|
||||
.bytesCount = data.vsize().v
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Images
|
||||
|
|
|
@ -19,6 +19,10 @@ namespace Images {
|
|||
not_null<Main::Session*> session,
|
||||
const MTPDdocument &document,
|
||||
const MTPPhotoSize &size);
|
||||
[[nodiscard]] ImageWithLocation FromVideoSize(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDdocument &document,
|
||||
const MTPVideoSize &size);
|
||||
[[nodiscard]] ImageWithLocation FromImageInMemory(
|
||||
const QImage &image,
|
||||
const char *format);
|
||||
|
|
Loading…
Reference in New Issue