mirror of https://github.com/procxx/kepka.git
Use Data::DocumentMedia to store good thumbnails.
This commit is contained in:
parent
61647275e8
commit
7db53599e8
|
@ -360,6 +360,8 @@ PRIVATE
|
|||
data/data_document.h
|
||||
data/data_document_good_thumbnail.cpp
|
||||
data/data_document_good_thumbnail.h
|
||||
data/data_document_media.cpp
|
||||
data/data_document_media.h
|
||||
data/data_drafts.cpp
|
||||
data/data_drafts.h
|
||||
data/data_folder.cpp
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_session.h"
|
||||
#include "data/data_streaming.h"
|
||||
#include "data/data_document_good_thumbnail.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "inline_bots/inline_bot_layout_item.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -569,7 +570,6 @@ void DocumentData::setattributes(
|
|||
_additional = nullptr;
|
||||
}
|
||||
}
|
||||
validateGoodThumbnail();
|
||||
if (isAudioFile() || isAnimation() || isVoiceMessage()) {
|
||||
setMaybeSupportsStreaming(true);
|
||||
}
|
||||
|
@ -612,7 +612,6 @@ bool DocumentData::checkWallPaperProperties() {
|
|||
return false; // #TODO themes support svg patterns
|
||||
}
|
||||
type = WallPaperDocument;
|
||||
validateGoodThumbnail();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -661,48 +660,65 @@ Storage::Cache::Key DocumentData::goodThumbnailCacheKey() const {
|
|||
return Data::DocumentThumbCacheKey(_dc, id);
|
||||
}
|
||||
|
||||
Image *DocumentData::goodThumbnail() const {
|
||||
return _goodThumbnail.get();
|
||||
bool DocumentData::goodThumbnailChecked() const {
|
||||
return (_goodThumbnailState & GoodThumbnailFlag::Mask)
|
||||
== GoodThumbnailFlag::Checked;
|
||||
}
|
||||
|
||||
void DocumentData::validateGoodThumbnail() {
|
||||
if (!isVideoFile()
|
||||
&& !isAnimation()
|
||||
&& !isWallPaper()
|
||||
&& !isTheme()
|
||||
&& (!sticker() || !sticker()->animated)) {
|
||||
_goodThumbnail = nullptr;
|
||||
} else if (!_goodThumbnail && hasRemoteLocation()) {
|
||||
_goodThumbnail = std::make_unique<Image>(
|
||||
std::make_unique<Data::GoodThumbSource>(this));
|
||||
}
|
||||
bool DocumentData::goodThumbnailGenerating() const {
|
||||
return (_goodThumbnailState & GoodThumbnailFlag::Mask)
|
||||
== GoodThumbnailFlag::Generating;
|
||||
}
|
||||
|
||||
void DocumentData::refreshGoodThumbnail() {
|
||||
if (_goodThumbnail && hasRemoteLocation()) {
|
||||
replaceGoodThumbnail(std::make_unique<Data::GoodThumbSource>(this));
|
||||
}
|
||||
bool DocumentData::goodThumbnailNoData() const {
|
||||
return (_goodThumbnailState & GoodThumbnailFlag::Mask)
|
||||
== GoodThumbnailFlag::NoData;
|
||||
}
|
||||
|
||||
void DocumentData::replaceGoodThumbnail(
|
||||
std::unique_ptr<Images::Source> &&source) {
|
||||
_goodThumbnail->replaceSource(std::move(source));
|
||||
void DocumentData::setGoodThumbnailGenerating() {
|
||||
_goodThumbnailState = (_goodThumbnailState & ~GoodThumbnailFlag::Mask)
|
||||
| GoodThumbnailFlag::Generating;
|
||||
}
|
||||
|
||||
void DocumentData::setGoodThumbnailOnUpload(
|
||||
QImage &&image,
|
||||
QByteArray &&bytes) {
|
||||
Expects(uploadingData != nullptr);
|
||||
void DocumentData::setGoodThumbnailDataReady() {
|
||||
_goodThumbnailState = GoodThumbnailFlag::DataReady
|
||||
| (goodThumbnailNoData()
|
||||
? GoodThumbnailFlag(0)
|
||||
: (_goodThumbnailState & GoodThumbnailFlag::Mask));
|
||||
}
|
||||
|
||||
if (image.isNull()) {
|
||||
void DocumentData::setGoodThumbnailChecked(bool hasData) {
|
||||
if (!hasData && (_goodThumbnailState & GoodThumbnailFlag::DataReady)) {
|
||||
_goodThumbnailState &= ~GoodThumbnailFlag::DataReady;
|
||||
_goodThumbnailState &= ~GoodThumbnailFlag::Mask;
|
||||
Data::DocumentMedia::CheckGoodThumbnail(this);
|
||||
return;
|
||||
}
|
||||
_goodThumbnail = std::make_unique<Image>(
|
||||
std::make_unique<Images::LocalFileSource>(
|
||||
QString(),
|
||||
std::move(bytes),
|
||||
sticker() ? "WEBP" : "JPG",
|
||||
std::move(image)));
|
||||
_goodThumbnailState = (_goodThumbnailState & ~GoodThumbnailFlag::Mask)
|
||||
| (hasData
|
||||
? GoodThumbnailFlag::Checked
|
||||
: GoodThumbnailFlag::NoData);
|
||||
}
|
||||
|
||||
std::shared_ptr<Data::DocumentMedia> DocumentData::createMediaView() {
|
||||
if (auto result = activeMediaView()) {
|
||||
return result;
|
||||
}
|
||||
auto result = std::make_shared<Data::DocumentMedia>(this);
|
||||
_media = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<Data::DocumentMedia> DocumentData::activeMediaView() {
|
||||
return _media.lock();
|
||||
}
|
||||
|
||||
void DocumentData::setGoodThumbnailPhoto(not_null<PhotoData*> photo) {
|
||||
_goodThumbnailPhoto = photo;
|
||||
}
|
||||
|
||||
PhotoData *DocumentData::goodThumbnailPhoto() const {
|
||||
return _goodThumbnailPhoto;
|
||||
}
|
||||
|
||||
auto DocumentData::bigFileBaseCacheKey() const
|
||||
|
@ -817,7 +833,8 @@ bool DocumentData::loaded(FilePathResolve resolve) const {
|
|||
ActiveCache().increment(ComputeUsage(that->sticker()));
|
||||
}
|
||||
|
||||
that->refreshGoodThumbnail();
|
||||
that->setGoodThumbnailDataReady();
|
||||
Data::DocumentMedia::CheckGoodThumbnail(that);
|
||||
destroyLoader();
|
||||
|
||||
if (!that->_data.isEmpty() || that->getStickerLarge()) {
|
||||
|
@ -1606,7 +1623,6 @@ void DocumentData::setRemoteLocation(
|
|||
}
|
||||
}
|
||||
}
|
||||
validateGoodThumbnail();
|
||||
}
|
||||
|
||||
void DocumentData::setContentUrl(const QString &url) {
|
||||
|
|
|
@ -32,6 +32,7 @@ class Loader;
|
|||
|
||||
namespace Data {
|
||||
class Session;
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
|
@ -180,11 +181,18 @@ public:
|
|||
ImagePtr thumbnailInline,
|
||||
ImagePtr thumbnail);
|
||||
|
||||
[[nodiscard]] Image *goodThumbnail() const;
|
||||
[[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const;
|
||||
void setGoodThumbnailOnUpload(QImage &&image, QByteArray &&bytes);
|
||||
void refreshGoodThumbnail();
|
||||
void replaceGoodThumbnail(std::unique_ptr<Images::Source> &&source);
|
||||
[[nodiscard]] bool goodThumbnailChecked() const;
|
||||
[[nodiscard]] bool goodThumbnailGenerating() const;
|
||||
[[nodiscard]] bool goodThumbnailNoData() const;
|
||||
void setGoodThumbnailGenerating();
|
||||
void setGoodThumbnailDataReady();
|
||||
void setGoodThumbnailChecked(bool hasData);
|
||||
|
||||
[[nodiscard]] std::shared_ptr<Data::DocumentMedia> createMediaView();
|
||||
[[nodiscard]] std::shared_ptr<Data::DocumentMedia> activeMediaView();
|
||||
void setGoodThumbnailPhoto(not_null<PhotoData*> photo);
|
||||
[[nodiscard]] PhotoData *goodThumbnailPhoto() const;
|
||||
|
||||
[[nodiscard]] auto bigFileBaseCacheKey() const
|
||||
-> std::optional<Storage::Cache::Key>;
|
||||
|
@ -258,6 +266,17 @@ private:
|
|||
using Flags = base::flags<Flag>;
|
||||
friend constexpr bool is_flag_type(Flag) { return true; };
|
||||
|
||||
enum class GoodThumbnailFlag : uchar {
|
||||
Checked = 0x01,
|
||||
Generating = 0x02,
|
||||
NoData = 0x03,
|
||||
Mask = 0x03,
|
||||
|
||||
DataReady = 0x04,
|
||||
};
|
||||
using GoodThumbnailState = base::flags<GoodThumbnailFlag>;
|
||||
friend constexpr bool is_flag_type(GoodThumbnailFlag) { return true; };
|
||||
|
||||
static constexpr Flags kStreamingSupportedMask = Flags()
|
||||
| Flag::StreamingMaybeYes
|
||||
| Flag::StreamingMaybeNo;
|
||||
|
@ -272,9 +291,8 @@ private:
|
|||
|
||||
friend class Serialize::Document;
|
||||
|
||||
LocationType locationType() const;
|
||||
[[nodiscard]] LocationType locationType() const;
|
||||
void validateLottieSticker();
|
||||
void validateGoodThumbnail();
|
||||
void setMaybeSupportsStreaming(bool supports);
|
||||
void setLoadedInMediaCacheLocation();
|
||||
|
||||
|
@ -294,8 +312,9 @@ private:
|
|||
|
||||
ImagePtr _thumbnailInline;
|
||||
ImagePtr _thumbnail;
|
||||
std::unique_ptr<Image> _goodThumbnail;
|
||||
Data::ReplyPreview _replyPreview;
|
||||
std::weak_ptr<Data::DocumentMedia> _media;
|
||||
PhotoData *_goodThumbnailPhoto = nullptr;
|
||||
|
||||
not_null<Data::Session*> _owner;
|
||||
|
||||
|
@ -304,6 +323,7 @@ private:
|
|||
std::unique_ptr<DocumentAdditionalData> _additional;
|
||||
int32 _duration = -1;
|
||||
mutable Flags _flags = kStreamingSupportedUnknown;
|
||||
GoodThumbnailState _goodThumbnailState = GoodThumbnailState();
|
||||
mutable std::unique_ptr<FileLoader> _loader;
|
||||
|
||||
};
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
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 "data/data_document_media.h"
|
||||
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_good_thumbnail.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_cloud_themes.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "main/main_session.h"
|
||||
#include "lottie/lottie_animation.h"
|
||||
#include "window/themes/window_theme_preview.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "app.h"
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtGui/QImageReader>
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto kReadAreaLimit = 12'032 * 9'024;
|
||||
constexpr auto kWallPaperThumbnailLimit = 960;
|
||||
constexpr auto kMaxVideoFrameArea = 7'680 * 4'320;
|
||||
constexpr auto kGoodThumbQuality = 87;
|
||||
|
||||
enum class FileType {
|
||||
Video,
|
||||
AnimatedSticker,
|
||||
WallPaper,
|
||||
Theme,
|
||||
};
|
||||
|
||||
[[nodiscard]] bool MayHaveGoodThumbnail(not_null<DocumentData*> owner) {
|
||||
return owner->isVideoFile()
|
||||
|| owner->isAnimation()
|
||||
|| owner->isWallPaper()
|
||||
|| owner->isTheme()
|
||||
|| (owner->sticker() && owner->sticker()->animated);
|
||||
}
|
||||
|
||||
[[nodiscard]] QImage PrepareGoodThumbnail(
|
||||
const QString &path,
|
||||
QByteArray data,
|
||||
FileType type) {
|
||||
if (type == FileType::Video) {
|
||||
return ::Media::Clip::PrepareForSending(path, data).thumbnail;
|
||||
} else if (type == FileType::AnimatedSticker) {
|
||||
return Lottie::ReadThumbnail(Lottie::ReadContent(data, path));
|
||||
} else if (type == FileType::Theme) {
|
||||
return Window::Theme::GeneratePreview(data, path);
|
||||
}
|
||||
auto buffer = QBuffer(&data);
|
||||
auto file = QFile(path);
|
||||
auto device = data.isEmpty() ? static_cast<QIODevice*>(&file) : &buffer;
|
||||
auto reader = QImageReader(device);
|
||||
const auto size = reader.size();
|
||||
if (!reader.canRead()
|
||||
|| (size.width() * size.height() > kReadAreaLimit)) {
|
||||
return QImage();
|
||||
}
|
||||
auto result = reader.read();
|
||||
if (!result.width() || !result.height()) {
|
||||
return QImage();
|
||||
}
|
||||
return (result.width() > kWallPaperThumbnailLimit
|
||||
|| result.height() > kWallPaperThumbnailLimit)
|
||||
? result.scaled(
|
||||
kWallPaperThumbnailLimit,
|
||||
kWallPaperThumbnailLimit,
|
||||
Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation)
|
||||
: result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DocumentMedia::DocumentMedia(not_null<DocumentData*> owner)
|
||||
: _owner(owner) {
|
||||
}
|
||||
|
||||
DocumentMedia::~DocumentMedia() = default;
|
||||
|
||||
void DocumentMedia::goodThumbnailWanted() {
|
||||
_flags |= Flag::GoodThumbnailWanted;
|
||||
}
|
||||
|
||||
Image *DocumentMedia::goodThumbnail() const {
|
||||
Expects((_flags & Flag::GoodThumbnailWanted) != 0);
|
||||
|
||||
if (!_goodThumbnail) {
|
||||
ReadOrGenerateThumbnail(_owner);
|
||||
}
|
||||
return _goodThumbnail.get();
|
||||
}
|
||||
|
||||
void DocumentMedia::setGoodThumbnail(QImage thumbnail) {
|
||||
if (!(_flags & Flag::GoodThumbnailWanted)) {
|
||||
return;
|
||||
}
|
||||
_goodThumbnail = std::make_unique<Image>(
|
||||
std::make_unique<Images::ImageSource>(std::move(thumbnail), "PNG"));
|
||||
_owner->session().downloaderTaskFinished().notify();
|
||||
}
|
||||
|
||||
void DocumentMedia::GenerateGoodThumbnail(not_null<DocumentData*> document) {
|
||||
const auto data = document->data();
|
||||
const auto type = document->isWallPaper()
|
||||
? FileType::WallPaper
|
||||
: document->isTheme()
|
||||
? FileType::Theme
|
||||
: document->sticker()
|
||||
? FileType::AnimatedSticker
|
||||
: FileType::Video;
|
||||
auto location = document->location().isEmpty()
|
||||
? nullptr
|
||||
: std::make_unique<FileLocation>(document->location());
|
||||
if (data.isEmpty() && !location) {
|
||||
document->setGoodThumbnailChecked(false);
|
||||
return;
|
||||
}
|
||||
const auto guard = base::make_weak(&document->owner().session());
|
||||
crl::async([=, location = std::move(location)] {
|
||||
const auto filepath = (location && location->accessEnable())
|
||||
? location->name()
|
||||
: QString();
|
||||
auto result = PrepareGoodThumbnail(filepath, data, type);
|
||||
auto bytes = QByteArray();
|
||||
if (!result.isNull()) {
|
||||
auto buffer = QBuffer(&bytes);
|
||||
const auto format = (type == FileType::AnimatedSticker)
|
||||
? "WEBP"
|
||||
: (type == FileType::WallPaper && result.hasAlphaChannel())
|
||||
? "PNG"
|
||||
: "JPG";
|
||||
result.save(&buffer, format, kGoodThumbQuality);
|
||||
}
|
||||
if (!filepath.isEmpty()) {
|
||||
location->accessDisable();
|
||||
}
|
||||
const auto cache = bytes.isEmpty() ? QByteArray("(failed)") : bytes;
|
||||
crl::on_main(guard, [=] {
|
||||
document->setGoodThumbnailChecked(true);
|
||||
if (const auto active = document->activeMediaView()) {
|
||||
active->setGoodThumbnail(result);
|
||||
}
|
||||
document->owner().cache().put(
|
||||
document->goodThumbnailCacheKey(),
|
||||
Storage::Cache::Database::TaggedValue{
|
||||
base::duplicate(cache),
|
||||
kImageCacheTag });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void DocumentMedia::CheckGoodThumbnail(not_null<DocumentData*> document) {
|
||||
if (!document->goodThumbnailChecked()) {
|
||||
ReadOrGenerateThumbnail(document);
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentMedia::ReadOrGenerateThumbnail(
|
||||
not_null<DocumentData*> document) {
|
||||
if (document->goodThumbnailGenerating()
|
||||
|| document->goodThumbnailNoData()
|
||||
|| !MayHaveGoodThumbnail(document)) {
|
||||
return;
|
||||
}
|
||||
document->setGoodThumbnailGenerating();
|
||||
|
||||
const auto guard = base::make_weak(&document->session());
|
||||
const auto active = document->activeMediaView();
|
||||
const auto got = [=](QByteArray value) {
|
||||
if (value.isEmpty()) {
|
||||
crl::on_main(guard, [=] {
|
||||
GenerateGoodThumbnail(document);
|
||||
});
|
||||
} else if (active) {
|
||||
crl::async([=] {
|
||||
const auto image = App::readImage(value, nullptr, false);
|
||||
crl::on_main(guard, [=] {
|
||||
document->setGoodThumbnailChecked(true);
|
||||
if (const auto active = document->activeMediaView()) {
|
||||
active->setGoodThumbnail(image);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
crl::on_main(guard, [=] {
|
||||
document->setGoodThumbnailChecked(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
document->owner().cache().get(document->goodThumbnailCacheKey(), got);
|
||||
}
|
||||
|
||||
} // namespace Data
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/flags.h"
|
||||
|
||||
namespace Data {
|
||||
|
||||
class DocumentMedia final {
|
||||
public:
|
||||
explicit DocumentMedia(not_null<DocumentData*> owner);
|
||||
~DocumentMedia();
|
||||
|
||||
void goodThumbnailWanted();
|
||||
[[nodiscard]] Image *goodThumbnail() const;
|
||||
void setGoodThumbnail(QImage thumbnail);
|
||||
|
||||
// For DocumentData.
|
||||
void validateGoodThumbnail();
|
||||
static void CheckGoodThumbnail(not_null<DocumentData*> document);
|
||||
|
||||
private:
|
||||
enum class Flag : uchar {
|
||||
GoodThumbnailWanted = 0x01,
|
||||
};
|
||||
inline constexpr bool is_flag_type(Flag) { return true; };
|
||||
using Flags = base::flags<Flag>;
|
||||
|
||||
static void ReadOrGenerateThumbnail(not_null<DocumentData*> document);
|
||||
static void GenerateGoodThumbnail(not_null<DocumentData*> document);
|
||||
|
||||
const not_null<DocumentData*> _owner;
|
||||
std::unique_ptr<Image> _goodThumbnail;
|
||||
Flags _flags;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
|
@ -750,23 +750,6 @@ bool MediaFile::updateSentMedia(const MTPMessageMedia &media) {
|
|||
return false;
|
||||
}
|
||||
parent()->history()->owner().documentConvert(_document, *content);
|
||||
|
||||
if (const auto good = _document->goodThumbnail()) {
|
||||
auto bytes = good->bytesForCache();
|
||||
if (const auto length = bytes.size()) {
|
||||
if (length > Storage::kMaxFileInMemory) {
|
||||
LOG(("App Error: Bad thumbnail data for saving to cache."));
|
||||
} else {
|
||||
parent()->history()->owner().cache().putIfEmpty(
|
||||
_document->goodThumbnailCacheKey(),
|
||||
Storage::Cache::Database::TaggedValue(
|
||||
std::move(bytes),
|
||||
Data::kImageCacheTag));
|
||||
_document->refreshGoodThumbnail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2421,6 +2421,7 @@ void Session::documentConvert(
|
|||
}();
|
||||
const auto oldKey = original->mediaKey();
|
||||
const auto oldCacheKey = original->cacheKey();
|
||||
const auto oldGoodKey = original->goodThumbnailCacheKey();
|
||||
const auto idChanged = (original->id != id);
|
||||
const auto sentSticker = idChanged && (original->sticker() != nullptr);
|
||||
if (idChanged) {
|
||||
|
@ -2444,6 +2445,7 @@ void Session::documentConvert(
|
|||
documentApplyFields(original, data);
|
||||
if (idChanged) {
|
||||
cache().moveIfEmpty(oldCacheKey, original->cacheKey());
|
||||
cache().moveIfEmpty(oldGoodKey, original->goodThumbnailCacheKey());
|
||||
if (savedGifs().indexOf(original) >= 0) {
|
||||
Local::writeSavedGifs();
|
||||
}
|
||||
|
@ -3180,10 +3182,10 @@ void Session::unregisterPlayingVideoFile(not_null<ViewElement*> view) {
|
|||
if (i != _playingVideoFiles.end()) {
|
||||
if (!--i->second) {
|
||||
_playingVideoFiles.erase(i);
|
||||
unregisterHeavyViewPart(view);
|
||||
view->checkHeavyPart();
|
||||
}
|
||||
} else {
|
||||
unregisterHeavyViewPart(view);
|
||||
view->checkHeavyPart();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3205,7 +3207,7 @@ void Session::checkPlayingVideoFiles() {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
unregisterHeavyViewPart(view);
|
||||
view->checkHeavyPart();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -237,15 +237,7 @@ bool WebPageData::applyChanges(
|
|||
}
|
||||
|
||||
void WebPageData::replaceDocumentGoodThumbnail() {
|
||||
if (!document || !photo || !document->goodThumbnail()) {
|
||||
return;
|
||||
if (document && photo) {
|
||||
document->setGoodThumbnailPhoto(photo);
|
||||
}
|
||||
const auto &location = photo->large()->location();
|
||||
if (location.valid()) {
|
||||
document->replaceGoodThumbnail(
|
||||
std::make_unique<Images::StorageSource>(
|
||||
location,
|
||||
photo->large()->bytesSize()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace {
|
||||
|
||||
constexpr auto kScrollDateHideTimeout = 1000;
|
||||
constexpr auto kUnloadHeavyPartsPages = 1;
|
||||
constexpr auto kUnloadHeavyPartsPages = 2;
|
||||
|
||||
// Helper binary search for an item in a list that is not completely
|
||||
// above the given top of the visible area or below the given bottom of the visible area
|
||||
|
|
|
@ -606,6 +606,12 @@ auto Element::verticalRepaintRange() const -> VerticalRepaintRange {
|
|||
};
|
||||
}
|
||||
|
||||
void Element::checkHeavyPart() {
|
||||
if (_media) {
|
||||
_media->checkHeavyPart();
|
||||
}
|
||||
}
|
||||
|
||||
void Element::unloadHeavyPart() {
|
||||
if (_media) {
|
||||
_media->unloadHeavyPart();
|
||||
|
|
|
@ -261,7 +261,8 @@ public:
|
|||
};
|
||||
[[nodiscard]] virtual VerticalRepaintRange verticalRepaintRange() const;
|
||||
|
||||
virtual void unloadHeavyPart();
|
||||
void checkHeavyPart();
|
||||
void unloadHeavyPart();
|
||||
|
||||
// Legacy blocks structure.
|
||||
HistoryBlock *block();
|
||||
|
|
|
@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_streaming.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_history.h"
|
||||
|
||||
|
@ -92,6 +93,8 @@ Gif::~Gif() {
|
|||
_data->owner().streaming().keepAlive(_data);
|
||||
setStreamed(nullptr);
|
||||
}
|
||||
_dataMedia = nullptr;
|
||||
checkHeavyPart();
|
||||
}
|
||||
|
||||
QSize Gif::sizeForAspectRatio() const {
|
||||
|
@ -404,7 +407,8 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
|
|||
}
|
||||
}
|
||||
} else {
|
||||
const auto good = _data->goodThumbnail();
|
||||
ensureDataMediaCreated();
|
||||
const auto good = _dataMedia->goodThumbnail();
|
||||
if (good && good->loaded()) {
|
||||
p.drawPixmap(rthumb.topLeft(), good->pixSingle({}, _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
|
||||
} else {
|
||||
|
@ -1071,6 +1075,15 @@ TextState Gif::getStateGrouped(
|
|||
: _savel);
|
||||
}
|
||||
|
||||
void Gif::ensureDataMediaCreated() const {
|
||||
if (_dataMedia) {
|
||||
return;
|
||||
}
|
||||
_dataMedia = _data->createMediaView();
|
||||
_dataMedia->goodThumbnailWanted();
|
||||
history()->owner().registerHeavyViewPart(_parent);
|
||||
}
|
||||
|
||||
bool Gif::uploading() const {
|
||||
return _data->uploading();
|
||||
}
|
||||
|
@ -1116,7 +1129,10 @@ void Gif::validateGroupedCache(
|
|||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
using Option = Images::Option;
|
||||
const auto good = _data->goodThumbnail();
|
||||
|
||||
ensureDataMediaCreated();
|
||||
|
||||
const auto good = _dataMedia->goodThumbnail();
|
||||
const auto useGood = (good && good->loaded());
|
||||
const auto thumb = _data->thumbnail();
|
||||
const auto useThumb = (thumb && thumb->loaded());
|
||||
|
@ -1245,6 +1261,17 @@ void Gif::parentTextUpdated() {
|
|||
}
|
||||
}
|
||||
|
||||
void Gif::checkHeavyPart() {
|
||||
if (!_dataMedia && !_streamed) {
|
||||
history()->owner().unregisterHeavyViewPart(_parent);
|
||||
}
|
||||
}
|
||||
|
||||
void Gif::unloadHeavyPart() {
|
||||
stopAnimation();
|
||||
_dataMedia = nullptr;
|
||||
}
|
||||
|
||||
void Gif::refreshParentId(not_null<HistoryItem*> realParent) {
|
||||
File::refreshParentId(realParent);
|
||||
if (_parent->media() == this) {
|
||||
|
|
|
@ -15,6 +15,10 @@ struct HistoryMessageReply;
|
|||
struct HistoryMessageForwarded;
|
||||
class Painter;
|
||||
|
||||
namespace Data {
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace Media {
|
||||
namespace View {
|
||||
class PlaybackProgress;
|
||||
|
@ -100,9 +104,8 @@ public:
|
|||
|
||||
void parentTextUpdated() override;
|
||||
|
||||
void unloadHeavyPart() override {
|
||||
stopAnimation();
|
||||
}
|
||||
void checkHeavyPart() override;
|
||||
void unloadHeavyPart() override;
|
||||
|
||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||
|
||||
|
@ -113,6 +116,7 @@ private:
|
|||
bool dataFinished() const override;
|
||||
bool dataLoaded() const override;
|
||||
|
||||
void ensureDataMediaCreated() const;
|
||||
void refreshCaption();
|
||||
|
||||
[[nodiscard]] bool autoplayEnabled() const;
|
||||
|
@ -161,11 +165,12 @@ private:
|
|||
StateRequest request,
|
||||
QPoint position) const;
|
||||
|
||||
not_null<DocumentData*> _data;
|
||||
const not_null<DocumentData*> _data;
|
||||
int _thumbw = 1;
|
||||
int _thumbh = 1;
|
||||
Ui::Text::String _caption;
|
||||
std::unique_ptr<Streamed> _streamed;
|
||||
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||
|
||||
QString _downloadSize;
|
||||
|
||||
|
|
|
@ -253,6 +253,8 @@ public:
|
|||
crl::time ms) const {
|
||||
}
|
||||
|
||||
virtual void checkHeavyPart() {
|
||||
}
|
||||
virtual void unloadHeavyPart() {
|
||||
}
|
||||
|
||||
|
|
|
@ -422,6 +422,12 @@ int GroupedMedia::checkAnimationCount() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void GroupedMedia::checkHeavyPart() {
|
||||
for (auto &part : _parts) {
|
||||
part.content->checkHeavyPart();
|
||||
}
|
||||
}
|
||||
|
||||
void GroupedMedia::unloadHeavyPart() {
|
||||
for (auto &part : _parts) {
|
||||
part.content->unloadHeavyPart();
|
||||
|
|
|
@ -88,6 +88,7 @@ public:
|
|||
|
||||
void stopAnimation() override;
|
||||
int checkAnimationCount() override;
|
||||
void checkHeavyPart() override;
|
||||
void unloadHeavyPart() override;
|
||||
|
||||
void parentTextUpdated() override;
|
||||
|
|
|
@ -34,6 +34,8 @@ public:
|
|||
}
|
||||
virtual void clearStickerLoopPlayed() {
|
||||
}
|
||||
virtual void checkHeavyPart() {
|
||||
}
|
||||
virtual void unloadHeavyPart() {
|
||||
}
|
||||
virtual void refreshLink() {
|
||||
|
@ -82,6 +84,9 @@ public:
|
|||
_content->clearStickerLoopPlayed();
|
||||
}
|
||||
|
||||
void checkHeavyPart() override {
|
||||
_content->checkHeavyPart();
|
||||
}
|
||||
void unloadHeavyPart() override {
|
||||
_content->unloadHeavyPart();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h" // isGifPausedAtLeastFor.
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "lottie/lottie_single_player.h"
|
||||
#include "styles/style_history.h"
|
||||
|
@ -55,12 +56,12 @@ namespace {
|
|||
|
||||
Sticker::Sticker(
|
||||
not_null<Element*> parent,
|
||||
not_null<DocumentData*> document,
|
||||
not_null<DocumentData*> data,
|
||||
const Lottie::ColorReplacements *replacements)
|
||||
: _parent(parent)
|
||||
, _document(document)
|
||||
, _data(data)
|
||||
, _replacements(replacements) {
|
||||
_document->loadThumbnail(parent->data()->fullId());
|
||||
_data->loadThumbnail(parent->data()->fullId());
|
||||
}
|
||||
|
||||
Sticker::~Sticker() {
|
||||
|
@ -72,9 +73,9 @@ bool Sticker::isEmojiSticker() const {
|
|||
}
|
||||
|
||||
void Sticker::initSize() {
|
||||
_size = _document->dimensions;
|
||||
_size = _data->dimensions;
|
||||
if (isEmojiSticker() || _diceIndex >= 0) {
|
||||
_size = GetAnimatedEmojiSize(&_document->session(), _size);
|
||||
_size = GetAnimatedEmojiSize(&_data->session(), _size);
|
||||
[[maybe_unused]] bool result = readyToDrawLottie();
|
||||
} else {
|
||||
_size = DownscaledSize(
|
||||
|
@ -92,13 +93,13 @@ bool Sticker::readyToDrawLottie() {
|
|||
if (!_lastDiceFrame.isNull()) {
|
||||
return true;
|
||||
}
|
||||
const auto sticker = _document->sticker();
|
||||
const auto sticker = _data->sticker();
|
||||
if (!sticker) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_document->checkStickerLarge();
|
||||
const auto loaded = _document->loaded();
|
||||
_data->checkStickerLarge();
|
||||
const auto loaded = _data->loaded();
|
||||
if (sticker->animated && !_lottie && loaded) {
|
||||
setupLottie();
|
||||
}
|
||||
|
@ -123,8 +124,8 @@ QSize Sticker::GetAnimatedEmojiSize(
|
|||
void Sticker::draw(Painter &p, const QRect &r, bool selected) {
|
||||
if (readyToDrawLottie()) {
|
||||
paintLottie(p, r, selected);
|
||||
} else if (_document->sticker()
|
||||
&& (!_document->sticker()->animated || !_replacements)) {
|
||||
} else if (_data->sticker()
|
||||
&& (!_data->sticker()->animated || !_replacements)) {
|
||||
paintPixmap(p, r, selected);
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +167,7 @@ void Sticker::paintLottie(Painter &p, const QRect &r, bool selected) {
|
|||
: (_diceIndex == 0)
|
||||
? false
|
||||
: (isEmojiSticker()
|
||||
|| !_document->session().settings().loopAnimatedStickers());
|
||||
|| !_data->session().settings().loopAnimatedStickers());
|
||||
const auto count = _lottie->information().framesCount;
|
||||
_atTheEnd = (frame.index + 1 == count);
|
||||
_nextLastDiceFrame = !paused
|
||||
|
@ -197,22 +198,24 @@ void Sticker::paintPixmap(Painter &p, const QRect &r, bool selected) {
|
|||
}
|
||||
|
||||
QPixmap Sticker::paintedPixmap(bool selected) const {
|
||||
ensureDataMediaCreated();
|
||||
|
||||
const auto o = _parent->data()->fullId();
|
||||
const auto w = _size.width();
|
||||
const auto h = _size.height();
|
||||
const auto &c = st::msgStickerOverlay;
|
||||
const auto good = _document->goodThumbnail();
|
||||
const auto good = _dataMedia->goodThumbnail();
|
||||
if (good && !good->loaded()) {
|
||||
good->load({});
|
||||
}
|
||||
if (const auto image = _document->getStickerLarge()) {
|
||||
if (const auto image = _data->getStickerLarge()) {
|
||||
return selected
|
||||
? image->pixColored(o, c, w, h)
|
||||
: image->pix(o, w, h);
|
||||
//
|
||||
// Inline thumbnails can't have alpha channel.
|
||||
//
|
||||
//} else if (const auto blurred = _document->thumbnailInline()) {
|
||||
//} else if (const auto blurred = _data->thumbnailInline()) {
|
||||
// return selected
|
||||
// ? blurred->pixBlurredColored(o, c, w, h)
|
||||
// : blurred->pixBlurred(o, w, h);
|
||||
|
@ -220,7 +223,7 @@ QPixmap Sticker::paintedPixmap(bool selected) const {
|
|||
return selected
|
||||
? good->pixColored(o, c, w, h)
|
||||
: good->pix(o, w, h);
|
||||
} else if (const auto thumbnail = _document->thumbnail()) {
|
||||
} else if (const auto thumbnail = _data->thumbnail()) {
|
||||
return selected
|
||||
? thumbnail->pixBlurredColored(o, c, w, h)
|
||||
: thumbnail->pixBlurred(o, w, h);
|
||||
|
@ -232,7 +235,7 @@ void Sticker::refreshLink() {
|
|||
if (_link) {
|
||||
return;
|
||||
}
|
||||
const auto sticker = _document->sticker();
|
||||
const auto sticker = _data->sticker();
|
||||
if (isEmojiSticker()) {
|
||||
const auto weak = base::make_weak(this);
|
||||
_link = std::make_shared<LambdaClickHandler>([weak] {
|
||||
|
@ -245,12 +248,20 @@ void Sticker::refreshLink() {
|
|||
that->_parent);
|
||||
});
|
||||
} else if (sticker && sticker->set.type() != mtpc_inputStickerSetEmpty) {
|
||||
_link = std::make_shared<LambdaClickHandler>([document = _document] {
|
||||
_link = std::make_shared<LambdaClickHandler>([document = _data] {
|
||||
StickerSetBox::Show(App::wnd()->sessionController(), document);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Sticker::ensureDataMediaCreated() const {
|
||||
if (_dataMedia) {
|
||||
return;
|
||||
}
|
||||
_dataMedia = _data->createMediaView();
|
||||
_dataMedia->goodThumbnailWanted();
|
||||
}
|
||||
|
||||
void Sticker::setDiceIndex(const QString &emoji, int index) {
|
||||
_diceEmoji = emoji;
|
||||
_diceIndex = index;
|
||||
|
@ -258,7 +269,7 @@ void Sticker::setDiceIndex(const QString &emoji, int index) {
|
|||
|
||||
void Sticker::setupLottie() {
|
||||
_lottie = Stickers::LottiePlayerFromDocument(
|
||||
_document,
|
||||
_data,
|
||||
_replacements,
|
||||
Stickers::LottieSize::MessageHistory,
|
||||
_size * cIntRetinaFactor(),
|
||||
|
|
|
@ -16,6 +16,7 @@ class Session;
|
|||
|
||||
namespace Data {
|
||||
struct FileOrigin;
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace Lottie {
|
||||
|
@ -31,7 +32,7 @@ class Sticker final
|
|||
public:
|
||||
Sticker(
|
||||
not_null<Element*> parent,
|
||||
not_null<DocumentData*> document,
|
||||
not_null<DocumentData*> data,
|
||||
const Lottie::ColorReplacements *replacements = nullptr);
|
||||
~Sticker();
|
||||
|
||||
|
@ -43,7 +44,7 @@ public:
|
|||
}
|
||||
|
||||
DocumentData *document() override {
|
||||
return _document;
|
||||
return _data;
|
||||
}
|
||||
void clearStickerLoopPlayed() override {
|
||||
_lottieOncePlayed = false;
|
||||
|
@ -71,13 +72,16 @@ private:
|
|||
void paintPixmap(Painter &p, const QRect &r, bool selected);
|
||||
[[nodiscard]] QPixmap paintedPixmap(bool selected) const;
|
||||
|
||||
void ensureDataMediaCreated() const;
|
||||
|
||||
void setupLottie();
|
||||
void unloadLottie();
|
||||
|
||||
const not_null<Element*> _parent;
|
||||
const not_null<DocumentData*> _document;
|
||||
const not_null<DocumentData*> _data;
|
||||
const Lottie::ColorReplacements *_replacements = nullptr;
|
||||
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
||||
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||
ClickHandlerPtr _link;
|
||||
QSize _size;
|
||||
QImage _lastDiceFrame;
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/history_view_element.h"
|
||||
#include "history/view/history_view_cursor_state.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
|
@ -181,8 +182,11 @@ void ThemeDocument::validateThumbnail() const {
|
|||
if (_thumbnailGood > 0) {
|
||||
return;
|
||||
}
|
||||
const auto good = _data->goodThumbnail();
|
||||
if (good) {
|
||||
if (!_dataMedia) {
|
||||
_dataMedia = _data->createMediaView();
|
||||
_dataMedia->goodThumbnailWanted();
|
||||
}
|
||||
if (const auto good = _dataMedia->goodThumbnail()) {
|
||||
if (good->loaded()) {
|
||||
prepareThumbnailFrom(good, 1);
|
||||
return;
|
||||
|
|
|
@ -9,9 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "history/view/media/history_view_file.h"
|
||||
|
||||
namespace Data {
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
class ThemeDocument : public File {
|
||||
class ThemeDocument final : public File {
|
||||
public:
|
||||
ThemeDocument(
|
||||
not_null<Element*> parent,
|
||||
|
@ -54,11 +58,12 @@ private:
|
|||
void validateThumbnail() const;
|
||||
void prepareThumbnailFrom(not_null<Image*> image, int good) const;
|
||||
|
||||
not_null<DocumentData*> _data;
|
||||
const not_null<DocumentData*> _data;
|
||||
int _pixw = 1;
|
||||
int _pixh = 1;
|
||||
mutable QPixmap _thumbnail;
|
||||
mutable int _thumbnailGood = -1; // -1 inline, 0 thumbnail, 1 good
|
||||
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||
|
||||
// For wallpaper documents.
|
||||
QColor _background;
|
||||
|
|
|
@ -10,7 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "media/streaming/media_streaming_instance.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/file_download.h" // Storage::kMaxFileInMemory.
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
|
@ -192,48 +194,53 @@ void Document::waitingChange(bool waiting) {
|
|||
}
|
||||
|
||||
void Document::validateGoodThumbnail() {
|
||||
const auto good = _document->goodThumbnail();
|
||||
if (_info.video.cover.isNull()
|
||||
|| (good && good->loaded())
|
||||
|| _document->uploading()) {
|
||||
if (_info.video.cover.isNull() || _document->goodThumbnailChecked()) {
|
||||
return;
|
||||
}
|
||||
auto image = [&] {
|
||||
auto result = _info.video.cover;
|
||||
if (_info.video.rotation != 0) {
|
||||
auto transform = QTransform();
|
||||
transform.rotate(_info.video.rotation);
|
||||
result = result.transformed(transform);
|
||||
const auto document = _document;
|
||||
const auto information = _info.video;
|
||||
const auto key = document->goodThumbnailCacheKey();
|
||||
const auto guard = base::make_weak(&document->session());
|
||||
document->owner().cache().get(key, [=](QByteArray value) {
|
||||
if (!value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (result.size() != _info.video.size) {
|
||||
result = result.scaled(
|
||||
_info.video.size,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
const auto image = [&] {
|
||||
auto result = information.cover;
|
||||
if (information.rotation != 0) {
|
||||
auto transform = QTransform();
|
||||
transform.rotate(information.rotation);
|
||||
result = result.transformed(transform);
|
||||
}
|
||||
if (result.size() != information.size) {
|
||||
result = result.scaled(
|
||||
information.size,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
auto bytes = QByteArray();
|
||||
{
|
||||
auto buffer = QBuffer(&bytes);
|
||||
image.save(&buffer, "JPG", kGoodThumbnailQuality);
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
|
||||
auto bytes = QByteArray();
|
||||
{
|
||||
auto buffer = QBuffer(&bytes);
|
||||
image.save(&buffer, "JPG", kGoodThumbnailQuality);
|
||||
}
|
||||
const auto length = bytes.size();
|
||||
if (!length || length > Storage::kMaxFileInMemory) {
|
||||
LOG(("App Error: Bad thumbnail data for saving to cache."));
|
||||
} else if (_document->uploading()) {
|
||||
_document->setGoodThumbnailOnUpload(
|
||||
std::move(image),
|
||||
std::move(bytes));
|
||||
} else {
|
||||
_document->owner().cache().putIfEmpty(
|
||||
_document->goodThumbnailCacheKey(),
|
||||
Storage::Cache::Database::TaggedValue(
|
||||
std::move(bytes),
|
||||
Data::kImageCacheTag));
|
||||
_document->refreshGoodThumbnail();
|
||||
}
|
||||
const auto length = bytes.size();
|
||||
if (!length || length > Storage::kMaxFileInMemory) {
|
||||
LOG(("App Error: Bad thumbnail data for saving to cache."));
|
||||
bytes = "(failed)";
|
||||
}
|
||||
crl::on_main(guard, [=] {
|
||||
if (const auto active = document->activeMediaView()) {
|
||||
active->setGoodThumbnail(image);
|
||||
}
|
||||
document->owner().cache().putIfEmpty(
|
||||
document->goodThumbnailCacheKey(),
|
||||
Storage::Cache::Database::TaggedValue(
|
||||
base::duplicate(bytes),
|
||||
Data::kImageCacheTag));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Document::waitingCallback() {
|
||||
|
|
|
@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_user.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_media_rotation.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "window/themes/window_theme_preview.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -2177,7 +2178,8 @@ void OverlayWidget::startStreamingPlayer() {
|
|||
void OverlayWidget::initStreamingThumbnail() {
|
||||
Expects(_doc != nullptr);
|
||||
|
||||
const auto good = _doc->goodThumbnail();
|
||||
const auto media = _doc->activeMediaView();
|
||||
const auto good = media ? media->goodThumbnail() : nullptr;
|
||||
const auto useGood = (good && good->loaded());
|
||||
const auto thumb = _doc->thumbnail();
|
||||
const auto useThumb = (thumb && thumb->loaded());
|
||||
|
|
|
@ -348,6 +348,7 @@ private:
|
|||
|
||||
PhotoData *_photo = nullptr;
|
||||
DocumentData *_doc = nullptr;
|
||||
std::shared_ptr<Data::DocumentMedia> _docMedia;
|
||||
int _rotation = 0;
|
||||
std::unique_ptr<SharedMedia> _sharedMedia;
|
||||
std::optional<SharedMediaWithLastSlice> _sharedMediaData;
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "media/view/media_view_playback_progress.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_media_rotation.h"
|
||||
|
@ -806,20 +807,20 @@ void PipPanel::updateDecorations() {
|
|||
|
||||
Pip::Pip(
|
||||
not_null<Delegate*> delegate,
|
||||
not_null<DocumentData*> document,
|
||||
not_null<DocumentData*> data,
|
||||
FullMsgId contextId,
|
||||
std::shared_ptr<Streaming::Document> shared,
|
||||
FnMut<void()> closeAndContinue,
|
||||
FnMut<void()> destroy)
|
||||
: _delegate(delegate)
|
||||
, _document(document)
|
||||
, _data(data)
|
||||
, _contextId(contextId)
|
||||
, _instance(std::move(shared), [=] { waitingAnimationCallback(); })
|
||||
, _panel(
|
||||
_delegate->pipParentWidget(),
|
||||
[=](QPainter &p, const FrameRequest &request) { paint(p, request); })
|
||||
, _playbackProgress(std::make_unique<PlaybackProgress>())
|
||||
, _rotation(document->owner().mediaRotation().get(document))
|
||||
, _rotation(data->owner().mediaRotation().get(data))
|
||||
, _roundRect(ImageRoundRadius::Large, st::radialBg)
|
||||
, _closeAndContinue(std::move(closeAndContinue))
|
||||
, _destroy(std::move(destroy)) {
|
||||
|
@ -835,9 +836,10 @@ void Pip::setupPanel() {
|
|||
if (!_instance.info().video.size.isEmpty()) {
|
||||
return _instance.info().video.size;
|
||||
}
|
||||
const auto good = _document->goodThumbnail();
|
||||
const auto media = _data->activeMediaView();
|
||||
const auto good = media ? media->goodThumbnail() : nullptr;
|
||||
const auto useGood = (good && good->loaded());
|
||||
const auto original = useGood ? good->size() : _document->dimensions;
|
||||
const auto original = useGood ? good->size() : _data->dimensions;
|
||||
return original.isEmpty() ? QSize(1, 1) : original;
|
||||
}();
|
||||
_panel.setAspectRatio(FlipSizeByRotation(size, _rotation));
|
||||
|
@ -1369,11 +1371,12 @@ QImage Pip::videoFrame(const FrameRequest &request) const {
|
|||
return _instance.frame(request);
|
||||
}
|
||||
const auto &cover = _instance.info().video.cover;
|
||||
const auto good = _document->goodThumbnail();
|
||||
const auto media = _data->activeMediaView();
|
||||
const auto good = media ? media->goodThumbnail() : nullptr;
|
||||
const auto useGood = (good && good->loaded());
|
||||
const auto thumb = _document->thumbnail();
|
||||
const auto thumb = _data->thumbnail();
|
||||
const auto useThumb = (thumb && thumb->loaded());
|
||||
const auto blurred = _document->thumbnailInline();
|
||||
const auto blurred = _data->thumbnailInline();
|
||||
const auto state = !cover.isNull()
|
||||
? ThumbState::Cover
|
||||
: useGood
|
||||
|
|
|
@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
namespace Data {
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace Ui {
|
||||
class IconButton;
|
||||
template <typename Widget>
|
||||
|
@ -121,7 +125,7 @@ public:
|
|||
|
||||
Pip(
|
||||
not_null<Delegate*> delegate,
|
||||
not_null<DocumentData*> document,
|
||||
not_null<DocumentData*> data,
|
||||
FullMsgId contextId,
|
||||
std::shared_ptr<Streaming::Document> shared,
|
||||
FnMut<void()> closeAndContinue,
|
||||
|
@ -197,12 +201,13 @@ private:
|
|||
void seekFinish(float64 value);
|
||||
|
||||
const not_null<Delegate*> _delegate;
|
||||
not_null<DocumentData*> _document;
|
||||
not_null<DocumentData*> _data;
|
||||
FullMsgId _contextId;
|
||||
Streaming::Instance _instance;
|
||||
PipPanel _panel;
|
||||
QSize _size;
|
||||
std::unique_ptr<PlaybackProgress> _playbackProgress;
|
||||
std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||
|
||||
bool _showPause = false;
|
||||
bool _startPaused = false;
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_media_types.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "styles/style_overview.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "core/file_utilities.h"
|
||||
|
@ -417,13 +418,10 @@ Video::Video(
|
|||
, _duration(formatDurationText(_data->getDuration())) {
|
||||
setDocumentLinks(_data);
|
||||
_data->loadThumbnail(parent->fullId());
|
||||
if (_data->hasThumbnail() && !_data->thumbnail()->loaded()) {
|
||||
if (const auto good = _data->goodThumbnail()) {
|
||||
good->load({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Video::~Video() = default;
|
||||
|
||||
void Video::initDimensions() {
|
||||
_maxw = 2 * st::overviewPhotoMinSize;
|
||||
_minh = _maxw;
|
||||
|
@ -436,12 +434,14 @@ int32 Video::resizeGetHeight(int32 width) {
|
|||
}
|
||||
|
||||
void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
|
||||
ensureDataMediaCreated();
|
||||
|
||||
const auto selected = (selection == FullSelection);
|
||||
const auto blurred = _data->thumbnailInline();
|
||||
const auto goodLoaded = _data->goodThumbnail()
|
||||
&& _data->goodThumbnail()->loaded();
|
||||
const auto thumbLoaded = _data->hasThumbnail()
|
||||
&& _data->thumbnail()->loaded();
|
||||
const auto goodLoaded = _dataMedia->goodThumbnail()
|
||||
&& _dataMedia->goodThumbnail()->loaded();
|
||||
|
||||
bool loaded = _data->loaded(), displayLoading = _data->displayLoading();
|
||||
if (displayLoading) {
|
||||
|
@ -459,7 +459,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
|||
|| (_pixBlurred && (thumbLoaded || goodLoaded)))) {
|
||||
auto size = _width * cIntRetinaFactor();
|
||||
auto img = goodLoaded
|
||||
? _data->goodThumbnail()->original()
|
||||
? _dataMedia->goodThumbnail()->original()
|
||||
: thumbLoaded
|
||||
? _data->thumbnail()->original()
|
||||
: Images::prepareBlur(blurred->original());
|
||||
|
@ -543,6 +543,14 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
|||
paintCheckbox(p, { checkLeft, checkTop }, selected, context);
|
||||
}
|
||||
|
||||
void Video::ensureDataMediaCreated() const {
|
||||
if (_dataMedia) {
|
||||
return;
|
||||
}
|
||||
_dataMedia = _data->createMediaView();
|
||||
_dataMedia->goodThumbnailWanted();
|
||||
}
|
||||
|
||||
float64 Video::dataProgress() const {
|
||||
return _data->progress();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ struct RoundCheckbox;
|
|||
|
||||
namespace Data {
|
||||
class Media;
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace Overview {
|
||||
|
@ -220,11 +221,12 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class Video : public RadialProgressItem {
|
||||
class Video final : public RadialProgressItem {
|
||||
public:
|
||||
Video(
|
||||
not_null<HistoryItem*> parent,
|
||||
not_null<DocumentData*> video);
|
||||
~Video();
|
||||
|
||||
void initDimensions() override;
|
||||
int32 resizeGetHeight(int32 width) override;
|
||||
|
@ -240,15 +242,17 @@ protected:
|
|||
bool iconAnimated() const override;
|
||||
|
||||
private:
|
||||
void ensureDataMediaCreated() const;
|
||||
void updateStatusText();
|
||||
|
||||
not_null<DocumentData*> _data;
|
||||
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||
StatusText _status;
|
||||
|
||||
QString _duration;
|
||||
QPixmap _pix;
|
||||
bool _pixBlurred = true;
|
||||
|
||||
void updateStatusText();
|
||||
|
||||
};
|
||||
|
||||
class Voice : public RadialProgressItem {
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/localimageloader.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -193,9 +194,18 @@ void Uploader::upload(
|
|||
std::move(file->thumb));
|
||||
document->uploadingData = std::make_unique<Data::UploadState>(
|
||||
document->size);
|
||||
document->setGoodThumbnailOnUpload(
|
||||
std::move(file->goodThumbnail),
|
||||
std::move(file->goodThumbnailBytes));
|
||||
if (!file->goodThumbnail.isNull()) {
|
||||
if (const auto active = document->activeMediaView()) {
|
||||
active->setGoodThumbnail(std::move(file->goodThumbnail));
|
||||
}
|
||||
}
|
||||
if (!file->goodThumbnailBytes.isEmpty()) {
|
||||
document->owner().cache().putIfEmpty(
|
||||
document->goodThumbnailCacheKey(),
|
||||
Storage::Cache::Database::TaggedValue(
|
||||
std::move(file->goodThumbnailBytes),
|
||||
Data::kImageCacheTag));
|
||||
}
|
||||
if (!file->content.isEmpty()) {
|
||||
document->setDataAndCache(file->content);
|
||||
if (file->type == SendMediaType::ThemeFile) {
|
||||
|
|
Loading…
Reference in New Issue